langchain调用外部工具(学习笔记)
langchain调用外部工具,理解LangChain中Agent的实现方式
·
LangChain调用外部工具
OpenWeather的API Key
在OpenWeather官网免费注册获取。
LangChain 调用外部工具流程
- 构建获取天气的函数
import json
import os
from langchain_core.tools import tool
from dotenv import load_dotenv
import requests
from langchain.chat_models import init_chat_model
from langchain.agents.output_parsers.tools import ToolsAgentOutputParser
from langchain_core.messages import ToolMessage
from langchain_core.runnables import RunnablePassthrough
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.agents import AgentExecutor
from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages
def get_weather(city: str):
"""获取指定城市的天气信息
Args:
city (str): 城市名称
Returns:
str: 包含天气信息的JSON字符串
"""
# 城市名称映射,解决中文城市名不被识别的问题
city_mapping = {
"北京": "Beijing",
"上海": "Shanghai",
"广州": "Guangzhou",
"深圳": "Shenzhen",
"杭州": "Hangzhou"
}
# 中文城市名,转换为英文
english_city = city_mapping.get(city, city)
# 构建请求
url = "https://api.openweathermap.org/data/2.5/weather"
# 设置查询参数
params = {
"q": english_city,
"appid": os.getenv("OPENWEATHER_API_KEY"), # 输入API key
"units": "metric", # 使用摄氏度而不是华氏度
"lang":"zh_cn" # 输出语言为简体中文
}
# 发送GET请求
response = requests.get(url, params=params)
print(response.json())
if __name__ == "__main__":
get_weather("北京")
输出结果为
- 将函数变成一个可以被大模型调用的工具
import json
import os
from langchain_core.tools import tool
from dotenv import load_dotenv
import requests
from langchain.chat_models import init_chat_model
from langchain.agents.output_parsers.tools import ToolsAgentOutputParser
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain import hub
load_dotenv(override=True)
@tool
def get_weather(city: str):
"""获取指定城市的天气信息
Args:
city (str): 城市名称
Returns:
str: 包含天气信息的JSON字符串
"""
# 城市名称映射,解决中文城市名不被识别的问题
city_mapping = {
"北京": "Beijing",
"上海": "Shanghai",
"广州": "Guangzhou",
"深圳": "Shenzhen",
"杭州": "Hangzhou"
}
# 中文城市名,转换为英文
english_city = city_mapping.get(city, city)
# 构建请求
url = "https://api.openweathermap.org/data/2.5/weather"
# 设置查询参数
params = {
"q": english_city,
"appid": os.getenv("OPENWEATHER_API_KEY"), # 输入API key
"units": "metric", # 使用摄氏度而不是华氏度
"lang":"zh_cn" # 输出语言为简体中文
}
# 发送GET请求
response = requests.get(url, params=params)
# 解析响应
data = response.json()
return json.dumps(data)
# 创建模型实例
model = init_chat_model(model="deepseek-chat", model_provider="deepseek")
tools = [get_weather]
# 创建带有工具的模型
llm_with_tools = model.bind_tools(tools)
# 发送查询
response = llm_with_tools.invoke("北京的天气怎么样?")
print("模型响应:", response)
print("工具调用:", response.tool_calls)
# 解析模型响应
agentAction = ToolsAgentOutputParser().invoke(response)
print("解析结果:", agentAction)
运行结果:
分析
模型响应:
content='我来帮您查询北京的天气情况。'
additional_kwargs={
'tool_calls': [{'id': 'call_00_adHbnN1etXUmizXt9QeD18RM',
'function': {'arguments': '{"city": "\\u5317\\u4eac"}',
'name': 'get_weather'},
'type': 'function',
'index': 0}],
'refusal': None}
response_metadata={
'token_usage': {'completion_tokens': 28,
'prompt_tokens': 175,
'total_tokens': 203,
'completion_tokens_details': None,
'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 128},
'prompt_cache_hit_tokens': 128,
'prompt_cache_miss_tokens': 47},
'model_name': 'deepseek-chat',
'system_fingerprint': 'fp_08f168e49b_prod0820_fp8_kvcache',
'id': '41c2e551-113e-4aae-984e-4bf1d0cd6e2c',
'service_tier': None,
'finish_reason': 'tool_calls',
'logprobs': None}
id='run--c5d7cb89-b76f-4a7c-a3ba-0345c4c81d6d-0'
tool_calls=[
{'name': 'get_weather',
'args': {'city': '北京'},
'id': 'call_00_adHbnN1etXUmizXt9QeD18RM',
'type': 'tool_call'}]
usage_metadata={
'input_tokens': 175,
'output_tokens': 28,
'total_tokens': 203,
'input_token_details': {'cache_read': 128}, 'output_token_details': {}}
工具调用: [{'name': 'get_weather', 'args': {'city': '北京'},
'id': 'call_00_adHbnN1etXUmizXt9QeD18RM',
'type': 'tool_call'}]
解析结果:
[ToolAgentAction(
tool='get_weather',
tool_input={'city': '北京'},
log="\nInvoking:
`get_weather` with `{'city': '北京'}`\nresponded: 我来帮您查询北京的天气情况。\n\n",
message_log=[AIMessage(content='我来帮您查询北京的天气情况。',
additional_kwargs={'tool_calls': [{'id': 'call_00_adHbnN1etXUmizXt9QeD18RM', 'function': {'arguments': '{"city": "\\u5317\\u4eac"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}],
'refusal': None},
response_metadata={'token_usage': {'completion_tokens': 28, 'prompt_tokens': 175, 'total_tokens': 203, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 128}, 'prompt_cache_hit_tokens': 128, 'prompt_cache_miss_tokens': 47}, 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_08f168e49b_prod0820_fp8_kvcache', 'id': '41c2e551-113e-4aae-984e-4bf1d0cd6e2c', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--c5d7cb89-b76f-4a7c-a3ba-0345c4c81d6d-0',
tool_calls=[{'name': 'get_weather', 'args': {'city': '北京'}, 'id': 'call_00_adHbnN1etXUmizXt9QeD18RM', 'type': 'tool_call'}],
usage_metadata={'input_tokens': 175, 'output_tokens': 28, 'total_tokens': 203, 'input_token_details': {'cache_read': 128}, 'output_token_details': {}})],
tool_call_id='call_00_adHbnN1etXUmizXt9QeD18RM')]
- 从ToolAgentAction中获取工具调用,并手动执行工具调用以获取工具调用的结果。
# # 执行工具调用
tool_output = None
for tool_call in response.tool_calls:
#创建一个字典映射
# selected_tool = {"get_weather": get_weather}[tool_call["name"].lower()]
#selected_tool 是一个可调用的函数对象(Callable)
tool_name = tool_call["name"].lower()
if tool_name == "get_weather":
selected_tool = get_weather
#传入参数,执行工具函数
tool_output = selected_tool.invoke(tool_call["args"])
print("工具执行结果:", tool_output)
输出结果分析
具执行结果:
{"coord": {"lon": 116.3972, "lat": 39.9075},
"weather": [{"id": 804,
"main": "Clouds",
"description": "\u9634\uff0c\u591a\u4e91",
"icon": "04d"}],
"base": "stations",
"main": {"temp": 21.94, "feels_like": 21.83, "temp_min": 21.94, "temp_max": 21.94, "pressure": 1022, "humidity": 63, "sea_level": 1022, "grnd_level": 1017},
"visibility": 10000,
"wind": {"speed": 2.19, "deg": 177, "gust": 3.17},
"clouds": {"all": 100},
"dt": 1758512282,
"sys": {"type": 1, "id": 9609, "country": "CN", "sunrise": 1758492101, "sunset": 1758535971},
"timezone": 28800,
"id": 1816670,
"name": "Beijing",
"cod": 200
}
- 工具调用结果转换为工具消息
#工具调用结果转换为工具消息
message=format_to_tool_messages(intermediate_steps = [(agentAction[0], tool_output)])
print("工具消息:", message)
运行结果
工具消息:
content='{"coord": {"lon": 116.3972, "lat": 39.9075},
"weather": [{"id": 804, "main": "Clouds", "description": "\\u9634\\uff0c\\u591a\\u4e91", "icon": "04d"}],
"base": "stations",
"main": {"temp": 21.94, "feels_like": 21.83, "temp_min": 21.94, "temp_max": 21.94, "pressure": 1022, "humidity": 63, "sea_level": 1022, "grnd_level": 1017},
"visibility": 10000,
"wind": {"speed": 2.19, "deg": 177, "gust": 3.17},
"clouds": {"all": 100}, "dt": 1758512831,
"sys": {"type": 1, "id": 9609, "country": "CN", "sunrise": 1758492101, "sunset": 1758535971},
"timezone": 28800,
"id": 1816670,
"name": "Beijing",
"cod": 200}'
tool_call_id='call_00_JLlZk2bYyLc7YRgHY41LmhM4'
- 将外部工具返回的信息添加到提示词中,用于调用模型生成最终的回复
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant that can answer questions about weather."),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad")
])
agent = (
RunnablePassthrough.assign(
agent_scratchpad=lambda x: format_to_openai_tool_messages(x["intermediate_steps"])
)
| prompt
| llm_with_tools
| ToolsAgentOutputParser()
)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = agent_executor.invoke({"input": "北京的天气怎么样?"})
print("执行结果:", result)
这是一个使用管道操作符(|)连接的处理链,包含以下组件:
- RunnablePassthrough.assign():用于处理输入数据,将 agent_scratchpad 添加到输入中
- prompt:定义的提示词模板,
- lm_with_tools:绑定了工具的模型
- ToolsAgentOutputParser():解析模型输出的工具
运行结果:
简单版本
import json
import os
from langchain_core.tools import tool
from dotenv import load_dotenv
import requests
from langchain.chat_models import init_chat_model
from langchain.agents import create_tool_calling_agent, tool
from langchain_core.prompts import ChatPromptTemplate
from langchain.agents import AgentExecutor
'''
langchain调用外部工具简单版本
'''
load_dotenv(override=True)
@tool
def get_weather(city: str):
"""获取指定城市的天气信息
Args:
city (str): 城市名称
Returns:
str: 包含天气信息的JSON字符串
"""
# 城市名称映射,解决中文城市名不被识别的问题
city_mapping = {
"北京": "Beijing",
"上海": "Shanghai",
"广州": "Guangzhou",
"深圳": "Shenzhen",
"杭州": "Hangzhou"
}
# 中文城市名,转换为英文
english_city = city_mapping.get(city, city)
# 构建请求
url = "https://api.openweathermap.org/data/2.5/weather"
# 设置查询参数
params = {
"q": english_city,
"appid": os.getenv("OPENWEATHER_API_KEY"), # 输入API key
"units": "metric", # 使用摄氏度而不是华氏度
"lang":"zh_cn" # 输出语言为简体中文
}
# 发送GET请求
response = requests.get(url, params=params)
# 解析响应
data = response.json()
return json.dumps(data)
tools = [get_weather]
# 构建提示模版
prompt = ChatPromptTemplate.from_messages(
[
("system", "你是天气助手,请根据用户的问题,给出相应的天气信息"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
]
)
# 初始化模型
model = init_chat_model("deepseek-chat", model_provider="deepseek")
# 直接使用`create_tool_calling_agent`创建代理
agent = create_tool_calling_agent(model, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
response = agent_executor.invoke({"input": "请问今天北京的天气怎么样?"})
print(response)
更多推荐
所有评论(0)