戳戳猫的小窝
更新日志
关于
## 1 使用API 完成工具调用(tool_calls) 工具调用,即 `tool_calls`,由函数调用(即 `function_call`)进化而来,在某些特定的语境下,或在阅读一些兼容性代码时,你也可以将工具调用 `tool_calls` 与函数调用 `function_call` 划等号,函数调用 `function_call` 是工具调用 `tool_calls` 的子集。 ## 2 什么是工具调用 tool_calls 工具调用 `tool_calls` 给予了大模型执行具体动作的能力。大模型能进行对话聊天并回答用户提出的问题,这是“说”的能力,而通过工具调用 `tool_calls`,大模型也拥有了“做”的能力,借助 `tool_calls`,大模型能帮你搜索互联网内容、查询数据库,甚至操作智能家居。 一次工具调用 `tool_calls` 包含了以下若干步骤: 1. 使用 JSON Schema 格式定义工具; 2. 通过 `tools` 参数将定义好的工具提交给大模型,你可以一次性提交多个工具; 3. 大模型会根据当前聊天的上下文,决定使用哪个或哪几个工具,Kimi 大模型也可以选择不使用工具; 4. 大模型会将调用工具所需要的参数和信息通过 JSON 格式输出; 5. 使用大模型输出的参数,执行对应的工具,并将工具执行结果提交给 Kimi 大模型; 6. 模型根据工具执行结果,给予用户回复; 阅读上述步骤,你可能会产生这样的疑惑: > 为什么大模型自己不能执行工具,还要我们根据大模型生成的工具参数“帮”大模型执行工具?既然是我们在执行工具调用,还要大模型干什么? 请思考这个问题。 ## 3 通过 `tool_calls` 让大模型能够准确计算乘法 数学计算一直是大模型的一个弱项,过去人们让大模型做乘法计算,例如68457×784,大模型都会计算错误。后来人们通过思维链让大模型一步一步计算,才提升大模型计算的正确率。但是,思维链也不是万能的,如果让大模型计算两个很大的数相乘,大模型也会得到一个错误的结果。 有没有一种方法能提高大模型计算的准确率呢? 如果让你计算两个数相乘,你是会在口算,还是在草稿纸上计算,又或者直接使用计算器? 我想如果计算比较复杂,大多数人还是会直接使用计算器。 因此,我们想让大模型这么做,当大模型意识到自己需要计算两个数相乘,那么就让它使用”计算器“。 当然,这里的计算器并不是说给一个把一个计算器给到大模型,而是让大模型去调用可以计算的函数。 例如,我们可以定义这么一个函数: ```python def multiply(a,b): return a * b ``` 这是一个用于计算两个数相乘的函数,函数接收2个参数a和b,返回的结果是a和b相乘的结果。 我们要做就是,当我们想大模型提问,例如: ``` 68457×784等于多少? ``` 大模型自己并不会去计算,而是返回一个结果,结果表示大模型想去调用multiply,于是我们帮大模型调用multiply这个函数, 计算出结果等于53670288,将这个结果放到message列表中再提交给大模型,于是大模型就能准确说出这个结果是多少。 接下来详细说明如何执行这个过程。 ### 3.1 定义Tool JSON Schema 在此之前,让我们先简单介绍一下 JSON Schema 格式: > [JSON Schema(opens in a new tab)](https://json-schema.org/) is a vocabulary that you can use to annotate and validate JSON documents. > > [JSON Schema(opens in a new tab)](https://json-schema.org/) 是一种用于描述 JSON 数据格式的 JSON 文档。 我们定义以下 JSON Schema: ```json { "type": "function", "function": { "name": "multiply", "description": "用于运算乘法的函数,可以支持2个a和b数相乘", "parameters": { "type": "object", "required": ["a","b"], "properties": { "a": { "type": "number", "description": "第一个数" }, "b": { "type": "number", "description": "第二个数" } } } } } ``` 其中: `"type": "function"`是一个固定的写法,表示我们要定义一个函数。 `"name": "multiply"`表示所定义的函数名称为”multiply“。 `description`用于描述此函数的作用。 `parameters` 字段用于定义函数接收的参数。 `"type": "object"`固定使用 type: object 来使大模型生成一个 JSON Object 参数 `required 字段`告诉大模型哪些参数是必填项。 `properties` 中是具体的参数定义,你可以定义多个参数,每一个参数都可以定义具体的名称、类型、参数描述。 ### 3.2 Tool调用 首先看普通调用。 请求https://api.siliconflow.cn/v1/chat/completions。 发送内容如下: ```json { "model": "Qwen/Qwen2.5-7B-Instruct", "messages": [ { "role": "user", "content": "68457×784等于多少?" } ] } ``` 返回内容如下: ```json { "id": "0195e704fa89b71ada2edf94e8762d25", "object": "chat.completion", "created": 1743337618, "model": "Qwen/Qwen2.5-7B-Instruct", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "68457乘以784等于53558368。" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 41, "completion_tokens": 20, "total_tokens": 61 }, "system_fingerprint": "" } ``` 可以看到,大模型直接返回结果,有一个字段需要注意,就是`finish_reason`,在这里,它的值为“stop”,表示正常停止。 再使用Tool Calling。 这次发送的内容如下: ```json { "model": "Qwen/Qwen2.5-7B-Instruct", "messages": [ { "role": "user", "content": "68457×784等于多少?" } ], "tools": [ { "type": "function", "function": { "name": "multiply", "description": "用于运算乘法的函数,可以支持2个a和b数相乘", "parameters": { "type": "object", "required": ["a","b"], "properties": { "a": { "type": "number", "description": "第一个数" }, "b": { "type": "number", "description": "第二个数" } } } } } ] } ``` 可以看到,这次我们把刚刚定义的函数放在了“tools”字段中。 发送后返回的结果如下: ```json { "id": "0195e7093b7b1cee8ef474f21f93a52c", "object": "chat.completion", "created": 1743337896, "model": "Qwen/Qwen2.5-7B-Instruct", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "", "tool_calls": [ { "id": "0195e7093f3a0f2cbb847cfd4032ad1c", "type": "function", "function": { "name": "multiply", "arguments": "{\"a\": 68457, \"b\": 784}" } } ] }, "finish_reason": "tool_calls" } ], "usage": { "prompt_tokens": 216, "completion_tokens": 32, "total_tokens": 248 }, "system_fingerprint": "" } ``` 可以看到,content中的值为空,finish_reason的值变为了tool_calls。 这说明此次停止的原因是因为大模型请求调用函数。 调用的值如下: ```json { "id": "0195e7093f3a0f2cbb847cfd4032ad1c", "type": "function", "function": { "name": "multiply", "arguments": "{\"a\": 68457, \"b\": 784}" } } ``` id表示此次调用的编号。 `"type": "function"`是固定的写法,表示要调用一个函数。 `"name": "multiply"`表示要调用名为multiply的函数。 `"arguments": "{\"a\": 68457, \"b\": 784}"`表示要传递的参数。 ### 3.3 Python实现 ```python import json from openai import OpenAI client = OpenAI( api_key="sk-**********************************", base_url="https://api.siliconflow.cn/v1", ) tools = [ { "type": "function", "function": { "name": "multiply", "description": "用于运算乘法的函数,可以支持2个a和b数相乘", "parameters": { "properties": { "a": { "type": "number", "description": "第一个数" }, "b": { "type": "number", "description": "第二个数" } }, "type": "object" } } }, ] def multiply(a,b): return a * b messages = [ {"role": "system", "content": "你是一名优秀的助手"}, {"role": "user", "content": "68457×784等于多少?"} ] completion = client.chat.completions.create( model="Qwen/Qwen2.5-7B-Instruct", messages=messages, temperature=0.3, tools=tools, ) choice = completion.choices[0] finish_reason = choice.finish_reason if finish_reason == "tool_calls": messages.append(choice.message) tool_call = choice.message.tool_calls[0] tool_call_id = tool_call.id tool_call_name = tool_call.function.name tool_result = 0 if tool_call_name == "multiply": tool_call_arguments = json.loads(tool_call.function.arguments) a = tool_call_arguments["a"] b = tool_call_arguments["b"] tool_result = multiply(a, b) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "name": tool_call_name, "content": json.dumps(tool_result) }) completion = client.chat.completions.create( model="Qwen/Qwen2.5-7B-Instruct", messages=messages, temperature=0.3, tools=tools, ) print(completion.choices[0].message.content) ``` 结果返回: ``` 68457乘以784等于53670288。 ```
Tool Calling