StructuredOutput

让模型「返回 JSON」写在 prompt 里,仍常出现缺字段、多余 markdown 围栏。with_structured_output 在 ChatModel 层绑定 Pydantic 或 JSON schema,由集成包走厂商 structured output API 或解析兜底,直接得到 typed 对象。

段末注释Structured Output(结构化输出)= 将模型回复约束为固定 schema 的能力;Pydantic = Python 数据验证库,常用作 schema 定义。


1. 一句话定位

维度 内容
角色 能力层 输出约束:AIMessage → Pydantic / dict
输入 → 输出 messages → BaseModel 实例或 {raw, parsed, parsing_error}
典型调用入口 model.with_structured_output(MySchema)
与 LangGraph 节点内解析;复杂校验环可上图

2. 实现逻辑

1
2
3
4
5
6
1. class Answer(BaseModel): reason: str; score: int
2. structured_model = model.with_structured_output(Answer)
3. obj = structured_model.invoke([HumanMessage("评价...")])
4. 内部:bind response_format / tool schema → 调 API → parse → Answer
5. obj.score、obj.reason 直接用于业务
6. include_raw=True 时同时保留 AIMessage 便于调试

字段级变形

1
2
3
HumanMessage("这段代码质量如何")
→ invoke
Answer(reason="可读性好", score=8) # BaseModel 实例

3. 原理说明

3.1 method 参数

with_structured_output(schema, *, method=None, include_raw=False, **kwargs)(方法,挂在 ChatModel 上)
功能:在模型层约束输出形状,invoke 直接返回 Pydantic 实例或 dict,而不是 AIMessage。
默认值:method 视厂商(OpenAI 类常为 json_schema);include_raw=False
最小维度:schema 至少 1 个字段;invoke 输入仍是 messages,len≥1。

1
2
structured = model.with_structured_output(Sentiment, method="json_mode")
result = structured.invoke([HumanMessage("这部电影太好看了")])

methodjson_schema / function_calling / json_mode。选错会 parse 失败。

3.2 Pydantic v2

schema 用 BaseModel(数据类)
功能:字段生成 JSON Schema,description 会进提示引导模型。

约束 说明 最小维度
字段个数 少而清晰 ≥1 个 Field
Optional / Literal 支持 Literal 至少 1 个枚举值
嵌套 model 支持 每层至少 1 字段
1
2
3
4
5
from pydantic import BaseModel, Field
class Sentiment(BaseModel):
"""评论情感。"""
label: str = Field(description="只能是 positive 或 negative")
confidence: float = Field(description="0 到 1")

include_raw=True 时返回 {"raw": AIMessage, "parsed": Sentiment, "parsing_error": ...}

3.3 与 OutputParser 对比

Parser 在链尾从 字符串 抠 JSON;with_structured_output模型层 约束,成功率更高(仍非 100%)。

3.4 Agent response_format

v1 create_agent(..., response_format=MySchema) 把同一 schema 当终止条件之一。MySchema 最小仍是 ≥1 字段的 BaseModel。


4. 最小可运行示例

1
pip install -U langchain-openai pydantic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

class Sentiment(BaseModel):
"""评论情感。"""
label: str = Field(description="只能是 positive 或 negative")
confidence: float = Field(description="0 到 1 的置信度")

model = ChatOpenAI(
model="qwen3.5:9b",
api_key="ollama",
base_url="http://localhost:11434/v1",
temperature=0,
)
# 本地 Ollama 对 json_schema 支持因模型而异;json_mode 走 response_format=json
structured = model.with_structured_output(Sentiment, method="json_mode")
result = structured.invoke([HumanMessage("这部电影太好看了,强烈推荐。")])
print(type(result).__name__, result.label, result.confidence)
# 预期形态:Sentiment positive 0.x(confidence 随模型)

重要配置参数

参数(API 名) 类型 / 默认值 功能说明 作用与影响 参考起点 配置指导
schema BaseModel / dict,必填 规定 invoke 返回对象的字段与类型 字段少而清晰更稳;过复杂易幻觉/漏 required 字段带 description 枚举写进 Field(description)
method str,视厂商 用 json_schema / function_calling / json_mode 哪种约束 与模型能力不匹配则 parse 失败 json_schema 按厂商文档选;Ollama 常用 json_mode
include_raw bool,默认 False 是否同时返回原始 AIMessage True 输出变 dict(raw/parsed),便于排错 False 调试开、生产关
strict bool,部分 API 禁止 schema 外多余字段 减少脏字段;不支持则报错 True 能开就开
temperature model 上 结构化任务的采样温度 宜 0,减少 JSON 漂移 0 与 method 一起设
max_tokens model 上 防止结构化 JSON 被截断 嵌套 schema 加大;过小 parse 失败 512+ 按 schema 深度留余量

5. 易踩坑

  1. method 与模型能力不匹配:小模型不支持 json_schema,parse 报错。
  2. schema 过复杂:幻觉字段或漏 required;拆成多步或缩小 schema。
  3. 仍不校验业务规则:Pydantic 只校验类型;范围约束用 @field_validator

小结

  • with_structured_output 在模型层绑定 Pydantic/schema
  • 优先于「prompt 里写 JSON」+ StrOutputParser。
  • method / strict 依厂商选型;temperature=0 更稳。
  • Agent 可用 response_format 结束于结构化对象。

参考链接

-------------本文结束感谢您的阅读-------------