协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
agentsop-structured-output-picker【开发与工程】Decide where to enforce structured LM output (constrain at decode time with Outlines vs validate-and-retry with Instructor vs grammar with Guidance) and which failure stance to take (Assert/hard-fail vs Suggest/soft-retry). Use when an LM's output is parsed or typed by downstream code and you must pick one enforcement library plus its failure handlin…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
One-liner: Three local libraries (Outlines, Instructor, Guidance) plus provider-native structured outputs all "make the model emit valid structure", but they enforce at different points and fail differently. Pick by how costly a malformed output is and whether you control the decoder. Then pick the failure stance — Assert (hard-fail + retry) vs Suggest (soft nudge, degrade gracefully) — borrowed from DSPy's constraint primitives.
This is an ENHANCE overlay. The four enforcement mechanisms each have a working local skill; what no single one provides is the cross-library *which-one
[[agentsop-output-format-by-model]] — this skill assumes the
shape is already chosen and asks only how to enforce it.Activate after you have decided the output shape (via
[[agentsop-output-format-by-model]]) and the answer was "a typed/validated object", and
before you write the parsing code.
| Trigger | Signal |
|---|---|
| LM output feeds a parser | json.loads(resp) / Model.model_validate(...) is in the next line of code |
| You picked a typed shape | format-by-model said "JSON / Pydantic / typed field" — now: who enforces it? |
| Repeated parse failures | JSONDecodeError, ValidationError, truncated/extra-prose responses in logs |
| Library is already installed | outlines, instructor, or guidance is in the env and you must choose between them |
| An enum / regex / range must hold | output must be one of N labels, a valid date, a bounded int |
| You must decide failure stance | "if the model returns garbage, do I crash, retry, or accept-and-flag?" |
Anti-triggers (skip this skill):
[[agentsop-output-format-by-model]]; enforcing a JSON grammar on code is the headline
anti-pattern there (Aider 61%→20%). Enforcement strength is the wrong question
when the shape is wrong. PROMPT ──────► DECODE ──────► RAW TEXT ──────► VALIDATE ──────► TYPED OBJECT
│ │ │
│ constraint at DECODE constraint at VALIDATE
│ (grammar masks tokens) (parse, check, retry on fail)
│ │ │
ask nicely Outlines / Guidance / Instructor / DSPy Suggest /
(weakest) provider strict-mode hand-rolled retry loop
↑ ↑
CANNOT emit invalid CAN emit invalid, then
structure — masked at catches it and re-asks
the logit level with the error injected
The pick is governed by one question: how costly is a malformed output?
[[agentsop-output-format-by-model]]. Grammar-constraining code yields valid JSON
containing degraded code: enforcement cannot buy back content quality.Independent of which library, you choose what happens on a constraint violation. DSPy names the two stances [dspy-sop-skill §Constraint primitives; arxiv.org/pdf/2312.13382]:
| Stance | Behavior on violation | Use when |
|---|---|---|
| Assert (hard) | retry up to N; then raise / halt | Dev-time bug-catching; downstream cannot tolerate a bad value; correctness > availability |
| Suggest (soft) | retry with error injected; then log + continue with best effort | Production; partial result beats no result; availability > strict correctness |
Decode-time grammar (Outlines/Guidance) is itself a hard guarantee on shape — but semantic checks (range, cross-field, business rules) still need an Assert/Suggest stance layered on top.
Three ordered steps. Each presupposes [[agentsop-output-format-by-model]] already said
"typed/validated object".
malformed output cost?
│
├── cheap to recover (retry OK, strong model, rare failures)
│ └──► VALIDATE-time enforcement (weakest sufficient — prefer this)
│
├── must never escape (enum/regex/grammar is a hard contract)
│ └──► DECODE-time grammar (only if you control the decoder)
│
└── no retry budget / hard real-time / batch where 1 bad token poisons many
└──► DECODE-time grammar (or provider strict-mode if API)
Heuristic: start at the weakest layer that meets the cost constraint. Validate
| You have | Output goes to | Pick |
|---|---|---|
| Closed API model (GPT/Claude) + Pydantic schema | typed object, retries acceptable | Instructor — validate-time, Pydantic + auto-retry [[instructor]] |
| Closed API model + provider supports native | typed object, want zero extra deps | provider native structured outputs / tool_use (then Instructor or hand-parse on top) |
| Local/open weights + must guarantee JSON/regex/enum | hard contract, no retry budget | Outlines — decode-time grammar/regex/JSON-schema [[outlines]] |
| Local/open weights + interleaved gen + control flow | multi-step / fill-in-the-middle / mixed text+constrained | Guidance — decode-time + Pythonic control flow [[guidance]] |
| Any model + only semantic checks needed (shape already valid) | range / cross-field / business rules | retry loop with Assert/Suggest stance (DSPy or hand-rolled) |
| # | Task | Mechanism | Stance | Rationale / Evidence |
|---|---|---|---|---|
| 1 | Extract invoice fields from GPT-4o, retry on miss | Instructor (Pydantic + max_retries) | Suggest | API model → validate-time; auto-retry on ValidationError [[instructor]] |
| 2 | Classify into a fixed 4-label enum on a local Llama | Outlines regex/choice | Assert | enum is a hard contract; one masked decode guarantees it [[outlines]] |
| 3 | Local model must emit schema-valid JSON, no retry budget (batch) | Outlines JSON-schema | Suggest (log shape always holds) | decode-time guarantee; a bad token in a 100k batch is too costly to catch later [[outlines]] |
| 4 | Interleave reasoning text + a constrained {action, arg} block, local | Guidance (control flow + grammar) | Suggest | Guidance interleaves free text and constrained spans in one program [[guidance]] |
| 5 | Closed API, want typed output with zero new deps | provider native structured outputs / tool_use | Assert on parse | provider strict-mode guarantees schema validity (not content quality) |
| 6 | Output shape already valid; need 0 <= score <= 1 and start < end | retry loop, no grammar | Assert (dev) / Suggest (prod) | semantic, not shape — grammar can't express cross-field; needs a check + stance [dspy 2312.13382] |
| 7 | Local model, must match a date/email regex | Outlines regex | Assert | regex is a decode-time native; cheaper than parse-and-retry [[outlines]] |
| 8 | Streaming partial Pydantic objects from an API as they arrive | Instructor streaming | Suggest | Instructor streams partial validated objects [[instructor]] |
Trigger: An extraction service on GPT-4o uses Instructor with max_retries=5.
Latency p95 spiked; logs show 15% of calls retry ≥2× on the same nested schema.
Constraints:
Decision steps:
[[agentsop-output-format-by-model]]
mixed-content trap).max_retries to 2 and flip the stance to Suggest with a logged
fallback object, so a stubborn case degrades instead of inflating p95.Outcome: Don't "switch to Outlines" (impossible here). Move shape-enforcement to the provider's native layer, keep Instructor for typing, cap retries, Suggest.
Trigger: Nightly batch over a local vLLM-served model. ~0.3% of rows produce JSON that fails to parse, poisoning the downstream load.
Constraints:
Decision steps:
amount >= 0) and write violators to
a quarantine table rather than failing the batch — availability of the 99.7%
beats halting on outliers.Outcome: Decode-time Outlines grammar removes the shape failures the retry model couldn't afford to catch; a Suggest semantic check quarantines the rest.
[[agentsop-output-format-by-model]].start < end or "id exists in DB". Those need a
validate-time check + stance, regardless of how shape was enforced.[[agentsop-output-format-by-model]], not here.Where each mechanism sits on the decode vs validate axis, and what it
guarantees. Cross-link [[agentsop-output-format-by-model]] for the prior shape decision.
| Mechanism | Constraint point | Needs decoder access? | Works on closed API? | Native failure model | Best for |
|---|---|---|---|---|---|
| Outlines [[outlines]] | Decode (token mask: regex / CFG / JSON-schema) | Yes (Transformers/vLLM/llama.cpp) | No | Cannot emit invalid shape — no failure to handle for shape | Local models; hard enum/regex/JSON guarantee; batch w/o retry budget |
| Instructor [[instructor]] | Validate (parse → Pydantic → auto-retry) | No | Yes | Catches ValidationError, re-asks with error; streaming partials | API models; Pydantic typing + graceful retry |
| Guidance [[guidance]] | Decode (grammar) + interleaved control flow | Yes | No | Constrained spans can't be invalid; free spans unconstrained | Local; interleaved text + constrained blocks; multi-step programs |
| Provider native (OpenAI structured outputs / Anthropic tool_use) | Decode (provider strict-mode) | N/A (provider-side) | Yes (that provider only) | Schema-valid guaranteed; content quality not | API models; zero extra deps; tool-call args |
| DSPy Assert/Suggest [dspy 2312.13382] | Validate (assertion + backtrack) | No | Yes | Assert raises after N; Suggest logs + continues | The stance layer on top of any of the above |
DECODE-TIME VALIDATE-TIME
(guarantee shape, need logits) (catch + retry, model-agnostic)
┌─────────────┬──────────────┐ ┌──────────────┬─────────────┐
│ Outlines │ Guidance │ │ Instructor │ DSPy Assert/ │
│ (regex/CFG/ │ (grammar + │ │ (Pydantic + │ Suggest │
│ JSON-sch.) │ control flow│ │ auto-retry) │ (stance) │
└─────────────┴──────────────┘ └──────────────┴─────────────┘
┌────────────────────────────┐
│ Provider native strict-mode│ (decode-time, but provider-side; API only)
└────────────────────────────┘
How the two skills compose:
[[agentsop-output-format-by-model]] → decides the SHAPE (code? JSON? prose? typed?)
│
shape == "typed/validated object"
▼
[[agentsop-structured-output-picker]] (this) → decides ENFORCEMENT
│
Step1 strength → Step2 library → Step3 Assert/Suggest
[[agentsop-output-format-by-model]] already lists Outlines/Guidance under "grammar libs"
and provider tool_use under its §7 — it says choose the format first, then let a
lower layer enforce it. This skill is that lower layer made into a decision.
┌────────────────────────────────────────────────────────────────────┐
│ STRUCTURED-OUTPUT ENFORCEMENT CARD │
├────────────────────────────────────────────────────────────────────┤
│ 0. Shape already "typed object"? If not → [[agentsop-output-format-by-model]]│
│ 1. How costly is a malformed output? │
│ cheap to recover → VALIDATE-time (Instructor / retry) │
│ must never escape → DECODE-time grammar (need decoder access) │
│ 2. Pick library: │
│ API model + Pydantic + retry ok → Instructor │
│ API model, zero deps → provider native │
│ local + hard enum/regex/JSON → Outlines │
│ local + interleaved text+constr. → Guidance │
│ only semantic/cross-field checks → retry loop + stance │
│ 3. Failure stance: │
│ prod default → Suggest (log + continue, capped retries) │
│ dev / unrecoverable value → Assert (raise after N) │
├────────────────────────────────────────────────────────────────────┤
│ NEVER: │
│ • Bolt Outlines/Guidance onto a closed API model (no logits) │
│ • Grammar-constrain code/prose (valid JSON, degraded content) │
│ • Assume strict-mode fixes content correctness │
│ • Run an uncapped retry loop │
│ • Assert where Suggest suffices (over-rejection) │
└────────────────────────────────────────────────────────────────────┘
Source lib skills (local):
[[outlines]] — decode-time grammar/regex/JSON-schema; local models
(Transformers/vLLM/llama.cpp); ~/.claude/skills/outlines/SKILL.md.[[instructor]] — validate-time Pydantic + auto-retry + streaming partials;
OpenAI/Anthropic; ~/.claude/skills/instructor/SKILL.md.[[guidance]] — decode-time grammar + Pythonic multi-step control flow; local;
~/.claude/skills/guidance/SKILL.md.Constraint-stance source:
Assert vs Suggest — dspy-sop-skill/SKILL.md §Constraint primitives;
DSPy Assertions paper [arxiv.org/pdf/2312.13382];
[dspy.ai/learn/programming/7-assertions/].Sibling Phase-D skill (cross-link, not duplicated):
[[agentsop-output-format-by-model]] — d-output-format-by-model-skill/SKILL.md. Decides
the shape; this skill decides enforcement. Anchors the "strict-mode ≠ content
quality" and "don't grammar-constrain code" claims (Aider code-in-JSON 61%→20%).Provider docs (named, re-verify before pasting code, May 2026):
All source SKILLs read on 2026-05-20. This overlay introduces no API absent
from the sources; see references/R1-source-evidence.md.