云计算百科
云计算领域专业知识百科平台

LangChain Agent 流式输出:`stream_mode=“values“` 数据结构解析

通过 create_agent() 可以创建 Agent 对象。创建后的 Agent 支持两种常见执行方式:

  • invoke():等待 Agent 执行完成,一次性获得最终结果。
  • stream():在 Agent 执行过程中,逐步获得运行状态。

本文主要介绍 Agent 的流式输出,以及下面这行代码的作用:

一、完整代码

下面创建两个股票查询工具,然后让 Agent 查询“传智教育”的股价和公司信息。

from langchain.agents import create_agent
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.tools import tool

@tool(description="获取股价,传入股票名称,返回字符串信息")
def get_price(name: str) > str:
return f"股票{name}的价格是20元"

@tool(description="获取股票信息,传入股票名称,返回字符串信息")
def get_info(name: str) > str:
return f"股票{name},是一家A股上市公司,专注于IT职业教育。"

agent = create_agent(
model=ChatTongyi(model="qwen3-max"),
tools=[get_price, get_info],
system_prompt="你是一个智能助手,可以回答股票相关问题"
)

for chunk in agent.stream(
{
"messages": [
{
"role": "user",
"content": "传智教育股价多少,并介绍一下"
}
]
},
stream_mode="values"
):
latest_message = chunk["messages"][1]

if latest_message.content:
print(
type(latest_message).__name__,
latest_message.content
)

try:
if latest_message.tool_calls:
print(
"工具调用:",
[tc["name"] for tc in latest_message.tool_calls]
)
except AttributeError:
pass

运行结果如下:
在这里插入图片描述

二、stream_mode="values" 返回什么?

stream_mode="values"

之后,Agent 每完成一个执行步骤,都会返回当前时刻的完整状态。

每个 chunk 都是一个字典,核心结构如下:

{
"messages": [
HumanMessage(...),
AIMessage(...),
ToolMessage(...),
AIMessage(...)
]
}

  • ToolMessage:工具执行后返回的结果。

Agent 执行过程中,messages 列表会不断变长。

例如第一次可能只有用户消息:

[
HumanMessage(...)
]

模型决定调用工具后:

[
HumanMessage(...),
AIMessage(tool_calls=[...])
]

工具执行完成后:

[
HumanMessage(...),
AIMessage(tool_calls=[...]),
ToolMessage(...),
ToolMessage(...)
]

三、为什么使用 chunk["messages"][-1]?

latest_message = chunk["messages"][1]

表示获取 Agent 当前状态中的最后一条消息,也就是最近产生的消息。

如果直接遍历整个列表:

for message in chunk["messages"]:
print(message)

由于每个 chunk 都包含完整消息历史,之前的消息会被重复打印。

使用 [-1],则每次只查看最后一条消息,输出会更加清晰。

四、content 和 tool_calls 分别是什么?

这两个都是 Message对象的属性

提取最新消息后,主要读取两个属性:

latest_message.content
latest_message.tool_calls

1. content

content 保存消息中的文字内容。

比如模型最终回答:

AIMessage(
content="传智教育当前股价为20元……"
)

if latest_message.content:
print(latest_message.content)
#输出消息中的文本。

2. tool_calls

tool_calls 保存模型产生的工具调用请求。

例如:

AIMessage(
content="",
tool_calls=[
{
"name": "get_price",
"args": {
"name": "传智教育"
},
"id": "call_xxx",
"type": "tool_call"
}
]
)

其中:

  • name:调用的工具名称。
  • args:传递给工具的参数。
  • id:本次工具调用的唯一标识。

[tc["name"] for tc in latest_message.tool_calls]
#会提取所有准备调用的工具名称。

五、为什么 tool_calls 会出现两次?

打印完整的 AIMessage 时,会看到:

AIMessage(
content="",

additional_kwargs={
"tool_calls": [
{
"function": {
"arguments": '{"name": "传智教育"}',
"name": "get_price"
}
}
]
},

tool_calls=[
{
"name": "get_price",
"args": {
"name": "传智教育"
}
}
]
)

工具调用同时出现在:

additional_kwargs["tool_calls"]

message.tool_calls

这两个位置的作用不同。
在这里插入图片描述

additional_kwargs

这里通常保存模型接口返回的附加数据,其结构更接近模型原始返回结果。

additional_kwargs 本身是一个 Python 字典,用于保存模型返回的附加数据。其中工具参数 function.arguments 可能仍然是 JSON 格式的字符串

"arguments": '{"name": "传智教育"}'

tool_calls

LangChain 会对工具调用数据进行解析和统一封装:

tool_calls=[ #如果调用多个工具 就会有多个字典
{
"name": "get_price",
"args": {
"name": "传智教育"
}
}
]

这样不管底层使用哪个模型,都可以通过统一方式读取工具调用。

六、总结

stream_mode="values" 返回的是 Agent 每一步执行后的完整状态,其中最重要的数据是:

chunk["messages"] #它保存了 Agent 当前积累的全部消息。

latest_message = chunk["messages"][1]
#表示从完整消息列表中取出最后一条消息,避免重复处理以前已经出现过的内容。

消息中的两个常用属性分别是:

message.content #用于获取文字内容;

message.tool_calls #用于获取模型准备调用的工具及其参数。

整个执行过程可以简单概括为:

用户问题

模型决定调用工具

工具返回查询结果

模型整合结果

生成最终回答

赞(0)
未经允许不得转载:网硕互联帮助中心 » LangChain Agent 流式输出:`stream_mode=“values“` 数据结构解析
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!