Structured Output & Reasoning Ops (B8)¶
Next-Gen 40 · feature B8 · ADR 0035 · spec
design/vision/specs/B8-structured-output-reasoning-ops.md
B8 gives the gateway (B2) / engine (E2) two capabilities that everything downstream — Skipper tool calls, RAG citations, extraction — depends on:
- Structured output that is guaranteed valid against a schema.
- Reasoning ops: enforce a thinking budget, account reasoning vs output cost separately, and capture redacted, TTL'd, tenant-scoped reasoning traces.
Everything is pure Python (uses jsonschema when installed, degrades to a built-in
validator) — no LLM, engine, or provider API needed to validate, repair, budget, or account.
Structured output — validate → repair → else fail¶
from examlops.structured import generate_structured
schema = {
"type": "object",
"properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
"required": ["name", "age"],
}
obj = generate_structured(prompt, schema, generate_fn=call_model, model="llama3.1-8b")
# obj is guaranteed to validate against `schema`
The rare invalid output is repaired — scalar types coerced ("5" → 5), unknown
properties dropped, required-but-missing filled with a typed zero — and revalidated. Only if
it still fails does it raise StructuredOutputError (R2). Agent tool-call args and RAG
citations use this so their structure is never "hopefully valid" (R3).
Every attempt is metered as valid / repaired / failed, giving a structured-output
failure rate (R8).
exa gateway schema test¶
exa gateway schema test schema.json candidate.json
# Object is valid against the schema.
# ...or, on a fixable object:
# Invalid — repaired to a valid object:
# { "name": "x", "age": 5 }
Reasoning ops¶
Budget (thinking cut off at the limit)¶
from examlops.structured import ReasoningBudget
allowed, was_cut = ReasoningBudget(max_thinking_tokens=1000).enforce(5000) # (1000, True)
Separate reasoning-vs-output accounting¶
Reasoning ("thinking") tokens are often billed differently from output tokens; B8 accounts them separately for C1 telemetry and FinOps:
exa gateway reasoning account llama3.1-8b --reasoning 1000 --output 200 \
--reasoning-rate 0.001 --output-rate 0.002
# llama3.1-8b: reasoning 1000tok ($1.0) + output 200tok ($0.4) = $1.4
exa gateway reasoning stats --model llama3.1-8b
Redacted, TTL'd, tenant-scoped traces¶
Where a reasoning trace is exposed, capturing it for observability (C4) must not leak PII or retain it forever:
from examlops.structured import capture_reasoning_trace, get_reasoning_trace
capture_reasoning_trace("req-42", trace_text, tenant="acme", ttl_seconds=3600)
get_reasoning_trace("req-42") # redacted trace, or None once the TTL passes
The trace is redacted through the D8 guardrail PII redactor before storage, stamped with the tenant, and expires after its TTL (R6 / GWT-6).
Related¶
- B2 / E2 — the gateway + engine that perform constrained decoding in production.
- C1 telemetry / FinOps — the reasoning-vs-output cost split feeds both.
- C4 AgentOps — reasoning traces are captured here for session analysis.
- D8 guardrails — the PII redactor applied to traces.