通过 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 #用于获取模型准备调用的工具及其参数。
整个执行过程可以简单概括为:
用户问题
↓
模型决定调用工具
↓
工具返回查询结果
↓
模型整合结果
↓
生成最终回答
网硕互联帮助中心





评论前必须登录!
注册