🌟 LangChain 30 天保姆级教程 · Day 13|OutputParser 进阶!让 AI 输出自动转为结构化对象,并支持自动重试!

39 阅读4分钟

系列目标:30 天从 LangChain 入门到企业级部署
今日任务:掌握 PydanticOutputParser + RetryOutputParser → 构建高可靠结构化输出链 → 让 Agent 返回标准 JSON 对象!


🎯 一、为什么需要“带重试的结构化输出”?

在 Day 6 中,我们用 PydanticOutputParser 让 AI 输出合法 JSON。
但现实是:即使加了格式指令,大模型偶尔仍会“跑偏”

  • 多了 Markdown 代码块(```json)
  • 字段名拼错("user_name" 写成 "username")
  • 返回一段解释文字而非纯 JSON

如果直接解析,程序会崩溃 ❌。

解决方案

✅ RetryOutputParser + PydanticOutputParser = 自动重试 + 自动修复

LangChain 会在解析失败时,自动把错误信息反馈给 LLM,让它重新生成,直到成功或达到最大重试次数。


🧱 二、核心组件介绍

表格

组件作用
PydanticOutputParser定义期望结构 + 生成格式指令 + 解析输出
RetryOutputParser包装 parser,支持自动重试
RunnableParallel / LCEL将 parser 集成到 Chain 或 Agent 中

💡 今天我们将构建一个“用户意图识别器”,要求 AI 从自然语言中提取:

class UserIntent(BaseModel):
    action: Literal["order", "refund", "inquiry"]
    product: str
    confidence: float  # 0.0 ~ 1.0

🛠️ 三、动手实践:构建带自动重试的结构化输出链

步骤 1:定义 Pydantic 模型

# day13_retry_output_parser.py
from langchain_ollama import ChatOllama
from langchain_core.pydantic_v1 import BaseModel, Field, Literal
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains import LLMChain

class UserIntent(BaseModel):
    action: Literal["order", "refund", "inquiry"] = Field(
        description="用户意图:下单(order)、退货(refund)、咨询(inquiry)"
    )
    product: str = Field(description="涉及的产品名称")
    confidence: float = Field(ge=0.0, le=1.0, description="置信度,0.0~1.0")

步骤 2:创建带重试的 OutputParser

python

编辑

# 创建基础 parser
base_parser = PydanticOutputParser(pydantic_object=UserIntent)

# 创建支持重试的 parser
retry_parser = base_parser.with_retry(retries=3)  # 自动重试 3 次

🔑 with_retry() 是 LangChain 0.1+ 提供的便捷方法,内部使用 RetryOutputParser


步骤 3:构建 Prompt(关键:插入格式指令)

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个用户意图分析器。"),
    ("human", "请分析以下用户语句的意图:\n{input}\n\n{format_instructions}")
]).partial(format_instructions=retry_parser.get_format_instructions())

💡 retry_parser.get_format_instructions() 会返回清晰的 JSON 格式示例。


步骤 4:组装 Chain 并测试

llm = ChatOllama(model="qwen:7b", temperature=0)

# 使用 LCEL 构建链:prompt → llm → retry_parser
chain = prompt | llm | retry_parser

# 测试用例(故意模糊)
test_inputs = [
    "我想买一副无线耳机",
    "这个手机我不想要了,怎么退?",
    "你们客服电话多少?"  # 不涉及产品,考验鲁棒性
]

for inp in test_inputs:
    print(f"\n👤 用户:{inp}")
    try:
        result = chain.invoke({"input": inp})
        print(f"✅ 成功!action={result.action}, product={result.product}, confidence={result.confidence:.2f}")
    except Exception as e:
        print(f"❌ 最终失败:{e}")

▶️ 成功输出示例:

👤 用户:这个手机我不想要了,怎么退?
✅ 成功!action=refund, product=手机, confidence=0.95

✅ 即使第一次输出格式错误,LangChain 也会自动重试,直到成功!


🤖 四、进阶:让 Agent 也返回结构化对象

Agent 默认返回自由文本,但我们希望它最终输出一个标准对象

from langchain.agents import Tool, AgentExecutor, create_react_agent

# 假设有一个工具
@tool
def dummy_tool(query: str) -> str:
    return "已完成操作"

tools = [dummy_tool]
llm = ChatOllama(model="qwen:7b", temperature=0)

# 创建普通 Agent
agent = create_react_agent(llm, tools, create_react_agent.get_default_prompt())
executor = AgentExecutor(agent=agent, tools=tools, verbose=False)

# 现在,我们想让整个 Agent 的最终输出是结构化的!
# 方案:在 executor 后接一个 parser

final_chain = executor | retry_parser

# 调用(注意:Agent 输入是 {"input": "..."},输出是 {"output": "..."})
try:
    result = final_chain.invoke({"input": "帮我查一下订单状态"})
    print("Agent 结构化结果:", result)
except Exception as e:
    print("解析失败:", e)

⚠️ 注意:Agent 的原始输出是字符串,需确保其内容符合 parser 要求。
更佳实践:在 Agent 的 system prompt 中强调“最终回答必须是合法 JSON”。


⚠️ 五、注意事项 & 最佳实践

表格

问题建议
重试后仍失败检查 prompt 是否足够清晰;降低 temperature
中文模型忽略格式在 system prompt 中强调:“只返回 JSON,不要任何其他文字”
字段缺失在 Pydantic 模型中标记为必填(默认就是)
性能敏感场景设置 retries=1 或 0,避免延迟过高
需要兼容旧系统可将 parser 输出转为 dict:result.dict()

💡 生产建议
所有对外 AI 接口都应使用带重试的结构化输出,避免脏数据进入下游系统!


📦 六、配套代码结构

langchain-30-days/
└── day13/
    ├── structured_output_with_retry.py   # 带重试的结构化输出链
    └── agent_with_structured_output.py   # Agent 返回结构化对象(进阶)

📝 七、今日小结

  • ✅ 理解了结构化输出在生产环境中的必要性
  • ✅ 学会了用 with_retry() 实现自动重试
  • ✅ 构建了高可靠的用户意图识别器
  • ✅ 掌握了将结构化输出集成到 Agent 的方法
  • ✅ 知道了如何平衡可靠性与性能

🎯 明日预告:Day 14 —— Callback 机制!监听 Chain/Agent 的每一步,实现日志、监控、审计!