前言
本期我将要介绍LangChain 中聊天模型的另一功能结构化输出。这将原来大模型输出的AIMessage变成以例如Json等格式化输出,以适应特定的开发场景。
一、with_structured_output() 方法
要想使用结构化输出能力,LangChain提供了一种方法.with_structured_output() 。该方法需要先定义输出结构,然后执行通过 .with_structured_output() 得到Runnable 实例。
(一)返回 Pydantic 对象
我们可以设置执行Runnable 后的输出结果指定为 Pydantic 类,这将返回一个 Pydantic 对象。当收到模型的响应后,LangChain 会提取出代表 Pydantic 参数的 JSON 对象,并用 Pydantic 模型对其进行解析和验证,将这个验证后的 JSON 转换为⼀个可用的 Pydantic 对象实例返回。
# 结构化返回 Pydantic model = ChatDeepSeek(model='deepseek-v4-flash') class Joke(BaseModel): """给用户讲的一个笑话""" setup:str = Field(description="笑话的开头") punchline: str = Field(description='笑话的妙语') rating: Optional[int] = Field(default=None,description="从1-10分,给这个笑话评分") class Data(BaseModel): """获取关于笑话的数据列表""" jokes: List[Joke] # print(model.invoke("讲一个关于薛定谔的猫的笑话").content) model_with_structured = model.with_structured_output(Data) print(model_with_structured.invoke("讲一个关于薛定谔的猫的笑话"))(二)返回 TypedDict
TypedDict 主要用于为字典对象提供精确的、结构化的类型提示。它允许我们指定字典中应该有哪些键,以及每个键对应的值的类型。它其中一个重要的能力就是捕捉键名拼写错误与类型错误。
因此我们也可以设置执行Runnable 后的输出结果指定为 TypedDict 类,这将就会返回一个字典,且输出后,会根据设定进行验证。
model = ChatDeepSeek(model='deepseek-v4-flash') # 结构化返回 TypedDict class Joke(TypedDict): """给用户讲的一个笑话""" setup:str = Field(description="笑话的开头") punchline: str = Field(description='笑话的妙语') rating: Optional[int] = Field(description="从1-10分,给这个笑话评分") model_with_structured = model.with_structured_output(Joke,include_raw=True) print(model_with_structured.invoke("讲一个关于薛定谔的猫的笑话"))(三)返回 JSON
为了声明 JSON,我们同时需要定义 JSON Schema。
model = ChatDeepSeek(model='deepseek-v4-flash') # 结构化返回 JSON Schema json_schema = { "title": "joke", "description": "给用户讲一个笑话。", "type": "object", "properties": { "setup": { "type": "string", "description": "这个笑话的开头", }, "punchline": { "type": "string", "description": "这个笑话的妙语", }, "rating": { "type": "integer", "description": "从1到10分,给这个笑话评分", "default": None, }, }, "required": ["setup", "punchline"], } model_with_structured = model.with_structured_output(json_schema) print(model_with_structured.invoke("讲一个关于薛定谔的猫的笑话"))(四)选择输出格式
创建具有联合类型属性的父模式。
model = ChatDeepSeek(model='deepseek-v4-flash') class Joke(BaseModel): """给用户讲的一个笑话""" setup: str = Field(description="这个笑话的开头") punchline: str = Field(description="这个笑话的妙语") rating: Optional[int] = Field(default=None, description="从1-10分,给这个笑话评分") class Response(BaseModel): """以对话的方式回应""" content: str = Field(description="用于对用户查询的会话响应") class FinalResponse(BaseModel): """最终回复,选择合适的输出结构""" final_output: Union[Joke, Response] model_with_structured = model.with_structured_output(FinalResponse) print(model_with_structured.invoke("讲一个关于薛定谔的猫的笑话")) print(model_with_structured.invoke("你是谁?"))二、实用案例
(一)信息提取
model = ChatDeepSeek(model='deepseek-v4-flash') # 结构化输出常见使用场景:信息提取 class Person(BaseModel): """一个人的信息。""" # 注意: # 1. 每个字段都是 Optional “可选的” —— 允许 LLM 在不知道答案时输出 None。 # 2. 每个字段都有一个 description “描述” —— LLM使用这个描述。 # 有一个好的描述可以帮助提高提取结果。 name: Optional[str] = Field(default=None, description="这个人的名字") hair_color: Optional[str] = Field(default=None, description="如果知道这个人头发的颜色") skin_color: Optional[str] = Field(default=None, description="如果知道这个人的肤色") height_in_meters: Optional[str] = Field(default=None, description="以米为单位的高度") structured_model = model.with_structured_output(schema=Person) messages = [ SystemMessage(content="你是一个提取信息的专家,只从文本中提取相关信息。如果您不知道要提取的属性的值,属性值返回null"), HumanMessage(content="史密斯身高6英尺,金发。") ] result = structured_model.invoke(messages) print(result)(二)与工具结合使用
model = ChatOpenAI( model='deepseek-v4-flash', api_key=os.environ.get('DEEPSEEK_API_KEY'), base_url="https://api.deepseek.com", ) # 结构化输出常见使用场景:与工具结合使用 tool = TavilySearch(max_results=4) model_with_tools = model.bind_tools([tool]) messages = [ HumanMessage("北京今天的天气怎么样?") ] ai_message = model_with_tools.invoke(messages) messages.append(ai_message) for tool_call in ai_message.tool_calls: tool_message = tool.invoke(tool_call) messages.append(tool_message) class SearchResult(BaseModel): """结构化搜索对象""" query: str = Field(description="搜索查询") findings: str = Field(description="查询结果摘要") model_with_structured = model_with_tools.with_structured_output(SearchResult) print(model_with_structured.invoke(messages))与工具相结合的方式下,它并不能直接帮我们输出想要的SearchResult搜索结果,而是只返回了AIMessage。所以with_structured_output 方法只是让模型知道有哪些工具可以调用,但是并不会自动执行工具。要获得工具执行后的结果并整合到最终的结构化输出中,我们需要手动执行。
结语
以上便是Langchain中如何使用聊天模型的格式化输出的内容了。如果喜欢我的内容,请点赞、收藏加关注,多多支持我,以及欢迎各位在评论区讨论交流,并指出我的不足,谢谢大家。