前言
日常开发中调用大模型,相信大家都踩过同一个坑:
调用模型返回一大段自由文本,人看着通俗易懂,但程序根本没法直接用。
想要从中提取关键词、数据字段、业务信息,只能手写正则、字符串分割、各种暴力匹配,不仅代码臃肿,还极易因为大模型话术变化直接解析报错。
而 LangChain 为聊天模型提供的结构化输出能力,完美解决了这个痛点。
简单来说:让大模型不再随心所欲说话,严格按照我们定义好的格式返回数据,从自由字符串输出,直接升级为程序可直接使用的结构化对象,开发效率直接拉满。
一、为什么一定要用结构化输出?
在没有结构化输出之前,我们调用聊天模型的代码十分简单:
python
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4o-mini")
res = model.invoke("说说苹果公司近期动态")
print(res.content)
最终拿到手的只是一串纯文本字符串。
传统自由文本三大痛点
-
解析成本极高:想要提取公司名称、股价、发布产品等信息,必须手写大量解析逻辑
-
稳定性极差:大模型回答语序、措辞稍有改动,解析代码直接失效
-
无法对接业务:文本无法直接入库、无法直接参与后续业务逻辑判断、无法做字段校验
结构化输出核心思想
提前定义好输出字段、字段类型、字段含义,强制大模型遵循预设规则返回结果,最终直接得到字典、Pydantic 对象等程序原生可识别数据,彻底抛弃手动解析。
二、核心 API:with_structured_output
LangChain 中实现结构化输出最主流、最稳定的方式,就是 with_structured_output() 方法。
整体使用流程
-
自定义输出数据结构(Pydantic / TypedDict / JsonSchema)
-
调用模型绑定该结构,生成支持结构化输出的可运行实例
-
直接调用实例发起对话,自动返回格式化好的数据
方法核心参数详解
python
def with_structured_output(
schema: 输出结构,
method: 生成策略,
include_raw: bool = False,
strict: bool | None = None,
**kwargs
)
schema
必传参数,支持三种格式:Pydantic 模型、TypedDict、标准 JSON Schema
method
-
json_schema(默认):调用模型原生结构化输出 API,稳定性最强
-
function_calling:基于函数调用能力实现结构化返回
-
json_mode:强制返回 JSON 字符串,需自行在提示词中约束格式
include_raw
-
False 默认:只返回解析完成后的结构化数据,解析失败直接抛异常
-
True:同时返回原始模型消息、解析结果、解析异常,方便调试排错
strict
-
True:强制严格匹配结构,字段、类型缺一不可
-
False:宽松匹配,允许字段缺失
三、三种主流结构化输出实战写法
3.1 首选方案:Pydantic 模型输出(企业开发最常用)
优势:自带数据类型校验、默认值、字段描述、嵌套结构,类型提示完善,代码可读性最强,后端项目首选。
python
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
from typing import Optional, List
# 1. 定义结构化输出模型
class JokeInfo(BaseModel):
"""笑话结构化数据"""
setup: str = Field(description="笑话开头引子")
punchline: str = Field(description="笑话点睛结尾")
score: Optional[int] = Field(default=None, description="笑话评分 1-10")
# 2. 初始化模型并绑定结构
llm = ChatOpenAI(model="gpt-4o-mini")
struct_llm = llm.with_structured_output(JokeInfo)
# 3. 直接调用
result = struct_llm.invoke("讲一个唱歌相关的笑话")
print(result.setup)
print(result.punchline)
print(result.score)
支持嵌套复杂结构
日常业务中多层级数据也能轻松实现:
python
class JokeInfo(BaseModel):
setup: str
punchline: str
class JokeList(BaseModel):
theme: str
joke_list: List[JokeInfo]
struct_llm = llm.with_structured_output(JokeList)
res = struct_llm.invoke("分别讲唱歌、跳舞两个笑话")
直接拿到列表嵌套对象,业务处理无比顺畅。
3.2 轻量方案:TypedDict 字典结构化输出
适合简单字典场景,仅做类型约束,轻量无依赖,快速定义键名与类型。
python
from typing_extensions import TypedDict, Annotated
from langchain_openai import ChatOpenAI
class JokeDict(TypedDict):
setup: Annotated[str, "笑话开头"]
punchline: Annotated[str, "笑话结尾"]
score: Annotated[int | None, "笑话评分"]
llm = ChatOpenAI(model="gpt-4o-mini")
struct_llm = llm.with_structured_output(JokeDict)
res = struct_llm.invoke("讲一个搞笑小笑话")
# 直接返回标准字典
print(res["setup"])
开启 include_raw=True 可调试原始返回内容,排查格式异常问题:
python
struct_llm = llm.with_structured_output(JokeDict, include_raw=True)
返回结果包含 raw 原始消息、parsed 解析数据、parsing_error 异常信息。
3.3 通用方案:JSON Schema 结构化输出
不依赖任何 Python 实体类,直接编写标准 JSON 规则,跨语言通用,对接第三方系统十分友好。
python
from langchain_openai import ChatOpenAI
json_schema = {
"title": "JokeSchema",
"type": "object",
"properties": {
"setup": {"type": "string", "description": "笑话开头"},
"punchline": {"type": "string", "description": "笑话结尾"},
"score": {"type": "integer", "description": "评分"}
},
"required": ["setup", "punchline"]
}
llm = ChatOpenAI(model="gpt-4o-mini")
struct_llm = llm.with_structured_output(json_schema)
res = struct_llm.invoke("讲一个职场笑话")
四、灵活适配:联合类型多格式输出
实际业务中,大模型回答可能分为问答回复、数据提取、指令执行多种形式,我们可以使用联合类型统一接收不同结构返回值。
python
from typing import Union
from pydantic import BaseModel, Field
class ChatReply(BaseModel):
content: str = Field(description="日常闲聊回复")
class WeatherData(BaseModel):
city: str
weather: str
temp: str
# 统一聚合输出结构
class FinalResult(BaseModel):
output: Union[ChatReply, WeatherData]
llm = ChatOpenAI(model="gpt-4o-mini")
struct_llm = llm.with_structured_output(FinalResult)
模型会自动根据用户问题,匹配对应结构返回数据。
五、企业级实用业务场景
场景 1:万能信息提取器
结构化输出最经典用法:从长文本中精准抽取指定字段,无需分词、无需正则。
python
from langchain_core.messages import SystemMessage, HumanMessage
class PersonInfo(BaseModel):
name: str | None = Field(default=None, description="人物姓名")
hair_color: str | None = Field(default=None, description="发色")
height: str | None = Field(default=None, description="身高")
llm = ChatOpenAI(model="gpt-4o-mini")
extract_llm = llm.with_structured_output(PersonInfo)
msg = [
SystemMessage(content="仅提取文本内存在的信息,未知字段返回空"),
HumanMessage(content="汤姆身高一米七五,有着一头黑色短发")
]
res = extract_llm.invoke(msg)
短短几行代码,完成高精度信息抽取,效率远超传统文本处理方案。
场景 2:结构化输出 + 工具调用搭配使用
很多同学会直接把工具和结构化输出绑定使用,这里划重点:
with_structured_output 不会自动执行工具,仅能让模型生成工具调用指令
正确使用流程:
-
模型绑定工具,生成工具调用请求
-
代码手动执行对应工具函数
-
将工具执行结果拼接进对话上下文
-
再通过结构化输出统一整理最终结果
这种写法流程偏繁琐,正式项目中不推荐原生组合,复杂工具 + 结构化输出业务,直接使用 LangGraph Agent 一站式实现,自动完成工具调用、结果汇总、结构化格式化全流程。
六、选型建议与开发总结
-
后端正式项目:优先使用 Pydantic 结构化输出,类型安全、校验完善、维护成本最低
-
快速脚本 / 简单项目:使用 TypedDict 轻量化字典结构
-
跨语言对接 / 第三方交互:使用标准 JSON Schema
-
需要调试排错:开启 include_raw=True 查看原始返回,快速定位格式错误
-
复杂智能体、自动化流程:放弃原生组合,直接上手 LangGraph
结尾
结构化输出可以说是 LangChain 从玩具 demo 走向企业生产的核心能力之一。
彻底摆脱 "大模型回答不可控、文本解析难维护" 的历史难题,让大模型输出真正融入程序业务流程,无论是数据提取、智能表单填充、接口参数生成、知识库问答整理,都能做到简洁优雅、稳定可靠。
后续学习 LangChain 智能代理、流式输出、RAG 知识库开发时,结构化输出也会作为基础能力贯穿全程,提前吃透事半功倍。