1. 为什么要绑定工具
大模型本身只是 "文字预测器",它没有办法去执行外部操作、查询实时数据、调用代码;绑定工具就是告诉模型:你有哪些外部能力可用、什么时候该调用,让模型从单纯 "聊天" 变成能动手做事的智能 Agent。
简单来说有点像是给模型装了一个手机,这样它就可以做事情了。
2.怎么绑定工具
2.1 创建工具
我们看下面的代码,这个就是在创建工具,因为我们在这边的话是测试,所以我们的工具就写的比较简单,这边的话我们就直接用@tool来写了。
这个时候我们在""""""里面写的描述就发挥了作用,模型在遇到我们用户的问题的时候会尝试调用这些工具,然后我们写在里面的描述就是模型选择工具的依据。
python
@tool
def my_add(
a:Annotated[int,...,"第一个整数"],
b:Annotated[int,...,"第二个整数"]
) -> int:
"""这个是两数相加"""
return a + b
@tool
def my_multiply(
a:Annotated[int,...,"第一个整数"],
b:Annotated[int,...,"第二个整数"]
)->int:
"""这个是两数相乘"""
return a * b
2.2 选择模型
我们在这边就直接怎么写就好了,因为我们在这边用的是deepseek,所以在这边的模型选择就是deepseek。
PS:这个前面的model是我们创建的变量。
python
model = ChatDeepSeek(model="deepseek-chat")
2.3 绑定工具
我们看下面这段代码,简单来说就是给我们上面创建的模型添加上工具,简单来说相当于是告诉模型有哪些工具。
python
my_tools = [my_add,my_multiply]#给模型这个两个工具
my_model_with_tools = model.bind_tools(tools=my_tools)
我们看下面这段代码,他和上面的代码唯一的区别就是多了一个tool_choice="any",这个的话是叫模型在回答问题的时候要强制的调用我们的工具,但是这个的话在很多时候是会出问题的。比如说我们在代码中假如询问了一次模型并要求模型整理结果并输出,那么最后的输出就会出问题。因为在第二遍整理结果的时候模型也被要求调用工具同时不许返回文字,那么我们最后的输出结果就是空。
PS:为什么不可以返回文字,这是因为我们的工具在return的时候没有文字。
python
tools = [my_add,my_multiply]#给模型这个两个工具
my_model_with_tools = model.bind_tools(tools=tools,tool_choice="any")
2.4 定义消息列表
这边的话是在定义用户消息队列,简单来说就是我们用户发送给模型的问题。然后我们
这个message的话我们可以理解为总的消息,包括用户消息,系统消息和模型消息。
那么为什么是需要写到这个message里面呢,这是因为模型本身是没有记忆的能力的,所以我们需要在这里面给模型添加一个外置的记忆库,也就是我们这里面的message。
python
# 定义消息列表,添加要传递给聊天模型的消息
message = [
HumanMessage("2乘3等于多少?6加6等于多少?")
]
ai_msg = my_model_with_tools.invoke(message)
message.append(ai_msg)
2.5 构造ToolMessage
什么是ToolMessage?
ToolMessage是 langchain_core.messages 里的消息类型,专门用来承载工具执行完之后的返回结果。
为什么需要这个呢?
因为我们需要执行结果回灌给模型。模型再处理这条消息,继续推理,最后得到回答。
实际在模型中的AI处理链路:
SystemMessage 可选
HumanMessage(用户提问)
-> 调用模型
-> AIMessage(tool_calls=...)
-> 外部系统执行工具
-> ToolMessage(tool_call_id=..., content=...)
-> 把完整消息历史再传给模型
-> 模型基于 HumanMessage + AIMessage + ToolMessage 继续推理
-> 最终输出 AIMessage
我们来看下面的代码,这个就是我们构造ToolMessage的完整过程。
简单来说就是先遍历ai_msg里面的toolcall,也就是消息请求,接着构造哈希,这样模型才可以在调用的时候找到对应的工具。接着把处理好的结果交给tool_msg,最后给message,这样好让模型对结果进行整理输出。
python
# 构造ToolMessage, 并添加到消息列表中去
for my_tool_call in ai_msg.tool_calls:
#这个for循环就是自动依次把 ai_msg.tool_calls 数组里面的每一项赋值给my_tool_call
selected_tool = {"my_add": my_add, "my_multiply": my_multiply}[my_tool_call["name"].lower()]
#这个是在构造哈希映射
tool_msg = selected_tool.invoke(my_tool_call)
message.append(tool_msg)
# 这个循环的话就相当于是说找到ai_msg里面的消息队列
# 接着去判断里面的是加法还是乘法
# 然后把selected_tool后的结果放入tool_msg
# 最后把tool_msg给拼接到message里面
2.6 输出结果
下面这个代码就是我们的输出打印,第一个打印是给我们看message,也就是没有经过模型处理的最后结果。第二行的输出的话就是打印出模型处理好后的结果。
python
print(message)
print(my_model_with_tools.invoke(message).content)
我们来看下面这个图片,第一行的输出就是我们所对应的第一行打印,没有经过模型的处理,使用是一整行,第二行的话就是模型处理好后的结果。
