LangChain调用外部工具

OpenWeather的API Key

OpenWeather官网免费注册获取。

LangChain 调用外部工具流程

  1. 构建获取天气的函数
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("北京")

输出结果为

在这里插入图片描述

  1. 将函数变成一个可以被大模型调用的工具
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')]
  1. 从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
  }
  1. 工具调用结果转换为工具消息
#工具调用结果转换为工具消息
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'
  1. 将外部工具返回的信息添加到提示词中,用于调用模型生成最终的回复
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)
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐