langchain 进阶 02-FuntionCalling

本文介绍 langchain 如何调用工具

单独的大模型只能给出文本信息,没有后续操作,langchain 可以通过定义 “工具调用” 的过程,响应 LLMs 的输出,扩展其能力。下面是为 LLMs 绑定工具的过程

1
2
3
4
5
6
7
from langchain_ollama import ChatOllama
# 初始化Ollama LLM,注意需要后台开启ollama服务
model_name = "qwen2.5:latest"
llm = ChatOllama(model=model_name)
query = "961 * 590?和11654 + 43249?的结果"
response=llm.invoke(query)
response.content,961 * 590,11654 + 43249

(‘我们分别计算这两个表达式:\n\n 1. 对于乘法表达式 \(961 \times 590\),我们可以直接进行计算:\n\[961 \times 590 = 567990\]\n\n 2. 对于加法表达式 \(11654 + 43249\),同样直接相加以得出结果:\n\[11654 + 43249 = 54903\]\n\n 所以,两个计算的结果分别是 567990 和 54903。’, 566990,54903)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from langchain_core.tools import tool
@tool
def add(a: int, b: int) -> int:
"""Adds a and b."""
return a + b
@tool
def multiply(a: int, b: int) -> int:
"""Multiplies a and b."""
return a * b
tools = [add, multiply]
llm_with_tools = llm.bind_tools(tools) # 为LLMs绑定工具
query = "961 * 590?的结果"
response=llm_with_tools.invoke(query)
response.content,response.tool_calls

(‘’,
[{‘name’: ‘multiply’,
‘args’: {‘a’: 961, ‘b’: 590},
‘id’: ‘e 0 a 9 ae 39-6 d 22-4 e 16-a 703-2 c 098 fbcd 0 e 9’,
‘type’: ‘tool_call’}])

为 LLMs 绑定工具后,不像前面一样直接给出了答案 (content=“”),而且多了信息输出 "‘tool_calls’: [{‘function’: {‘name’: ‘multiply’, ‘arguments’: {‘a’: 3, ‘b’: 12}}}]",这里 LLMs 通过 query “找到要调用的函数及其输入参数”,对于多个问答也被解析出来。这里就很神奇 LLMs 知道自己要执行的函数,实际上它是根据函数名去匹配的。以下即使提问多个实例,也可以被正确解析

1
2
3
query = "961 * 590?和11654 + 43249?的结果"
response=llm_with_tools.invoke(query)
response.tool_calls

[{‘name’: ‘multiply’,
‘args’: {‘a’: 961, ‘b’: 590},
‘id’: ‘b 831 b 71 c-cf 46-4200-b 22 e-df 991 f 9 fca 16’,
‘type’: ‘tool_call’},
{‘name’: ‘add’,
‘args’: {‘a’: 11654, ‘b’: 43249},
‘id’: ‘53 ea 47 e 6-031 e-4 f 18-b 745-e 074 f 3 b 8 e 59 b’,
‘type’: ‘tool_call’}]

以上调用 LLMs 只返回了 “待调用的函数及参数”,并没有真正执行计算,也就是没有得到最终结果。为了得到最终结果,需要调用外部函数计算,然后将计算结果再次返回给 LLMs,进行最后的总结

1
2
3
4
5
6
7
from langchain_core.messages import HumanMessage
query = "961 * 590?和11654 + 43249?的结果"
messages = [HumanMessage(query)]
print(messages)
ai_msg = llm_with_tools.invoke(messages)
print(ai_msg) # AIMessage类
print(ai_msg.tool_calls)

[HumanMessage (content=‘961 * 590? 和 11654 + 43249? 的结果’, additional_kwargs={}, response_metadata={})]
content=‘’ additional_kwargs={} response_metadata={‘model’: ‘qwen 2.5: latest’, ‘created_at’: ‘2024-12-01 T08:04:14.6225541 Z’, ‘done’: True, ‘done_reason’: ‘stop’, ‘total_duration’: 2700687500, ‘load_duration’: 42063200, ‘prompt_eval_count’: 241, ‘prompt_eval_duration’: 5000000, ‘eval_count’: 104, ‘eval_duration’: 2648000000, ‘message’: Message (role=‘assistant’, content=‘’, images=None, tool_calls=[ToolCall (function=Function (name=‘multiply’, arguments={‘a’: 961, ‘b’: 590})), ToolCall (function=Function (name=‘add’, arguments={‘a’: 11654, ‘b’: 43249}))])} id=‘run-36 f 8 ee 4 b-cb 15-4 d 0 d-bada-7 d 3627 d 4 aebb-0’ tool_calls=[{‘name’: ‘multiply’, ‘args’: {‘a’: 961, ‘b’: 590}, ‘id’: ‘e 7274 d 80-b 843-4 d 4 c-9 fb 8-9 f 39 e 9720 f 60’, ‘type’: ‘tool_call’}, {‘name’: ‘add’, ‘args’: {‘a’: 11654, ‘b’: 43249}, ‘id’: ‘1 bef 98 c 8-473 f-4 bc 7-bdc 7-33 ca 775 fb 566’, ‘type’: ‘tool_call’}] usage_metadata={‘input_tokens’: 241, ‘output_tokens’: 104, ‘total_tokens’: 345}
[{‘name’: ‘multiply’, ‘args’: {‘a’: 961, ‘b’: 590}, ‘id’: ‘e 7274 d 80-b 843-4 d 4 c-9 fb 8-9 f 39 e 9720 f 60’, ‘type’: ‘tool_call’}, {‘name’: ‘add’, ‘args’: {‘a’: 11654, ‘b’: 43249}, ‘id’: ‘1 bef 98 c 8-473 f-4 bc 7-bdc 7-33 ca 775 fb 566’, ‘type’: ‘tool_call’}]

LLMs 解析出输入 query 要执行的函数,以下遍历调用拿到结果,并结果信息收集和之前的输入合并

1
2
3
4
5
6
for tool_call in response.tool_calls:
selected_tool = {"add": add, "multiply": multiply}[tool_call["name"].lower()]
tool_msg = selected_tool.invoke(tool_call)
print(tool_call,tool_msg) # AIMessage类
messages.append(tool_msg)
print(messages)

{‘name’: ‘multiply’, ‘args’: {‘a’: 961, ‘b’: 590}, ‘id’: ‘b 831 b 71 c-cf 46-4200-b 22 e-df 991 f 9 fca 16’, ‘type’: ‘tool_call’} content=‘566990’ name=‘multiply’ tool_call_id=‘b 831 b 71 c-cf 46-4200-b 22 e-df 991 f 9 fca 16’
{‘name’: ‘add’, ‘args’: {‘a’: 11654, ‘b’: 43249}, ‘id’: ‘53 ea 47 e 6-031 e-4 f 18-b 745-e 074 f 3 b 8 e 59 b’, ‘type’: ‘tool_call’} content=‘54903’ name=‘add’ tool_call_id=‘53 ea 47 e 6-031 e-4 f 18-b 745-e 074 f 3 b 8 e 59 b’
[HumanMessage (content=‘961 * 590? 和 11654 + 43249? 的结果’, additional_kwargs={}, response_metadata={}), ToolMessage (content=‘566990’, name=‘multiply’, tool_call_id=‘b 831 b 71 c-cf 46-4200-b 22 e-df 991 f 9 fca 16’), ToolMessage (content=‘54903’, name=‘add’, tool_call_id=‘53 ea 47 e 6-031 e-4 f 18-b 745-e 074 f 3 b 8 e 59 b’)]

合并后的信息再次输入 LLMs,综合输出结果

1
2
response=llm_with_tools.invoke(messages)
response.content,961 * 590,11654 + 43249

(‘The multiplication of 961 and 590 is 566,990.\n\nAnd the addition of 11,654 and 43,249 is 54,903.’, 566990,54903)

即使是组合运算,LLMs 也能解析出来要调用的函数,langchain 真的神奇

1
2
3
query = "11*2 + 49的结果"
response=llm_with_tools.invoke(query)
print(response.tool_calls)

[{‘name’: ‘multiply’, ‘args’: {‘a’: 11, ‘b’: 2}, ‘id’: ‘3 a 213 d 29-1 df 2-44 ca-9297-500 d 5254 f 41 d’, ‘type’: ‘tool_call’}]