【langchain】结构化输出:ToolStrategy与ProviderStrategy
【langchain】结构化输出:ToolStrategy与ProviderStrategy
当AI开始"说人话",但你需要的是JSON
你有没有遇到过这种抓狂的场景?
让AI分析一段文本,它给你回了一大段优美的散文——“根据您提供的信息,这位客户的姓名似乎是张三,他的联系方式可能是138xxxx…”
“似乎”、“可能”、“根据您提供的信息”…这些客套话在代码里全是噪音。
你真正想要的是:
{"name": "张三", "phone": "138xxxx", "email": "zhangsan@example.com"}
就像去餐厅点餐,服务员给你念了五分钟的菜品介绍,而你只想知道价格和卡路里。
今天,我们就来聊聊LangChain 1.0如何让AI"闭嘴",直接给你结构化数据。
两种"驯服"AI的策略
LangChain 1.0提供了两种结构化输出策略,就像两种不同的话术技巧,让AI乖乖按格式输出:
| 策略 | 适用场景 | 可靠性 | 兼容性 |
|---|---|---|---|
| ProviderStrategy | OpenAI、Anthropic、Gemini等原生支持 | ⭐⭐⭐⭐⭐ | 仅限特定厂商 |
| ToolStrategy | 所有支持工具调用的模型 | ⭐⭐⭐⭐ | 通用兼容 |
ProviderStrategy:原生派的"特权"
想象你走进一家高级餐厅,服务员训练有素,你一说"按这个格式报菜名",他立刻用标准格式回复。
这就是ProviderStrategy——利用模型厂商原生的结构化输出能力。
from pydantic import BaseModel, Field
from langchain.agents import create_agent
from langchain.agents.structured_output import ProviderStrategy
class OrderSummary(BaseModel):
"""订单摘要"""
customer: str = Field(description="客户名称")
total_items: int = Field(description="商品总数")
total_amount: float = Field(description="订单总金额(美元)")
# 使用原生结构化输出
agent = create_agent(
model="openai:gpt-4o",
tools=[],
response_format=ProviderStrategy(OrderSummary),
)
result = agent.invoke({
"messages": [{"role": "user", "content": "Acme Corp买了10个Widget A($29.99)和5个Widget B($49.99)"}]
})
print(result["structured_response"])
# OrderSummary(customer='Acme Corp', total_items=15, total_amount=549.85)
优势很明显:
- ✅ 模型在生成时就强制遵循Schema,不会"跑偏"
- ✅ 支持严格模式(strict mode),使用约束解码
- ✅ 通常性能更好,延迟更低
但有个坑要注意:DeepSeek等部分国内大模型暂时不支持ProviderStrategy,会直接报400错误。
ToolStrategy:万能派的"曲线救国"
如果服务员没受过专业训练怎么办?你可以说:“请把信息填在这个表格里”——本质上是用"填表"这个工具来约束输出格式。
这就是ToolStrategy的工作原理:
from langchain.agents.structured_output import ToolStrategy
agent = create_agent(
model="deepseek-chat", # 或其他不支持原生结构化的模型
tools=[],
response_format=ToolStrategy(OrderSummary),
)
LangChain会悄悄创建一个"虚拟工具",让模型以为自己在调用工具,实际上是在生成结构化数据。
它的优势:
- ✅ 兼容所有支持工具调用的模型(几乎是全部)
- ✅ 不挑厂商,本地模型、开源模型都能用
但也有代价:
- ❌ 多了一层转换,可靠性略低于原生方案
- ❌ 需要模型支持工具调用(虽然这已经普及了)
Pydantic:你的数据"模具"
无论用哪种策略,你都需要先定义输出格式。LangChain推荐使用Pydantic模型——这就像给AI一个精确的模具,告诉它"按这个形状浇筑数据"。
基础定义
from pydantic import BaseModel, Field, EmailStr, validator
from typing import List, Optional
from enum import Enum
class Priority(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
class TaskItem(BaseModel):
"""单个任务项"""
title: str = Field(description="任务标题")
completed: bool = Field(description="是否已完成")
class TaskList(BaseModel):
"""任务清单"""
project_name: str = Field(description="项目名称")
priority: Priority = Field(description="优先级")
tasks: List[TaskItem] = Field(description="任务列表")
deadline: Optional[str] = Field(None, description="截止日期(可选)")
# 自定义验证
@validator('project_name')
def validate_name(cls, v):
if len(v) < 2:
raise ValueError("项目名称至少需要2个字符")
return v.strip()
支持的Schema类型
LangChain很灵活,你可以用多种形式定义结构:
| 类型 | 示例 | 返回结果 |
|---|---|---|
| Pydantic BaseModel | class Contact(BaseModel) |
Pydantic实例 |
| TypedDict | class Contact(TypedDict) |
字典 |
| dataclass | @dataclass class Contact |
字典 |
| JSON Schema | {"type": "object", ...} |
字典 |
推荐用Pydantic,因为它提供运行时类型验证,还能加自定义校验逻辑。
错误处理:当AI"手滑"时
即使是最先进的模型,偶尔也会"手滑"——返回不符合格式的数据。ToolStrategy提供了错误重试机制:
# 方式1:自动处理所有错误(默认)
ToolStrategy(schema=OrderSummary, handle_errors=True)
# 方式2:自定义错误提示
ToolStrategy(
schema=OrderSummary,
handle_errors="请提供完整的订单信息,包括客户名、商品数量和总金额。"
)
# 方式3:自定义错误处理函数
def my_error_handler(error: Exception) -> str:
return f"格式错误:{str(error)}。请检查数字字段是否为数值类型。"
ToolStrategy(schema=OrderSummary, handle_errors=my_error_handler)
# 方式4:不处理,直接抛出异常(调试时用)
ToolStrategy(schema=OrderSummary, handle_errors=False)
工作原理:当验证失败时,错误信息会被送回给模型,AI会尝试修正并重新输出。这就像一个自动纠错循环,直到输出符合格式或达到重试上限。

实战:智能订单解析器
让我们把学到的知识串起来,做一个实用的例子——从混乱的客户消息中提取结构化订单信息:
from pydantic import BaseModel, Field
from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy, ProviderStrategy
from langchain.chat_models import init_chat_model
class LineItem(BaseModel):
"""订单行项目"""
product_name: str = Field(description="产品名称")
quantity: int = Field(description="数量", ge=1)
unit_price: float = Field(description="单价", gt=0)
class CustomerOrder(BaseModel):
"""客户订单"""
customer_name: str = Field(description="客户姓名")
items: List[LineItem] = Field(description="订单项目")
notes: Optional[str] = Field(None, description="特殊备注")
@property
def total(self) -> float:
return sum(item.quantity * item.unit_price for item in self.items)
# 初始化模型
model = init_chat_model("openai:gpt-4o-mini")
# 策略选择:优先ProviderStrategy,不支持则回退到ToolStrategy
try:
response_format = ProviderStrategy(CustomerOrder, strict=True)
except:
response_format = ToolStrategy(
CustomerOrder,
handle_errors="请确保所有数字字段正确填写。"
)
agent = create_agent(
model=model,
tools=[],
response_format=response_format,
)
# 模拟一条混乱的客户消息
messy_message = """
嗨,我是李明,想订点东西。
需要3个无线耳机,每个299元,
再加2个充电宝,单价150吧。
对了,希望能尽快发货,急用!
"""
result = agent.invoke({
"messages": [{"role": "user", "content": messy_message}]
})
order = result["structured_response"]
print(f"客户:{order.customer_name}")
print(f"总计:¥{order.total:.2f}")
print(f"商品数:{len(order.items)}件")
# 输出:
# 客户:李明
# 总计:¥1197.00
# 商品数:2件
关键细节:
- 结果存储在
result["structured_response"]中 - 这是一个已验证的Pydantic实例,可以直接访问属性
- 如果启用了错误处理,验证失败会自动触发重试
策略选择决策树
面对不同场景,该如何选择?记住这个简单的决策流程:
模型是否支持原生结构化输出?
├─ 是(OpenAI GPT-4o、Anthropic Claude等)
│ └─ 使用 ProviderStrategy(strict=True) 获得最佳可靠性
│
└─ 否(DeepSeek、部分开源模型等)
└─ 使用 ToolStrategy(handle_errors=True) 保证兼容性
懒人版:直接传Pydantic类,让LangChain自动选择:
# LangChain会自动检测模型能力,选择最优策略
agent = create_agent(
model=model,
tools=[],
response_format=CustomerOrder, # 直接传Schema
)
但要注意:LangChain 1.0之后,显式使用Strategy是推荐做法,自动选择可能在某些边缘情况下表现不稳定。
生产环境 checklist
在把结构化输出部署到生产环境前,检查这几项:
✅ Schema版本化:业务变动时,保留旧版本Schema以保证兼容性
✅ 错误监控:记录验证失败率,如果过高可能需要调整Prompt或Schema
✅ 超时设置:重试机制会增加延迟,设置合理的超时时间
✅ 敏感信息:不要在Schema中定义包含PII(个人身份信息)的字段描述
小结
今天我们学习了如何让AI"说机器能听懂的话":
- ProviderStrategy 是"VIP通道",利用模型原生能力,可靠性最高但兼容性有限
- ToolStrategy 是"万能钥匙",通过工具调用实现,兼容所有支持工具调用的模型
- Pydantic 是你的"数据模具",定义清晰的结构并自动验证
- 错误重试 是安全网,让AI有机会自我修正
结构化输出不只是技术细节,它是AI从"玩具"走向"工具"的关键一步。当你的应用能稳定地从AI输出中提取结构化数据时,自动化流程、数据分析、系统集成才能真正落地。
下一篇,我们将聊聊流式处理——如何让AI的响应像打字机一样实时呈现,而不是让用户盯着"思考中…"的转圈图标发呆。

关注公众号【dev派】,发送 “agent” 获取全部源码和模板
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)