Was this page helpful?
结构化输出让您可以精确定义希望从智能体获取的数据形状。智能体可以使用任何需要的工具来完成任务,最终您仍然能获得与您的 schema 匹配的经过验证的 JSON。定义一个 JSON Schema 来描述您需要的结构,SDK 会保证输出与之匹配。
要获得完整的类型安全,可以使用 Zod(TypeScript)或 Pydantic(Python)来定义您的 schema,并获取强类型对象。
智能体默认返回自由格式的文本,这对聊天来说没问题,但当您需要以编程方式使用输出时就不够了。结构化输出为您提供类型化数据,可以直接传递给应用逻辑、数据库或 UI 组件。
考虑一个食谱应用,智能体搜索网络并带回食谱。没有结构化输出时,您得到的是需要自己解析的自由格式文本。有了结构化输出,您定义想要的形状,就能获得可以直接在应用中使用的类型化数据。
要使用结构化输出,定义一个描述您想要的数据形状的 JSON Schema,然后通过 outputFormat 选项(TypeScript)或 output_format 选项(Python)将其传递给 query()。当智能体完成时,结果消息包含一个 structured_output 字段,其中包含与您的 schema 匹配的经过验证的数据。
下面的示例要求智能体研究 Anthropic 并以结构化输出的形式返回公司名称、成立年份和总部所在地。
您可以使用 Zod(TypeScript)或 Pydantic(Python)来定义 schema,而不是手动编写 JSON Schema。这些库会为您生成 JSON Schema,并让您将响应解析为完全类型化的对象,可以在整个代码库中使用自动补全和类型检查。
下面的示例定义了一个功能实现计划的 schema,包含摘要、步骤列表(每个步骤都有复杂度级别)和潜在风险。智能体规划功能并返回一个类型化的 FeaturePlan 对象。然后您可以访问 plan.summary 等属性,并以完整的类型安全遍历 plan.steps。
优势:
safeParse() 或 model_validate() 进行运行时验证outputFormat(TypeScript)或 output_format(Python)选项接受一个包含以下内容的对象:
type:设置为 "json_schema" 以使用结构化输出schema:定义输出结构的 JSON Schema 对象。您可以使用 z.toJSONSchema() 从 Zod schema 生成,或使用 .model_json_schema() 从 Pydantic 模型生成SDK 支持标准 JSON Schema 特性,包括所有基本类型(object、array、string、number、boolean、null)、enum、const、required、嵌套对象和 $ref 定义。有关支持的完整特性列表和限制,请参阅 JSON Schema 限制。
此示例演示了结构化输出如何与多步骤工具使用配合工作。智能体需要在代码库中查找 TODO 注释,然后查找每个注释的 git blame 信息。它自主决定使用哪些工具(Grep 用于搜索,Bash 用于运行 git 命令),并将结果组合成单个结构化响应。
schema 包含可选字段(author 和 date),因为 git blame 信息可能并非对所有文件都可用。智能体会填入它能找到的信息,省略其余部分。
当智能体无法生成与您的 schema 匹配的有效 JSON 时,结构化输出生成可能会失败。这通常发生在 schema 对于任务来说过于复杂、任务本身模糊不清,或者智能体在尝试修复验证错误时达到重试限制的情况下。
当发生错误时,结果消息有一个 subtype 指示出了什么问题:
| Subtype | 含义 |
|---|---|
success | 输出已成功生成并验证 |
error_max_structured_output_retries | 智能体在多次尝试后仍无法生成有效输出 |
下面的示例检查 subtype 字段以确定输出是否成功生成,或者您是否需要处理失败情况:
避免错误的技巧:
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
}
}
})) {
// 结果消息包含带有经过验证数据的 structured_output
if (message.type === 'result' && message.structured_output) {
console.log(message.structured_output)
// { company_name: "Anthropic", founded_year: 2021, headquarters: "San Francisco, CA" }
}
}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)
// 在查询中使用
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.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}`)
})
}
}
}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']
}
// 智能体使用 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.structured_output) {
const data = message.structured_output
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}`)
}
})
}
}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')
}
}
}