结构化输出
人看自然语言,机器看 JSON。当 Claude Code 要嵌进 CI、被脚本调用、和别的服务对接时,你需要的不是「它说了一段话」,而是「它吐了一个符合 schema 的对象」。这一页讲清楚怎么让 Claude 的输入输出都是结构化的、可程序化解析的、契约化的——这是 headless 集成的核心。
三种输出格式
Section titled “三种输出格式”--output-format 决定 Claude 怎么吐结果。三种格式从「给人看」到「给机器看」逐档升级:
# text:默认,纯文本,给人看claude -p "Explain file Header.tsx"
# json:一次性结构化对象,含 cost/session_id 等元信息claude -p "How does the data layer work?" --output-format json
# stream-json:流式逐条 JSON,每行一个事件claude -p "Build an application" --output-format stream-json| 格式 | 像什么 | 适合 |
|---|---|---|
text |
人话 | 直接给人看 |
json |
一张表 | 一次性结果,脚本解析 |
stream-json |
一条流水 | 实时追踪进度、UI 渲染 |
json 模式跑完输出一个完整对象;stream-json 模式输出多行 JSON(JSONL 格式),每行一个事件——assistant 消息、tool_use、tool_result,最后一条是带统计信息的 result。每段对话以一条 init 系统消息开场。
–json-schema:契约化输出
Section titled “–json-schema:契约化输出”「让模型随便吐 JSON 然后祈祷它符合格式」是 headless 集成最大的痛苦。--json-schema 解决这个问题——你给一个 JSON Schema,输出会被验证符合 schema 才返回,不符合就重试或报错。
claude -p "分析这个 PR 的风险点" \ --json-schema '{ "type": "object", "properties": { "risk_level": {"type": "string", "enum": ["low","medium","high"]}, "issues": {"type": "array", "items": {"type": "string"}} }, "required": ["risk_level","issues"] }'输出会是一个严格匹配 schema 的 JSON 对象:
{ "risk_level": "medium", "issues": [ "未对用户输入做 SQL 转义", "密码以明文形式记到日志" ]}这种「契约化输出」让 Claude 真正可以嵌进 CI 检查、自动分类、数据抽取这类下游需要确定结构的流程——下游代码不再需要写「如果格式不对就降级」的兜底逻辑。
两种输入格式
Section titled “两种输入格式”--input-format 决定怎么把内容喂给 Claude。
# text:默认,单次输入claude -p "解释这个函数" --input-format text
# stream-json:多轮对话,按 JSON 流喂入echo '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"Explain this code"}]}}' | \ claude -p --output-format stream-json --input-format stream-json --verbosestream-json 输入是 JSONL 格式——每行一个完整的 JSON 对象,对应一轮用户消息。这样可以多轮对话而不重启 claude 进程,也能在 Claude 处理请求时继续往里喂引导信息。
流式相关的精细化 flag
Section titled “流式相关的精细化 flag”几个 flag 让流式输出更精细:
| Flag | 作用 | 必需搭配 |
|---|---|---|
--include-partial-messages |
stream-json 里包含增量片段 | --print + --output-format stream-json |
--include-hook-events |
包含 hook 触发的事件 | --output-format stream-json |
--replay-user-messages |
在输出里回显用户消息,便于对齐对话 | --input-format stream-json + --output-format stream-json |
# 调试 hooks 时看完整事件流claude -p "跑测试" \ --output-format stream-json \ --include-hook-events | jq .
# 多轮对话回显用户消息,便于对齐claude -p \ --input-format stream-json \ --output-format stream-json \ --replay-user-messages不留痕:–no-session-persistence
Section titled “不留痕:–no-session-persistence”有些场景你不希望会话被存到磁盘——例如一次性 webhook、隐私敏感的一次性查询。--no-session-persistence 让 Claude 跑完即弃,不留 session_id,无法 --resume 接续。
claude -p --no-session-persistence "process this webhook payload"只对 print 模式有效。环境变量 CLAUDE_NO_SESSION_PERSISTENCE 在任何模式下都能起到相同作用。
适合编程式集成
Section titled “适合编程式集成”把这些 flag 组合起来,Claude Code 就是一个完全可程序化的函数:
# 1. CI 里做代码审查,输出契约化结论claude -p "审查这个 diff 的风险" \ --output-format json \ --json-schema '{"type":"object","properties":{"risk":{"type":"string"},"issues":{"type":"array","items":{"type":"string"}}}}' \ --max-budget-usd 2
# 2. 流式监控长任务,只看工具调用claude -p "重构 src/legacy 模块" \ --output-format stream-json \ --include-partial-messages | jq 'select(.type=="tool_use")'
# 3. 多轮对话脚本(输入输出都用 stream-json)echo '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"先列出所有 TODO"}]}}' | \ claude -p --input-format stream-json --output-format stream-json输出契约:JSON 响应字段
Section titled “输出契约:JSON 响应字段”--output-format json 跑完输出的对象包含这些字段(详见 Headless 模式):
| 字段 | 含义 |
|---|---|
type |
消息类型,最终结果为 result |
subtype |
子类型,success 表示成功 |
total_cost_usd |
本次花费 |
is_error |
是否出错 |
duration_ms |
总耗时 |
num_turns |
agentic 轮数 |
result |
最终回答文本 |
session_id |
会话 ID,可用于 --resume 接续 |
用 jq 把字段抠出来:
claude -p "列出所有 TODO" --output-format json | jq -r '.result'结构化输出的核心是契约:
--output-format json让 Claude 吐结构化对象,--json-schema让结构被验证,--input-format stream-json让多轮对话可程序化。这套组合把 Claude 从「会说话的助手」变成「可调用的函数」。
下一篇看 GitHub Actions,把这套 headless + 结构化输出能力嵌进 CI。🤖