目前演示的是langchainV0.3版本智能体调用
import json import os import httpx from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain_classic.agents import create_tool_calling_agent from langchain_classic.agents import AgentExecutor from langchain_core.prompts import ChatPromptTemplate from langchain_core.tools import tool ''' 多工具并行调用,一次性发起了同一个外部函数的两次调用请求并将最后结果聚合 一次问题 → 多工具调用 → 聚合回答 ''' load_dotenv() @tool def get_weather(loc): """ 查询即时天气函数 :param loc: 必要参数,字符串类型,用于表示查询天气的具体城市名称。 注意,中国的城市需要用对应城市的英文名称代替,例如如果需要查询北京市天气, 则 loc 参数需要输入 'Beijing'/'shanghai'。 :return: OpenWeather API 查询即时天气的结果。具体 URL 请求地址为: https://api.openweathermap.org/data/2.5/weather。 返回结果对象类型为解析之后的 JSON 格式对象,并用字符串形式进行表示, 其中包含了全部重要的天气信息。 """ # Step 1. 构建请求 URL url = "https://api.openweathermap.org/data/2.5/weather" # Step 2. 设置查询参数,包括城市名、API Key、单位和语言 params = { "q": loc, #"appid": os.getenv("OPENWEATHER_API_KEY"), # 从环境变量中读取 API Key "appid": "fc19f7b552b4c1ae467e36fe69556668", # 从环境变量中读取 API Key "units": "metric", # 使用摄氏度 "lang": "zh_cn" # 输出语言为简体中文 } # Step 3. 发送 GET 请求获取天气数据 response = httpx.get(url, params=params,timeout=30) # Step 4. 解析响应内容为 JSON 并序列化为字符串返回 data = response.json() print(json.dumps(data)) return json.dumps(data) # 初始化模型实例,用于处理自然语言任务 llm = ChatOpenAI( model="deepseek-v4-pro", api_key=os.getenv("DEEPSEEK_API_KEY"), base_url="https://api.deepseek.com" ) # 创建聊天提示模板,定义agent的对话结构和角色 prompt = ChatPromptTemplate.from_messages( [ ("system", "你是天气助手,请根据用户的问题,给出相应的天气信息"), ("human", "{input}"), ("placeholder", "{agent_scratchpad}"), ] ) # 定义可用工具列表,包含获取天气信息的工具函数 tools = [get_weather] # 创建工具调用agent,整合语言模型、工具和提示模板。该agent能够根据用户问题调用相应工具获取天气信息 agent = create_tool_calling_agent(llm, tools, prompt) # 创建agent执行器,负责协调agent和工具的执行流程 # agent参数指定要执行的agent实例 # tools参数提供agent可调用的工具列表 # verbose参数设置为True,启用详细输出模式便于调试 agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) # 执行agent,处理用户关于北京和上海天气的查询请求 result = agent_executor.invoke({"input": "请问今天北京和上海的天气怎么样,哪个城市更热?"}) # 输出执行结果 print(result)返回的结果是
D:\python310\python.exe D:\PycharmProjects\PythonProject\12_agent\AgentSmartSelectV0.3.py > Entering new AgentExecutor chain... Invoking: `get_weather` with `{'loc': 'Beijing'}` responded: 好的!我来同时查询北京和上海的天气,马上为您比较。 {"coord": {"lon": 116.3972, "lat": 39.9075}, "weather": [{"id": 804, "main": "Clouds", "description": "\u9634\uff0c\u591a\u4e91", "icon": "04d"}], "base": "stations", "main": {"temp": 28.24, "feels_like": 34.14, "temp_min": 28.24, "temp_max": 28.24, "pressure": 1000, "humidity": 88, "sea_level": 1000, "grnd_level": 995}, "visibility": 10000, "wind": {"speed": 2.93, "deg": 350, "gust": 3.69}, "clouds": {"all": 96}, "dt": 1783757479, "sys": {"country": "CN", "sunrise": 1783716899, "sunset": 1783770257}, "timezone": 28800, "id": 1816670, "name": "Beijing", "cod": 200} {"coord": {"lon": 116.3972, "lat": 39.9075}, "weather": [{"id": 804, "main": "Clouds", "description": "\u9634\uff0c\u591a\u4e91", "icon": "04d"}], "base": "stations", "main": {"temp": 28.24, "feels_like": 34.14, "temp_min": 28.24, "temp_max": 28.24, "pressure": 1000, "humidity": 88, "sea_level": 1000, "grnd_level": 995}, "visibility": 10000, "wind": {"speed": 2.93, "deg": 350, "gust": 3.69}, "clouds": {"all": 96}, "dt": 1783757479, "sys": {"country": "CN", "sunrise": 1783716899, "sunset": 1783770257}, "timezone": 28800, "id": 1816670, "name": "Beijing", "cod": 200} Invoking: `get_weather` with `{'loc': 'shanghai'}` responded: 好的!我来同时查询北京和上海的天气,马上为您比较。 {"coord": {"lon": 121.4581, "lat": 31.2222}, "weather": [{"id": 804, "main": "Clouds", "description": "\u9634\uff0c\u591a\u4e91", "icon": "04d"}], "base": "stations", "main": {"temp": 30.02, "feels_like": 35.58, "temp_min": 30.02, "temp_max": 30.02, "pressure": 1000, "humidity": 72, "sea_level": 1000, "grnd_level": 999}, "visibility": 10000, "wind": {"speed": 7.56, "deg": 72, "gust": 16.19}, "clouds": {"all": 100}, "dt": 1783757402, "sys": {"country": "CN", "sunrise": 1783717073, "sunset": 1783767654}, "timezone": 28800, "id": 1796236, "name": "Shanghai", "cod": 200} {"coord": {"lon": 121.4581, "lat": 31.2222}, "weather": [{"id": 804, "main": "Clouds", "description": "\u9634\uff0c\u591a\u4e91", "icon": "04d"}], "base": "stations", "main": {"temp": 30.02, "feels_like": 35.58, "temp_min": 30.02, "temp_max": 30.02, "pressure": 1000, "humidity": 72, "sea_level": 1000, "grnd_level": 999}, "visibility": 10000, "wind": {"speed": 7.56, "deg": 72, "gust": 16.19}, "clouds": {"all": 100}, "dt": 1783757402, "sys": {"country": "CN", "sunrise": 1783717073, "sunset": 1783767654}, "timezone": 28800, "id": 1796236, "name": "Shanghai", "cod": 200}以下是今天北京和上海的天气对比: --- ### 🌤️ **北京天气** | 项目 | 详情 | |------|------| | ☁️ 天气 | 阴,多云 | | 🌡️ 温度 | **28.24°C** | | 🥵 体感温度 | 34.14°C | | 💧 湿度 | **88%** | | 🌬️ 风速 | 2.93 m/s(北风) | ### 🌤️ **上海天气** | 项目 | 详情 | |------|------| | ☁️ 天气 | 阴,多云 | | 🌡️ 温度 | **30.02°C** | | 🥵 体感温度 | 35.58°C | | 💧 湿度 | 72% | | 🌬️ 风速 | 7.56 m/s(东北风) | --- ### 📊 对比结论:**上海更热!** - 上海的实际气温 **30.02°C**,比北京高出约 **1.8°C**; - 体感温度方面,上海(35.58°C)也比北京(34.14°C)高出约 **1.4°C**; - 不过北京的湿度高达 **88%**,比上海更潮湿闷热,所以虽然温度略低,但闷热感并不逊色。 总体来说,今天两个城市都是阴天多云,气温都偏高,建议出门注意防暑降温哦!🌞 > Finished chain. {'input': '请问今天北京和上海的天气怎么样,哪个城市更热?', 'output': '以下是今天北京和上海的天气对比:\n\n---\n\n### 🌤️ **北京天气**\n| 项目 | 详情 |\n|------|------|\n| ☁️ 天气 | 阴,多云 |\n| 🌡️ 温度 | **28.24°C** |\n| 🥵 体感温度 | 34.14°C |\n| 💧 湿度 | **88%** |\n| 🌬️ 风速 | 2.93 m/s(北风) |\n\n### 🌤️ **上海天气**\n| 项目 | 详情 |\n|------|------|\n| ☁️ 天气 | 阴,多云 |\n| 🌡️ 温度 | **30.02°C** |\n| 🥵 体感温度 | 35.58°C |\n| 💧 湿度 | 72% |\n| 🌬️ 风速 | 7.56 m/s(东北风) |\n\n---\n\n### 📊 对比结论:**上海更热!**\n\n- 上海的实际气温 **30.02°C**,比北京高出约 **1.8°C**;\n- 体感温度方面,上海(35.58°C)也比北京(34.14°C)高出约 **1.4°C**;\n- 不过北京的湿度高达 **88%**,比上海更潮湿闷热,所以虽然温度略低,但闷热感并不逊色。\n\n总体来说,今天两个城市都是阴天多云,气温都偏高,建议出门注意防暑降温哦!🌞'} Process finished with exit code 0这里的:
("placeholder", "{agent_scratchpad}")可以理解为:在提示词中预留一个位置,用来放 Agent 调用工具的过程记录。
1.placeholder是什么?
placeholder表示“消息占位符”。
普通消息是固定角色的一条消息:
("system", "你是天气助手") ("human", "{input}")而:
("placeholder", "{agent_scratchpad}")不是一条固定消息。运行时,LangChain 会把agent_scratchpad中的一组消息插入到这里。
它大致等价于:
MessagesPlaceholder(variable_name="agent_scratchpad")2.agent_scratchpad是什么?
它是 Agent 的“临时工作记录区”,主要保存:
- 模型决定调用哪个工具
- 调用工具时传入的参数
- 工具返回的结果
- Agent 根据结果继续进行的下一步操作
这里的“scratchpad”可以直译为“草稿纸”。
但它不是模型真正的隐藏思维过程,而是Agent 执行工具所必需的结构化消息记录。
3. 在这段代码中的执行过程
用户输入:
请问今天北京和上海的天气怎么样,哪个城市更热?第一次发送给模型的内容大致是:
System: 你是天气助手,请根据用户的问题,给出相应的天气信息 Human: 请问今天北京和上海的天气怎么样,哪个城市更热?此时:
agent_scratchpad = []因为还没有调用工具,所以占位符中暂时没有内容。
模型判断需要查询两个城市,生成工具调用,例如:
调用 get_weather(loc="Beijing") 调用 get_weather(loc="Shanghai")AgentExecutor执行工具后,会得到天气查询结果。接着,这些工具调用和工具返回值会被放进agent_scratchpad:
Assistant: 调用 get_weather(loc="Beijing") Tool: 北京天气查询结果 Assistant: 调用 get_weather(loc="Shanghai") Tool: 上海天气查询结果然后再次把完整提示发送给模型:
System: 你是天气助手…… Human: 请问今天北京和上海的天气怎么样,哪个城市更热? Assistant: 调用 get_weather(loc="Beijing") Tool: 北京天气查询结果 Assistant: 调用 get_weather(loc="Shanghai") Tool: 上海天气查询结果模型看到查询结果后,才能生成最终回答:
北京今天 30℃,上海今天 34℃,因此上海更热。整体循环可以概括为:
用户问题 ↓ LLM 判断是否需要工具 ↓ 调用 get_weather ↓ 工具结果写入 agent_scratchpad ↓ 重新调用 LLM ↓ 生成最终答案4. 为什么不能删除?
create_tool_calling_agent()要求提示模板中包含:
agent_scratchpad如果删除,通常会报类似错误:
Prompt missing required variables: {'agent_scratchpad'}即便某些实现没有立即报错,模型也看不到之前的工具调用结果,无法根据天气 API 的返回值完成最终回答。
一句话总结:
placeholder决定“在提示词的什么位置插入消息”,agent_scratchpad保存“Agent 调用了什么工具以及工具返回了什么”。