【LangChain 工具调用详解】工具篇
·
LangChain 工具调用详解
目录
2. 工具调用(Tools)
2.1 基础工具定义
使用 @tool 装饰器
from langchain.tools import tool
@tool
def add_number(a: int, b: int) -> int:
"""两个整数相加"""
return a + b
# 调用工具
result = add_number.invoke({"a": 1, "b": 12})
print(result) # 13
# 查看工具元信息
print(f"{add_number.name=}") # add_number.name='add_number'
print(f"{add_number.description=}") # add_number.description='两个整数相加'
print(f"{add_number.args=}") # 参数字段定义
@tool 装饰器自动生成的内容
| 属性 | 说明 |
|---|---|
name |
默认使用函数名(可自定义) |
description |
自动使用函数的 docstring |
args |
根据函数签名自动生成参数 schema |
工具元信息详解
# args 的结构(LangChain 自动生成)
{
'a': {'title': 'A', 'type': 'integer'},
'b': {'title': 'B', 'type': 'integer'}
}
2.2 使用 Pydantic 定义参数
为什么使用 Pydantic?
-
更清晰的参数描述
-
更好的类型验证
-
支持默认值、默认值校验等高级功能
基础 Pydantic 模型
from pydantic import BaseModel, Field class FieldInfo(BaseModel): """定义加法运算所需的参数信息""" a: int = Field(description="第1个参数") b: int = Field(description="第2个参数")
使用 args_schema 绑定
from langchain_core.tools import tool
from pydantic import BaseModel, Field
class FieldInfo(BaseModel):
a: int = Field(description="第1个参数")
b: int = Field(description="第2个参数")
@tool(args_schema=FieldInfo)
def add_number(a: int, b: int) -> int:
return a + b
# 调用
res = add_number.invoke({"a": 1, "b": 2})
print(res) # 3
Pydantic 验证示例
文件:08_tools/PydanticDemo.py
from pydantic import BaseModel, ValidationError, StrictInt class User(BaseModel): id: StrictInt # 严格整数,拒绝类型转换 name: str age: int = 0 # 可选,默认值 # 正常情况 u = User(id=42, name="z3") print(u.id, type(u.id)) # 42 <class 'int'> # 严格模式:字符串无法自动转换 try: User(id="41", name="z3") # ❌ 失败 except ValidationError as e: print(e)
2.3 天气查询工具
完整实现
from langchain_core.tools import tool
import json
import os
import httpx
from dotenv import load_dotenv
load_dotenv(encoding='utf-8')
@tool
def get_weather(loc: str) -> str:
"""
查询即时天气函数
:param loc: 必要参数,字符串类型,用于表示查询天气的具体城市名称。
注意,中国的城市需要用对应城市的英文名称,例如 'Beijing'/'Shanghai'。
:return: OpenWeather API 查询即时天气的结果,JSON 格式字符串。
"""
url = "https://api.openweathermap.org/data/2.5/weather"
params = {
"q": loc,
"appid": "your_api_key_here", # OpenWeather API Key
"units": "metric", # 使用摄氏度
"lang": "zh_cn" # 输出简体中文
}
response = httpx.get(url, params=params, timeout=30)
data = response.json()
return json.dumps(data)
OpenWeather API 返回数据示例
{
"coord": {"lon": 116.3972, "lat": 39.9075},
"weather": [{"id": 800, "main": "Clear", "description": "晴", "icon": "01d"}],
"main": {
"temp": 23.29,
"feels_like": 21.94,
"humidity": 10,
"pressure": 1013
},
"wind": {"speed": 2.35, "deg": 220, "gust": 3.54},
"visibility": 10000,
"name": "Beijing"
}
2.4 工具与 LLM 绑定
核心流程
┌─────────────────────────────────────────────────────────┐
│ 工具调用完整流程 │
├─────────────────────────────────────────────────────────┤
│ │
│ 用户: "请问北京今天的天气如何?" │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ 1. LLM + bind_tools │ │
│ │ 判断需要调用 get_weather │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ 2. JsonOutputKeyToolsParser │ │
│ │ 解析出 {loc: "Beijing"} │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ 3. get_weather.invoke({...}) │ │
│ │ 调用外部 API 获取天气数据 │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ 4. output_chain │ │
│ │ 将 JSON 转换为自然语言 │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 用户: "北京现在天气晴,气温 23℃..." │
│ │
└─────────────────────────────────────────────────────────┘
完整代码
import os
from langchain_core.output_parsers import JsonOutputKeyToolsParser, StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from loguru import logger
from QueryWeatherTool import get_weather
from dotenv import load_dotenv
load_dotenv(encoding='utf-8')
# 初始化大语言模型
llm = ChatOpenAI(
model="qwen-plus",
api_key=os.getenv("aliQwen-api"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
# 1. 将模型与工具绑定
llm_with_tools = llm.bind_tools([get_weather])
# 2. 创建解析器
parser = JsonOutputKeyToolsParser(key_name=get_weather.name, first_tool_only=True)
# 3. 构建工具调用链:模型 -> 解析器 -> 调用工具
get_weather_chain = llm_with_tools | parser | get_weather
# 4. 定义输出提示模板(JSON -> 自然语言)
output_prompt = PromptTemplate.from_template(
"""你将收到一段 JSON 格式的天气数据{weather_json},
请用简洁自然的方式将其转述给用户。
例如:"北京现在天气:晴,气温 23℃,湿度 10%,微风..." """
)
# 5. 创建字符串输出解析器
output_parser = StrOutputParser()
# 6. 构建最终输出链:提示模板 -> 模型 -> 输出解析器
output_chain = output_prompt | llm | output_parser
# 7. 构建完整处理链
full_chain = get_weather_chain | (lambda x: {"weather_json": x}) | output_chain
# 8. 执行
result = full_chain.invoke("请问北京今天的天气如何?")
logger.info(result)
LCEL 链式调用详解
| 步骤 | 组件 | 作用 |
|---|---|---|
| 1 | llm.bind_tools([get_weather]) |
让模型知道有哪些工具可用 |
| 2 | JsonOutputKeyToolsParser |
解析模型输出的工具调用 |
| 3 | parser \| get_weather |
执行工具调用并获取结果 |
| 4 | output_prompt \| llm \| output_parser |
将 JSON 结果转换为自然语言 |
2.5 工具调用进阶技巧
多个工具绑定
# 绑定多个工具 llm_with_tools = llm.bind_tools([get_weather, add_number, search_tool])
first_tool_only 参数
# 只使用第一个工具调用(忽略后续可能的调用) parser = JsonOutputKeyToolsParser(key_name=get_weather.name, first_tool_only=True)
自定义工具名称
@tool(name="custom_weather") def get_weather(loc: str) -> str: """...""" pass 工具调用要点
| 概念 | 说明 |
|---|---|
| @tool 装饰器 | 将函数定义为 LangChain 工具 |
| Pydantic args_schema | 定义参数校验和描述 |
| bind_tools | 绑定工具到 LLM |
| JsonOutputKeyToolsParser | 解析工具调用输出 |
| LCEL 链式调用 | 组合多个组件形成完整流程 |
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)