结构化输出
使用带有解析模式的 --output-format json。
结构化输出 是 CoddyKit 上的免费 Claude Architect 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Claude Architect 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Claude Architect 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
Why Structured Output in CI/CD
When you run Claude Code inside a pipeline, a human is not reading the result — a script is. A CI job needs a stable, machine-parseable answer so it can fail the build, post a comment, or gate a merge.
Two flags make this possible:
-p(or--print) runs Claude Code non-interactively — required in any pipeline.--output-format jsonreturns a parseable result instead of free-form text.
This lesson is Domain 4 (Prompt Engineering & Structured Output) meeting Scenario 5 (Claude Code for CI/CD).
claude -p "Review the staged diff for security bugs" \
--output-format jsonThe Problem With Free-Form Text
If you let the model answer in prose, your pipeline has to scrape that prose with regexes — counting words, hunting for phrases like "looks good" or "found issues". That is brittle and a classic anti-pattern.
The same rule applies to the agentic loop: you terminate on a stop_reason, never by parsing text for words like "done". In CI, you decide pass/fail from structured fields, never from free text.
Structured output replaces fragile text-scraping with a contract your script can trust.
Adding a Schema
--output-format json gives you JSON, but plain JSON can still vary in shape. Pair it with a JSON Schema so the output always has the exact fields your pipeline expects.
A schema delivers two guarantees:
- It eliminates syntax errors — no half-formed JSON to crash your parser.
- It enforces required fields — the fields you mark required are always present.
Schema-constrained output is the same mechanism that powers tool use: tool_use + JSON Schema is how Claude returns reliable structured data.
{
"type": "object",
"properties": {
"verdict": { "type": "string", "enum": ["pass", "fail"] },
"issues": {
"type": "array",
"items": { "type": "object" }
}
},
"required": ["verdict", "issues"]
}Designing the Issue Object
Make each finding a precise object the pipeline can act on. A good review schema gives every issue a location, a severity, and an explanation — so the job can annotate the exact line.
Use an enum for severity to keep values consistent across runs. Free-text severities like "kinda bad" are unparseable.
{
"type": "object",
"properties": {
"file": { "type": "string" },
"line": { "type": "integer" },
"severity": { "type": "string",
"enum": ["blocker", "major", "minor"] },
"message": { "type": "string" }
},
"required": ["file", "severity", "message"]
}Required Fields: The Golden Rule
Mark a field required only if it is always present. This is the single most-tested structured-output rule.
If you require a field that may be absent — say line for a project-wide finding that has no specific line — the model will fabricate a value to satisfy the schema. That hallucinated line number then drives a wrong CI annotation.
In the previous scene, line was deliberately left out of required: not every issue maps to one line.
Enums + an "other" Escape Hatch
Enums keep values clean, but a rigid enum can box the model in when reality doesn't fit any category. The extensible pattern: add an "other" enum value plus a free-text detail field.
Now the model can stay in-schema for the common cases and still report the unexpected one without fabricating a wrong category.
{
"category": {
"type": "string",
"enum": ["security", "performance",
"style", "other"]
},
"category_detail": {
"type": "string",
"description": "Free text when category is 'other'"
}
}Guaranteeing Structure With tool_choice
When you call Claude through the SDK rather than the CLI, you guarantee structured output by combining a tool whose input_schema is your JSON Schema with the right tool_choice:
"auto"— the model may answer in text OR call a tool (no guarantee)."any"— the model MUST call some tool, which guarantees structured output.{"type":"tool","name":"X"}— forces one specific tool.
For a CI review where you always need the report object, force the exact tool by name.
resp = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
tools=[review_report_tool], # input_schema = your JSON Schema
tool_choice={"type": "tool", "name": "emit_review"},
messages=[{"role": "user", "content": diff_text}],
)Parsing the CI Result
In the pipeline you read the JSON, then branch on a field — never on the prose. Pull the structured payload and let the verdict decide the exit code.
Because the schema marked verdict and issues as required, this code never has to guess whether the keys exist.
import json, subprocess, sys
out = subprocess.run(
["claude", "-p", PROMPT, "--output-format", "json"],
capture_output=True, text=True,
).stdout
report = json.loads(out)
if report["verdict"] == "fail":
for i in report["issues"]:
print(f"{i['file']}:{i.get('line','-')} {i['message']}")
sys.exit(1)Validate, Then Retry With Feedback
Even with a schema, a value can be semantically wrong (a bad arithmetic total, a malformed reference). Validate the parsed object with Pydantic-style checks, and on a structural/format error use retry-with-feedback.
Send the model three things: the original input, the wrong output it produced, and the exact validation error. This fixes format, structural, and arithmetic mistakes.
Key limit: retry does NOT help when the information is simply absent from the source — no amount of re-prompting invents data that isn't there.
from pydantic import BaseModel, ValidationError
class Review(BaseModel):
verdict: str
issues: list[dict]
try:
review = Review.model_validate_json(out)
except ValidationError as e:
retry(original=diff_text, bad_output=out, error=str(e))Review in an Isolated Session
If the same conversation that generated code also reviews it, the reviewer keeps its own reasoning and won't challenge itself — same-session self-review is an anti-pattern.
Run the structured review in an isolated, fresh session. An independent instance is far better at catching real defects. This pairs naturally with structured output: a clean session in, a clean JSON report out.
Tune the prompt with explicit criteria ("flag a comment only when it contradicts the code") to minimize false positives that would block good merges.
Blocking Checks vs. Overnight Audits
A pre-merge CI gate is blocking and time-sensitive — run it synchronously with -p --output-format json. Using the Message Batches API here is wrong: batches are 50% cheaper but have no latency SLA, up to a 24h window, and don't support multi-turn tool calling.
Reserve the Batch API for non-blocking jobs — an overnight audit of the whole repo, a nightly report — where custom_id correlates each request and you re-submit only failures.
Quick Check
Apply the structured-output rules to a real pipeline decision.
Recap: Structured Output in CI/CD
Key takeaways:
- In pipelines run Claude Code with
-p(non-interactive) and--output-format jsonplus a schema; branch on fields, never on prose. - A JSON Schema eliminates syntax errors and enforces required fields.
- Mark a field required ONLY if it is always present — requiring a possibly-absent field causes fabrication.
- Use enums with an
"other"value + a detail field for extensibility. - Via the SDK,
tool_choice"any"or a forced tool guarantees structured output;"auto"does not. - Validate (Pydantic-style) and retry-with-feedback (original + wrong output + exact error) for format errors — but retries can't supply absent data.
- Review in an isolated/fresh session, not the generating one; minimize false positives with explicit criteria.
- Blocking gate = synchronous; Batch API only for non-blocking overnight jobs.
常见问题解答
「结构化输出」课时是免费的吗?
是的 — 「结构化输出」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Claude Architect 课程的其余内容,请升级到 CoddyKit PRO。 Claude Architect 课程共包含 4 节课。
「结构化输出」这节课中我会学到什么?
使用带有解析模式的 --output-format json。 你通过在浏览器中直接运行的动手代码来练习 Claude Architect,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Claude Architect 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Claude Architect 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「结构化输出」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Claude Architect 课中编写并运行代码吗?
能。每节 Claude Architect 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。