LangGraph中的输出范式

https://blog.csdn.net/brucexia/article/details/158845706

如果把普通大模型(LLM)的输出比作"一张便签"------只写着最终答案,那么LangGraph的输出更像"一份带流程的工作交接单":不仅要写清当前任务的结果,还得告诉下一个环节"该谁接手、做什么"。

为什么会这样?因为LangGraph本质是个"团队协作框架":整个工作流由多个"节点"(就像团队里的不同角色,比如"信息收集员""分析员""决策者")组成,节点之间靠"图结构"(类似于团队分工流程图)连接,谁先做、谁后做、遇到特殊情况转交给谁,都有明确规则。这种情况下,单个节点的输出如果只是一句零散的话,下一个节点根本不知道该怎么接------就像市场部交了一份"客户好像喜欢红色"的便签,产品部既不知道这个结论怎么来的,也不知道接下来该设计红色包装还是红色广告。

因此,LangGraph的输出必须是"结构化的",得同时干以下两件事。

  • 传内容:把当前节点的核心成果说清楚(比如"客户偏好调研显示,30~40岁的女性更青睐粉色系,预算集中在200~500元")。
  • 控流程:明确告诉系统下一步该怎么走(比如"请转交给产品设计节点,基于此数据设计3款样品",或者"信息不足,请返回用户调研节点补充询问预算范围")。

这就像快递单:既要有"包裹里是什么(内容)",也要有"下一站寄到哪(流程)",缺了任何一个,整个链条都会卡住。这种结构化设计正是LangGraph能让多个节点"默契配合"、灵活应对复杂任务的关键------就像团队里的交接单写得越清楚,大家干活越顺畅,不容易出错。

那么,怎么让大模型输出这种"带流程的交接单"呢?主要有以下两种办法。

  • 提示工程:提前跟大模型说清楚"交接单该怎么写"。例如给节点发个"工作指南":你的输出必须包含两部分:①你分析出的客户需求;②下一步建议(选"转报价组"或"转产品组"),用"###"分隔开。
  • 输出解析器+提示工程:给个"固定模板",让大模型必须按模板填。例如强制要求输出格式是"{"结果":"...","下一步":"..."}",再配合提示确保它不瞎写,就像给交接单印好表格,只让填指定位置。

我们目前可以将提示工程简单地理解为"提示词",而对于输出解析器,则一般使用LangGraph中的结构化输出对其进行处理。本节将主要讨论其中的两种结构化输出:字符串String与结构化JSON形式。

3.4.1 LangGraph中的格式化输出1:StrOutputParser

在之前的工具绑定示例中,我们发现模型返回的结果包含content、tool_calls、response_metadata等大量冗余元数据,直接使用时需要手动提取核心信息,不仅烦琐,还容易出错。而StrOutputParser作为LangChain中最基础且常用的输出解析器,其核心作用是过滤冗余元数据,直接提取模型返回的纯文本内容,让输出结果更简洁、更易于后续处理,完美适配LangGraph工作流中"节点间数据传递"的需求。

StrOutputParser的设计逻辑非常简单:它会自动解析大模型的返回对象,提取其中的content字段(自然语言文本),忽略tool_calls、response_metadata等额外信息,最终返回一个纯净的字符串。

它的主要适用场景包括:

  • 模型直接生成自然语言回答(无须工具调用)时,快速获取纯文本结果。
  • 工具调用后,模型整理结果生成回答时,过滤元数据只保留最终回复。
  • LangGraph节点间传递文本数据时,简化数据格式,避免冗余信息干扰。

下面是一个使用StrOutputParser的示例:

import bigmodel

from langchain_core.prompts import PromptTemplate

from datetime import datetime

system_prompt=PromptTemplate(

input_variables="user_query","datatime_now",

template="你是小华,是一个有用的智能助手,帮助解决用户的问题{user_query},并根据注意{datatime_now}"

).partial(datatime_now=datetime.now())

from langchain_core.output_parsers import StrOutputParser

llm=system_prompt|bigmodel.llm | StrOutputParser()

print(llm.invoke("你是谁?"))

输出结果如下:

你好!我是小华,一个乐于助人的智能助手。我的目标是帮助你解答问题、提供信息或协助完成各种任务。

根据你提供的注意时间:2025年11月10日16:27:42.100315,目前系统时间已设定为该时刻(可能是用于参考或日程安排)。如果你有任何问题、需要提醒、计算、写作帮助,或者其他支持,请随时告诉我!

可以看到,此时根据我们的要求,自动输出了文本内容,并且剔除了其中的干扰项。

3.4.2 LangGraph中的格式化输出2:JSON格式

除了前面我们需要完成的文本输出外,对于输出格式,我们还可以要求其输出特定的JSON格式,如下所示:

import bigmodel

from langchain_core.prompts import PromptTemplate

from datetime import datetime

system_prompt=PromptTemplate(

input_variables="user_query","datatime_now",

template="你是小华,是一个有用的智能助手,帮助解决用户的问题{user_query},并根据注意{datatime_now}时间。"

).partial(datatime_now=datetime.now())

from langchain.tools import tool

@tool

def get_weather(loc:str,now_data:datetime):

"""

用于查询指定地点在指定日期的天气情况。

参数:

loc:地点名称(字符串类型,例如"上海")

now_data:查询的日期(datetime类型,包含年/月/日)

返回:包含日期、地点和天气详情的字符串

"""

return f"今天的日期是{now_data},查询到{loc}的天气晴朗,风和日丽,温度为21摄氏度"

tools=get_weather

llm_withtool=system_prompt | bigmodel.llm.bind_tools(get_weather)

#解析工具调用指令

tool_calls=llm_withtool.invoke("上海的天气是什么").tool_calls

tools_by_name={tool.name:toolfortoolintools}

tool_results=\[\]

fortool_callintool_calls:

tools_call_name=tool_call"name"

tools_call_args=tool_call"args"

tool_result=tools_by_nametools_call_name.invoke(tools_call_args)

tool_results.append(tool_result)

#将工具结果回传给模型,生成最终回答

final_prompt=f"用户问的是上海的天气,工具返回结果:{tool_results},请以JSON格式回答。"

final_answer=bigmodel.llm.invoke(final_prompt).content

print(final_answer)

输出结果如下:

{

"date":"2025-11-10",

"time":"16:35:25.701372",

"location":"上海",

"weather":"晴朗",

"description":"风和日丽",

"temperature":21,

"unit":"摄氏度"

}

可以看到,这里对于final_prompt的设计,通过明确指令"请以JSON格式回答",引导模型将工具返回的文本结果转换为键值对格式的结构化数据。

3.4.3 LangGraph中的格式化输出3:可控的JSON格式

以上示例演示了JSON格式的输出,可以看到我们将结果拆分成一个特定的JSON格式,虽然这样可以解决输出结果要求限定在特定格式下,但是对于输出结果的要求,目前是出于不可控的形式。

以下示例演示对输出结果进行控制,并限制输出的JSON值的内容:

from pydantic import BaseModel,Field

from datetime import datetime

class WeatherReport(BaseModel):

"""

结构化的天气报告模型,用于标准化工具返回的天气信息

包含天气查询的核心数据字段,便于后续解析、存储或跨系统传递

"""

date:datetime=Field(

default_factory=lambda:datetime.now().strftime("%Y年.%m月.%d号"),#格式化当前日期为Y.M.D

description="天气查询的日期(包含年/月/日/时/分/秒),默认使用当前时间"

)

location:str=Field(

default="",

description="查询的地点名称(如城市名、区域名等,字符串类型)"

)

temperature:float=Field(

default=0.0,

description="查询地点的温度,单位为摄氏度(数值类型,支持小数)"

)

这段代码基于Pydantic库定义了一个名为WeatherReport的结构化数据模型,其核心用途是标准化天气查询结果的数据格式,避免信息混乱。代码开头先导入了必要的依赖:BaseModel是Pydantic实现数据建模和验证的基础类,Field用于配置字段的元数据,datetime则用于处理日期时间相关逻辑。WeatherReport类继承自BaseModel后,自动获得了Pydantic的类型校验、字段约束等核心能力,而类内的文档字符串清晰说明了模型的作用------统一天气信息格式,方便后续的解析、存储或跨系统传递,解决了纯文本结果难以进行机器处理的问题。

模型内部定义了三个核心字段,分别对应天气报告的关键信息:date字段标注为datetime类型,用于存储查询日期,通过default_factory指定默认值为当前时间格式化后的字符串(格式为"年.月.号"),但需注意,此处存在类型不匹配的潜在问题(strftime返回字符串,与datetime类型标注冲突);location字段为字符串类型,默认值为空字符串,用于存储查询的地点名称(如城市名);temperature字段为浮点型,默认值为0.0,用于存储以摄氏度为单位的温度,支持小数精度。每个字段通过description参数补充了详细说明,既方便开发者理解,也能辅助后续与大模型交互时明确数据要求,确保输入输出的一致性。

可控JSON格式的使用示例如下:

import bigmodel

from langchain_core.prompts import PromptTemplate

from datetime import datetime

system_prompt=PromptTemplate(

input_variables="user_query","datatime_now",

template="你是小华,是一个有用的智能助手,帮助解决用户的问题{user_query},并根据注意{datatime_now}时间。"

).partial(datatime_now=datetime.now())

from langchain.tools import tool

@tool

def get_weather(loc:str,now_data:datetime):

"""

用于查询指定地点在指定日期的天气情况。

参数:

loc:地点名称(字符串类型,例如"上海")

now_data:查询的日期(datetime类型,包含年/月/日)

返回:包含日期、地点和天气详情的字符串

"""

return f"今天的日期是{now_data},查询到{loc}的天气晴朗,风和日丽,温度为21摄氏度"

tools=get_weather

llm_withtool=system_prompt|bigmodel.llm.bind_tools(get_weather)

#解析工具调用指令

tool_calls=llm_withtool.invoke("上海的天气是什么").tool_calls

tools_by_name={tool.name:toolfortoolintools}

tool_results=\[\]

fortool_callintool_calls:

tools_call_name=tool_call"name"

tools_call_args=tool_call"args"

tool_result=tools_by_nametools_call_name.invoke(tools_call_args)

tool_results.append(tool_result)

from pydantic import BaseModel,Field

from datetime import datetime

class WeatherReport(BaseModel):

"""

结构化的天气报告模型,用于标准化工具返回的天气信息

包含天气查询的核心数据字段,便于后续解析、存储或跨系统传递

"""

date:datetime=Field(

default_factory=lambda:datetime.now().strftime("%Y年.%m月.%d号"),#格式化当前日期为Y.M.D

description="天气查询的日期(包含年/月/日/时/分/秒),默认使用当前时间"

)

location:str=Field(

default="",

description="查询的地点名称(如城市名、区域名等,字符串类型)"

)

temperature:float=Field(

default=0.0,

description="查询地点的温度,单位为摄氏度(数值类型,支持小数)"

)

#将工具结果回传给模型,生成最终回答

final_prompt=f"用户问的是上海的天气,工具返回结果:{tool_results},请以JSON格式回答。"

final_answer=bigmodel.llm.with_structured_output(WeatherReport).invoke(final_prompt)

print(final_answer)

输出结果如下:

date=datetime.datetime(2025,11,10,0,0)location='上海'temperature=21.0

从输出结果可以看到,通过with_structured_output(WeatherReport)方法,我们成功实现了"可控且标准化的JSON格式输出"------最终返回的不再是自由格式的JSON字符串,而是WeatherReport类的实例化对象,字段值严格匹配模型定义的类型和含义:date为datetime类型(自动解析为2025年11月10日)、location为字符串类型(准确提取"上海")、temperature为浮点类型(正确转换为21.0),完全避免了纯提示词要求"JSON格式"时可能出现的字段缺失、类型混乱等问题。

这种"Pydantic模型+with_structured_output"的组合是LangChain中实现可控JSON输出的核心方案,其核心逻辑是通过Pydantic模型定义"数据契约",再让大模型按照契约生成结构化数据。具体来说,with_structured_output(WeatherReport)会自动将WeatherReport的字段定义、类型约束和描述转换为大模型能理解的提示指令,无须手动编写"包含哪些字段、类型是什么"的烦琐提示;同时,大模型返回结果后,LangChain会自动进行类型校验和转换,比如工具返回的温度是文本"21摄氏度",会被自动提取数值并转为float类型,日期字符串会被解析为datetime对象,最终封装成WeatherReport实例。这种方式不仅让输出格式完全可控,还省去了手动解析JSON字符串、校验字段类型的步骤,后续可直接通过final_answer.location、final_answer.temperature等属性快速获取关键数据,极大地简化了代码逻辑。

在实际应用中,这种可控JSON格式尤其适合需要严格数据规范的场景,比如将天气报告存入数据库时,可直接通过final_answer.model_dump()将实例转换为标准字典;跨系统传递数据时,通过final_answer.model_dump_json()生成合规JSON字符串,无须担心格式不兼容;在LangGraph工作流中,WeatherReport实例可直接作为节点间传递的状态数据,后续节点能精准提取字段进行二次决策(如根据temperature判断是否推荐户外活动)。相比单纯依赖提示词要求JSON格式,这种方案的稳定性和可维护性大幅提升,是在LangGraph中进行结构化数据处理的首选方式。

相关推荐
JJJennie7771 小时前
当AI开始学会欺骗
网络·人工智能
糖果店的幽灵1 小时前
大模型测评DeepEval快速入门-安全与通用指标详解
人工智能·安全·langgraph·大模型测评·deepeval
江畔柳前堤7 小时前
roLabelImg 详细安装教程
开发语言·人工智能·后端·云原生
阿里云大数据AI技术7 小时前
分链路差异化设计的DSP准实时数仓|钛动科技基于阿里云实时计算 Flink 版 + DLF Paimon + EMR Serverless StarRocks 的实践
人工智能·flink
陕西企来客7 小时前
2026年7月AI智能搜索曝光趋势研判
大数据·人工智能·机器学习·ai智能搜索曝光
阿里云大数据AI技术8 小时前
从算力到智能体,面向 Agentic AI 的基础设施演进
人工智能·agent
hangyuekejiGEO8 小时前
GEO技术服务选型指南
大数据·人工智能·python
阿里云大数据AI技术9 小时前
EMR Serverless Spark AI Function 的双维降本实践
人工智能·sql·spark
维基框架9 小时前
GitHub源码处理提速 一趟扫描反而更慢
人工智能·github
冬奇Lab9 小时前
代码库知识库系列(05):向量检索 vs 知识图谱——加了调用图并没有变更好
人工智能