一句话结论: bind_tools() 不修改原 LLM 实例、不绑定 Chain、不注册函数逻辑,仅把工具元信息(名称、描述、入参 JSON Schema)封装到 LLM 调用参数;后续每次invoke自动携带工具清单传给大模型服务,让模型具备输出结构化tool_calls的能力。

硬件类比:给 CPU(LLM)写入外设驱动描述表,告知 CPU 本机可用外设列表;Chain(指令流水线)看不到驱动定义,只负责执行 CPU 下发的 IO 调用指令。

一、外层作用

  1. 返回全新包装后的 Runnable LLM 实例,原 llm 对象不变

python

运行

llm_raw = ChatOpenAI()
llm_with_tool = llm_raw.bind_tools(tools)
# llm_raw 依旧原生无工具能力;llm_with_tool携带工具元数据
  1. 后续任意prompt | llm_with_tool组成的 Chain,不用再传入 tools,模型天然认识全部工具。
  2. 模型自主二选一输出:
    • 无需工具:直接返回普通文本AIMessage.content
    • 需要工具:返回结构化AIMessage.tool_calls: list[dict](工具名 + 入参 + call_id)!!

二、内部底层机理(OpenAI 系模型为例)

1. bind_tools 阶段:仅缓存 tools 的 JSON 描述,不序列化函数本体

bind_tools遍历每个@tool工具,自动提取三类信息:

  1. name:函数名
  2. description:函数文档字符串
  3. args_schema:入参 Pydantic→JSON Schema(参数名、类型、必填、说明)

把上述信息组装成 OpenAI Function-Call 标准 tools 数组,存在新 Runnable 的配置缓存中,不保存 Python 可执行函数

重点:API 只传描述,不传 Python 函数代码;模型只懂参数格式,无法直接执行函数,执行必须由外部 Chain / 业务代码完成查表调用。

2. invoke 调用阶段:请求自动注入 tools 参数或描述

执行llm_with_tool.invoke(messages)时,底层在向 OpenAI 接口发 HTTP 请求时,自动在请求体追加"tools": [...]字段:

json

{
  "model":"gpt-3.5-turbo",
  "messages":[...],
  "tools":[
    {
      "type":"function",
      "function":{
        "name":"add",
        "description":"两个数字相加",
        "parameters":{"type":"object","properties":{"a":{...},"b":{...}},"required":["a","b"]}
      }
    }
  ]
}
  • llm_raw.invoke()请求不带 tools 字段,模型不会输出 tool_call;
  • llm_with_tool.invoke()框架自动塞入 tools 数组,接口收到工具列表。

3. 大模型服务端逻辑

OpenAI 云端拿到 tools 列表后:

  1. 结合用户提问判断是否需要调用工具;
  2. 需要工具 → 按照约定 JSON 格式生成函数调用参数,封装在返回体tool_calls
  3. 不需要 → 正常输出自然语言。

4. 客户端 LangChain 解析返回报文

SDK 收到返回 JSON,自动把工具调用内容封装进AIMessage.tool_calls属性,供外层 Chain 解析、查找本地真实 Python 函数执行。

三、关键细节:函数与模型彻底分离

  1. 模型只有工具 “说明书”,没有工具实体代码 bind_tools只序列化 Schema,Python 函数对象保存在本地业务代码(tool_map 字典);模型生成调用参数后,Chain 拿着 name 去本地字典找函数执行
  2. 更换部署环境、跨机器调用模型:只要工具 Schema 不变,模型输出格式不变,本地实现的函数可以随意重写。

四、与传统 Agent 区别(create_openai_tools_agent)

  1. bind_tools:工具描述绑定 LLM,函数实现留在业务侧,多 Chain 共享同一个带工具 LLM;
  2. 老式 Agent:tools 同时传给 Agent 构造器,工具列表被封装进 Chain 内部,每条 Agent 独享 tools,复用繁琐。

五、极简代码验证机理

python

运行

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool

@tool
def add(a:float,b:float)->float:
    """加法运算"""
    return a+b

llm = ChatOpenAI(temperature=0)
llm_bind = llm.bind_tools([add])

# 打印绑定后内置的工具配置(底层缓存的schema)
print(llm_bind.kwargs["tools"])
# 可以看到:只有name/desc/schema,无函数代码

六、总结

  1. bind_tools = 预编译工具说明书,挂载在 LLM 请求参数上
  2. 绑定时:提取工具元数据→缓存到新 LLM 实例;
  3. 调用时:自动把工具清单塞进接口请求体传给大模型;
  4. 运行时:模型根据说明书生成调用指令,本地代码查表执行真实函数。
Logo

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

更多推荐