通过 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],则每次只查看最后一条消息,输出会更加清晰。

四、contenttool_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 #用于获取模型准备调用的工具及其参数。

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

用户问题
    ↓
模型决定调用工具
    ↓
工具返回查询结果
    ↓
模型整合结果
    ↓
生成最终回答

更多推荐