给智能体绑定工具与运行机制
给智能体绑定工具与运行机制
create_agent 绑定自定义与内置工具、ReAct 循环与一次完整 Function calling 的消息流转、工具失败时的自主重试,以及工具选择的三类常见问题
上一篇创建的 Agent 还只会”空口回答”。只有接入了工具,Agent 的创建才算完整——这一篇讲怎么给它接工具,以及接上工具后它在内部到底怎么跑。
绑定工具
工具可以是 LangChain 内置的,也可以是自定义的。执行时:
- 静态绑定:创建 Agent 时写死在
tools=[...]里 - 动态绑定:运行时按条件决定给哪些工具(需要中间件,第 8 章讲)
图:AI 智能体工作流——用户问题 → Agent 分析 → 判断”需要工具吗” → 需要就调用工具、获取结果,不需要就直接回答,最后生成回答
自定义工具:@tool 装饰器
from langchain.agents import create_agentfrom langchain.tools import tool
@tool(parse_docstring=True)def get_weather(city: str) -> str: """天气查询工具
Args: city: 城市名称 """ return f"{city}的天气为晴朗,25°C。"
agent = create_agent( model=model, tools=[get_weather],)
resp = agent.invoke({ "messages": [ {"role": "system", "content": "你是一个天气查询助手,只回答天气相关的问题,其他问题请直接回答:我不清楚这问题答案。"}, {"role": "user", "content": "北京的天气怎么样?"}, ]})
图:给这个 agent 挂上 get_weather 之后画出来的图结构——多了 tools 节点,模型判断需要工具时就会走 model → tools → model
@tool(parse_docstring=True) 这个参数到底做了什么?(实测对比)
| 写法 | 工具的 description | 参数的 description |
|---|---|---|
@tool | 整个 docstring,含 Args: 那一大段 | ❌ 无 |
@tool(parse_docstring=True) | 只取摘要行「天气查询工具」 | ✅ city: 城市名称 |
默认 @tool → "天气查询工具\n\nArgs:\n city: 城市名称"parse_docstring=True → "天气查询工具",参数描述 {"city": {"description": "城市名称"}}加上这个参数,你写的 Args 段会变成规范的参数描述——模型挑工具、填参数都靠这些文字,值得多写一行。
内置工具:TavilySearch
LangChain 生态里内置了大量实用工具(完整列表:https://docs.langchain.com/oss/python/integrations/tools)。以网络搜索工具为例:
图:课程列出的典型内置工具——搜索(DuckDuckGo / Brave / Bing)、网页浏览(Playwright / Selenium)、生产力(Slack / Jira / Google Drive)、数据库(SQLDatabase / 向量库)、代码执行(Python REPL / Shell)、多模态(DALL·E / Whisper)、RAG 检索、云函数与文件处理等
from langchain_tavily import TavilySearchimport os
web_search = TavilySearch( tavily_api_key=os.getenv("TAVILY_API_KEY"), # 去 tavily 官网注册(每月有免费额度) max_results=2,)
# 它是个高度封装好的工具,可以单独调用看看效果web_search.invoke("请问2026年足球世界杯有哪些参赛队?")# 返回:{'query': ..., 'results': [{'url': ..., 'title': ..., 'content': ..., 'score': ...}, ...], 'response_time': 0.79, ...}
图:Tavily 官网账户页的 API Keys 区——把 tvly-dev-*** 这一串复制出来写进 .env 的 TAVILY_API_KEY
直接把实例塞进 tools 就能交给 Agent 用:
agent = create_agent( model=model, tools=[web_search], system_prompt="你是一名多才多艺的智能助手,可以调用工具帮助用户解决问题。",)内置工具用起来省事,但每个工具都有自己的依赖:TavilySearch 要注册 API-KEY 并写进 .env 的 TAVILY_API_KEY。用之前先看文档要什么。
绑定多个工具
一个 Agent 可以同时挂多个工具,tools 传列表即可:
@tool(parse_docstring=True)def get_weather(city: str): """天气查询工具
Args: city: 城市名称 """ return f"{city}今天天气挺好"
@tool(parse_docstring=True)def get_news(): """新闻查询工具""" return "近期废旧手机回收市场迎来“火热潮”,回收价格普遍上涨……"
agent = create_agent(model, tools=[get_weather, get_news])response = agent.invoke({"messages": ["你好,杭州今天的天气如何?今天有哪些新闻?"]})问一句包含两件事的话,Agent 会自己判断需要调两个工具(甚至可能连续调)。
运行机制:ReAct 循环
LangChain 的 Agent 把”模型”和”工具”结合起来,在实现上由一张基于 LangGraph 的图来编排执行流程。本质上就是经典的 ReAct 结构——一个具备「思考 → 行动 → 观察」不断循环的自主工作者:
用户问题 → AI 思考 → 调用工具 → 观察结果 → 继续思考 → ... → 最终答案
图:ReAct 的两种画法——左边是 LangGraph 视角(input 进 model,模型在 action 走 tools、在 observation 回到 model、在 finish 出 output),右边是”用户输入 → LLM 推理 → 决定调用工具/执行工具 → 决定完成并生成答案”
它会在一个循环里反复调用模型和工具,直到某次模型输出中不再包含工具调用则结束,最后综合所有信息给出最终答案。
一次完整流程长什么样
以「找出当前最流行的无线耳机并检查库存」为例:
| 步骤 | 发生了什么 |
|---|---|
| 1. 输入解析与初始推理 | LLM 分析任务:“要找出’最流行’的产品需要最新市场信息,我应该先用搜索工具” |
| 2. 第一次行动 + 观察 | 调用 search_products("wireless headphones") → 返回”找到5款匹配产品,Top 结果:WH-1000XM5…” |
| 3. 迭代推理 | “WH-1000XM5 排第一,现在需要确认库存才能回答” |
| 4. 第二次行动 + 观察 | 调用 check_inventory("WH-1000XM5") → 返回”库存 10 件” |
| 5. 最终输出 | 信息齐了,生成最终答案,不再调用工具 |
图:一次工具调用的消息流——用户提问(HumanMessage)→ AI 分析”需要工具吗” → AI 决定调用(AIMessage 带 tool_calls)→ 执行工具(ToolMessage)→ AI 看结果生成答案(AIMessage)
从消息层面看,一次工具调用会产出 4 条消息(这是典型的 Function calling 流程):
HumanMessage # 用户提问AIMessage # AI 的工具调用请求(function call)ToolMessage # 工具返回结果(function response)AIMessage # 最终回答(final response)
图:一次完整的 Function calling 流程(课程以”查 2024 年诺贝尔物理学奖得主”为例)——用户查询 → 代理思考并决定调用工具 → Tavily 生成查询并返回结果(ToolMessage)→ LangChain 构建最终回答
循环的退出条件是”模型这一轮没有工具调用”。所以工具越多、任务越绕,消息列表就越长——这也解释了为什么 Agent 的 token 消耗会比普通对话高很多。
消息里的关键字段:tool_call_id 与 finish_reason
课程把 resp 整份打印出来,能看到”请求”和”结果”是靠 ID 配对的。看一次问天气的完整消息(节选):
AIMessage( # ← 工具调用请求 content='', # 发起调用时正文是空的 response_metadata={..., 'finish_reason': 'tool_calls'}, # ← 标记"我要去调工具" tool_calls=[ { 'name': 'get_weather', 'args': {'city': '北京'}, 'id': 'call_4dp4PGy6Ghaj5m6WcNkrwKFe', # ← 这次调用的编号 'type': 'tool_call' } ], invalid_tool_calls=[]),ToolMessage( # ← 工具返回结果 content='北京的天气为晴朗,25°C。', name='get_weather', id='b5b82403-973c-463b-b9f2-2aa76e0bff77', tool_call_id='call_4dp4PGy6Ghaj5m6WcNkrwKFe' # ← 和上面的 id 一模一样),AIMessage( content='北京天气晴朗,25°C。', response_metadata={..., 'finish_reason': 'stop'}, # ← 这次是真说完了 tool_calls=[] # ← 没有新的调用)| 消息 | 关键字段 | 作用 |
|---|---|---|
AIMessage(工具调用请求) | tool_calls[].id | 这次调用的唯一编号 |
tool_calls[].name / .args | 调哪个工具、参数是什么({'city': '北京'}) | |
response_metadata['finish_reason'] | 'tool_calls' 表示”还要干活” | |
ToolMessage(工具返回) | tool_call_id | 与上面 tool_calls[].id 一一对应——模型就是靠它知道”这个结果属于哪次调用” |
name | 哪个工具返回的 | |
AIMessage(最终回答) | response_metadata['finish_reason'] | 'stop' 表示任务结束 |
tool_calls | [](空列表) |
一次并行调两个工具时,一条 AIMessage 的 tool_calls 里会有两项,随后跟两条 ToolMessage,各自的 tool_call_id 分别对上——课程”绑定多个工具”的例子(问一句”杭州天气如何?今天有哪些新闻?“)就是这样:
AIMessage(... tool_calls=[{'name': 'get_weather', ..., 'id': 'call_w9ARuAgN8iqfG2GR7gv00iBq'}, {'name': 'get_news', ..., 'id': 'call_vOLekRymIme8bWuVQdIew4vu'}])ToolMessage(content='杭州今天天气挺好', name='get_weather', tool_call_id='call_w9ARuAgN8iqfG2GR7gv00iBq')ToolMessage(content='近期,受全球储蓄芯片短缺…', name='get_news', tool_call_id='call_vOLekRymIme8bWuVQdIew4vu')实测(用假服务端抓一次真实流转):AIMessage 的 tool_calls[0].id = 'call_fake01',紧接着的 ToolMessage.tool_call_id 也是 'call_fake01',finish_reason 分别是 'tool_calls' 和 'stop'——配对关系和课程完全一致。
自己手工拼消息历史(比如把历史存下来下一轮再传)时,这两个 ID 必须成对搬运——ToolMessage 的 tool_call_id 一定要指向前面某条 AIMessage 里真实存在的调用 id。
重试机制:让 Agent 自己再试一次
Agent 可以在工具调用结果不满足要求时自主重试。做法很朴素:让工具把”临时故障”写在返回值里,再用提示词告诉模型这种情况该怎么办。
from langchain.agents import create_agentfrom langchain.tools import toolfrom langchain.messages import SystemMessage, HumanMessage
flag = 0
@tooldef get_weather(city: str): """天气查询工具
Args: city: 城市名称 """ global flag flag += 1 if flag < 3: # 也可以改成抛异常:raise Exception("暂时无法访问") return "TEMP_UNAVAILABLE: 天气服务暂时不可用,请稍后重试" return f"{city}今天天气挺好"
messages = [ SystemMessage("""你是一个天气助手。当工具返回以 'TEMP_UNAVAILABLE:' 开头的结果时,说明是临时故障,不要立即放弃;你应再次调用同一个工具,最多重试 3 次。如果 3 次后仍失败,再向用户说明服务暂时不可用。"""), HumanMessage("你好,杭州今天的天气如何?"),]
agent = create_agent(model, tools=[get_weather])response = agent.invoke({"messages": messages})这里做了三件事:
| 角色 | 做了什么 |
|---|---|
| 工具 | 前两次返回 TEMP_UNAVAILABLE: ...(模拟临时故障);第三次才返回真数据 |
| 系统提示词 | 说明”以这个前缀开头的返回 = 临时故障”,并要求最多重试 3 次、3 次都失败才放弃 |
| Agent | 读到故障标记后自己再次调用同一个工具,直到成功 |
“重试”不是框架内置的自动机制,而是靠提示词引导模型的行为。所以:
- 工具的错误返回值要有稳定、可识别的标记(如统一前缀)
- 提示词里要写清楚重试几次、最终怎么回答用户,否则模型可能无限重试或者一次就放弃
同样的规则,换个写法:放进 system_prompt
上面那段提示词是塞在 messages 列表里的。重试规则是”这个 Agent 的规矩”,更适合放进 system_prompt——两种写法效果一样,区别只在”只影响这一次调用”还是”整个 Agent 都生效”(第 15 篇细讲):
from langchain.agents import create_agentfrom langchain.tools import toolfrom langchain.messages import SystemMessage, HumanMessage
flag = 0
@tooldef get_weather(city: str): """天气查询工具
Args: city: 城市名称 """ global flag flag += 1 if flag < 3: # raise Exception("暂时无法访问") return "TEMP_UNAVAILABLE: 天气服务暂时不可用,请稍后重试" return f"{city}今天天气挺好"
messages = [ HumanMessage("你好,杭州今天的天气如何?") # ← 这次提示词不在这里]
agent = create_agent( model=model, tools=[get_weather], system_prompt=SystemMessage( # ← 规则写在 Agent 上 "你是一个天气助手。" "当工具返回以 'TEMP_UNAVAILABLE:' 开头的结果时," "说明是临时故障,不要立即放弃;" "你应再次调用同一个工具,最多重试 3 次。" "如果 3 次后仍失败,再向用户说明服务暂时不可用。" ))
response = agent.invoke({"messages": messages})for msg in response["messages"]: msg.pretty_print()pretty_print() 打出来的完整过程(模型真的把同一个工具调了三次):
================================ Human Message =================================你好,杭州今天的天气如何?================================== Ai Message ==================================Tool Calls: get_weather (call_1NZMHHj1xByT0Zx7WhiK6AO1) Call ID: call_1NZMHHj1xByT0Zx7WhiK6AO1 Args: city: 杭州================================= Tool Message =================================Name: get_weather
TEMP_UNAVAILABLE: 天气服务暂时不可用,请稍后重试================================== Ai Message ==================================Tool Calls: get_weather (call_Lgfn3Ll8WTJqQRVVwLIzRQnX) Call ID: call_Lgfn3Ll8WTJqQRVVwLIzRQnX Args: city: 杭州================================= Tool Message =================================Name: get_weather
TEMP_UNAVAILABLE: 天气服务暂时不可用,请稍后重试================================== Ai Message ==================================Tool Calls: get_weather (call_PghYww2kjkigDZK8h6P5Lth0) Call ID: call_PghYww2kjkigDZK8h6P5Lth0 Args: city: 杭州================================= Tool Message =================================Name: get_weather
杭州今天天气挺好================================== Ai Message ==================================杭州今天天气挺好。三个细节值得留意:
- 每次调用的
Call ID都不一样(call_1NZMH…/call_Lgfn3…/call_PghYw…)——每次重试都是一次全新的工具调用,不是”重发同一个请求”。 - 用
system_prompt传提示词时,返回的消息列表里看不到那条 SystemMessage(输出直接以 Human Message 开头);写在messages里时它会作为第一条消息出现在返回值里。 - 最终那条
Ai Message的正文就是”杭州今天天气挺好。“——第三次工具返回的真数据,说明提示词里的”最多重试 3 次”被模型老老实实执行了。
常见问题
问题1:Agent 如何选择工具?
依据是工具的 docstring——模型只看得到名字、描述和参数说明。
@tooldef get_weather(city: str) -> str: """获取指定城市的天气信息""" # ← AI Agent 读这个! ...
@tooldef calculator(operation: str, a: float, b: float) -> str: """执行基本的数学计算""" # ← AI Agent 也读这个! ...它综合判断三件事:① 问题内容 ② 每个工具的描述 ③ 自动选择最匹配的。
问题2:Agent 为什么没有调用工具?
| 原因 | 解决 |
|---|---|
| 工具的 docstring 不清晰 | 写清楚能做什么、什么时候用 |
| 问题表述不明确 | 把用户问题问清楚 |
| 模型认为不需要工具 | 用系统提示词明确”这类问题必须用工具” |
# ❌ 不好:太模糊@tooldef tool1(x: str) -> str: """做一些事情"""
# ✅ 好:写清用途和参数示例@tooldef get_weather(city: str) -> str: """获取指定城市的实时天气信息
Args: city: 城市名称,如"北京"、"上海" """问题3:Agent 选错工具?
原因通常是多个工具的功能描述相似,或者工具太多导致混淆。三条对策:
- 只给必要的工具(2-5 个最佳)
- 工具描述要有明确区分
- 在
system_prompt里说明工具使用场景
# ✅ 好:只给需要的工具agent = create_agent(model=model, tools=[get_weather, calculator])这套”工具描述就是文档”的思路和第 09 篇讲 Tool 时完全一致:模型没有读心术,它只读你写的描述。
问题4:如何知道 Agent 何时完成?
判断依据只有一条:某条 AIMessage 里不含 tool_calls。
from langchain.messages import AIMessage
for msg in response['messages']: if isinstance(msg, AIMessage): if hasattr(msg, 'tool_calls') and msg.tool_calls: print("还在调用工具...") else: print("完成!最终答案:", msg.content)msg.tool_calls非空 → 这条 AI 消息是”我要调工具”(content通常是空的),还没完msg.tool_calls为空 → 这条是最终回答,任务结束
实测(假服务端跑一次”问天气”):上面这段代码依次打印
还在调用工具...完成!最终答案: 杭州今天天气挺好。想直接拿答案,其实不用循环——response["messages"][-1].content 就是它(Agent 返回时保证最后一条是最终回答,见第 13 篇)。
问题5:Agent 可以调用多少次工具?
默认没有限制,直到得到最终答案。但”没有限制”不是好事,课程点出三种可能的结果:
| 可能的结果 | 说明 |
|---|---|
| 超时 | 工具慢 + 调用多,整体耗时不可控 |
| 达到 token 限制 | 消息列表越滚越长(每轮都要把全部历史重发),最终撞上上下文上限 |
| 模型决定停止 | 最好的情况——但它什么时候”觉得够了”由模型说了算,不稳定 |
实测补充:读源码可以看到,create_agent 编译图时写了一行 config = {"recursion_limit": 10_000}(langchain/agents/factory.py),LangGraph 自身的默认值也是 10000。所以”默认没有限制”严格说是”默认上限 10000 步”——对普通任务约等于不限。
我实测让假服务端一直返回 tool_calls,Agent 连着调了 31 次模型都没停(最后是假服务端改成正常回答才结束)——一旦模型陷入”我要再查一次”的死循环,Agent 会一直烧钱,所以问题 6 那个限制值得会写。
问题6:如何限制工具调用次数?
create_agent 底层是 LangGraph,可以用 recursion_limit 配置限制:
# 注意:这是高级用法,后续会详细学习config = { "recursion_limit": 5 # 最多 5 步}
response = agent.invoke(input, config=config) # input 就是平时那个 {"messages": [...]}实测这个参数的真实行为(假服务端持续返回 tool_calls):
抛异常: GraphRecursionError -> Recursion limit of 5 reached without hitting a stop condition. You can increase the limit by setting the `recursion_limit` config key.三个要点:
- 它是”报错”而不是”停下来给答案”——超限时 Agent 中断并抛出
GraphRecursionError,所以它更适合当防死循环的兜底,而不是”限制次数后继续正常工作”。 - 计数单位是 LangGraph 的”步”(super-step):一次模型调用算一步,一次工具执行也算一步。实测
recursion_limit=5时模型只被调了 3 次(模型→工具→模型→工具→模型,正好 5 步)。 - 想要”限次数但不报错”,课程在第 8 章给了正经工具——
ToolCallLimitMiddleware(可按工具限量,还能选”优雅结束”还是”抛错”,见第 20 篇)。recursion_limit是 LangGraph 的通用兜底,两者用途不同。
相关
练习题
一、回忆填空(写完再展开对答案)
- 工具绑定分两种:创建 Agent 时写死的____绑定,和运行时决定的____绑定(后者要中间件)
@tool默认把整个 docstring 当作____;加上____=True后,摘要行做描述、Args段变成____的描述- Agent 的本质是经典的 ____ 结构:____ → ____ → ____ 不断循环,直到某轮模型输出里没有____
- 一次工具调用会产出四条消息:Human → ____(工具调用请求)→ ____(工具返回结果)→ ____(最终回答)
- 让 Agent 自主重试的做法:工具返回____的失败标记 + 系统提示词里写清重试____和最终答复方式
- Agent 选择工具的依据是工具的____;判断三要素是问题内容、每个工具的____、自动选择最匹配的
- 不调用工具的常见原因:docstring 太____、问题表述不明确、模型认为不需要工具
- 选错工具的两个原因:多个工具描述____、工具____导致混淆;对策是只给必要的工具(____ 个最佳)并在系统提示词里说明使用场景
填空答案(做完再点开)
- 静态 / 动态 2. description(工具描述) /
parse_docstring/ 参数 3. ReAct / 思考 / 行动 / 观察 / 工具调用 4. AIMessage / ToolMessage / AIMessage 5. 可识别(如统一前缀) / 次数 6. docstring(描述) / 描述 7. 模糊 8. 相似 / 太多 / 2-5
二、裸写题
-
2-1 让 Agent 用上一个自定义工具 写一个
get_weather(city)工具(用@tool(parse_docstring=True),Args 里写清参数含义),创建 Agent 并问”北京的天气怎么样?“,然后遍历返回的消息列表,确认里面出现了ToolMessage。提示(先自己想,实在想不出再点开)一级 · 思路:能看到 ToolMessage 就说明”模型真的调了工具”,而不是自己编的 二级 · 方法:
create_agent(model=model, tools=[get_weather])三级 · 骨架:打印消息类型时用type(msg).__name__,ToolMessage 的 content 就是工具返回值 -
2-2 一句话触发两个工具 再定义
get_news()工具,把两个工具一起绑定,问”杭州今天的天气如何?今天有哪些新闻?“,观察消息列表里出现了几次工具调用。提示一级 · 思路:多工具场景下模型会自己分配任务 二级 · 方法:
tools=[get_weather, get_news]三级 · 骨架:数一数有几条 AIMessage 带tool_calls、有几条 ToolMessage -
2-3 实现”自主重试” 改造工具:用一个全局计数器,前两次返回
TEMP_UNAVAILABLE: 服务暂时不可用,第三次才返回真实天气;再写一段系统提示词,要求模型遇到这个前缀就重试(最多 3 次)。观察最终能不能拿到真实天气。提示一级 · 思路:工具负责”报错”,提示词负责”怎么处理错误” 二级 · 方法:
global flag计数器 +SystemMessage(...)三级 · 骨架:提示词里务必写”最多重试 3 次”和”3 次后怎么回复用户”,否则模型可能死循环
参考答案(做完再点开)
import osfrom dotenv import load_dotenvfrom langchain.agents import create_agentfrom langchain.chat_models import init_chat_modelfrom langchain.messages import HumanMessage, SystemMessagefrom langchain.tools import tool
load_dotenv(override=True)
model = init_chat_model( model="deepseek-v4-flash", model_provider="openai", api_key=os.getenv("DEEPSEEK_API_KEY"), base_url=os.getenv("DEEPSEEK_BASE_URL"),)
# ---------- 2-1 自定义工具 ----------@tool(parse_docstring=True)def get_weather(city: str) -> str: """天气查询工具
Args: city: 城市名称 """ return f"{city}的天气为晴朗,25°C。"
agent = create_agent(model=model, tools=[get_weather])resp = agent.invoke({ "messages": [ {"role": "system", "content": "你是一个天气查询助手,只回答天气相关的问题。"}, {"role": "user", "content": "北京的天气怎么样?"}, ]})for msg in resp["messages"]: print(type(msg).__name__, "→", msg.content[:40])# HumanMessage → 北京的天气怎么样?# AIMessage → '' ← 带 tool_calls# ToolMessage → 北京的天气为晴朗,25°C。 ← 工具真的被调用了# AIMessage → 北京今天天气晴朗,气温 25°C
# ---------- 2-2 两个工具 ----------@tool(parse_docstring=True)def get_news() -> str: """新闻查询工具""" return "近期废旧手机回收市场迎来“火热潮”,回收价格普遍上涨。"
agent2 = create_agent(model=model, tools=[get_weather, get_news])resp2 = agent2.invoke({"messages": ["杭州今天的天气如何?今天有哪些新闻?"]})tool_calls = [m for m in resp2["messages"] if getattr(m, "tool_calls", None)]tool_msgs = [m for m in resp2["messages"] if type(m).__name__ == "ToolMessage"]print(f"模型发起 {len(tool_calls)} 轮工具调用,工具返回 {len(tool_msgs)} 条结果")
# ---------- 2-3 自主重试 ----------flag = 0
@tool(parse_docstring=True)def get_weather_flaky(city: str) -> str: """天气查询工具
Args: city: 城市名称 """ global flag flag += 1 if flag < 3: return "TEMP_UNAVAILABLE: 天气服务暂时不可用,请稍后重试" return f"{city}今天天气挺好"
agent3 = create_agent(model=model, tools=[get_weather_flaky])messages = [ SystemMessage( "你是一个天气助手。" "当工具返回以 'TEMP_UNAVAILABLE:' 开头的结果时,说明是临时故障,不要立即放弃;" "你应再次调用同一个工具,最多重试 3 次。" "如果 3 次后仍失败,再向用户说明服务暂时不可用。" ), HumanMessage("你好,杭州今天的天气如何?"),]resp3 = agent3.invoke({"messages": messages})print(resp3["messages"][-1].content)评论区
如果你喜欢,那么欢迎来到我的世界!
了解更多













