LangGraph实现自治循环代理ReAct及事件流的应用

  • 之前介绍的 Router AgentTool Calling Agent,我们通过两个实际的案例证明了随着任务需求的复杂性增加,代理架构中对中间流程的控制自由度也必须相应提高。之所以要从 Router Agent 调整到 Tool Calling Agent 架构的原因在于,当路由分支中的节点涉及多个工具时,需要Agent可以根据用户的实际输入灵活选择工具,这一需求是 Router Agent 无法满足的。然而,Tool Calling Agent 的局限性又在于:虽然它可以自主选择工具,但在其架构中,每次仅能执行一次函数调用(无论是单个外部函数还是多个外部函数)。因此,当任务需要依次执行 A 工具、B 工具和 C 工具时,它无法支持这种自主控制的过程。因此,面对这种更复杂的需求,就需要引入了 Full Autonomous(自治循环代理)架构,即如下图所示:

   Full Autonmonous 以两种主要的方式去扩展了Agent对工作流的控制,分别是:

  • 多步骤决策: Agent可以控制一系列决策,而不仅仅是一个决策。
  • 工具访问: Agent可以选择并使用多种工具来完成任务。

  满足上述两个条件,典型且通用的代理架构,就是基于ReAct思想而形成的代理模式。在《Ch.3 ReAct Agent 基本理论与项目实战》课程中,我们重点讲解了ReAct的核心理念,并手动实现了基于该思想构建的自治循环代理流程。整体来看,其核心还是在于为大模型配备足够丰富的外部工具,使用合适的提示词,引导大模型在接收到用户输入后,进入自主思考和循环执行的状态,以实现最终目标。 当然,这是我们从非技术角度通俗的解释和理解自治循环代理的这个过程。

1、LangGraph中ReAct的构建原理

  在 LangGraph 开发框架中有一些预构建的组件。上节课介绍的 ToolNode 是其中一个,它用于处理外部函数调用,其内部结合了 LangGraph 底层的图结构,能够接收 JSON Schema 形式的数据,执行工具函数并返回结果。除此之外,LangGraph的预构建组件中还包含了 ReAct 代理架构,在 LangGraph 框架中,ReAct 组件被改造成适配图结构的循环代理,其具体过程是:大模型可以在一个 while 循环中被重复调用。每一步,代理来自主决定调用哪些工具及其输入,然后执行这些工具,并将输出作为观察结果反馈给大模型。当代理判断不再需要调用更多工具时,while 循环便会终止,输出最终的结果。

  因此,我们需要理解的关键概念是:LangGraph预构建的ReAct组件,其实就是通过接入大模型,搭配着Tool Calling Agent,再结合Router Agent 共同构建起来的图,这个图以自治循环代理的架构形式提供服务。其图结构如下图所示:

image-20260207144959751

  如上图所示的代理架构在 LangGraph 中的实现机制类似于 LangChain 中的 ReAct Agent,毕竟 LangGraph 的底层语言是 LangChainLCEL 表达式语言。因此,该 ReAct Agent 架构是从 LangChain 已实现的 ReAct Agent 迁移而来,不同的是在LangGraph框架中适配的是图结构,而非AgentExecuter。其本质依然基于一种规划(Planning)的思想:

LangChain Agents: https://reference.langchain.com/python/langchain/agents/

Agent Planning:https://smith.langchain.com/hub/hwchase17/react?organizationId=33612d73-91c5-5140-b8a0-f3155ff5dc45

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Answer the following questions as best you can. You have access to the following tools:

{tools}

Use the following format:

Question: the input question you must answer

Thought: you should always think about what to do

Action: the action to take, should be one of [{tool_names}]

Action Input: the input to the action

Observation: the result of the action

... (this Thought/Action/Action Input/Observation can repeat N times)

Thought: I now know the final answer

Final Answer: the final answer to the original input question

Begin!

Question: {input}

Thought:{agent_scratchpad}

  这种代理实现的机制表明了,在LangGraph中实现的预构建ReAct代理结构,它支持:

  • Tool calling :允许大模型根据需要选择和使用各种工具。
  • Memory:使代理能够保留和使用先前步骤中的信息。
  • Planning :授权大模型制定并遵循多步骤计划以实现目标。

  而其在图结构中的具体构建的工作流如下图所示:

  如图所示,Agent节点使用消息列表的形式来调用大语言模型,Messages Modifier指的是在传递到大模型之前,修饰用户的原始输入内容,可以是SystemMessage(作为背景信息添加的消息列表的开头)、Runnable(可运行)等不同状态,如果生成的 AIMessage 包含tool_calls,则该图将调用 toolstools 节点执行工具(每个 tool_call 1 个工具)并且将响应作为ToolMessage对象添加到消息列表。然后Agent节点再次调用大语言模型。重复该过程,直到响应中不再存在tool_calls ,最终由Agent节点将完整的消息列表作为包含键 messages的字典返回。

  那么如何实现上述这个非常复杂的过程呢?非常简单,既然我们一直提到的是预构建组件,则说明整个过程已经由LangGraph内部封装好了,其提供给开发者使用的接口就是:create_react_agent方法。

LangGraph create_react_agent:点击查看源码参数介绍

2. 案例实操:构建复杂工具应用的ReAct自治代理

  在这个案例中,我们将通过一个多工具场景需求来测试 LangGraphReAct 代理的构建方法和效果。我们设计了几个工具,以实现实时数据的查询和管理。首先,用户可以通过一个工具根据城市名称实时获取当前天气信息。接着,如果用户希望将查询到的天气数据保存到本地数据库中,可以使用另一个工具完成数据的插入操作。此外,我们还提供了一个工具,允许用户基于本地数据库中的天气数据进行提问数据进行提问。通过这些工具的组合,我们能够快速验证如何在复杂的应用场景中有效地整合不同功能,并实际的感知LangGraph框架下ReAct代理模式带来的开发便捷性和可扩展性。

  首先,我们设置一下LangSmith的配置,用于追踪和可视化ReAct的中间过程。这里新建了一个项目,命名为langGraph_ReAct,导入基础配置的代码如下图所示:

LangSmith:https://www.langchain.com/langsmith

1
2
3
4
5
6
7
8
9
10
11
import os

# 设置环境变量
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "xxx" # 需要更改为自己的 langsmith API_KEY
os.environ["LANGCHAIN_PROJECT"]="langGraph_ReAct" # 需要更改为自己实际创建的项目名称

# 验证环境变量是否设置成功
print(os.getenv("LANGCHAIN_TRACING_V2"))
print(os.getenv("LANGCHAIN_API_KEY"))
print(os.getenv("LANGCHAIN_PROJECT"))
true
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
langGraph_ReAct

  首先,我们接入实时天气数据查询的在线API,代码定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import requests

def get_weather(loc):
"""
Function to query current weather.
:param loc: Required parameter, of type string, representing the specific city name for the weather query. \
Note that for cities in China, the corresponding English city name should be used. For example, to query the weather for Beijing, \
the loc parameter should be input as 'Beijing'.
:return: The result of the OpenWeather API query for current weather, with the specific URL request address being: https://api.openweathermap.org/data/2.5/weather. \
The return type is a JSON-formatted object after parsing, represented as a string, containing all important weather information.
"""
# Step 1.构建请求
url = "https://api.openweathermap.org/data/2.5/weather"

# Step 2.设置查询参数
params = {
"q": loc,
"appid": "xxx", # 输入API key
"units": "metric", # 使用摄氏度而不是华氏度
"lang":"zh_cn" # 输出语言为简体中文
}

# Step 3.发送GET请求
response = requests.get(url, params=params)

# Step 4.解析响应
data = response.json()
return json.dumps(data)

  测试一下get_weather函数的有效性,正常情况下可以得到输入城市名的实时天气信息。测试代码如下所示:

1
get_weather('beijing')
'{"coord": {"lon": 116.3972, "lat": 39.9075}, "weather": [{"id": 800, "main": "Clear", "description": "\\u6674", "icon": "01d"}], "base": "stations", "main": {"temp": 20.5, "feels_like": 19.28, "temp_min": 19.94, "temp_max": 20.5, "pressure": 1016, "humidity": 26, "sea_level": 1016, "grnd_level": 1010}, "visibility": 10000, "wind": {"speed": 1.95, "deg": 270, "gust": 5.15}, "clouds": {"all": 0}, "dt": 1730190567, "sys": {"type": 2, "id": 2000403, "country": "CN", "sunrise": 1730155186, "sunset": 1730193377}, "timezone": 28800, "id": 1816670, "name": "Beijing", "cod": 200}'

  从返回的结果是Json数据类型,包含了非常丰富的实时天气数据,如天气条件、温度、湿度、风速、天气描述等信息,这里我们选择一些重要的数据参数进行存储操作(存储至Mysql数据库中)。提取的参数如下:

字段名称 描述
city_id 城市的唯一标识符
city_name 城市名称
main_weather 主要天气状况
description 天气的详细描述
temperature 当前温度
feels_like 体感温度
temp_min 最低温度
temp_max 最高温度

  接下来,设计一个用于存储实时天气信息的表。这里我们定义一个新的模型 Weather,并包括上述所提取出来的的字段。连接 Mysql数据库及创建表的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from sqlalchemy import create_engine, Column, Integer, String, Float
from sqlalchemy.orm import sessionmaker, declarative_base

# 创建基类
Base = declarative_base()

# 定义 WeatherInfo 模型
class Weather(Base):
__tablename__ = 'weather'
city_id = Column(Integer, primary_key=True) # 城市ID
city_name = Column(String(50)) # 城市名称
main_weather = Column(String(50)) # 主要天气状况
description = Column(String(100)) # 描述
temperature = Column(Float) # 温度
feels_like = Column(Float) # 体感温度
temp_min = Column(Float) # 最低温度
temp_max = Column(Float) # 最高温度


# 数据库连接 URI,这里要替换成自己的Mysql 连接信息,以下是各个字段的对应解释:
# root:MySQL 数据库的用户名。
# snowball950123:MySQL 数据库的密码。
# 192.168.110.131:MySQL 服务器的 IP 地址。
# langgraph_agent:要连接的数据库的名称。
# charset=utf8mb4:设置数据库的字符集为 utf8mb4,支持更广泛的 Unicode 字符
DATABASE_URI = 'mysql+pymysql://root:[email protected]/langgraph_agent?charset=utf8mb4'
engine = create_engine(DATABASE_URI)

# 如果表不存在,则创建表
Base.metadata.create_all(engine)

# 创建会话
Session = sessionmaker(bind=engine)

  接下来,使用LangChaintool 装饰器将普通的函数注册为LangGraph中支持的工具服务,根据需求的设计,我们要依次创建三个外部函数,分别是:

  1. get_weather工具:用于根据城市名称实时查询该城市的当前天气数据。
  2. insert_weather_to_db工具:如果用户想要把查询到的天气数据插入到数据库的表中,则使用此函数完成数据库的插入操作。
  3. query_weather_from_db工具:如果用户想基于本地数据库的天气数据直接进行提问,则使用此函数完成数据库的查询操作。

  如上节课实践的流程一样,我们依然使用pydantic来做工具的参数校验和结构化输出。三个工具函数的定义代码依次如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
from langchain_core.tools import tool
from typing import Union, Optional
from pydantic import BaseModel, Field
import requests

class WeatherLoc(BaseModel):
location: str = Field(description="The location name of the city")


class WeatherInfo(BaseModel):
"""Extracted weather information for a specific city."""
city_id: int = Field(..., description="The unique identifier for the city")
city_name: str = Field(..., description="The name of the city")
main_weather: str = Field(..., description="The main weather condition")
description: str = Field(..., description="A detailed description of the weather")
temperature: float = Field(..., description="Current temperature in Celsius")
feels_like: float = Field(..., description="Feels-like temperature in Celsius")
temp_min: float = Field(..., description="Minimum temperature in Celsius")
temp_max: float = Field(..., description="Maximum temperature in Celsius")

class QueryWeatherSchema(BaseModel):
"""Schema for querying weather information by city name."""
city_name: str = Field(..., description="The name of the city to query weather information")


@tool(args_schema=WeatherInfo)
def insert_weather_to_db(city_id, city_name, main_weather, description, temperature, feels_like, temp_min, temp_max):
"""Insert weather information into the database."""
session = Session() # 确保为每次操作创建新的会话
try:
# 创建天气实例
weather = Weather(
city_id=city_id,
city_name=city_name,
main_weather=main_weather,
description=description,
temperature=temperature,
feels_like=feels_like,
temp_min=temp_min,
temp_max=temp_max
)
# 使用 merge 方法来插入或更新(如果已有记录则更新)
session.merge(weather)
# 提交事务
session.commit()
return {"messages": [f"天气数据已成功存储至Mysql数据库。"]}
except Exception as e:
session.rollback() # 出错时回滚
return {"messages": [f"数据存储失败,错误原因:{e}"]}
finally:
session.close() # 关闭会话


@tool(args_schema=QueryWeatherSchema)
def query_weather_from_db(city_name: str):
"""Query weather information from the database by city name."""
session = Session()
try:
# 查询天气数据
weather_data = session.query(Weather).filter(Weather.city_name == city_name).first()
if weather_data:
return {
"city_id": weather_data.city_id,
"city_name": weather_data.city_name,
"main_weather": weather_data.main_weather,
"description": weather_data.description,
"temperature": weather_data.temperature,
"feels_like": weather_data.feels_like,
"temp_min": weather_data.temp_min,
"temp_max": weather_data.temp_max
}
else:
return {"messages": [f"未找到城市 '{city_name}' 的天气信息。"]}
except Exception as e:
return {"messages": [f"查询失败,错误原因:{e}"]}
finally:
session.close() # 关闭会话

  然后,定义实时联网检索外部工具,通过该函数获取最新的网络数据信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class SearchQuery(BaseModel):
query: str = Field(description="Questions for networking queries")


@tool(args_schema = SearchQuery)
def fetch_real_time_info(query):
"""Get real-time Internet information"""
url = "https://google.serper.dev/search"
payload = json.dumps({
"q": query,
"num": 1,
})
headers = {
'X-API-KEY': 'xxx',
'Content-Type': 'application/json'
}

response = requests.post(url, headers=headers, data=payload)
data = json.loads(response.text) # 将返回的JSON字符串转换为字典
if 'organic' in data:
return json.dumps(data['organic'], ensure_ascii=False) # 返回'organic'部分的JSON字符串
else:
return json.dumps({"error": "No organic results found"}, ensure_ascii=False) # 如果没有'organic'键,返回错误信息

  然后把所有定义的工具存储在一个列表中,如下代码所示:

1
tools = [fetch_real_time_info, get_weather, insert_weather_to_db, query_weather_from_db]
1
tools
[StructuredTool(name='fetch_real_time_info', description='Get real-time Internet information', args_schema=<class '__main__.SearchQuery'>, func=<function fetch_real_time_info at 0x00000222A40605E0>),
 <function __main__.get_weather(loc)>,
 StructuredTool(name='insert_weather_to_db', description='Insert weather information into the database.', args_schema=<class '__main__.WeatherInfo'>, func=<function insert_weather_to_db at 0x00000222A4060C20>),
 StructuredTool(name='query_weather_from_db', description='Query weather information from the database by city name.', args_schema=<class '__main__.QueryWeatherSchema'>, func=<function query_weather_from_db at 0x00000222A4060CC0>)]

  准备好工具后,接下来定义用于构建AI Agent的大模型实例,这里我们使用OpenAI的在线GPT-4模型。代码如下:

1
2
3
4
5
6
7
8
9
import getpass
import os
from langchain_openai import ChatOpenAI

if not os.environ.get("OPENAI_API_KEY"):
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")


llm = ChatOpenAI(model="gpt-4o")

  当有了工具列表和模型后,就可以通过create_react_agent这个LangGraph框架中预构建的方法来创建自治循环代理(ReAct)的工作流,其必要的参数如下:

  • model: 支持工具调用的LangChain聊天模型。
  • tools: 工具列表、ToolExecutor 或 ToolNode 实例。
  • state_schema:图的状态模式。必须有messagesis_last_step键。默认为定义这两个键的Agent State

  上述三点我们均在前面的课程中详细且作为重点介绍过,大家应该是比较容易理解的。所以,创建ReAct代理的代码就如下所示:

1
2
3
from langgraph.prebuilt import create_react_agent

graph = create_react_agent(llm, tools=tools)
1
graph
<langgraph.graph.state.CompiledStateGraph at 0x222a674c610>
image-20260207160130274  

我们可以逐步的分析和解释一下这一行代码中涉及的图构建过程:

  • Step 1. 定义图状态模式

  LangGraph中的主要图类型是StateGraph。每个节点通过State中的参数获取有效信息,执行完节点的内部逻辑后,更新该State状态中的值。不同的状态模式,可以通过注释设置状态的特定属性(例如覆盖现有值)或添加到现有属性。伪代码如下:

1
2
3
4
5
6
7
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph.message import add_messages


class State(TypedDict):
messages: Annotated[list, add_messages]
  • Step 2. 定义Router Function

  设置边缘条件,有条件的原因是,根据节点的输出,可以采用多个路径之一。在该节点运行之前,所采用的路径是未知的(由大模型决定)。

  • 条件边缘:调用代理后,如果代理说要采取行动,那么应该调用调用工具的函数。如果代理说已经完成,那么就应该完成。
  • 正常边:调用工具后,它应该始终返回给代理来决定下一步做什么。

  伪代码如下:

1
2
3
4
5
6
7
8
9
10
# 定义决定是否继续执行任务的路由函数
def should_continue(state: State):
messages = state["messages"]
last_message = messages[-1]
# 如果不是工具调用,则结束
if not last_message.tool_calls:
return END
# 如果是的话,则进入工具库中选择函数执行
else:
return "tools"
  • Step 3. 定义大模型的交互函数

  接下来需要通过一个节点函数加载我想要使用的大模型。它需要满足两个标准:

  • 应该与消息一起使用,因为图的状态主要是消息列表(聊天历史记录)。
  • 需要与工具调用一起使用,其内部使用的是预构建的ToolNode。

  伪代码如下:

1
2
3
4
5
6
7
8
9
10
from typing import Literal

from langchain_core.runnables import RunnableConfig

# 定义大模型交互的节点函数
async def call_model(state: State, config: RunnableConfig):
messages = state["messages"]
response = await model.ainvoke(messages, config)
# 将调用大模型后得到的响应,追加到消息列表中
return {"messages": response}
  • Step 4. 构建图结构

  最后,把上述所有的组件放在一起构建图结构,这与我们手动构建图的方式基本一致,伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from langgraph.graph import END, START, StateGraph

# 定义一个新图
workflow = StateGraph(State)

# 添加两个节点
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)

# 设置起始节点为 agent
workflow.add_edge(START, "agent")

# 添加条件边 -- > Router Agent
workflow.add_conditional_edges(
"agent",
should_continue,
["tools", END],
)

# 添加回调边
workflow.add_edge("tools", "agent")

# 编译图
app = workflow.compile()

  理解了上面的create_react_agent方法内部的构建原理后,其实就能明白:当通过create_react_agent(llm, tools=tools)一行代码的执行,现在得到的已经是一个编译后、可执行的图了。我们可以通过mermaid方法来可视化经过create_react_agent方法构造出来的图结构,代码如下所示:

1
2
3
from IPython.display import Image, display

display(Image(graph.get_graph().draw_mermaid_png()))
image-20260207160529118

  返回的是编译好的LangGraph可运行程序,可直接用于聊天交互。调用方式则和之前使用的方法一样,我们可以依次针对不同复杂程度的需求依次进行提问。首先是测试是否可以不使用工具,直接调用大模型生成响应。

1
2
3
4
5
6
# query="你好,请你介绍一下你自己"
# input_message = {"messages": [HumanMessage(content=query)]}

# 可以自动处理成 HumanMessage 的消息格式
finan_response = graph.invoke({"messages":["你好,请你介绍一下你自己"]})
finan_response
{'messages': [HumanMessage(content='你好,请你介绍一下你自己', additional_kwargs={}, response_metadata={}, id='268158b3-ec6d-44a7-bbd5-bb43d449ff7e'),
  AIMessage(content='你好!我是一个由人工智能驱动的助手,旨在帮助解答问题、提供信息并协助完成各种任务。我可以处理广泛的主题,包括但不限于科技、教育、娱乐、天气、新闻等。如果你有任何特定的问题或需要帮助的地方,请随时告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 67, 'prompt_tokens': 343, 'total_tokens': 410, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'stop', 'logprobs': None}, id='run-968ec2f8-eb4b-45cf-ac55-398deba6e6fe-0', usage_metadata={'input_tokens': 343, 'output_tokens': 67, 'total_tokens': 410, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}
1
finan_response["messages"][-1].content
'你好!我是一个由人工智能驱动的助手,旨在帮助解答问题、提供信息并协助完成各种任务。我可以处理广泛的主题,包括但不限于科技、教育、娱乐、天气、新闻等。如果你有任何特定的问题或需要帮助的地方,请随时告诉我!'

  加大输入问题的复杂度,接下来我们提问的问题希望它能够自动找到正确的工具函数,基于工具的执行结果作为既定的事实,引导生成最终的回复。

1
2
3
finan_response = graph.invoke({"messages":["北京今天的天气怎么样?"]})

finan_response
<__main__.Weather object at 0x00000222A5896390>

{'messages': [HumanMessage(content='北京今天的天气怎么样?', additional_kwargs={}, response_metadata={}, id='3ea29a69-311d-4003-935f-18ca24bc9e6f'),
  AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_BMA4Jp782AMVBw4VS1x3nv8h', 'function': {'arguments': '{"city_name":"Beijing"}', 'name': 'query_weather_from_db'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 18, 'prompt_tokens': 342, 'total_tokens': 360, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-eb43ab41-161c-4acb-b8d7-b5890745ce55-0', tool_calls=[{'name': 'query_weather_from_db', 'args': {'city_name': 'Beijing'}, 'id': 'call_BMA4Jp782AMVBw4VS1x3nv8h', 'type': 'tool_call'}], usage_metadata={'input_tokens': 342, 'output_tokens': 18, 'total_tokens': 360, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),
  ToolMessage(content='{"city_id": 1816670, "city_name": "Beijing", "main_weather": "Clouds", "description": "晴,少云", "temperature": 14.94, "feels_like": 13.59, "temp_min": 14.94, "temp_max": 14.94}', name='query_weather_from_db', id='8b21e310-8581-4a4f-b3a0-c3c2b4b22195', tool_call_id='call_BMA4Jp782AMVBw4VS1x3nv8h'),
  AIMessage(content='北京今天的天气是多云的。具体情况如下:\n\n- 天气描述:晴,少云\n- 当前温度:14.94°C\n- 体感温度:13.59°C\n- 最低温度:14.94°C\n- 最高温度:14.94°C', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 67, 'prompt_tokens': 440, 'total_tokens': 507, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'stop', 'logprobs': None}, id='run-25dabd3b-195e-49ce-a431-b9f535fdd01c-0', usage_metadata={'input_tokens': 440, 'output_tokens': 67, 'total_tokens': 507, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}
1
finan_response["messages"][-1].content
'北京今天的天气是多云的。具体情况如下:\n\n- 天气描述:晴,少云\n- 当前温度:14.94°C\n- 体感温度:13.59°C\n- 最低温度:14.94°C\n- 最高温度:14.94°C'
1
2
3
finan_response = graph.invoke({"messages":["北京今天的天气怎么样?"]})

finan_response
<__main__.Weather object at 0x00000222A5896390>

{'messages': [HumanMessage(content='北京今天的天气怎么样?', additional_kwargs={}, response_metadata={}, id='3ea29a69-311d-4003-935f-18ca24bc9e6f'),
  AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_BMA4Jp782AMVBw4VS1x3nv8h', 'function': {'arguments': '{"city_name":"Beijing"}', 'name': 'query_weather_from_db'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 18, 'prompt_tokens': 342, 'total_tokens': 360, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-eb43ab41-161c-4acb-b8d7-b5890745ce55-0', tool_calls=[{'name': 'query_weather_from_db', 'args': {'city_name': 'Beijing'}, 'id': 'call_BMA4Jp782AMVBw4VS1x3nv8h', 'type': 'tool_call'}], usage_metadata={'input_tokens': 342, 'output_tokens': 18, 'total_tokens': 360, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),
  ToolMessage(content='{"city_id": 1816670, "city_name": "Beijing", "main_weather": "Clouds", "description": "晴,少云", "temperature": 14.94, "feels_like": 13.59, "temp_min": 14.94, "temp_max": 14.94}', name='query_weather_from_db', id='8b21e310-8581-4a4f-b3a0-c3c2b4b22195', tool_call_id='call_BMA4Jp782AMVBw4VS1x3nv8h'),
  AIMessage(content='北京今天的天气是多云的。具体情况如下:\n\n- 天气描述:晴,少云\n- 当前温度:14.94°C\n- 体感温度:13.59°C\n- 最低温度:14.94°C\n- 最高温度:14.94°C', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 67, 'prompt_tokens': 440, 'total_tokens': 507, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'stop', 'logprobs': None}, id='run-25dabd3b-195e-49ce-a431-b9f535fdd01c-0', usage_metadata={'input_tokens': 440, 'output_tokens': 67, 'total_tokens': 507, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}
1
2
3
finan_response = graph.invoke({"messages":["你知道 cloud 3.5 发布的 computer use 吗?请用中文回复我"]})

finan_response
{'messages': [HumanMessage(content='你知道 cloud 3.5 发布的 computer use 吗?请用中文回复我', additional_kwargs={}, response_metadata={}, id='c1ba742a-2c74-4aed-b774-b176ab60e8e1'),
  AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_xt4I3LDtRRzOYKyb01fA4Rv5', 'function': {'arguments': '{"query":"cloud 3.5 发布的 computer use"}', 'name': 'fetch_real_time_info'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 24, 'prompt_tokens': 355, 'total_tokens': 379, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-cb591e6e-f410-4ab0-a77a-ece56767b728-0', tool_calls=[{'name': 'fetch_real_time_info', 'args': {'query': 'cloud 3.5 发布的 computer use'}, 'id': 'call_xt4I3LDtRRzOYKyb01fA4Rv5', 'type': 'tool_call'}], usage_metadata={'input_tokens': 355, 'output_tokens': 24, 'total_tokens': 379, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),
  ToolMessage(content='[{"title": "升级了来自Anthropic 的Claude 3.5 Sonnet(现已推出) - AWS", "link": "https://aws.amazon.com/cn/blogs/china/upgraded-claude-3-5-sonnet-from-anthropic-available-now-computer-use-public-beta-and-claude-3-5-haiku-coming-soon-in-amazon-bedrock/", "snippet": "计算机使用– Claude 3.5 Sonnet 目前在Amazon Bedrock 中提供计算机使用功能(公测版),这使得Claude 能够感知并与计算机界面进行交互。开发人员可以 ...", "date": "5 days ago", "position": 1}]', name='fetch_real_time_info', id='dba1ac63-46d2-4b19-926f-3c28da7b29f6', tool_call_id='call_xt4I3LDtRRzOYKyb01fA4Rv5'),
  AIMessage(content='关于 Cloud 3.5 发布的 computer use 功能,目前的信息显示,Claude 3.5 Sonnet 现在在 Amazon Bedrock 中提供计算机使用功能(公测版)。这使得 Claude 能够感知并与计算机界面进行交互。更多详情可以查看 [AWS 官方博客](https://aws.amazon.com/cn/blogs/china/upgraded-claude-3-5-sonnet-from-anthropic-available-now-computer-use-public-beta-and-claude-3-5-haiku-coming-soon-in-amazon-bedrock/)。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 122, 'prompt_tokens': 541, 'total_tokens': 663, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_45c6de4934', 'finish_reason': 'stop', 'logprobs': None}, id='run-e45a1550-0c7d-4096-b1a0-238ca7cc8248-0', usage_metadata={'input_tokens': 541, 'output_tokens': 122, 'total_tokens': 663, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}
1
finan_response["messages"][-1].content
'关于 Cloud 3.5 发布的 computer use 功能,目前的信息显示,Claude 3.5 Sonnet 现在在 Amazon Bedrock 中提供计算机使用功能(公测版)。这使得 Claude 能够感知并与计算机界面进行交互。更多详情可以查看 [AWS 官方博客](https://aws.amazon.com/cn/blogs/china/upgraded-claude-3-5-sonnet-from-anthropic-available-now-computer-use-public-beta-and-claude-3-5-haiku-coming-soon-in-amazon-bedrock/)。'

  继续加大问题的难度,我们要在一个问题中涉及多个工具的使用,比如:

1
2
3
finan_response = graph.invoke({"messages":["帮我查一下北京、上海,哈尔滨三个城市的天气,告诉我哪个城市最适合出游。同时,把查询到的数据存储到数据库中"]})

finan_response
{'messages': [HumanMessage(content='帮我查一下北京、上海,哈尔滨三个城市的天气,告诉我哪个城市最适合出游。同时,把查询到的数据存储到数据库中', additional_kwargs={}, response_metadata={}, id='7da34790-3f00-46d0-859e-b6f7cef4ee5d'),
  AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_ro4igb9igPivvs0HZXKHAhwG', 'function': {'arguments': '{"loc": "Beijing"}', 'name': 'get_weather'}, 'type': 'function'}, {'id': 'call_IRBeslzB7okZa28rAnrNdNbB', 'function': {'arguments': '{"loc": "Shanghai"}', 'name': 'get_weather'}, 'type': 'function'}, {'id': 'call_J3yXYOErmnZmooW7A0Wrsh5I', 'function': {'arguments': '{"loc": "Harbin"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 60, 'prompt_tokens': 370, 'total_tokens': 430, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-e630e698-033f-463c-8b48-2107eaa616c2-0', tool_calls=[{'name': 'get_weather', 'args': {'loc': 'Beijing'}, 'id': 'call_ro4igb9igPivvs0HZXKHAhwG', 'type': 'tool_call'}, {'name': 'get_weather', 'args': {'loc': 'Shanghai'}, 'id': 'call_IRBeslzB7okZa28rAnrNdNbB', 'type': 'tool_call'}, {'name': 'get_weather', 'args': {'loc': 'Harbin'}, 'id': 'call_J3yXYOErmnZmooW7A0Wrsh5I', 'type': 'tool_call'}], usage_metadata={'input_tokens': 370, 'output_tokens': 60, 'total_tokens': 430, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),
  ToolMessage(content='{"coord": {"lon": 116.3972, "lat": 39.9075}, "weather": [{"id": 800, "main": "Clear", "description": "\\u6674", "icon": "01n"}], "base": "stations", "main": {"temp": 17.72, "feels_like": 16.36, "temp_min": 14.94, "temp_max": 17.72, "pressure": 1017, "humidity": 31, "sea_level": 1017, "grnd_level": 1012}, "visibility": 10000, "wind": {"speed": 1.3, "deg": 282, "gust": 4.19}, "clouds": {"all": 0}, "dt": 1730195826, "sys": {"type": 2, "id": 2000403, "country": "CN", "sunrise": 1730155186, "sunset": 1730193377}, "timezone": 28800, "id": 1816670, "name": "Beijing", "cod": 200}', name='get_weather', id='969b2663-e3db-4b18-b5ce-433b65adf673', tool_call_id='call_ro4igb9igPivvs0HZXKHAhwG'),
  ToolMessage(content='{"coord": {"lon": 121.4581, "lat": 31.2222}, "weather": [{"id": 800, "main": "Clear", "description": "\\u6674", "icon": "01n"}], "base": "stations", "main": {"temp": 17.92, "feels_like": 17.31, "temp_min": 17.92, "temp_max": 17.93, "pressure": 1019, "humidity": 59, "sea_level": 1019, "grnd_level": 1017}, "visibility": 10000, "wind": {"speed": 5, "deg": 20}, "clouds": {"all": 0}, "dt": 1730196000, "sys": {"type": 1, "id": 9659, "country": "CN", "sunrise": 1730153230, "sunset": 1730192904}, "timezone": 28800, "id": 1796236, "name": "Shanghai", "cod": 200}', name='get_weather', id='75725f62-f9d2-4fe2-8865-fea606416b6a', tool_call_id='call_IRBeslzB7okZa28rAnrNdNbB'),
  ToolMessage(content='{"coord": {"lon": 126.65, "lat": 45.75}, "weather": [{"id": 500, "main": "Rain", "description": "\\u5c0f\\u96e8", "icon": "10n"}], "base": "stations", "main": {"temp": 8.62, "feels_like": 8.62, "temp_min": 8.62, "temp_max": 8.62, "pressure": 1016, "humidity": 70, "sea_level": 1016, "grnd_level": 999}, "visibility": 10000, "wind": {"speed": 0.91, "deg": 129, "gust": 1.16}, "rain": {"1h": 0.36}, "clouds": {"all": 97}, "dt": 1730196009, "sys": {"country": "CN", "sunrise": 1730153336, "sunset": 1730190306}, "timezone": 28800, "id": 2037013, "name": "Harbin", "cod": 200}', name='get_weather', id='6b49bbfe-e45d-449b-84b2-314f760467ca', tool_call_id='call_J3yXYOErmnZmooW7A0Wrsh5I'),
  AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_izOMSYgvfloxuJkXgDB1Voz6', 'function': {'arguments': '{"city_id": 1816670, "city_name": "Beijing", "main_weather": "Clear", "description": "晴", "temperature": 17.72, "feels_like": 16.36, "temp_min": 14.94, "temp_max": 17.72}', 'name': 'insert_weather_to_db'}, 'type': 'function'}, {'id': 'call_Bc8WJdfNZMzo3hXCyunaCznj', 'function': {'arguments': '{"city_id": 1796236, "city_name": "Shanghai", "main_weather": "Clear", "description": "晴", "temperature": 17.92, "feels_like": 17.31, "temp_min": 17.92, "temp_max": 17.93}', 'name': 'insert_weather_to_db'}, 'type': 'function'}, {'id': 'call_NanSRD2EDHeOlUktShccuSaW', 'function': {'arguments': '{"city_id": 2037013, "city_name": "Harbin", "main_weather": "Rain", "description": "小雨", "temperature": 8.62, "feels_like": 8.62, "temp_min": 8.62, "temp_max": 8.62}', 'name': 'insert_weather_to_db'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 202, 'prompt_tokens': 1177, 'total_tokens': 1379, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-8a14762c-6309-4f27-8eae-a422867a293d-0', tool_calls=[{'name': 'insert_weather_to_db', 'args': {'city_id': 1816670, 'city_name': 'Beijing', 'main_weather': 'Clear', 'description': '晴', 'temperature': 17.72, 'feels_like': 16.36, 'temp_min': 14.94, 'temp_max': 17.72}, 'id': 'call_izOMSYgvfloxuJkXgDB1Voz6', 'type': 'tool_call'}, {'name': 'insert_weather_to_db', 'args': {'city_id': 1796236, 'city_name': 'Shanghai', 'main_weather': 'Clear', 'description': '晴', 'temperature': 17.92, 'feels_like': 17.31, 'temp_min': 17.92, 'temp_max': 17.93}, 'id': 'call_Bc8WJdfNZMzo3hXCyunaCznj', 'type': 'tool_call'}, {'name': 'insert_weather_to_db', 'args': {'city_id': 2037013, 'city_name': 'Harbin', 'main_weather': 'Rain', 'description': '小雨', 'temperature': 8.62, 'feels_like': 8.62, 'temp_min': 8.62, 'temp_max': 8.62}, 'id': 'call_NanSRD2EDHeOlUktShccuSaW', 'type': 'tool_call'}], usage_metadata={'input_tokens': 1177, 'output_tokens': 202, 'total_tokens': 1379, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),
  ToolMessage(content='{"messages": ["天气数据已成功存储至Mysql数据库。"]}', name='insert_weather_to_db', id='3faca92c-6a82-40ba-9f59-a5f62326400f', tool_call_id='call_izOMSYgvfloxuJkXgDB1Voz6'),
  ToolMessage(content='{"messages": ["天气数据已成功存储至Mysql数据库。"]}', name='insert_weather_to_db', id='fafbdce3-6ea1-4d93-8ec3-8a32606e6ca7', tool_call_id='call_Bc8WJdfNZMzo3hXCyunaCznj'),
  ToolMessage(content='{"messages": ["天气数据已成功存储至Mysql数据库。"]}', name='insert_weather_to_db', id='0c98e550-8562-4125-9e08-2391c7c1b703', tool_call_id='call_NanSRD2EDHeOlUktShccuSaW'),
  AIMessage(content='以下是北京、上海和哈尔滨的天气情况:\n\n1. **北京**:\n   - 天气:晴\n   - 温度:17.72°C\n   - 体感温度:16.36°C\n   - 最低温度:14.94°C\n   - 最高温度:17.72°C\n\n2. **上海**:\n   - 天气:晴\n   - 温度:17.92°C\n   - 体感温度:17.31°C\n   - 最低温度:17.92°C\n   - 最高温度:17.93°C\n\n3. **哈尔滨**:\n   - 天气:小雨\n   - 温度:8.62°C\n   - 体感温度:8.62°C\n   - 最低温度:8.62°C\n   - 最高温度:8.62°C\n\n根据天气情况,北京和上海的天气都是晴朗的,比较适合出游。哈尔滨有小雨,不太适合出游。如果一定要选择一个最适合出游的城市,我会推荐上海,因为气温稍微高一点,更加舒适。\n\n所有查询到的天气数据已经成功存储到数据库中。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 267, 'prompt_tokens': 1558, 'total_tokens': 1825, 'prompt_tokens_details': {'cached_tokens': 1280}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'stop', 'logprobs': None}, id='run-51e04ca7-3475-49fb-a5c0-8493faf347a1-0', usage_metadata={'input_tokens': 1558, 'output_tokens': 267, 'total_tokens': 1825, 'input_token_details': {'cache_read': 1280}, 'output_token_details': {'reasoning': 0}})]}
1
finan_response["messages"][-1].content
'以下是北京、上海和哈尔滨的天气情况:\n\n1. **北京**:\n   - 天气:晴\n   - 温度:17.72°C\n   - 体感温度:16.36°C\n   - 最低温度:14.94°C\n   - 最高温度:17.72°C\n\n2. **上海**:\n   - 天气:晴\n   - 温度:17.92°C\n   - 体感温度:17.31°C\n   - 最低温度:17.92°C\n   - 最高温度:17.93°C\n\n3. **哈尔滨**:\n   - 天气:小雨\n   - 温度:8.62°C\n   - 体感温度:8.62°C\n   - 最低温度:8.62°C\n   - 最高温度:8.62°C\n\n根据天气情况,北京和上海的天气都是晴朗的,比较适合出游。哈尔滨有小雨,不太适合出游。如果一定要选择一个最适合出游的城市,我会推荐上海,因为气温稍微高一点,更加舒适。\n\n所有查询到的天气数据已经成功存储到数据库中。'

  同时,可以在数据库中查看数据的插入情况:

1
2
3
finan_response = graph.invoke({"messages":["帮我分析一下数据库中北京和哈尔滨城市天气的信息,做一个详细的对比,并生成出行建议"]})

finan_response
<__main__.Weather object at 0x00000222A72E6350>
<__main__.Weather object at 0x00000222A6F4AC50>

{'messages': [HumanMessage(content='帮我分析一下数据库中北京和哈尔滨城市天气的信息,做一个详细的对比,并生成出行建议', additional_kwargs={}, response_metadata={}, id='de625a6f-c247-41dd-9bf0-e5e2af41459f'),
  AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_f2h95mzFmIAZ7LwcBaL1QUHP', 'function': {'arguments': '{"city_name": "Beijing"}', 'name': 'query_weather_from_db'}, 'type': 'function'}, {'id': 'call_8P3qlq6yM9kelaHqRZ9zZ4O0', 'function': {'arguments': '{"city_name": "Harbin"}', 'name': 'query_weather_from_db'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 52, 'prompt_tokens': 361, 'total_tokens': 413, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-33535fcc-cb90-4bc5-b8e2-421d7b20e68b-0', tool_calls=[{'name': 'query_weather_from_db', 'args': {'city_name': 'Beijing'}, 'id': 'call_f2h95mzFmIAZ7LwcBaL1QUHP', 'type': 'tool_call'}, {'name': 'query_weather_from_db', 'args': {'city_name': 'Harbin'}, 'id': 'call_8P3qlq6yM9kelaHqRZ9zZ4O0', 'type': 'tool_call'}], usage_metadata={'input_tokens': 361, 'output_tokens': 52, 'total_tokens': 413, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),
  ToolMessage(content='{"city_id": 1816670, "city_name": "Beijing", "main_weather": "Clear", "description": "晴", "temperature": 17.72, "feels_like": 16.36, "temp_min": 14.94, "temp_max": 17.72}', name='query_weather_from_db', id='d1b400d9-02f4-4ffd-9f00-0cfc2298bf92', tool_call_id='call_f2h95mzFmIAZ7LwcBaL1QUHP'),
  ToolMessage(content='{"city_id": 2037013, "city_name": "Harbin", "main_weather": "Rain", "description": "小雨", "temperature": 8.62, "feels_like": 8.62, "temp_min": 8.62, "temp_max": 8.62}', name='query_weather_from_db', id='d84861cd-fc8f-44f8-8faa-5b5b8218bace', tool_call_id='call_8P3qlq6yM9kelaHqRZ9zZ4O0'),
  AIMessage(content='### 天气对比分析\n\n#### 北京\n- **天气状况**: 晴\n- **详细描述**: 晴\n- **当前温度**: 17.72°C\n- **体感温度**: 16.36°C\n- **最低温度**: 14.94°C\n- **最高温度**: 17.72°C\n\n#### 哈尔滨\n- **天气状况**: 雨\n- **详细描述**: 小雨\n- **当前温度**: 8.62°C\n- **体感温度**: 8.62°C\n- **最低温度**: 8.62°C\n- **最高温度**: 8.62°C\n\n### 出行建议\n\n#### 北京\n1. **穿着建议**: 北京天气晴朗,温度适中,建议穿轻便的春秋装。\n2. **活动建议**: 适合户外活动,如散步、慢跑或骑行。\n3. **防晒措施**: 即使是晴天,依然建议使用防晒霜和佩戴太阳镜。\n\n#### 哈尔滨\n1. **穿着建议**: 哈尔滨气温较低且有小雨,建议穿保暖的衣物,并携带雨具。\n2. **活动建议**: 降雨可能影响户外活动,建议选择室内活动。\n3. **行车安全**: 雨天路滑,驾车请注意安全,保持车距。\n\n这两座城市当前的天气差异较大,出行前请根据实际天气情况做好相应准备。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 355, 'prompt_tokens': 566, 'total_tokens': 921, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_45c6de4934', 'finish_reason': 'stop', 'logprobs': None}, id='run-af1a77c2-2fd4-4549-8683-d8df867221d1-0', usage_metadata={'input_tokens': 566, 'output_tokens': 355, 'total_tokens': 921, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}
1
print(finan_response["messages"][-1].content)
### 天气对比分析

#### 北京
- **天气状况**: 晴
- **详细描述**: 晴
- **当前温度**: 17.72°C
- **体感温度**: 16.36°C
- **最低温度**: 14.94°C
- **最高温度**: 17.72°C

#### 哈尔滨
- **天气状况**: 雨
- **详细描述**: 小雨
- **当前温度**: 8.62°C
- **体感温度**: 8.62°C
- **最低温度**: 8.62°C
- **最高温度**: 8.62°C

### 出行建议

#### 北京
1. **穿着建议**: 北京天气晴朗,温度适中,建议穿轻便的春秋装。
2. **活动建议**: 适合户外活动,如散步、慢跑或骑行。
3. **防晒措施**: 即使是晴天,依然建议使用防晒霜和佩戴太阳镜。

#### 哈尔滨
1. **穿着建议**: 哈尔滨气温较低且有小雨,建议穿保暖的衣物,并携带雨具。
2. **活动建议**: 降雨可能影响户外活动,建议选择室内活动。
3. **行车安全**: 雨天路滑,驾车请注意安全,保持车距。

这两座城市当前的天气差异较大,出行前请根据实际天气情况做好相应准备。

  通过对不同复杂程度输入问题的测试,我们发现当前架构能够非常准确且快速地完成任务目标。在涉及多个任务的顺序执行时,ReAct 代理能够自主决策并执行,真正实现了完全的自治循环代理。此外,其可扩展性也十分出色。对于不同的业务需求,我们只需调整接入的大模型实例(可使用其他开源或在线模型)作为 ReAct 的基础模型。对于工具的配置,也无需特别进行复杂的编排,只需明确定义每个工具的输入和输出,然后通过工具列表的形式直接注册到大模型实例及 ToolNode 实例中。这种方法在快速构建智能代理方面,非常值得大家尝试。

3. LangGraph中的事件流

  流式输出的作用在于,它能实时捕捉并输出任务处理过程中的状态变化。这意味着,任何中间过程中的新状态和值都可以被即时获取到。所以,流式输出功能本质上不直接参与Agent的执行过程,仅仅是用来追踪、记录Agent在处理不同任务时产生的各个事件、状态和值。

  在实际应用中,流式输出尤其适用于需要快速反馈的业务场景,如聊天机器人,因为大语言模型可能需要几秒钟才能生成对查询的完整响应,这远远慢于应用程序对最终用户的响应速度约为 200-300 毫秒的阈值,如果是涉及多个大模型调用的复杂应用程序,这种延时会变得更加明显。让应用程序感觉响应更快的关键策略是显示中间进度;即,通过 token 流式传输大模型Token的输出,以此来显著提升用户体验。而在开发阶段,利用流式输出功能可以准确追踪到事件的具体执行阶段,并捕获相关数据,从而接入不同逻辑的数据处理和决策流程。是我们在应用开发中必须理解和掌握的技术点。

  流式输出功能在LangGraph 框架中的实现方式,相较于Assistant API是简单很多的,但基本思路一样。因为LangGraph底层是基于 LangChain 构建的,所有就直接把LangChain中的回调系统拿过来使用了。LangChain中的流式输出是:以块的形式传输最终输出,即一旦监测到有可用的块,就直接生成它。最常见和最关键的流数据是大模型本身生成的输出。 大模型通常需要时间才能生成完整的响应,通过实时流式传输输出,用户可以在生成时看到部分结果,这可以提供即时反馈并有助于减少用户的等待时间。如下所示:

1
2
3
4
5
6
7
8
9
import getpass
import os
from langchain_openai import ChatOpenAI

if not os.environ.get("OPENAI_API_KEY"):
os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")


llm = ChatOpenAI(model="gpt-4o")
1
2
3
4
chunks = []
async for chunk in llm.astream("你好,请你详细的介绍一下你自己。"):
chunks.append(chunk)
print(chunk.content, end="|", flush=True)
|你好|!|我是|一个|由|人工|智能|驱|动|的|虚|拟|助手|,|旨|在|帮助|回答|问题|和|提供|信息|。我|能够|处理|各种|主题|,包括|常|识|问题|、|技术|支持|、|语言|翻|译|、|写|作|建议|等等|。|我的|设计|目标|是|尽|量|理解|你的|问题|并|提供|有|用|的|答案|。

|由于|我是|基|于|大|规模|的|语言|模型|构|建|的|,因此|我的|知识|和|能力|是|基|于|对|大量|文本|数据|的|分析|。我|没有|个人|经验|或|感|情|,但|我|会|尽|力|为|你|提供|准确|和|及时|的信息|。

|如果|你|有|任何|问题|或|需要|帮助|,请|随|时|告诉|我|!||
1
chunks[0]
AIMessageChunk(content='', additional_kwargs={}, response_metadata={}, id='run-034a91b3-9509-4442-8c0d-3d17774451bf')

  每一个块,都是一个AIMessageChunk对象,用来代表AIMessage对象的一部分。消息块在设计上是可加的,比如:

1
chunks[0] + chunks[1] + chunks[2] + chunks[3] + chunks[4]
AIMessageChunk(content='你好!我是一个', additional_kwargs={}, response_metadata={}, id='run-034a91b3-9509-4442-8c0d-3d17774451bf')

  而进一步的,除了流式传输大模型的输出之外,通过更复杂的工作流程或管道流式传输进度也很有用,比如 AI Agent 中的中间处理过程,这就涉及到工作流概念。

3.1 LangGraph使用流输出

  LangGraph框架中的工作流中由各个步骤的节点和边组成。这里的流式传输涉及在各个节点请求更新时跟踪图状态的变化。这样可以更精细地监控工作流中当前处于活动状态的节点,并在工作流经过不同阶段时提供有关工作流状态的实时更新。其实现方式也是和LangChain一样通过.stream.astream方法执行流式输出,只不过适配到了图结构中。调用.stream.astream方法时可以指定几种不同的模式,即:

  • “values” :在图中的每个步骤之后流式传输状态的完整值。
  • “updates” :在图中的每个步骤之后将更新流式传输到状态。如果在同一步骤中进行多个更新(例如运行多个节点),则这些更新将单独流式传输。
  • “debug” :在整个图的执行过程中流式传输尽可能多的信息,主要用于调试程序。
  • “messages”:记录每个messages中的增量token
  • “custom”:自定义流,通过LangGraph 的 StreamWriter方法

  首先来看Stream方法,该方法返回一个迭代器,在生成输出块时同步生成它们。我们可以使用for循环来实时处理每个块。生成的块的类型取决于正在流式传输的组件。例如,当从大模型流式传输时,每个组件将是一个AIMessageChunk,但是,对于其他组件,块可能会有所不同。其LangGraph框架中实现的源码如下:

LangGraph Graph stream:https://reference.langchain.com/python/langgraph/graphs/#langgraph.graph.state.CompiledStateGraph.stream

1
2
3
4
5
6
7
8
9
10
11
12
def stream(
self,
input: Union[dict[str, Any], Any], # 图中的输入,从状态中取值
config: Optional[RunnableConfig] = None,
*,
stream_mode: Optional[Union[StreamMode, list[StreamMode]]] = None,
output_keys: Optional[Union[str, Sequence[str]]] = None, # 流媒体的键,默认为所有非上下文通道。
interrupt_before: Optional[Union[All, Sequence[str]]] = None, # 中断之前的节点,默认为图中的所有节点。
interrupt_after: Optional[Union[All, Sequence[str]]] = None, # 中断之后的节点,默认为图中的所有节点。
debug: Optional[bool] = None, # 执行过程中是否打印调试信息,默认为False。
subgraphs: bool = False, # 是否流式传输子图
) -> Iterator[Union[dict[str, Any], Any]]:
  • values :在图表的每个步骤之后流式传输状态的完整值。
1
2
3
4
5
6
7
8
def print_stream(stream):
for sub_stream in stream:
# print(sub_stream) # 就是上面的示例中非流式直接调用的全部信息
message = sub_stream["messages"][-1]
message.pretty_print()

input_message = {"messages": ["你好,南京现在的天气怎么样?"]}
print_stream(graph.stream(input_message, stream_mode="values"))
================================ Human Message =================================

你好,南京现在的天气怎么样?
================================== Ai Message ==================================
Tool Calls:
  query_weather_from_db (call_xfRWSscdr2S6Fgo1GnxAQUFk)
 Call ID: call_xfRWSscdr2S6Fgo1GnxAQUFk
  Args:
    city_name: Nanjing
None
================================= Tool Message =================================
Name: query_weather_from_db

{"messages": ["未找到城市 'Nanjing' 的天气信息。"]}
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_Wd4DNds56FewTYwx7Z6SEBnw)
 Call ID: call_Wd4DNds56FewTYwx7Z6SEBnw
  Args:
    loc: Nanjing
================================= Tool Message =================================
Name: get_weather

{"coord": {"lon": 118.7778, "lat": 32.0617}, "weather": [{"id": 800, "main": "Clear", "description": "\u6674", "icon": "01d"}], "base": "stations", "main": {"temp": 18.75, "feels_like": 18.12, "temp_min": 18.75, "temp_max": 18.75, "pressure": 1023, "humidity": 55, "sea_level": 1023, "grnd_level": 1020}, "visibility": 10000, "wind": {"speed": 4.89, "deg": 77, "gust": 6.84}, "clouds": {"all": 0}, "dt": 1730257590, "sys": {"country": "CN", "sunrise": 1730240389, "sunset": 1730279826}, "timezone": 28800, "id": 1799962, "name": "Nanjing", "cod": 200}
================================== Ai Message ==================================
Tool Calls:
  insert_weather_to_db (call_rcwMjfSIFM5S1WihC2RD8xIC)
 Call ID: call_rcwMjfSIFM5S1WihC2RD8xIC
  Args:
    city_id: 1799962
    city_name: Nanjing
    main_weather: Clear
    description: 晴
    temperature: 18.75
    feels_like: 18.12
    temp_min: 18.75
    temp_max: 18.75
================================= Tool Message =================================
Name: insert_weather_to_db

{"messages": ["天气数据已成功存储至Mysql数据库。"]}
================================== Ai Message ==================================

南京现在的天气是晴天,气温为18.75°C,体感温度约为18.12°C。空气清新,能见度良好。
  • updates :在图中的每个步骤之后将更新流式传输到状态。
1
2
3
4
5
6
def print_stream(stream):
for sub_stream in stream:
print(sub_stream) # 就是上面的示例中非流式直接调用的全部信息

input_message = {"messages": ["你好,天津、内蒙现在的天气怎么样?"]}
print_stream(graph.stream(input_message, stream_mode="updates"))
{'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Ma7bxsvHjIXCXozwmJieVtJJ', 'function': {'arguments': '{"loc": "Tianjin"}', 'name': 'get_weather'}, 'type': 'function'}, {'id': 'call_uM3KOsUgIogoBdJbcXwPYEqp', 'function': {'arguments': '{"loc": "Inner Mongolia"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 47, 'prompt_tokens': 347, 'total_tokens': 394, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-5cd03389-b67e-416d-a92f-9c02e4ca75b0-0', tool_calls=[{'name': 'get_weather', 'args': {'loc': 'Tianjin'}, 'id': 'call_Ma7bxsvHjIXCXozwmJieVtJJ', 'type': 'tool_call'}, {'name': 'get_weather', 'args': {'loc': 'Inner Mongolia'}, 'id': 'call_uM3KOsUgIogoBdJbcXwPYEqp', 'type': 'tool_call'}], usage_metadata={'input_tokens': 347, 'output_tokens': 47, 'total_tokens': 394, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}}
{'tools': {'messages': [ToolMessage(content='{"coord": {"lon": 117.1767, "lat": 39.1422}, "weather": [{"id": 800, "main": "Clear", "description": "\\u6674", "icon": "01d"}], "base": "stations", "main": {"temp": 18.97, "feels_like": 18.46, "temp_min": 18.97, "temp_max": 18.97, "pressure": 1025, "humidity": 59, "sea_level": 1025, "grnd_level": 1024}, "visibility": 10000, "wind": {"speed": 7, "deg": 140}, "clouds": {"all": 0}, "dt": 1730258008, "sys": {"type": 1, "id": 9619, "country": "CN", "sunrise": 1730241393, "sunset": 1730279591}, "timezone": 28800, "id": 1792947, "name": "Tianjin", "cod": 200}', name='get_weather', id='d667c453-d237-438f-9735-1b6d7854717d', tool_call_id='call_Ma7bxsvHjIXCXozwmJieVtJJ'), ToolMessage(content='{"cod": "404", "message": "city not found"}', name='get_weather', id='c81bf119-461b-4956-aab7-4bcfd67dc461', tool_call_id='call_uM3KOsUgIogoBdJbcXwPYEqp')]}}
{'agent': {'messages': [AIMessage(content='天津的天气情况如下:\n- 天气:晴\n- 温度:18.97°C\n- 体感温度:18.46°C\n- 风速:7 m/s\n- 湿度:59%\n\n内蒙古的天气信息暂时无法获取,可能是因为城市名不够具体或者数据暂时不可用。如果你有具体的内蒙古城市名称,可以提供给我以便查询。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 90, 'prompt_tokens': 659, 'total_tokens': 749, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'stop', 'logprobs': None}, id='run-e89e91d2-14a3-420c-b19d-08e59a57883f-0', usage_metadata={'input_tokens': 659, 'output_tokens': 90, 'total_tokens': 749, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}}
  • debug :在整个图中的执行过程中流式传输尽可能多的信息
1
2
3
4
5
6
def print_stream(stream):
for sub_stream in stream:
print(sub_stream) # 就是上面的示例中非流式直接调用的全部信息

input_message = {"messages": ["你好,天津、内蒙现在的天气怎么样?"]}
print_stream(graph.stream(input_message, stream_mode="debug"))
{'type': 'task', 'timestamp': '2024-10-30T03:14:44.538467+00:00', 'step': 1, 'payload': {'id': 'ec74ada5-a269-f1ab-3344-64ef7aa0cb0d', 'name': 'agent', 'input': {'messages': [HumanMessage(content='你好,天津、内蒙现在的天气怎么样?', additional_kwargs={}, response_metadata={}, id='2b048b3c-6ff7-4576-9e97-f5e1986ae085')], 'is_last_step': False}, 'triggers': ['start:agent']}}
{'type': 'task_result', 'timestamp': '2024-10-30T03:14:47.434922+00:00', 'step': 1, 'payload': {'id': 'ec74ada5-a269-f1ab-3344-64ef7aa0cb0d', 'name': 'agent', 'error': None, 'result': [('messages', [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_NaK0YDbmUSm1pSPgmcuaglHl', 'function': {'arguments': '{"loc": "Tianjin"}', 'name': 'get_weather'}, 'type': 'function'}, {'id': 'call_870GtpjxM8Rgw36N7wIqfRDq', 'function': {'arguments': '{"loc": "Inner Mongolia"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 47, 'prompt_tokens': 347, 'total_tokens': 394, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-6c23f36c-e854-4e3f-beef-04be5ae46041-0', tool_calls=[{'name': 'get_weather', 'args': {'loc': 'Tianjin'}, 'id': 'call_NaK0YDbmUSm1pSPgmcuaglHl', 'type': 'tool_call'}, {'name': 'get_weather', 'args': {'loc': 'Inner Mongolia'}, 'id': 'call_870GtpjxM8Rgw36N7wIqfRDq', 'type': 'tool_call'}], usage_metadata={'input_tokens': 347, 'output_tokens': 47, 'total_tokens': 394, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})])], 'interrupts': []}}
{'type': 'task', 'timestamp': '2024-10-30T03:14:47.434922+00:00', 'step': 2, 'payload': {'id': '29849df1-72f9-e753-4982-c0ca4403a93d', 'name': 'tools', 'input': {'messages': [HumanMessage(content='你好,天津、内蒙现在的天气怎么样?', additional_kwargs={}, response_metadata={}, id='2b048b3c-6ff7-4576-9e97-f5e1986ae085'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_NaK0YDbmUSm1pSPgmcuaglHl', 'function': {'arguments': '{"loc": "Tianjin"}', 'name': 'get_weather'}, 'type': 'function'}, {'id': 'call_870GtpjxM8Rgw36N7wIqfRDq', 'function': {'arguments': '{"loc": "Inner Mongolia"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 47, 'prompt_tokens': 347, 'total_tokens': 394, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-6c23f36c-e854-4e3f-beef-04be5ae46041-0', tool_calls=[{'name': 'get_weather', 'args': {'loc': 'Tianjin'}, 'id': 'call_NaK0YDbmUSm1pSPgmcuaglHl', 'type': 'tool_call'}, {'name': 'get_weather', 'args': {'loc': 'Inner Mongolia'}, 'id': 'call_870GtpjxM8Rgw36N7wIqfRDq', 'type': 'tool_call'}], usage_metadata={'input_tokens': 347, 'output_tokens': 47, 'total_tokens': 394, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})], 'is_last_step': False}, 'triggers': ['branch:agent:should_continue:tools']}}
{'type': 'task_result', 'timestamp': '2024-10-30T03:14:48.719462+00:00', 'step': 2, 'payload': {'id': '29849df1-72f9-e753-4982-c0ca4403a93d', 'name': 'tools', 'error': None, 'result': [('messages', [ToolMessage(content='{"coord": {"lon": 117.1767, "lat": 39.1422}, "weather": [{"id": 800, "main": "Clear", "description": "\\u6674", "icon": "01d"}], "base": "stations", "main": {"temp": 18.97, "feels_like": 18.46, "temp_min": 18.97, "temp_max": 18.97, "pressure": 1025, "humidity": 59, "sea_level": 1025, "grnd_level": 1024}, "visibility": 10000, "wind": {"speed": 7, "deg": 140}, "clouds": {"all": 0}, "dt": 1730258008, "sys": {"type": 1, "id": 9619, "country": "CN", "sunrise": 1730241393, "sunset": 1730279591}, "timezone": 28800, "id": 1792947, "name": "Tianjin", "cod": 200}', name='get_weather', id='ed06d7f2-4d33-4511-be9c-3325dccdc5de', tool_call_id='call_NaK0YDbmUSm1pSPgmcuaglHl'), ToolMessage(content='{"cod": "404", "message": "city not found"}', name='get_weather', id='d4f47099-64d4-4071-8956-515ae231cf79', tool_call_id='call_870GtpjxM8Rgw36N7wIqfRDq')])], 'interrupts': []}}
{'type': 'task', 'timestamp': '2024-10-30T03:14:48.719462+00:00', 'step': 3, 'payload': {'id': 'c0a70cf0-9581-d545-c4db-564234efbf12', 'name': 'agent', 'input': {'messages': [HumanMessage(content='你好,天津、内蒙现在的天气怎么样?', additional_kwargs={}, response_metadata={}, id='2b048b3c-6ff7-4576-9e97-f5e1986ae085'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_NaK0YDbmUSm1pSPgmcuaglHl', 'function': {'arguments': '{"loc": "Tianjin"}', 'name': 'get_weather'}, 'type': 'function'}, {'id': 'call_870GtpjxM8Rgw36N7wIqfRDq', 'function': {'arguments': '{"loc": "Inner Mongolia"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 47, 'prompt_tokens': 347, 'total_tokens': 394, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-6c23f36c-e854-4e3f-beef-04be5ae46041-0', tool_calls=[{'name': 'get_weather', 'args': {'loc': 'Tianjin'}, 'id': 'call_NaK0YDbmUSm1pSPgmcuaglHl', 'type': 'tool_call'}, {'name': 'get_weather', 'args': {'loc': 'Inner Mongolia'}, 'id': 'call_870GtpjxM8Rgw36N7wIqfRDq', 'type': 'tool_call'}], usage_metadata={'input_tokens': 347, 'output_tokens': 47, 'total_tokens': 394, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}), ToolMessage(content='{"coord": {"lon": 117.1767, "lat": 39.1422}, "weather": [{"id": 800, "main": "Clear", "description": "\\u6674", "icon": "01d"}], "base": "stations", "main": {"temp": 18.97, "feels_like": 18.46, "temp_min": 18.97, "temp_max": 18.97, "pressure": 1025, "humidity": 59, "sea_level": 1025, "grnd_level": 1024}, "visibility": 10000, "wind": {"speed": 7, "deg": 140}, "clouds": {"all": 0}, "dt": 1730258008, "sys": {"type": 1, "id": 9619, "country": "CN", "sunrise": 1730241393, "sunset": 1730279591}, "timezone": 28800, "id": 1792947, "name": "Tianjin", "cod": 200}', name='get_weather', id='ed06d7f2-4d33-4511-be9c-3325dccdc5de', tool_call_id='call_NaK0YDbmUSm1pSPgmcuaglHl'), ToolMessage(content='{"cod": "404", "message": "city not found"}', name='get_weather', id='d4f47099-64d4-4071-8956-515ae231cf79', tool_call_id='call_870GtpjxM8Rgw36N7wIqfRDq')], 'is_last_step': False}, 'triggers': ['tools']}}
{'type': 'task_result', 'timestamp': '2024-10-30T03:14:50.707154+00:00', 'step': 3, 'payload': {'id': 'c0a70cf0-9581-d545-c4db-564234efbf12', 'name': 'agent', 'error': None, 'result': [('messages', [AIMessage(content='天津的天气情况如下:\n\n- 天气:晴\n- 温度:18.97°C\n- 体感温度:18.46°C\n- 风速:7 m/s\n- 湿度:59%\n\n很遗憾,无法获取内蒙古的具体天气信息。如果你能提供一个具体的城市名称,我可以为你查询更详细的天气信息。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 82, 'prompt_tokens': 659, 'total_tokens': 741, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'stop', 'logprobs': None}, id='run-461964bb-3be1-41b2-9766-305990a9ffec-0', usage_metadata={'input_tokens': 659, 'output_tokens': 82, 'total_tokens': 741, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})])], 'interrupts': []}}

  如果在异步开发环境中,则可以使用astream方法来实现流式传输,是专为非阻塞工作流程而设计。可使用的模式和stream是一致的,只不过需要调整为异步函数的定义方法,代码如下所示:

1
2
async for chunk in graph.astream(input={"messages": ["你好,四川的天气怎么样?"]}, stream_mode="values"):
message = chunk["messages"][-1].pretty_print()
================================ Human Message =================================

你好,四川的天气怎么样?
================================== Ai Message ==================================
Tool Calls:
  query_weather_from_db (call_jElzMBgWJamba4swVQlUZ5IW)
 Call ID: call_jElzMBgWJamba4swVQlUZ5IW
  Args:
    city_name: Sichuan
<__main__.Weather object at 0x00000222AAA89490>
================================= Tool Message =================================
Name: query_weather_from_db

{"city_id": 1794299, "city_name": "Sichuan", "main_weather": "Clouds", "description": "多云", "temperature": 1.67, "feels_like": -0.58, "temp_min": 1.67, "temp_max": 1.67}
================================== Ai Message ==================================

四川目前的天气是多云,气温为1.67°C,体感温度接近-0.58°C。

  如果只想得到最终结果,可以使用相同的方法并只跟踪收到的最后一个值,代码如下:

1
2
async for chunk in graph.astream(input={"messages": ["你好,四川的天气怎么样?"]}, stream_mode="values"):
final_result = chunk
1
final_result["messages"][-1].pretty_print()
================================== Ai Message ==================================

四川目前的天气是多云。当前气温为1.67°C,体感温度是-0.58°C。
1
2
3
4
5
6
inputs = {"messages": [("human", "你好,乌鲁木齐的天气怎么样?")]}
async for chunk in graph.astream(inputs, stream_mode="updates"):
for node, values in chunk.items():
print(f"接收到的更新节点: '{node}'")
print(values)
print("\n\n")
接收到的更新节点: 'agent'
{'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_ieilOQoqoNZDnjLzDwtSiSGa', 'function': {'arguments': '{"city_name":"Urumqi"}', 'name': 'query_weather_from_db'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 19, 'prompt_tokens': 346, 'total_tokens': 365, 'prompt_tokens_details': {'cached_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-98d46758-afbd-4c95-965b-8f44d83fe959-0', tool_calls=[{'name': 'query_weather_from_db', 'args': {'city_name': 'Urumqi'}, 'id': 'call_ieilOQoqoNZDnjLzDwtSiSGa', 'type': 'tool_call'}], usage_metadata={'input_tokens': 346, 'output_tokens': 19, 'total_tokens': 365, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}


​ 接收到的更新节点: ‘tools’
​ {‘messages’: [ToolMessage(content=’{“messages”: [“未找到城市 'Urumqi' 的天气信息。”]}’, name=’query_weather_from_db’, id=’0852ae9f-b8a8-4a21-926e-765c7f084400’, tool_call_id=’call_ieilOQoqoNZDnjLzDwtSiSGa’)]}


​ 接收到的更新节点: ‘agent’
​ {‘messages’: [AIMessage(content=’’, additional_kwargs={‘tool_calls’: [{‘id’: ‘call_FA2ZvwygZsZLNgQfWE6zBH8X’, ‘function’: {‘arguments’: ‘{“loc”:”Urumqi”}’, ‘name’: ‘get_weather’}, ‘type’: ‘function’}], ‘refusal’: None}, response_metadata={‘token_usage’: {‘completion_tokens’: 16, ‘prompt_tokens’: 393, ‘total_tokens’: 409, ‘prompt_tokens_details’: {‘cached_tokens’: 0}, ‘completion_tokens_details’: {‘reasoning_tokens’: 0}}, ‘model_name’: ‘gpt-4o-2024-08-06’, ‘system_fingerprint’: ‘fp_72bbfa6014’, ‘finish_reason’: ‘tool_calls’, ‘logprobs’: None}, id=’run-5cd79453-e69d-47b0-a8d8-198be000ad1e-0’, tool_calls=[{‘name’: ‘get_weather’, ‘args’: {‘loc’: ‘Urumqi’}, ‘id’: ‘call_FA2ZvwygZsZLNgQfWE6zBH8X’, ‘type’: ‘tool_call’}], usage_metadata={‘input_tokens’: 393, ‘output_tokens’: 16, ‘total_tokens’: 409, ‘input_token_details’: {‘cache_read’: 0}, ‘output_token_details’: {‘reasoning’: 0}})]}


​ 接收到的更新节点: ‘tools’
​ {‘messages’: [ToolMessage(content=’{“coord”: {“lon”: 87.6005, “lat”: 43.801}, “weather”: [{“id”: 801, “main”: “Clouds”, “description”: “\u6674\uff0c\u5c11\u4e91”, “icon”: “02d”}], “base”: “stations”, “main”: {“temp”: 5.53, “feels_like”: 3.99, “temp_min”: 5.53, “temp_max”: 5.53, “pressure”: 1029, “humidity”: 81, “sea_level”: 1029, “grnd_level”: 926}, “visibility”: 10000, “wind”: {“speed”: 2, “deg”: 110}, “clouds”: {“all”: 20}, “dt”: 1730260508, “sys”: {“type”: 1, “id”: 9677, “country”: “CN”, “sunrise”: 1730248978, “sunset”: 1730286202}, “timezone”: 28800, “id”: 1529102, “name”: “\u00dcr\u00fcmqi”, “cod”: 200}’, name=’get_weather’, id=’57b6b3b8-cfc4-435b-ba94-65380b28cf11’, tool_call_id=’call_FA2ZvwygZsZLNgQfWE6zBH8X’)]}


​ 接收到的更新节点: ‘agent’
​ {‘messages’: [AIMessage(content=’’, additional_kwargs={‘tool_calls’: [{‘id’: ‘call_RiMagTnBGHBCVFdy2ApzG2qt’, ‘function’: {‘arguments’: ‘{“city_id”:1529102,”city_name”:”Ürümqi”,”main_weather”:”Clouds”,”description”:”晴,少云”,”temperature”:5.53,”feels_like”:3.99,”temp_min”:5.53,”temp_max”:5.53}’, ‘name’: ‘insert_weather_to_db’}, ‘type’: ‘function’}], ‘refusal’: None}, response_metadata={‘token_usage’: {‘completion_tokens’: 68, ‘prompt_tokens’: 672, ‘total_tokens’: 740, ‘prompt_tokens_details’: {‘cached_tokens’: 0}, ‘completion_tokens_details’: {‘reasoning_tokens’: 0}}, ‘model_name’: ‘gpt-4o-2024-08-06’, ‘system_fingerprint’: ‘fp_72bbfa6014’, ‘finish_reason’: ‘tool_calls’, ‘logprobs’: None}, id=’run-d3fb79a3-b429-4c47-8d72-19d2901f21dc-0’, tool_calls=[{‘name’: ‘insert_weather_to_db’, ‘args’: {‘city_id’: 1529102, ‘city_name’: ‘Ürümqi’, ‘main_weather’: ‘Clouds’, ‘description’: ‘晴,少云’, ‘temperature’: 5.53, ‘feels_like’: 3.99, ‘temp_min’: 5.53, ‘temp_max’: 5.53}, ‘id’: ‘call_RiMagTnBGHBCVFdy2ApzG2qt’, ‘type’: ‘tool_call’}], usage_metadata={‘input_tokens’: 672, ‘output_tokens’: 68, ‘total_tokens’: 740, ‘input_token_details’: {‘cache_read’: 0}, ‘output_token_details’: {‘reasoning’: 0}})]}


​ 接收到的更新节点: ‘tools’
​ {‘messages’: [ToolMessage(content=’{“messages”: [“天气数据已成功存储至Mysql数据库。”]}’, name=’insert_weather_to_db’, id=’124ec142-2441-4865-b75b-b597e2023ce1’, tool_call_id=’call_RiMagTnBGHBCVFdy2ApzG2qt’)]}


​ 接收到的更新节点: ‘agent’
​ {‘messages’: [AIMessage(content=’乌鲁木齐当前的天气情况是:晴,少云。气温为5.53°C,体感温度为3.99°C。天气数据已成功存储到数据库中。’, additional_kwargs={‘refusal’: None}, response_metadata={‘token_usage’: {‘completion_tokens’: 44, ‘prompt_tokens’: 766, ‘total_tokens’: 810, ‘prompt_tokens_details’: {‘cached_tokens’: 0}, ‘completion_tokens_details’: {‘reasoning_tokens’: 0}}, ‘model_name’: ‘gpt-4o-2024-08-06’, ‘system_fingerprint’: ‘fp_72bbfa6014’, ‘finish_reason’: ‘stop’, ‘logprobs’: None}, id=’run-c551db7f-4bd0-4c06-bbe0-59b98bd89fb9-0’, usage_metadata={‘input_tokens’: 766, ‘output_tokens’: 44, ‘total_tokens’: 810, ‘input_token_details’: {‘cache_read’: 0}, ‘output_token_details’: {‘reasoning’: 0}})]}

  而如果我们想流式传输每个过程中的 Tokens, 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from langchain_core.messages import AIMessageChunk, HumanMessage

inputs = [HumanMessage(content="what is the weather in sf")]

first = True
async for msg, metadata in graph.astream({"messages": ["你好,帮我查询一下数据库中都有哪些城市的天气数据"]}, stream_mode="messages"):
if msg.content and not isinstance(msg, HumanMessage):
print(msg.content, end="|", flush=True)

if isinstance(msg, AIMessageChunk):
if first:
gathered = msg
first = False
else:
gathered = gathered + msg

if msg.tool_call_chunks:
print(gathered.tool_calls)
[{'name': 'fetch_real_time_info', 'args': {}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {'query': ''}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {'query': '查询'}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {'query': '查询数据库'}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {'query': '查询数据库中'}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {'query': '查询数据库中所有'}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {'query': '查询数据库中所有城市'}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {'query': '查询数据库中所有城市的'}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {'query': '查询数据库中所有城市的天气'}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {'query': '查询数据库中所有城市的天气数据'}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{'name': 'fetch_real_time_info', 'args': {'query': '查询数据库中所有城市的天气数据'}, 'id': 'call_fgn93Rd0qvQrb2g8CSBASi5h', 'type': 'tool_call'}]
[{"title": "天气和气象数据网站集合原创 - CSDN博客", "link": "https://blog.csdn.net/qq_912917507/article/details/104323432", "snippet": "我们可以使用天气网,全球天气网(www.tianqi.com)提供全国各大城市的历史天气预报查询,历史气温查询,历史天气数据来源于城市当天的天气预报信息。 ... 在IT ...", "date": "Feb 15, 2020", "position": 1}]|目前|我|无法|直接|从|数据库|中|查询|所有|城市|的|天气|数据|。如果|您|需要|查询|某|个|特|定|城市|的|天气|数据|,请|提供|城市|名称|,我|将|为|您|查询|。|

  astream中其他的模式大家可以自行尝试,这里不重复进行说明,总体而言,我们要理解的是,同步stream和异步astream都是流式传输的默认实现,用于流式传输链中的最终输出。

3.2 LangGraph中的事件流

  对于上述使用的.stream().astream()仅流式传输链中最后一步的输出,这对于一些对话聊天类的应用程序来说基本就足够了,但是当我们的AI Agent是一个使用了多个大模型调用的更复杂的链时,我们有时希望在最终输出中也使用到一些中间值。例如,在构建RAG对话应用程序时,很多场景都是最终生成的响应 + 检索到的源文档一起返回给用户,例如:

  如果想获取到这样的中间事件和步骤,可以使用LangGraph框架中的 astream_events 方法,注意:此方法仅支持异步。用来访问自定义事件和中间输出。使用该方法运行图时,可以得到如下相关事件:

LangChain CallBack:https://docs.langchain.com/oss/python/langchain/models#streaming-events

  如下代码可以打印包含流式聊天模型输出的事件,其中 version=”v2” 参数是指定使用 测试版 API 的版本,现在必须指定。

1
2
3
async for event in graph.astream_events({"messages": ["你好,请你介绍一下你自己"]}, version="v2"):
kind = event["event"]
print(f"{kind}: {event['name']}")
on_chain_start: LangGraph
on_chain_start: __start__
on_chain_end: __start__
on_chain_start: agent
on_chain_start: call_model
on_chain_start: RunnableSequence
on_chain_start: StateModifier
on_chain_end: StateModifier
on_chat_model_start: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_stream: ChatOpenAI
on_chat_model_end: ChatOpenAI
on_chain_end: RunnableSequence
on_chain_end: call_model
on_chain_start: _write
on_chain_end: _write
on_chain_start: should_continue
on_chain_end: should_continue
on_chain_stream: agent
on_chain_end: agent
on_chain_stream: LangGraph
on_chain_end: LangGraph

  这个过程明确标识了Agent执行的每个阶段。从on_chain_start: LangGraph 开始,写入__start__节点,启动call_model节点( on_chain_start: call_model )。然后开始聊天模型调用( on_chat_model_start: ChatOpenAI ), 按token的增量流式返回 ( on_chat_model_stream: ChatOpenAI ),直到聊天模型( on_chat_model_end: ChatOpenAI )输出完全部内容后停止。继而将结果写回通道( ChannelWrite<call_model,messages> ),再次回到call_model节点做决策,最终完成整个图的运行流程。

  我们可以从中提取具体的某个 event(事件),比如:

1
2
3
events = []
async for event in graph.astream_events({"messages": ["你好,请你介绍一下你自己"]}, version="v2"):
events.append(event)
1
events[0]
{'event': 'on_chain_start',
 'data': {'input': {'messages': ['你好,请你介绍一下你自己']}},
 'name': 'LangGraph',
 'tags': [],
 'run_id': '82a8cc1d-4607-47bc-88e5-cf4027857fd0',
 'metadata': {},
 'parent_ids': []}
1
events[10]
{'event': 'on_chat_model_stream',
 'data': {'chunk': AIMessageChunk(content='您好', additional_kwargs={}, response_metadata={}, id='run-fd2157b0-6ff4-40df-8749-84deab32adbd')},
 'run_id': 'fd2157b0-6ff4-40df-8749-84deab32adbd',
 'name': 'ChatOpenAI',
 'tags': ['seq:step:2'],
 'metadata': {'langgraph_step': 1,
  'langgraph_node': 'agent',
  'langgraph_triggers': ['start:agent'],
  'langgraph_path': ('__pregel_pull', 'agent'),
  'langgraph_checkpoint_ns': 'agent:b43bb514-1964-53fd-a747-94d646ccd17c',
  'checkpoint_ns': 'agent:b43bb514-1964-53fd-a747-94d646ccd17c',
  'ls_provider': 'openai',
  'ls_model_name': 'gpt-4o',
  'ls_model_type': 'chat',
  'ls_temperature': 0.7},
 'parent_ids': ['82a8cc1d-4607-47bc-88e5-cf4027857fd0',
  '4d367cb2-9d0a-4d5b-9f31-b0295ea3fce1',
  'aa31ad82-b577-4b8c-bbb9-cb8879b42dda',
  'aa2387eb-9371-4e02-a238-bb7fd8185cba']}

  所有事件都会包含eventnamedata字段,其中:

  • event :正在发出的事件类型。
  • name :这是事件的名称
  • data :这是与事件关联的数据。

  基于此就可以按照nametagstype等不同的字段来进行事件过滤,比如我们现在选择仅包含聊天模型的输出:

1
2
3
4
async for event in graph.astream_events({"messages": ["你好,请你介绍一下你自己"]}, version="v2"):
kind = event["event"]
if kind == "on_chat_model_stream":
print(event, end="|", flush=True)
{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='你好', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='!', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='我是', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='一个', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='由', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='人工', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='智能', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='驱', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='动', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='的', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='助手', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=',可以', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='帮助', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='回答', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='问题', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='、', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='提供', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='信息', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='、', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='进行', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='任务', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='自动', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='化', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='等', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='。我', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='可以', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='处理', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='多', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='种', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='语言', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='的', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='文本', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=',并', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='能', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='与', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='各种', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='应用', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='程序', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='和', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='工具', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='进行', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='集', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='成', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=',以', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='满足', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='不同', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='的', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='需求', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='。如果', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='你', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='有', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='任何', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='问题', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='或者', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='需要', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='帮助', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content=',', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='随', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='时', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='告诉', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='我', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='!', additional_kwargs={}, response_metadata={}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|{'event': 'on_chat_model_stream', 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={}, response_metadata={'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_72bbfa6014'}, id='run-599ff39e-910f-48a7-a87b-eaabd1154d29')}, 'run_id': '599ff39e-910f-48a7-a87b-eaabd1154d29', 'name': 'ChatOpenAI', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_path': ('__pregel_pull', 'agent'), 'langgraph_checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'checkpoint_ns': 'agent:79d639f6-6c89-f63f-9d09-4c0be3bd44d7', 'ls_provider': 'openai', 'ls_model_name': 'gpt-4o', 'ls_model_type': 'chat', 'ls_temperature': 0.7}, 'parent_ids': ['c1ebffad-910f-4fe7-914f-832bf6967cad', '85a346c6-9632-4039-902b-abad71845000', 'e7c1e9cf-b472-4e13-bdac-197b1981df38', 'b7763813-9d0b-488c-b6bf-cc035dacad80']}|

  每种类型的事件都包含不同格式的数据。而其中data是一个非常重要的,包含此事件的实际数据。在on_chat_model_stream事件中,就是需要响应的流式Token,如上图所示是一个 AIMessageChunk,其中包含消息的content以及id ,提取的代码就非常简单了,和我们上面实现的方式一致,即直接采用如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
first = True
async for msg, metadata in graph.astream({"messages": ["你好,请你介绍一下你自己"]}, stream_mode="messages"):
if msg.content and not isinstance(msg, HumanMessage):
print(msg.content, end="|", flush=True)

if isinstance(msg, AIMessageChunk):
if first:
gathered = msg
first = False
else:
gathered = gathered + msg

if msg.tool_call_chunks:
print(gathered.tool_calls)
你好|!|我是|一个|由|人工|智能|驱|动|的|助手|,|旨|在|帮助|回答|各种|问题|和|执行|特|定|任务|。我|能够|进行|自然|语言|处理|,|提供|信息|查询|、|天气|预|报|、|简单|计算|等|服务|。如果|你|有|任何|问题|或|需要|帮助|,|随|时|可以|告诉|我|!|

  stream_mode=”messages”模式是直接做的格式化提取的实现过程,当然,理解了上述事件流,我们也可以直接在当前的流程下自定义数据流,比如:

1
2
3
4
async for event in graph.astream_events({"messages": ["你好,请你介绍一下你自己"]}, version="v2"):
kind = event["event"]
if kind == "on_chat_model_stream":
print(event["data"]["chunk"].content, end="|", flush=True)
|你好|!|我是|一个|由|人工|智能|驱|动|的|助手|,|旨|在|帮助|回答|问题|、|提供|信息|和|执行|任务|。|我的|能力|包括|自然|语言|理解|、|信息|检|索|、|数据|处理|等等|。如果|你|有|任何|问题|或者|需要|帮助|,|随|时|可以|问|我|!||

  由此可见,在处理事件流中的信息时,我们可以根据实际需求灵活地选择输出和展示的内容格式。这种灵活性正是在复杂业务流程中引入事件流的核心原因。

  至此,我们就完整实现了在LangGraphReAct自治代理的完整构建,对于这个预构建的ReAct组件,它是集成了外部工具、记忆和规划三个核心概念,所以除了我们可以自定义外部工具以外,还可以给它制定不同的步骤规划方式,即Planning,以及通过Memory去赋予Agent多轮对话的能力,而这两部分的内容,我们将在下一节课程中展开详细的探讨和实践。