为什么要绑定工具?

在没有绑定工具时,模型只会输出纯文本。绑定工具后,模型就能在回答问题时自动判断是否需要调用某个工具,如果需要,它会在输出中包含一个工具调用请求(Tool Call),你的程序可以捕获这个请求并真正执行对应的函数,然后将结果返回给模型继续对话。这种能力被称为 Function Calling 或 Tool Use


1、绑定工具的方式

使用聊天模型的 .bind_tools() 方法,将工具列表传递进去即可。

from langchain_openai import ChatDeepSeek

# 定义大模型
model = ChatDeepSeek(model="deepseek-chat")

# 假设你已经提前定义好了两个工具:add 和 multiply
tools = [add, multiply]

# 绑定工具,返回一个 Runnable 实例
model_with_tools = model.bind_tools(tools)

这里 add 和 multiply 是提前用 @tool 装饰器或 Pydantic 类定义的工具对象。绑定后,model_with_tools 就变成了一个“具备工具调用能力的代理”,接下来就可以像普通模型一样使用它。

注意bind_tools() 返回的不是模型本身,而是一个 Runnable 实例,这意味着你可以使用 .invoke().stream() 等方法与它交互。


2、bind_tools() 方法签名与参数详解

bind_tools(
    tools: Sequence[dict[str, Any] | type | Callable | BaseTool],
    *,
    tool_choice: dict | str | Literal['auto', 'none', 'required', 'any'] | bool | None = None,
    strict: bool | None = None,
    parallel_tool_calls: bool | None = None,
    **kwargs: Any,
) -> Runnable[...]

2.1、tools (必填)

要绑定到此聊天模型的工具定义列表

支持多种工具描述形式:

  • 字典:直接传递符合 OpenAI Function Calling 格式的字典。

  • Pydantic BaseModel 类:定义一个继承自 BaseModel 的类,模型会用该类的 Schema 生成函数调用。

  • Python 函数:一个普通 Python 函数,LangChain 会自动解析其签名和 docstring 来生成工具描述。

  • BaseTool 实例:通过 @tool 装饰器创建的 LangChain 工具对象。

# 方式1:直接使用函数
def add(a: int, b: int) -> int:
    """Add two integers."""
    return a + b

# 方式2:使用 @tool 装饰器
from langchain_core.tools import tool

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

tools = [add, multiply]   # 函数也可直接使用

2.2、tool_choice (可选,默认 None

控制模型必须或倾向于调用哪个工具。

  • 设置为字符串 "tool_name"
    强制模型只能调用名为 tool_name 的工具,比如 "add"

  • "auto":模型自行决定是否调用工具,以及调用哪个工具(这是默认的 OpenAI 行为)。

  • "none":禁止模型调用任何工具,相当于没有绑定工具的效果。

  • "any" 或 "required" 或 True:强制模型至少调用一个工具,但具体调用哪个由模型决定。

  • False 或 None:无效值,保持模型默认行为(即等同于未设置)。

# 强制只调用 multiply
model_with_tools = model.bind_tools(tools, tool_choice="multiply")

2.3、strict (可选,默认 None

控制是否要求模型按照工具的 JSON Schema 严格输出

  • True

    • 保证模型生成的结构化输出完全匹配工具定义中的 Schema。

    • 输入也会根据 Schema 进行验证。

  • False:不对模型输出进行严格验证,也不验证输入。

  • None:不向底层 API 传递 strict 参数,由 API 采用默认行为。

建议在需要精确工具调用回复的生产环境中开启 strict=True,以避免格式错误。

2.4、parallel_tool_calls (可选,默认 None

是否允许模型在一次回复中并行调用多个工具

  • None:允许并行调用(默认开启)。

  • False:禁止并行调用,模型一次只能返回一个工具调用的请求。

2.5、**kwargs (其他参数)

任何额外的关键字参数都会被直接传递给底层的 bind() 方法,用于满足不同模型提供商的特殊参数需求。


3、返回值:Runnable 实例

bind_tools() 返回的是一个 Runnable,它封装了模型和工具的定义。

支持的输入格式:

  • PromptValue(原始提示对象)

  • 字符串,比如:“上海天气如何?”

  • 消息或消息列表,例如:

[HumanMessage(content="上海天气如何?")]

输出内容: 

返回的通常是 AIMessage,其中可能包含:

  • 普通的文本回复

  • 一个或多个 tool_calls(工具调用请求),每个调用包含工具名称、参数等信息。

示例输出结构(概念):

AIMessage(
    content="",
    tool_calls=[{
        "name": "add",
        "args": {"a": 3, "b": 5},
        "id": "call_abc123"
    }]
)

4、工具调用实战:从绑定到调用

绑定完成后,下一步就是通过 .invoke() 触发调用。

from langchain_openai import ChatDeepSeek
from langchain_core.messages import HumanMessage

# 定义工具
def add(a: int, b: int) -> int:
    """Add two integers."""
    return a + b

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

# 绑定工具
model = ChatDeepSeek(model="deepseek-chat")
model_with_tools = model.bind_tools([add, multiply])

# 构造输入消息
messages = [HumanMessage(content="3加5等于多少?")]

# 调用模型
response = model_with_tools.invoke(messages)

# 查看模型是否想要调用工具
if response.tool_calls:
    for tool_call in response.tool_calls:
        print(f"欲调用工具:{tool_call['name']},参数:{tool_call['args']}")
else:
    print("模型直接回复:", response.content)

如果一切正常,输出会显示模型希望调用 add 工具,参数为 {"a": 3, "b": 5}


5、小结

绑定工具 是让聊天模型具备外部工具调用能力的关键一步。

使用 model.bind_tools(tools) 即可完成绑定,返回一个 Runnable

通过参数 tool_choicestrict 和 parallel_tool_calls 可以精细控制工具调用的行为。

绑定后,调用 .invoke() 发送消息,模型会根据对话内容决定是否返回工具调用请求。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐