在 LangChain 里,工具调用是利用外部工具(像搜索引擎、计算器等)来增强大语言模型(LLM)处理复杂任务能力的关键功能。
bind_tools
和 agent
是构建智能代理系统时常用的功能,bind_tools
可用于将工具绑定到特定的组件上,而 agent
则是一个智能实体,它可以根据输入和可用的工具来决定如何采取行动以实现目标。下面将详细介绍如何使用 bind_tools
和 agent
来调用工具。
bind_tools
在 LangChain
里,bind_tools
是一种将工具绑定到链(Chain
)或模型(LLM
)上的方法,目的是让模型能够自动调用这些工具来完成特定任务。它主要用于简化工具调用的流程,使得模型在处理输入时可以直接利用绑定的工具进行信息查询或其他操作。
import os
from langchain_community.tools import TavilySearchResults
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tools import tool
from model.deepseek import deepseek_llm
# 搜索工具
os.environ["TAVILY_API_KEY"] = ''
search_tool = TavilySearchResults(max_results=5)
# 定义几个计算工具
from pydantic import BaseModel
class CalculatorArgs(BaseModel):
operation: str
operand1: float
operand2: float
@tool("Calculator", return_direct=True, args_schema=CalculatorArgs)
def calculator(operation, operand1, operand2):
"""
计算器工具,支持加减乘除四种基本运算。
参数:
operation (str): 运算类型,可选值为 'add', 'subtract', 'multiply', 'divide'。
operand1 (float): 第一个操作数。
operand2 (float): 第二个操作数。
返回:
float: 运算结果。
异常:
ValueError: 如果运算类型不支持或除数为零。
"""
if operation == "add":
return operand1 + operand2
elif operation == "subtract":
return operand1 - operand2
elif operation == "multiply":
return operand1 * operand2
elif operation == "divide":
if operand2 == 0:
raise ValueError("Cannot divide by zero.")
return operand1 / operand2
else:
raise ValueError(f"Unsupported operation: {operation}")
tools = [search_tool, calculator]
model_with_tools = deepseek_llm.bind_tools(tools)
prompt_template = ChatPromptTemplate.from_messages(
[
("system", "你是一个助手,请根据用户输入提供准确的回答。"),
("user", "{input}")
]
)
chain = prompt_template | model_with_tools
# 示例:调用工具的逻辑
def invoke_tool_example(user_input):
# 调用模型并传递工具
res = chain.invoke({"input": user_input})
# 解析返回结果
if res.response_metadata["finish_reason"] == 'tool_calls':
# 处理工具调用
for tool_call in res.tool_calls:
tool_name = tool_call['name']
tool_args = tool_call['args']
# 根据工具名称调用相应的工具
print(f"Tool name: {tool_name}, Args: {tool_args}")
if tool_name == 'Calculator':
result = calculator.invoke({"input": tool_args})
print(f"Calculator result: {result}")
elif tool_name == 'tavily_search_results_json':
result = search_tool.invoke(tool_args['query'])
print(f"search tool: {result}")
else:
print(res.content)
# 执行示例函数
while True:
user_input = input("请输入你的问题(输入 'exit' 退出):")
if user_input.lower() == 'exit':
break
invoke_tool_example(user_input)
测试
agent
可以理解为一个智能决策者,它基于大语言模型(LLM),根据输入的问题和工具的描述,决定调用哪些工具以及如何使用它们来生成答案
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool
from pydantic import Field, BaseModel
from model.zhipu import zhipu_llm
class AddInput(BaseModel):
num1: int = Field(description="计算的第一个数字")
num2: int = Field(description="计算的第二个数字")
@tool("add_num", args_schema=AddInput, description="求两个数字的和")
def add_num(num1: int, num2: int) -> int:
"""求两个数字的和"""
print(f"工具被调用:num1: {num1}, num2: {num2}")
return num1 + num2
prompt = ChatPromptTemplate.from_messages(
[
("system", "你是一个智能助手,尽可能的调用工具回答用户的问题"),
MessagesPlaceholder(variable_name="chat_history", optional=True),
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad", optional=True),
]
)
agent = create_tool_calling_agent(zhipu_llm, [add_num], prompt)
executor = AgentExecutor(agent=agent, tools=[add_num])
result = executor.invoke({"input": "我昨天赚了100,今天赚了200, 总共赚了多少?"})
print(result)
bind_tools
与 Agent
的对比
1. Agent
概述
Agent
是 LangChain
中一种更高级的机制,它可以根据输入动态地决定是否调用工具、调用哪个工具以及如何使用工具的输出。Agent
通常包含一个决策逻辑,能够根据模型的输出和任务的需求进行智能决策。
2. 优点对比
bind_tools
- 代码简单,适合初学者和简单任务。
- 工具调用流程固定,易于调试和理解。
Agent
- 自主性强:能够根据任务的复杂性和输入内容动态地决定是否调用工具以及调用哪个工具,更适合处理复杂任务。
- 适应性好:可以处理多步推理和复杂决策的任务,能够根据工具的输出进一步调整处理流程。
3. 缺点对比
bind_tools
- 缺乏自主性,不能根据情况动态调整工具调用。
- 对于复杂任务的处理能力有限。
Agent
- 代码复杂:需要配置决策逻辑、工具选择策略等,代码编写和调试的难度较大。
- 性能开销大:由于需要进行额外的决策和推理,
Agent
的运行时间和资源消耗可能会更高。
综上所述,bind_tools
适合简单任务,追求代码简洁和快速实现;而 Agent
则更适合复杂任务,需要模型具备智能决策和多步推理能力的场景。