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 อะไร

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