Appearance
配置结构化输出后,Agent 工作流能返回匹配你定义的 JSON Schema 的验证数据,而非自由文本。通过 outputFormat(TS)或 output_format(Python)参数传入 schema 即可生效。支持 Zod(TypeScript)和 Pydantic(Python)定义 schema 以获得全类型安全对象。若验证重试超过限制,返回 error_max_structured_output_retries 而非结构数据。适合需要把代理输出直接接入应用逻辑、数据库或 UI 的场景。
Claude Code Agent SDK 结构化输出配置
结构化输出让你精确定义从 Agent 返回的数据形状。Agent 可以自由使用所需工具完成多轮任务,最终返回匹配你定义的 JSON Schema 的验证数据。定义一个 JSON Schema 描述所需的数据结构,SDK 会在 Agent 完成后验证输出,失败则重新提示。如果在重试限制内未通过验证,结果会返回错误而不是结构化数据;详见错误处理。
为了实现全类型安全,可以用 Zod(TypeScript)或 Pydantic(Python)定义 schema,获得带强类型的对象。
为什么需要结构化输出
Agent 默认返回自由格式文本,这对聊天场景适用,但当你需要程序化使用输出时就力不从心了。结构化输出给你提供类型化的数据,可以直接传给应用逻辑、数据库或 UI 组件。
以菜谱应用为例:Agent 搜索网页带回菜谱。不用结构化输出,你得到的是自由文本,需要自己解析。用结构化输出,你定义好数据形状,就能拿到类型数据直接用在应用里。
**不用结构化输出时的返回示例:** ``` Here's a classic chocolate chip cookie recipe!Chocolate Chip Cookies Prep time: 15 minutes | Cook time: 10 minutes
Ingredients:
- 2 1/4 cups all-purpose flour
- 1 cup butter, softened ...
要在应用中使用这些数据,你需要解析出标题、把"15 minutes"转成数字、分离原料和步骤,还得处理不同响应中的格式不一致。 </blockquote> <blockquote> **使用结构化输出时的返回示例:** ```json { "name": "Chocolate Chip Cookies", "prep_time_minutes": 15, "cook_time_minutes": 10, "ingredients": [ { "item": "all-purpose flour", "amount": 2.25, "unit": "cups" }, { "item": "butter, softened", "amount": 1, "unit": "cup" } ], "steps": ["Preheat oven to 375°F", "Cream butter and sugar"] }类型化的数据可以直接用在 UI 中。
快速开始
使用结构化输出,需要定义一个 JSON Schema 描述你期望的数据形状,然后通过 outputFormat(TypeScript)或 output_format(Python)参数传给 query()。Agent 完成后,结果消息的 structured_output 字段会包含验证过的数据。
下面的例子让 Agent 调研 Anthropic 并返回公司名称、成立年份和总部地址,数据格式符合定义的 schema。
typescript
import { query } from "@anthropic-ai/claude-agent-sdk";
// 定义你想拿回的数据形状
const schema = {
type: "object",
properties: {
company_name: { type: "string" },
founded_year: { type: "number" },
headquarters: { type: "string" }
},
required: ["company_name"]
};
for await (const message of query({
prompt: "Research Anthropic and provide key company information",
options: {
outputFormat: {
type: "json_schema",
schema: schema
}
}
})) {
// 结果消息包含 validated data 的 structured_output
if (message.type === "result" && message.subtype === "success" && message.structured_output) {
console.log(message.structured_output);
// { company_name: "Anthropic", founded_year: 2021, headquarters: "San Francisco, CA" }
}
}python
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
# 定义你想拿回的数据形状
schema = {
"type": "object",
"properties": {
"company_name": {"type": "string"},
"founded_year": {"type": "number"},
"headquarters": {"type": "string"},
},
"required": ["company_name"],
}
async def main():
async for message in query(
prompt="Research Anthropic and provide key company information",
options=ClaudeAgentOptions(
output_format={"type": "json_schema", "schema": schema}
),
):
# 结果消息包含 validated data 的 structured_output
if isinstance(message, ResultMessage) and message.structured_output:
print(message.structured_output)
# {'company_name': 'Anthropic', 'founded_year': 2021, 'headquarters': 'San Francisco, CA'}
asyncio.run(main())类型安全的 Schema:Zod 和 Pydantic
不手写 JSON Schema,可以用 Zod(TypeScript)或 Pydantic(Python)定义 schema。这些库会自动生成 JSON Schema,然后你可以把响应解析成全类型对象,在代码库中启用自动补全和类型检查。
下面的例子定义了一个功能实现计划 schema,包含摘要、步骤列表(每步有复杂等级)和潜在风险。Agent 规划功能后返回带类型的 FeaturePlan 对象,你可以直接用 plan.summary 和遍历 plan.steps,全程类型安全。
typescript
import { z } from "zod";
import { query } from "@anthropic-ai/claude-agent-sdk";
// 用 Zod 定义 schema
const FeaturePlan = z.object({
feature_name: z.string(),
summary: z.string(),
steps: z.array(
z.object({
step_number: z.number(),
description: z.string(),
estimated_complexity: z.enum(["low", "medium", "high"])
})
),
risks: z.array(z.string())
});
type FeaturePlan = z.infer<typeof FeaturePlan>;
// 转为 JSON Schema
const schema = z.toJSONSchema(FeaturePlan);
// 在 query 中使用
for await (const message of query({
prompt:
"Plan how to add dark mode support to a React app. Break it into implementation steps.",
options: {
outputFormat: {
type: "json_schema",
schema: schema
}
}
})) {
if (message.type === "result" && message.subtype === "success" && message.structured_output) {
// 验证并获取全类型结果
const parsed = FeaturePlan.safeParse(message.structured_output);
if (parsed.success) {
const plan: FeaturePlan = parsed.data;
console.log(`Feature: ${plan.feature_name}`);
console.log(`Summary: ${plan.summary}`);
plan.steps.forEach((step) => {
console.log(`${step.step_number}. [${step.estimated_complexity}] ${step.description}`);
});
}
}
}python
import asyncio
from pydantic import BaseModel
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
class Step(BaseModel):
step_number: int
description: str
estimated_complexity: str # 'low', 'medium', 'high'
class FeaturePlan(BaseModel):
feature_name: str
summary: str
steps: list[Step]
risks: list[str]
async def main():
async for message in query(
prompt="Plan how to add dark mode support to a React app. Break it into implementation steps.",
options=ClaudeAgentOptions(
output_format={
"type": "json_schema",
"schema": FeaturePlan.model_json_schema(),
}
),
):
if isinstance(message, ResultMessage) and message.structured_output:
# 验证并获取全类型结果
plan = FeaturePlan.model_validate(message.structured_output)
print(f"Feature: {plan.feature_name}")
print(f"Summary: {plan.summary}")
for step in plan.steps:
print(
f"{step.step_number}. [{step.estimated_complexity}] {step.description}"
)
asyncio.run(main())优势:
- 全类型推导(TypeScript)和类型提示(Python)
- 运行时验证:
safeParse()或model_validate() - 错误信息更清晰
- schema 可组合、可复用
输出格式配置项
outputFormat(TypeScript)或 output_format(Python)参数接受一个对象,包含:
type:设置为"json_schema"启用结构化输出schema:一个 JSON Schema 对象,定义输出结构。可以从 Zod schema(z.toJSONSchema())或 Pydantic 模型(.model_json_schema())生成
SDK 支持标准 JSON Schema 特性,包括所有基础类型(object、array、string、number、boolean、null)、enum、const、required、嵌套对象和 $ref 定义。完整支持列表和限制详见 JSON Schema limitations。
示例:TODO 追踪 Agent
这个示例展示结构化输出如何与多步工具调用配合。Agent 需要先在代码库中找到 TODO 注释,然后查看每个 TODO 的 git blame 信息。它自主决定使用哪些工具(Grep 搜索,Bash 执行 git 命令),然后将结果汇总为一条结构化响应。
schema 中 author 和 date 字段设为可选,因为某些文件可能没有 git blame 信息。Agent 填入能找到的信息,缺失部分省略。
typescript
import { query } from "@anthropic-ai/claude-agent-sdk";
// 定义 TODO 提取的结构
const todoSchema = {
type: "object",
properties: {
todos: {
type: "array",
items: {
type: "object",
properties: {
text: { type: "string" },
file: { type: "string" },
line: { type: "number" },
author: { type: "string" },
date: { type: "string" }
},
required: ["text", "file", "line"]
}
},
total_count: { type: "number" }
},
required: ["todos", "total_count"]
};
// Agent 使用 Grep 查找 TODO,用 Bash 获取 git blame 信息
for await (const message of query({
prompt: "Find all TODO comments in this codebase and identify who added them",
options: {
outputFormat: {
type: "json_schema",
schema: todoSchema
}
}
})) {
if (message.type === "result" && message.subtype === "success" && message.structured_output) {
const data = message.structured_output as { total_count: number; todos: Array<{ file: string; line: number; text: string; author?: string; date?: string }> };
console.log(`Found ${data.total_count} TODOs`);
data.todos.forEach((todo) => {
console.log(`${todo.file}:${todo.line} - ${todo.text}`);
if (todo.author) {
console.log(` Added by ${todo.author} on ${todo.date}`);
}
});
}
}python
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
# 定义 TODO 提取的结构
todo_schema = {
"type": "object",
"properties": {
"todos": {
"type": "array",
"items": {
"type": "object",
"properties": {
"text": {"type": "string"},
"file": {"type": "string"},
"line": {"type": "number"},
"author": {"type": "string"},
"date": {"type": "string"},
},
"required": ["text", "file", "line"],
},
},
"total_count": {"type": "number"},
},
"required": ["todos", "total_count"],
}
async def main():
# Agent 使用 Grep 查找 TODO,用 Bash 获取 git blame 信息
async for message in query(
prompt="Find all TODO comments in this codebase and identify who added them",
options=ClaudeAgentOptions(
output_format={"type": "json_schema", "schema": todo_schema}
),
):
if isinstance(message, ResultMessage) and message.structured_output:
data = message.structured_output
print(f"Found {data['total_count']} TODOs")
for todo in data["todos"]:
print(f"{todo['file']}:{todo['line']} - {todo['text']}")
if "author" in todo:
print(f" Added by {todo['author']} on {todo['date']}")
asyncio.run(main())错误处理
结构化输出生成失败的情况包括:Agent 无法生成匹配你 schema 的有效 JSON。典型原因有:schema 对当前任务过于复杂、任务本身模糊不清、Agent 在重试修正验证错误时达到限制。
当出错时,结果消息的 subtype 字段会指明原因:
subtype | 含义 |
|---|---|
success | 输出已生成并通过验证 |
error_max_structured_output_retries | Agent 多次尝试后仍无法生成有效输出 |
下面的示例检查 subtype 字段,判断输出是否成功生成,是否需要处理失败:
typescript
for await (const msg of query({
prompt: "Extract contact info from the document",
options: {
outputFormat: {
type: "json_schema",
schema: contactSchema
}
}
})) {
if (msg.type === "result") {
if (msg.subtype === "success" && msg.structured_output) {
// 使用验证过的输出
console.log(msg.structured_output);
} else if (msg.subtype === "error_max_structured_output_retries") {
// 处理失败 - 重试更简单的提示、回退到非结构化输出等
console.error("Could not produce valid output");
}
}
}python
async for message in query(
prompt="Extract contact info from the document",
options=ClaudeAgentOptions(
output_format={"type": "json_schema", "schema": contact_schema}
),
):
if isinstance(message, ResultMessage):
if message.subtype == "success" and message.structured_output:
# 使用验证过的输出
print(message.structured_output)
elif message.subtype == "error_max_structured_output_retries":
# 处理失败
print("Could not produce valid output")避免出错的技巧:
- 保持 schema 聚焦。 深度嵌套、多必填字段的 schema 更难满足。先简单,按需增加复杂度。
- 匹配 schema 与任务。 如果任务可能不包含 schema 要求的所有信息,把这些字段设为可选。
- 提示词要明确。 模糊的提示让 Agent 更难知道要输出什么。
相关资源
- JSON Schema 文档:学习用嵌套对象、数组、枚举和验证约束定义复杂 schema 的 JSON Schema 语法
- API 结构化输出:直接在 Claude API 中使用结构化输出,适用于单轮请求、无工具使用的场景
- 自定义工具:给 Agent 添加自定义工具,在返回结构化输出前调用
常见问题
结构化输出失败返回纯文本怎么办?
检查 subtype 是否为 error_max_structured_output_retries。如果是,说明 Agent 多次重试后仍无法生成符合 schema 的有效 JSON。常见原因有 schema 太复杂、任务要求的信息不全、或提示词模糊。尝试简化 schema、把必填字段改为可选、或让提示更清晰。
怎么让代理返回指定格式的 JSON 数据?
在 query() 调用时传入 outputFormat(TS)/ output_format(Python)参数,设置 type: "json_schema" 和定义好的 schema。Agent 完成多轮工具调用后,result 消息的 structured_output 字段就包含已验证的 JSON。如果使用 Zod(TS)或 Pydantic(Python),用 safeParse() 或 model_validate() 可以进一步获得全类型对象。
结构化输出支持多步工具调用吗?
支持。Agent 自主决定使用哪些工具完成多轮调用,最终返回一个符合 schema 的结构化 JSON。例如 TODO 追踪示例中,Agent 先用 Grep 搜索 TODO 注释,再用 Bash 查 git blame,最后汇总数据写入 structured_output。