Skip to main content

รับ structured output จาก agents

คืนค่า JSON ที่ผ่านการตรวจสอบความถูกต้องจาก agent workflows โดยใช้ JSON Schema, Zod, หรือ Pydantic รับข้อมูลที่ type-safe และมีโครงสร้างหลังจาก multi-turn tool use

Structured outputs ช่วยให้คุณกำหนดรูปร่างที่แน่นอนของข้อมูลที่คุณต้องการจาก agent agent สามารถใช้ tools ใดก็ได้ที่ต้องการเพื่อทำงานให้เสร็จ และคุณยังได้รับ JSON ที่ผ่านการตรวจสอบที่ตรงกับ schema ของคุณในตอนท้าย กำหนด JSON Schema สำหรับโครงสร้างที่คุณต้องการ และ SDK จะตรวจสอบ output กับมัน โดย re-prompt เมื่อไม่ตรงกัน

สำหรับ type safety เต็มรูปแบบ ให้ใช้ Zod (TypeScript) หรือ Pydantic (Python) เพื่อกำหนด schema ของคุณและรับ objects ที่มี strong type กลับมา

ทำไมต้องใช้ Structured Outputs?​

Agents คืนค่า free-form text โดยค่าเริ่มต้น ซึ่งทำงานได้สำหรับ chat แต่ไม่ใช่เมื่อคุณต้องการใช้ output แบบ programmatic Structured outputs ให้ข้อมูลที่มี type ที่คุณสามารถส่งโดยตรงไปยัง application logic, database, หรือ UI components ของคุณ

ลองพิจารณาแอปสูตรอาหารที่ agent ค้นหาเว็บและนำสูตรอาหารกลับมา โดยไม่มี structured outputs คุณจะได้ free-form text ที่คุณต้องการ parse เอง ด้วย structured outputs คุณกำหนดรูปร่างที่คุณต้องการและรับข้อมูลที่มี type ที่คุณสามารถใช้โดยตรงในแอปของคุณ

ตัวอย่างเปรียบเทียบ:

โดยไม่มี structured outputs:

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
...

ด้วย structured outputs:

{
"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"]
}

Quick Start​

หากต้องการใช้ structured outputs ให้กำหนด JSON Schema ที่อธิบายรูปร่างของข้อมูลที่คุณต้องการ จากนั้นส่งไปที่ query() ผ่าน option outputFormat (TypeScript) หรือ output_format (Python) เมื่อ agent เสร็จสิ้น result message จะมี field structured_output พร้อมข้อมูลที่ผ่านการตรวจสอบที่ตรงกับ schema ของคุณ

import { query } from "@anthropic-ai/claude-agent-sdk";

// Define the shape of data you want back
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
}
}
})) {
// The result message contains structured_output with validated data
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" }
}
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

# Define the shape of data you want back
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}
),
):
# The result message contains structured_output with validated data
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())

Type-safe Schemas ด้วย Zod และ Pydantic​

แทนที่จะเขียน JSON Schema ด้วยตนเอง คุณสามารถใช้ Zod (TypeScript) หรือ Pydantic (Python) เพื่อกำหนด schema ของคุณ library เหล่านี้สร้าง JSON Schema ให้คุณและให้คุณ parse response เป็น object ที่มี type เต็มรูปแบบ

import { z } from "zod";
import { query } from "@anthropic-ai/claude-agent-sdk";

// Define schema with Zod
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>;

// Convert to JSON Schema
const schema = z.toJSONSchema(FeaturePlan);

// Use in 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) {
// Validate and get fully typed result
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 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:
# Validate and get fully typed result
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())

ประโยชน์:

  • Type inference เต็มรูปแบบ (TypeScript) และ type hints (Python)
  • Runtime validation ด้วย safeParse() หรือ model_validate()
  • Error messages ที่ดีกว่า
  • Schemas ที่ composable และ reusable

การ Configure Output Format​

Option outputFormat (TypeScript) หรือ output_format (Python) รับ object ที่มี:

  • type: ตั้งค่าเป็น "json_schema" สำหรับ structured outputs
  • schema: object JSON Schema ที่กำหนดโครงสร้าง output ของคุณ คุณสามารถสร้างจาก Zod schema ด้วย z.toJSONSchema() หรือ Pydantic model ด้วย .model_json_schema()

SDK รองรับฟีเจอร์ JSON Schema มาตรฐานรวมถึงทุก basic types (object, array, string, number, boolean, null), enum, const, required, nested objects, และ $ref definitions

ตัวอย่าง: TODO Tracking Agent​

ตัวอย่างนี้แสดงให้เห็นวิธีที่ structured outputs ทำงานกับ multi-step tool use Agent ต้องค้นหา TODO comments ใน codebase จากนั้นค้นหาข้อมูล git blame สำหรับแต่ละรายการ Agent จะตัดสินใจเองว่าจะใช้ tools ใด (Grep เพื่อค้นหา, Bash เพื่อรัน git commands) และรวมผลลัพธ์เป็น response ที่มีโครงสร้างเดียว

import { query } from "@anthropic-ai/claude-agent-sdk";

// Define structure for TODO extraction
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 uses Grep to find TODOs, Bash to get git blame info
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}`);
}
});
}
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

# Define structure for TODO extraction
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 uses Grep to find TODOs, Bash to get git blame info
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())

การจัดการข้อผิดพลาด​

การสร้าง structured output อาจล้มเหลวเมื่อ agent ไม่สามารถสร้าง JSON ที่ตรงกับ schema ของคุณได้ ซึ่งมักเกิดขึ้นเมื่อ schema ซับซ้อนเกินไปสำหรับงาน, งานเองไม่ชัดเจน, หรือ agent ถึงขีดจำกัดการลองใหม่

Subtypeความหมาย
successOutput ถูกสร้างและตรวจสอบความถูกต้องสำเร็จ
error_max_structured_output_retriesไม่มี output ที่ถูกต้องรอดผ่านหลังจากหลายครั้งที่พยายาม
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) {
// Use the validated output
console.log(msg.structured_output);
} else if (msg.subtype === "error_max_structured_output_retries") {
// Handle the failure - retry with simpler prompt, fall back to unstructured, etc.
console.error("Could not produce valid output");
}
}
}
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:
# Use the validated output
print(message.structured_output)
elif message.subtype == "error_max_structured_output_retries":
# Handle the failure
print("Could not produce valid output")

เคล็ดลับในการหลีกเลี่ยงข้อผิดพลาด:

  • รักษา schemas ให้เน้นเรื่องเดียว Schemas ที่ซ้อนกันลึกพร้อม fields บังคับมากมายนั้นยากที่จะตอบสนอง เริ่มแบบง่ายและเพิ่มความซับซ้อนตามที่จำเป็น
  • จับคู่ schema กับงาน หากงานอาจไม่มีข้อมูลทั้งหมดที่ schema ของคุณต้องการ ให้ทำให้ fields เหล่านั้นเป็น optional
  • ใช้ prompts ที่ชัดเจน Prompts ที่คลุมเครือทำให้ agent ยากที่จะรู้ว่าจะสร้าง output อะไร

แหล่งข้อมูลที่เกี่ยวข้อง​