一、Model vs Agent结构化输出
二、结构化输出的 4 种策略
LangChain 的 create_agent 会自动处理结构化输出。
用户设置所需的结构化输出模式,当模型生成结构化数据时,系统会将其捕获、验证,并返回到Agent 状态中的 'structured_response'
def create_agent(
...
response_format: Union[
ToolStrategy[StructuredResponseT],
ProviderStrategy[StructuredResponseT],
type[StructuredResponseT],
None,
]
)
三、Response format
当直接传入一个 Schema 类型时,LangChain 会自动选择:
- 如果选用的模型与模型服务商支持原生结构化输出,则使用
ProviderStrategy(例如 OpenAI、Anthropic、xAI,) - 其余所有模型,一律使用
ToolStrategy****(推荐)
JSON Schema 字典必须显式包裹在策略对象(****ProviderStrategy 或 **ToolStrategy****)内,**如果直接传给 response_format,不会被自动识别
四、Provider strategy
一些模型提供商通过其API原生支持结构化输出(例如OpenAI、xAI(Grok)、Gemini、Anthropic(Claude))
class ProviderStrategy(Generic[SchemaT]):
schema: type[SchemaT]
strict: bool | None = None
The
strictparam requireslangchain>=1.2.
参数schema:必选
schema支持一下四种结构化输出定义:
- Pydantic models:继承自
BaseModel的子类,自带字段校验。返回经过校验的 Pydantic 实例对象 - Dataclasses:带类型注解的 Python 数据类。返回字典(dict)
- TypedDict:类型化字典类。返回字典(dict)
- JSON Schema:遵循 JSON Schema 规范的字典。顶层必须包含 title 和 description 两个键。返回字典(dict)
例如:
class ContactInfo(BaseModel):
"""用户的联系方式"""
name: str = Field(description="用户姓名")
email: str = Field(description="用户邮箱地址")
phone: str = Field(description="用户的手机号")
# 3.agent初始化
agent = create_agent(
model=model,
#response_format=ContactInfo # 自动选择 ProviderStrategy
response_format=ProviderStrategy(ContactInfo)
)
# 4.调用
response = agent.invoke({
"messages": [HumanMessage("从这段话中抽取结构化信息:吴老狗的邮箱地址为:wu-old-dog@qq.com,手机号:19999999999")]
})
for msg in response["messages"]:
msg.pretty_print()
五、Tool calling strategy
5.1 定义
对于不支持原生结构化输出的模型,LangChain 通过调用工具来实现相同的效果。
该方法适用于所有支持工具调用的模型(大多数现代模型)。
要使用此策略,配置一个 ToolStrategy即可
class ToolStrategy(Generic[SchemaT]):
schema: type[SchemaT]
tool_message_content: str | None
handle_errors: Union[
bool,
str,
type[Exception],
tuple[type[Exception], ...],
Callable[[Exception], str],
]
5.2 参数
(1)参数schema:必选
schema支持一下五种结构化输出定义:
- Pydantic models:继承自
BaseModel的子类,自带字段校验。返回经过校验的 Pydantic 实例对象。 - Dataclasses:带有类型注解的 Python 数据类。返回字典(dict)
- TypedDict:类型化字典类。返回字典(dict)
- JSON Schema:遵循 JSON Schema 规范的字典。顶层必须包含 title 和 description 键。返回字典(dict)
- Union types:联合类型,支持多种 Schema 选项。模型会根据上下文选择最合适的 Schema。
(2)参数handle_errors
结构化输出校验失败时的错误处理策略。默认值为 True。
True:捕获全部异常,使用内置默认错误提示模板str:捕获全部异常,使用该自定义字符串作为错误提示type[Exception]:仅捕获指定这一类异常,使用默认错误提示tuple[type[Exception], ...]:仅捕获元组内列举的多种异常,使用默认错误提示Callable[[Exception], str]:自定义回调函数,入参为异常对象,返回错误提示字符串False:不进行重试,直接向上抛出异常
5.3 案例
5.3.1 Pydantic models
from pydantic import BaseModel, Field
from typing import Literal
from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy
class ProductReview(BaseModel):
"""Analysis of a product review."""
rating: int | None = Field(description="The rating of the product", ge=1, le=5)
sentiment: Literal["positive", "negative"] = Field(description="The sentiment of the review")
key_points: list[str] = Field(description="The key points of the review. Lowercase, 1-3 words each.")
agent = create_agent(
model=model,
response_format=ToolStrategy(ProductReview)
)
result = agent.invoke({
"messages": [{"role": "user", "content": "Analyze this review: 'Great product: 5 out of 5 stars. Fast shipping, but expensive'"}]
})
rprint(result["structured_response"])
5.3.2 dataclass
5.3.3 TypedDict
5.3.4 JSON Schema
product_review_schema = {
"title": "ProductReview",
"type": "object",
"description": "Analysis of a product review.",
"properties": {
"rating": {
"type": ["integer", "null"],
"description": "The rating of the product (1-5)",
"minimum": 1,
"maximum": 5
},
"sentiment": {
"type": "string",
"enum": ["positive", "negative"],
"description": "The sentiment of the review"
},
"key_points": {
"type": "array",
"items": {"type": "string"},
"description": "The key points of the review"
}
},
"required": ["sentiment", "key_points"]
}
agent = create_agent(
model=model,
response_format=ToolStrategy(product_review_schema)
)
5.3.5 Union Types
class ProductReview(BaseModel):
"""商品评论分析结果。"""
rating: int | None = Field(description="商品的评分,取值范围1‑5分", ge=1, le=5)
sentiment: Literal["positive", "negative"] = Field(description="评论的情感倾向")
key_points: list[str] = Field(description="评论的核心要点。全部小写,每条1‑3个单词。")
class CustomerComplaint(BaseModel):
"""客户针对产品或服务提出的投诉。"""
issue_type: Literal["product", "service", "shipping", "billing"] = Field(description="问题类型")
severity: Literal["low", "medium", "high"] = Field(description="投诉严重等级")
description: str = Field(description="对投诉内容的简短描述")
agent = create_agent(
model=model,
response_format=ToolStrategy(Union[ProductReview, CustomerComplaint])
)
5.4 自定义工具的返回值
5.5 错误处理
5.5.1 多结构化输出错误处理
当model错误地调用多个结构化输出工具时,agent 会通过 ToolMessage 提供错误反馈,并提示模型重试:
class ContactInfo(BaseModel):
name: str = Field(description="人名")
email: str = Field(description="邮箱地址")
class EventDetails(BaseModel):
event_name: str = Field(description="事件名")
date: str = Field(description="事件时间")
agent = create_agent(
model=model,
# Default: handle_errors=True
response_format=ToolStrategy(Union[ContactInfo, EventDetails])
# 两种同等效果
response_format=ToolStrategy(Union[ContactInfo, EventDetails],
handle_errors = MultipleStructuredOutputsError
)
result = agent.invoke({
"messages": [{"role": "user", "content": "提取信息:吴老狗(dog@email.com)将于 3 月 15 日 在杭州举办养狗大会"}]
})
handle_errors=False,直接报错
5.5.2 处理多种异常类型
如果 handle_errors 是一个异常元组,代理仅在抛出的异常属于指定类型时才会重试(使用默认错误消息)。
在所有其他情况下,异常将被正常抛出。
class ProductRating(BaseModel):
"""商品评论分析结果。"""
rating: str | None = Field(description="评分范围 1 到 5 分", ge=1, le=5)
comment: int = Field(description="评审意见")
agent= create_agent(
model=model,
# Default: handle_errors=True
response_format = ToolStrategy(ProductRating,handle_errors = (ValueError, TypeError)
),
system_prompt="你是一个用于解析产品评论的实用助手。**不得编造任何字段和数值。**"
)
result= agent.invoke({
"messages": [{"role": "user", "content": "解析这个:很棒的产品,满分 10 分!"}]
})
六、小结
- 核心机制:
create_agent通过response_format参数接管结构化输出,最终结果统一存放在状态的structured_response字段中。 - 四种策略:
- 直接传 Schema(懒人包):LangChain 自动根据模型能力在 Provider 和 Tool 之间二选一,日常开发首选。
- ProviderStrategy(原生效能):调用模型厂商的原生 API 能力(如 OpenAI/Claude),性能和准确率最高。
- ToolStrategy(万金油):把 Schema 伪装成工具调用,兼容所有支持 Function Call 的模型。
- None(摆烂模式):不强制要求结构化,模型爱咋输出咋输出。
- Schema 定义:支持 Pydantic、Dataclass、TypedDict、JSON Schema,甚至 Union 联合类型(让模型自己判断该用哪个)。
搞懂了结构化输出,你的 Agent 才算真正“能干活”。
如果这篇干货帮你少踩了几个坑,欢迎点赞、在看、转发三连!关于结构化输出,你还有哪些想深挖的实战场景?欢迎在评论区留言交流~