文章目录
- 一、结构化输出概述
- 什么是结构化输出
- 核心价值
- Pydantic 等结构化方案的好处
- 结构化输出模式
- 二、四种模式的使用
- 模式1:Pydantic(推荐)
- 基本使用
- 举例1:
- 举例2
- 高级特性
- 情况1:可选字段
- 情况2:默认值
- 情况3:枚举类型
- 情况4:列表提取
- 情况5:嵌套结构
- 情况6:限制条件
- 工作流程图解
- 模式2:TypedDict
- 什么是 TypedDict
- 基本使用
- 模式3:JSON Schema(不推荐)
- 模式4:@dataclass
- 三、关于类型校验
- 四、获取结构化结果方式
- 使用with_structured_output
- 使用输出解析器(不推荐)
- 参考视频
一、结构化输出概述
什么是结构化输出
要求模型最终返回一个符合预定义结构的数据对象,例如固定字段的JSON、Pydantic 模型、TypedDict,而不再是无格式的自然语言文本。
它的核心目标是把“ 自然语言回答 ”变成“ 程序可以稳定消费的数据 ”。
核心价值
- 更容易被代码处理:下游系统可以直接读字段,而不是再从自然语言里做解析。
- 结果更稳定:减少“模型说法变了但意思差不多”导致的解析失败。
- 更适合工程化:适用于表单抽取、分类、路由、调用工具参数生成、工作流状态传递等场景。
Pydantic 等结构化方案的好处
- Prompt 变干净了: 字段的 description 直接充当了 Prompt 的一部分。
- 类型安全: 编辑器能自动补全,代码运行前就能做类型检查。
- 极其稳定: 依托大模型厂商底层的 JSON 模式,输出错误率降到了极低。
结构化输出模式
目前LangChain 1.x 支持多种Schema与结构化输出方式:
- Pydantic(字段校验、描述、嵌套结构,功能最丰富)
- TypedDict(轻量类型约束)
- JSON Schema(与前后端/跨语言接口最通用)
- dataclass
模型对象可以调用 with_structured_output() 绑定输出模式(schema)。
只有 Pydantic 返回的是Schema类实例,其余三种方式返回的都是 字典 ;也只有 Pydantic 在类型不匹配时会抛出异常。
二、四种模式的使用
模式1:Pydantic(推荐)
它通过在运行时强制执行类型提示,确保数据的正确性和一致性,是生产场景首选 。
基本使用
需要满足的几个要素:
- 所有结构化输出的数据模型都必须继承 BaseModel
- 使用 类型提示 。Pydantic 支持丰富的字段类型:str 、int、float、List[xxx]、Optional[xxx]等
- 使用 Field() 添加字段默认值和描述,帮助 LLM 理解字段含义
举例1:
fromlangchain.messagesimportHumanMessagefromlangchain_core.toolsimporttoolfromlangchain.chat_modelsimportinit_chat_modelfromdotenvimportload_dotenvimportosfrompydanticimportBaseModel,Fieldfromtraitlets.utils.descriptionsimportdescribe load_dotenv(override=True)DASHSCOPE_API_KEY=os.getenv("DASHSCOPE_API_KEY")DASHSCOPE_BASE_URL=os.getenv("DASHSCOPE_BASE_URL")model=init_chat_model(model="openai:qwen-plus",# 底层调用的是ChatOpenAIapi_key=DASHSCOPE_API_KEY,base_url=DASHSCOPE_BASE_URL)# 定义 Pydantic 模型classPerson(BaseModel):"""人物信息"""name:str=Field(description="姓名")age:int=Field(description="年龄")occupation:str=Field(description="职业")# 使用 with_structured_output 即可引导模型进行结构化输出# 创建结构化输出的 LLMstructured_llm=model.with_structured_output(Person)# 调用result=structured_llm.invoke("张三是一名 30 岁的软件工程师")print(result)print(type(result))# result 是 Person 实例print(result.name)# "张三"print(result.age)# 30print(result.occupation)# "软件工程师"举例2
高级特性
情况1:可选字段
情况2:默认值
情况3:枚举类型
如果嫌单独定义一个 Enum 类太麻烦,也可以直接导入 typing 中的 Literal ,直接在字段里把允许的值写死。
情况4:列表提取
情况5:嵌套结构
说明:LLM 能力有限,复杂嵌套结构可能会出错。所以建议:
- 嵌套层级 ≤ 3 层
- 使用清晰的 description
- 必要时拆分成多个调用
情况6:限制条件
工作流程图解
模式2:TypedDict
什么是 TypedDict
基本使用
Annotated的使用
上述代码的 … 是Python的字面量,等价于 Ellipsis ,可以理解为占位符。下游框架(如LangChain)可以对 … 作定制化处理,如LangChain中Annotated的 … 表示当前字段是必须存在的,不可省略,用来指示模型的输出。
模式3:JSON Schema(不推荐)
这种方式需要按照JSON Schema规范拼接JSON字符串,比较繁琐,并且缺少校验机制。不推荐
模式4:@dataclass
三、关于类型校验
用Pydantic定义schema,在接收到响应后会进行校验,字段不匹配则抛出异常,其余三种方式不校验。
四、获取结构化结果方式
使用with_structured_output
这种方式是 最新 、 最简洁 的API,直接让模型“理解”你需要的数据结构,并返回解析好的对象。
此外,我们可以在with_structured_output方法中传入 include_raw=True 参数,表示返回解析前的 原始AIMessage ,从而访问令牌用量等元数据。
使用输出解析器(不推荐)
参考视频
https://www.bilibili.com/video/BV1rv7A6oEeP?spm_id_from=333.788.videopod.episodes&vd_source=0467ab39cc5ec5940fee22a0e7797575&p=41