LangChain 工具调用详解


目录

LangChain 工具调用详解

2. 工具调用(Tools)

2.1 基础工具定义

使用 @tool 装饰器

@tool 装饰器自动生成的内容

工具元信息详解

2.2 使用 Pydantic 定义参数

为什么使用 Pydantic?

基础 Pydantic 模型

使用 args_schema 绑定

Pydantic 验证示例

2.3 天气查询工具

完整实现

OpenWeather API 返回数据示例

2.4 工具与 LLM 绑定

核心流程

完整代码

LCEL 链式调用详解

2.5 工具调用进阶技巧

多个工具绑定

first_tool_only 参数

自定义工具名称

3. 总结

记忆系统要点

工具调用要点



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 链式调用 组合多个组件形成完整流程

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐