【LangChain系列三】聊天模型中:工具调用,让大模型拥有超能力

大模型再聪明,也有两个硬伤:知识有截止日期,没法直接调外部 API。工具调用就是解决这个问题的。

聊天模型的局限

你问 ChatGPT “今天上海天气怎么样”,它答不上来——因为它没有联网能力。你让它帮你查数据库,它也做不到——因为它只是个语言模型,没有手。

工具调用(Tool Calling)的本质就是给大模型装上"手"。模型不直接执行操作,而是输出一段结构化的调用指令,由外部程序去执行。

整个流程分三步:定义工具 → 绑定工具 → 调用工具

用 @tool 装饰器创建工具

最简单的方式,一个装饰器搞定:

from langchain_core.tools import tool

@tool
def search_weather(city: str) -> str:
    """查询指定城市的当前天气信息"""
    # 这里调用真实天气 API
    return f"{city}今天晴,25°C"

三个要素缺一不可:

  • 函数名 search_weather → 工具名称,模型通过这个名字引用工具
  • 文档字符串 "查询指定城市的当前天气信息" → 工具描述,告诉模型这个工具能干嘛
  • 类型提示 city: str → 参数说明,告诉模型怎么填参数

LangChain 会自动从这些信息生成 JSON Schema 交给模型。模型看到的大概长这样:

{
  "name": "search_weather",
  "description": "查询指定城市的当前天气信息",
  "parameters": {
    "type": "object",
    "properties": {
      "city": {"type": "string"}
    },
    "required": ["city"]
  }
}

三种定义工具的方式

方式一:@tool 装饰器(推荐)

@tool
def multiply(a: int, b: int) -> int:
    """将两个整数相乘"""
    return a * b

简单直接,大多数场景够用。

方式二:Pydantic 类

from pydantic import BaseModel, Field

class MultiplyTool(BaseModel):
    """将两个整数相乘"""
    a: int = Field(description="第一个乘数")
    b: int = Field(description="第二个乘数")

# 转成工具
from langchain_core.tools import StructuredTool
multiply = StructuredTool.from_function(
    func=lambda a, b: a * b,
    args_schema=MultiplyTool
)

Pydantic 的好处是参数描述更精确,适合参数复杂的工具。

方式三:Annotated 注解

from typing import Annotated

@tool
def divide(
    a: Annotated[float, "被除数"],
    b: Annotated[float, "除数,不能为0"]
) -> float:
    """两个数相除"""
    return a / b

直接在类型注解里写描述,比文档字符串更贴近参数。

工具的 content 和 artifact

有些工具执行后既要给模型看结果,又要给后续组件留数据。用 response_format="content_and_artifact" 来处理:

@tool(response_format="content_and_artifact")
def get_stock_price(symbol: str) -> tuple:
    """查询股票实时价格"""
    # 模拟查询
    price = 150.25
    detail = {"symbol": symbol, "price": price, "volume": 1000000}
    return f"{symbol}当前价格:{price}元", detail

返回的元组里,第一个元素是 content(给模型看的文本),第二个是 artifact(留给后续处理的原始数据)。

绑定工具到模型

创建好工具后,绑定到模型上:

from langchain_deepseek import ChatDeepSeek

llm = ChatDeepSeek(model="deepseek-chat", temperature=0)
llm_with_tools = llm.bind_tools([search_weather, multiply])

绑定后模型就知道自己有哪些工具可以用。调用时模型会自己判断要不要用工具、用哪个工具。

调用工具

单工具调用

response = llm_with_tools.invoke("北京今天天气怎么样?")

# 检查模型是否要调用工具
if response.tool_calls:
    for tc in response.tool_calls:
        print(f"工具:{tc['name']}")
        print(f"参数:{tc['args']}")
        print(f"ID:{tc['id']}")

response.tool_calls 是一个列表,每个元素包含 nameargsid 三个字段。

拿到工具调用指令后,你需要自己执行并把结果喂回去:

from langchain_core.messages import ToolMessage

# 执行工具
tool_result = search_weather.invoke(tc['args'])

# 把结果发回模型
messages = [
    response,
    ToolMessage(content=tool_result, tool_call_id=tc['id'])
]
final_response = llm_with_tools.invoke(messages)

多工具调用

模型可能同时调用多个工具,遍历 tool_calls 就行:

messages = [response]
for tc in response.tool_calls:
    # 根据工具名找到对应的函数
    tool_fn = {"search_weather": search_weather, "multiply": multiply}[tc['name']]
    result = tool_fn.invoke(tc['args'])
    messages.append(ToolMessage(content=str(result), tool_call_id=tc['id']))

final = llm_with_tools.invoke(messages)

工具选择策略

默认情况下,模型自己决定用不用工具。你也可以强制:

# 强制使用工具(任意一个)
llm.bind_tools([search_weather], tool_choice="any")

# 强制使用特定工具
llm.bind_tools([search_weather], tool_choice="search_weather")

# 禁止使用工具
llm.bind_tools([search_weather], tool_choice="none")

LangChain 内置工具

LangChain 提供了不少现成工具,以 Tavily 搜索为例:

from langchain_community.tools import TavilySearchResults

search = TavilySearchResults(max_results=3)
llm_with_search = llm.bind_tools([search])

response = llm_with_search.invoke("最新发布的 Python 3.13 有什么新特性?")

需要先申请 Tavily API Key 并设置环境变量 TAVILY_API_KEY

DeepSeek 的坑

用 DeepSeek 做工具调用时有几个要注意的地方:

  1. 关闭思考模式:DeepSeek 的思考模式可能干扰工具调用格式
  2. 强制工具调用:建议设 tool_choice="any",不然模型有时候会"偷懒"不用工具
llm = ChatDeepSeek(
    model="deepseek-chat",
    temperature=0
).bind_tools(
    tools=[search_weather],
    tool_choice="any"
)

小结

工具调用是 LangChain 里最实用的能力之一。模型负责理解意图和生成调用指令,你负责执行和返回结果。这种"大脑+双手"的架构,让大模型从聊天机器人进化成了真正的智能代理。


下一篇我们聊结构化输出——怎么让模型吐出程序能直接用的数据。

觉得有帮助的话,点个赞👍收藏⭐支持一下吧!

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐