目录

一、为什么需要工具调用?

二、创建工具:从简单到专业(3种核心模式)

2.1 模式一:使用 @tool 装饰器(最简单入门)

2.1.1 基础用法

2.1.2 进阶:依赖 Pydantic(复杂参数验证)

2.1.3 进阶:依赖 Annotated(简洁元数据传递)

2.2 模式二:使用 StructuredTool(精细控制)

2.2.1 常规用法

2.2.2 高级:配置 response_format(优化复杂结果处理)

三、绑定工具:让模型“看见”自身能力

3.1 bind_tools() 基础用法

3.2 bind_tools() 核心参数(控制模型调用行为)

四、工具调用:完整工作流详解(从决策到执行)

4.1 第一步:模型决策(核心环节)

场景一:需要调用工具(如数学计算)

场景二:不需要调用工具(如简单问候)

场景三:强制调用工具(指定 tool_choice)

4.2 第二步:执行工具(将指令转为结果)

4.3 第三步:回传结果,生成最终回答

五、总结与展望:从“有工具”到“用好工具”


大语言模型(LLM)虽然强大,但本质上是一个“只读”的知识库,无法直接与外部世界交互。而工具调用(Tool Calling)正是打破这一壁垒的关键技术。它让 LLM 不再局限于训练数据,能够执行计算、查询数据库、调用 API,甚至生成图表,从而真正成为一个强大的自动化助手。

本文将整合工具调用的基础认知、创建方法、绑定使用、执行回传及实战技巧,从零到一、由浅入深,帮助你完整掌握 LangChain 工具调用技术,轻松构建可交互、能落地的 AI 应用。


一、为什么需要工具调用?

LLM 本身是一个封闭的系统,其能力受限于训练数据的时效性和内在的文本生成逻辑。工具调用的作用体现在以下四个核心方面,也是其成为 LLM 生产力升级关键的原因:

  1. 扩展能力边界:让模型完成自身无法完成的任务,如执行复杂数学计算、实时查询天气、操作数据库或调用任何外部 API,打破“文本生成”的单一局限。

  2. 保证信息实时性:通过搜索引擎或数据库获取最新信息,避免 LLM 因训练数据滞后而“一本正经地胡说八道”,提升回答的准确性和实用性。

  3. 处理复杂任务:将复杂的用户请求(如“分析我上个月的消费趋势并生成图表”)分解为多个步骤,依次调用不同的工具协同完成,实现复杂工作流的自动化。

  4. 连接现有系统:将企业内部的系统、API 和数据库封装成工具,让 LLM 用自然语言驱动,无需额外开发交互界面,极大提升自动化和系统集成能力。

在 LangChain 中,工具调用的过程非常直观。例如,当你问“夏威夷的天气怎么样?”时,模型会生成一个结构化的工具调用请求,然后由系统执行并返回结果,最终整合为自然语言回答。

AIMessage(
    tool_calls=[{
        "name": "get_weather",
        "args": {"location": "Hawaii"},
        "id": "call_abc123",
        "type": "tool_call"
    }]
)

二、创建工具:从简单到专业(3种核心模式)

在 LangChain 中,创建工具的核心是将 Python 函数(或外部能力)封装成模型可理解的接口(包含名称、描述、参数规范)。根据需求复杂度,主要有三种创建模式,从简单到进阶逐步升级。

2.1 模式一:使用 @tool 装饰器(最简单入门)

@tool 装饰器是定义自定义工具的最简方式,它会自动将函数名、文档字符串和类型提示,转换为模型理解工具所需的 Schema(名称、描述、参数规范),无需额外配置。

2.1.1 基础用法
from langchain_core.tools import tool

@tool
def multiply(a: int, b: int) -> int:
    """Multiply two integers.

    Args:
        a: First integer
        b: Second integer
    """
    return a * b

# 调用工具(测试)
print(multiply.invoke({"a": 2, "b": 3}))  # 输出: 6
print(multiply.name)                       # 输出: multiply(工具名称,自动取函数名)
print(multiply.description)                # 输出: Multiply two integers...(工具描述,自动取文档字符串)
print(multiply.args)                       # 输出: {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}(参数Schema)
2.1.2 进阶:依赖 Pydantic(复杂参数验证)

当工具参数较多、需要更严格的输入验证,或需要更详细的参数描述时,可以结合 Pydantic 定义输入模型,让工具的 Schema 更清晰、更规范。

from langchain_core.tools import tool
from pydantic import BaseModel, Field

# 定义输入参数的 Pydantic 模型(包含参数描述和验证)
class AdderInput(BaseModel):
    """Add two integers."""  # 输入模型描述,辅助模型理解
    a: int = Field(..., description="First integer")  # ... 表示必填
    b: int = Field(..., description="Second integer")

# 绑定输入模型,定义工具
@tool(args_schema=AdderInput)
def add(a: int, b: int) -> int:
    """Add two integers."""  # 工具功能描述
    return a + b
2.1.3 进阶:依赖 Annotated(简洁元数据传递)

如果不需要复杂的输入验证,仅需给参数添加描述,也可以使用 typing_extensions.Annotated 传递元数据,语法更简洁。

from langchain_core.tools import tool
from typing_extensions import Annotated

@tool
def add(a: Annotated[int, "First integer"],
       b: Annotated[int, "Second integer"]) -> int:
    """Add two integers."""
    return a + b

2.2 模式二:使用 StructuredTool(精细控制)

当你需要对工具进行更精细的控制(如自定义工具名称、描述,或处理复杂的返回结果),或者从现有函数快速创建工具时,StructuredTool.from_function() 是更灵活的选择。

2.2.1 常规用法
from langchain_core.tools import StructuredTool

# 定义普通 Python 函数
def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b

# 从函数创建工具,自定义工具名称和描述
calculator_tool = StructuredTool.from_function(
    func=multiply,
    name="Calculator",  # 自定义工具名称(替代函数名)
    description="Multiply two numbers"  # 自定义工具描述
)
2.2.2 高级:配置 response_format(优化复杂结果处理)

在处理包含大量数据(如图表、表格、长文本)的工具时,直接返回原始数据会消耗大量 Token,降低效率。通过 response_format="content_and_artifact" 可将结果分为两部分,优化处理效率:

  • content:给模型看的简洁摘要,节省 Token。

  • artifact:存储原始的、结构化的复杂数据,供后续步骤(如保存、二次处理)使用。

from pydantic import BaseModel, Field
from langchain_core.tools import StructuredTool

# 定义输入模型
class CalculatorInput(BaseModel):
    a: int = Field(description="first number")
    b: int = Field(description="second number")

# 定义返回 content 和 artifact 的函数
def multiply(a: int, b: int) -> tuple[str, list[int]]:
    """Multiply two numbers and return a summary and the full result."""
    result = a * b
    # content: 给模型的简洁描述
    content = f"The result of {a} * {b} is {result}"
    # artifact: 存储的复杂数据结构(此处为示例,可替换为表格、图表等)
    artifact = [a, b, result]
    return content, artifact

# 创建工具,配置返回格式
calculator_tool = StructuredTool.from_function(
    func=multiply,
    name="Calculator",
    description="Multiply two numbers",
    args_schema=CalculatorInput,
    response_format="content_and_artifact"  # 关键配置
)

三、绑定工具:让模型“看见”自身能力

创建好工具后,下一步是将工具“绑定”到 LLM 上——这相当于告诉模型:“你现在可以调用这些工具了,它们的功能和参数是这样的”。绑定后,模型会自动分析用户需求,决定是否调用工具、调用哪个工具。

在 LangChain 中,绑定工具通过 `bind_tools()` 方法实现,它返回一个新的 Runnable 实例,封装了模型和工具的组合,无需修改模型本身的配置。

3.1 bind_tools() 基础用法

from langchain_openai import ChatOpenAI

# 1. 初始化大语言模型(以 OpenAI 模型为例)
model = ChatOpenAI(model="gpt-4o-mini")

# 2. 准备已创建的工具(沿用之前的 add, multiply 工具)
tools = [add, multiply]

# 3. 将工具绑定到模型上
model_with_tools = model.bind_tools(tools)

3.2 bind_tools() 核心参数(控制模型调用行为)

bind_tools() 提供了多个关键参数,可灵活控制模型的工具调用逻辑,适配不同场景需求,具体如下表所示:

参数名

核心作用

tools

接收可绑定的工具类型列表,支持函数、Pydantic 类或 BaseModel(即我们前面创建的各类工具)。

tool_choice

控制模型是否/如何调用工具(核心参数):- "auto" (默认): 自动判断,可调用或不调用;- "none": 强制不调用任何工具;- "any": 强制调用至少一个工具;- {"name": "<tool_name>"}: 强制调用指定的工具。

strict

如果为 True,则模型输出严格遵循工具的 JSON Schema,拒绝任何参数偏差,避免调用失败。

parallel_tool_calls

控制是否允许模型并行调用多个工具(如同时调用天气查询和时间查询),默认为 True,提升效率。


四、工具调用:完整工作流详解(从决策到执行)

绑定工具后,一个标准的工具调用流程包含 5 个关键步骤,形成完整的交互闭环: 1. 用户提问 → 2. 模型决策(是否调用工具、调用哪个)→ 3. 执行工具 → 4. 回传工具结果 → 5. 模型生成最终回答。

4.1 第一步:模型决策(核心环节)

当我们向绑定了工具的模型提问时,模型会首先分析问题的性质,自动决策: - 若问题可直接通过自身知识回答(如“Hello world!”),则不调用工具,直接返回自然语言; - 若问题需要外部能力(如计算、查实时数据),则生成结构化的 tool_calls 指令,指定要调用的工具和参数。

场景一:需要调用工具(如数学计算)
# 向绑定工具的模型提问
result = model_with_tools.invoke("9乘以5等于多少?")
print(result)

输出结果(AIMessage):模型返回空内容,仅生成 tool_calls 指令,告知系统需要调用 multiply 工具。

{
  "content": "",
  "additional_kwargs": {
    "tool_calls": [
      {
        "id": "call_abc123",
        "type": "function",
        "function": {
          "name": "multiply",
          "arguments": {"a": 9, "b": 5}
        }
      }
    ]
  }
}
场景二:不需要调用工具(如简单问候)
# 提问无需工具的问题
result = model_with_tools.invoke("Hello world!")
print(result)

输出结果(AIMessage):模型不生成 tool_calls,直接返回自然语言回答。

{
  "content": "Hello! How can I assist you today?",
  "additional_kwargs": {"refusal": None}
}
场景三:强制调用工具(指定 tool_choice)

有时我们希望模型必须使用工具(如测试工具可用性),即使问题可直接回答,此时可通过 tool_choice 参数强制调用。

# 强制模型调用至少一个工具
model_with_tools_forced = model.bind_tools(tools, tool_choice="any")

# 即使是简单问候,模型也会强制生成工具调用
result = model_with_tools_forced.invoke("Hello world!")
print(result.tool_calls)

4.2 第二步:执行工具(将指令转为结果)

模型生成的 tool_calls 只是“指令”,无法直接产生结果,需要我们手动(或通过系统)提取指令、执行对应的工具,并获取执行结果。

from langchain_core.messages import HumanMessage, ToolMessage

# 1. 构建对话历史(包含用户提问)
messages = [HumanMessage(content="9乘以5等于多少?5加3等于多少?")]

# 2. 模型生成工具调用指令(多个工具并行调用)
ai_msg = model_with_tools.invoke(messages)
messages.append(ai_msg)  # 将工具调用指令加入对话历史,便于后续回传

# 3. 遍历所有 tool_calls,执行对应的工具
for tool_call in ai_msg.tool_calls:
    # 根据工具名称,匹配对应的工具函数(此处可扩展为工具池查询)
    selected_tool = {"add": add, "multiply": multiply}[tool_call["name"]]
    # 执行工具:传入工具参数,获取执行结果
    tool_result = selected_tool.invoke(tool_call["args"])
    # 将结果包装成 ToolMessage(关联工具调用ID,便于模型对应),加入对话历史
    messages.append(ToolMessage(tool_result, tool_call_id=tool_call["id"]))

4.3 第三步:回传结果,生成最终回答

将包含工具执行结果的 ToolMessage 再次发送给模型,模型会自动关联工具调用指令和执行结果,整合信息后生成自然、流畅的最终回答,完成整个交互闭环。

# 模型根据对话历史(用户提问 + 工具调用 + 工具结果),生成最终回答
final_response = model.invoke(messages)
print(final_response.content)

输出结果:9乘以5等于45,5加3等于8。

关键说明:整个流程中,我们实际上调用了两次 LLM: 1. 第一次调用:仅让模型分析需求,生成工具调用指令(不直接回答); 2. 第二次调用:让模型结合工具执行结果,整合信息并生成最终回答。


五、总结与展望:从“有工具”到“用好工具”

工具调用不是简单的“函数调用”,而是 LLM 与外部世界交互的完整心智模型,也是 LLM 应用从“玩具”走向“生产力工具”的关键一步。结合本文内容,我们可梳理出 LangChain 工具调用的核心逻辑:

  1. 定义工具:通过 @tool 装饰器、StructuredTool 等方式,将外部能力(函数、API、数据库等)封装成模型可理解的接口,核心是明确工具的名称、描述和参数 Schema。

  2. 绑定工具:通过 bind_tools() 方法将工具与 LLM 关联,配置 tool_choice 等参数,控制模型的调用行为,让模型“知道”自己拥有哪些能力。

  3. 智能决策:模型接收用户输入后,自动分析需求,决定是否调用工具、调用哪个工具,生成结构化的调用指令。

  4. 执行调用:提取工具调用指令,执行对应的工具,将结果包装成 ToolMessage,与对话历史关联。

  5. 整合回答:模型结合用户提问、工具调用指令和执行结果,生成整合后的自然语言回答,完成闭环。

掌握了这套完整流程,你就可以灵活扩展 LLM 的能力边界——无论是实时查询、数据计算,还是系统集成、复杂工作流自动化,都能通过 LangChain 工具调用轻松实现。

未来,随着 Agent 智能体技术的发展,工具调用将不再局限于“单个任务执行”,而是成为复杂工作流的自动化编排中心:模型可自主规划步骤、选择工具、处理异常,真正实现“输入需求,输出结果”的全自动化 AI 助手。

Logo

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

更多推荐