
MiniCPM3 Function Calling 实战基于 vLLM 与自定义 Tool Parser 的工具调用全流程指南【免费下载链接】MiniCPMMiniCPM5: SOTA on-device LLMs, small yet powerful.项目地址: https://gitcode.com/GitHub_Trending/mi/MiniCPM本文以 MiniCPM3-4B 的 Function Calling工具调用能力为主线完整讲解两条实战路径一是通过 vLLM 启动 OpenAI 兼容的工具调用服务并用 OpenAI SDK 接入二是基于 vLLM 推理引擎编写带多轮工具执行循环的本地脚本。同时结合仓库源码深入剖析背后两项关键组件——工具调用解析器minicpm_tool_parser.py与工具聊天模板minicpm_chat_template_with_tool.jinja的工作原理。读完本文你将能够在 MiniCPM 项目中独立完成工具调用的服务化部署与本地推理验证。一、示例代码结构与运行环境本示例代码位于仓库 demo/minicpm3/function_call 目录包含以下文件文件作用README.md使用说明本文即围绕该文档展开function_calling.py本地推理示例多轮工具调用 工具执行循环minicpm_tool_parser.pyMiniCPM3 专用工具调用解析器注册为 vLLM 的minicpmparserminicpm_chat_template_with_tool.jinja带工具定义的工具聊天模板将 JSON Schema 编译为 Python 类型签名requirements.txt依赖datamodel_code_generator与vllm示例以开源模型openbmb/MiniCPM3-4B为推理目标推理引擎统一使用 vLLM文档进阶功能章节明确说明样例代码基于 vLLM 进行推理参见 docs/README-minicpm3-cn.md。运行前安装依赖cd demo/minicpm3/function_call pip install -r requirements.txt二、方式一启动 vLLM 工具调用服务OpenAI 兼容README 提供了最小可用的服务启动命令这是让 MiniCPM3 具备 OpenAI 兼容工具调用能力的关键步骤python -m vllm.entrypoints.openai.api_server \ --model openbmb/MiniCPM3-4B \ --dtype auto \ --api-key token-abc123 \ --tensor-parallel-size 1 \ --trust-remote-code \ --enable-auto-tool-choice \ --tool-call-parser minicpm \ --tool-parser-plugin minicpm_tool_parser.py各参数含义如下--model openbmb/MiniCPM3-4B指定模型路径或 Hugging Face 模型名--dtype auto自动选择推理精度根据硬件支持情况自动落到float16/bfloat16等--api-key token-abc123为 OpenAI 兼容服务设置访问密钥客户端请求时需携带相同值--tensor-parallel-size 1张量并行度设为 1单卡即可运行--trust-remote-code允许加载模型仓库中的自定义代码MiniCPM3 需要--enable-auto-tool-choice开启自动工具选择让模型根据用户请求自行决定是否调用工具--tool-call-parser minicpm指定工具调用解析器为minicpmvLLM 通过ToolParserManager.register_module(minicpm)注册的解析器即来自仓库中的 minicpm_tool_parser.py见该文件第 24 行装饰器--tool-parser-plugin minicpm_tool_parser.py告诉 vLLM 从本仓库示例文件加载该解析器插件。服务启动后默认监听http://localhost:8000/v1。仓库主 README 中另有基于 SGLang 的推荐方案但本文严格聚焦于 vLLM 路径。三、OpenAI SDK 客户端调用示例服务就绪后即可用 OpenAI Python SDK 发起带工具的对话请求。README 给出的完整客户端示例from openai import OpenAI client OpenAI(base_urlhttp://localhost:8000/v1, api_keytoken-abc123) tools [ { type: function, function: { name: get_current_weather, description: Get the current weather in a given location, parameters: { type: object, properties: { location: { type: string, description: The city and state, e.g. San Francisco, CA, }, unit: {type: string, enum: [celsius, fahrenheit]}, }, required: [location], }, } } ] messages [{role: user, content: Whats the weather like in Boston today?}] completion client.chat.completions.create( modelopenbmb/MiniCPM3-4B, messagesmessages, toolstools, tool_choiceauto ) print(completion)要点说明base_url与api-key必须与服务端启动参数保持一致tools使用 OpenAI 标准的 Function 格式JSON Schema 描述参数required声明必填字段tool_choiceauto允许模型自主判断直接回答、追问信息或发起工具调用当模型决定调用工具时响应中会携带tool_calls字段含函数名与参数服务端由minicpm解析器将模型输出的文本转换为 OpenAI 兼容的ToolCall结构。这一转换逻辑在 minicpm_tool_parser.py 的extract_tool_calls方法中完成第 4073 行解析器先调用fc2dict把模型输出还原为字典若包含非空tool_calls则逐条构造ToolCall(typefunction, functionFunctionCall(name..., arguments...))其中arguments是参数对象经json.dumps序列化后的字符串模型在工具调用前输出的文本则作为content一并返回。四、方式二本地多轮工具调用推理脚本如果不想起服务README 提供了直接跑本地推理的入口python functioncall.py仓库中实际的脚本文件名为function_calling.py核心逻辑如下已省略部分注释from transformers import AutoTokenizer from vllm import LLM, SamplingParams from minicpm_tool_parser import fc2dict import json model_path openbmb/MiniCPM3-4B tools [ { type: function, function: { name: get_delivery_date, description: Get the delivery date for a customers order. Call this whenever you need to know the delivery date, for example when a customer asks Where is my package, parameters: { type: object, properties: { order_id: { type: string, description: The customers order ID., }, }, required: [order_id], additionalProperties: False, }, }, } ] messages [ {role: system, content: You are a helpful customer support assistant. Use the supplied tools to assist the user.}, {role: user, content: Hi, can you tell me the delivery date for my order? The order id is 1234 and 4321.}, ] tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) prompt tokenizer.apply_chat_template( messages, toolstools, tokenizeFalse, add_generation_promptTrue ) llm LLM(model_path, trust_remote_codeTrue) sampling_params SamplingParams(temperature0.8, top_p0.95, max_tokens1000)该示例演示了客服查询订单发货日期的场景用户同时询问两个订单号1234 和 4321模型需要并行发起两次get_delivery_date调用。多轮工具调用循环是本脚本的核心while Truedef fake_tool_execute(toolcall): data { delivery_date: 2024-09-05, order_id: toolcall.get(function, {}) .get(arguments, {}) .get(order_id, order_id), } return json.dumps(data) while True: prompt tokenizer.apply_chat_template( messages, toolstools, tokenizeFalse, add_generation_promptTrue ) outputs llm.generate([prompt], sampling_params) response outputs[0].outputs[0].text msg fc2dict(response) if ( tool_calls in msg and msg[tool_calls] is not None and len(msg[tool_calls]) 0 ): messages.append(msg) print(msg) for toolcall in msg[tool_calls]: tool_response fake_tool_execute(toolcall) tool_msg { role: tool, content: tool_response, tool_call_id: toolcall[id], } messages.append(tool_msg) print(tool_msg) else: messages.append(msg) print(msg) break循环的执行流程可以概括为拼装提示每次迭代都用apply_chat_template将最新的messages包含历史工具调用与工具返回渲染为模型输入生成响应用LLM.generate推理SamplingParams(temperature0.8, top_p0.95, max_tokens1000)控制采样与最大长度解析结果fc2dict(response)把模型输出的文本解析为结构化消息判断是否包含tool_calls执行工具若包含工具调用则遍历每个调用用fake_tool_execute模拟工具执行生成role: tool消息并附上tool_call_id与模型输出的调用 id 一一对应追加进messages收敛退出若模型不再产生工具调用说明它已收集足够信息将最终回答追加到messages后break退出。脚本中注释保留了一段“标准多轮对话”的参考形态role: assistant携带tool_calls含id与arguments随后跟多条role: tool的结果最终由带thought字段的 assistant 消息给出总结。thought字段是 MiniCPM3 工具调用协议的一个特色——模型会在|thought_start|与|thought_end|之间输出“思考”说明为何调用工具、计划如何解决问题。五、工具调用解析器 minicpm_tool_parser.py 原理剖析minicpm_tool_parser.py 是整套工具调用链路的翻译官承担模型自然语言输出 ↔ OpenAI 结构化工具调用的双向转换。5.1 特殊标记与停止符解析器构造函数第 3238 行定义了四个关键标记self.thought_start_token |thought_start| self.thought_end_token |thought_end| self.tool_call_start_token |tool_call_start| self.tool_call_end_token |tool_call_end| self.stop_token_ids [2, 73440]其中stop_token_ids包含 EOS token2与模型的特殊结束 token73440用于判断流式生成是否结束。5.2 非流式解析 extract_tool_calls非流式场景下模型输出是完整文本直接交给fc2dict处理即可第 4073 行将结果中每个工具调用包装成 vLLM 协议的ToolCall对象。注意ExtractedToolCallInformation的tools_called恒为True当没有工具调用时返回空列表tool_calls[]由上层逻辑据此区分回答/追问与调用工具。5.3 流式解析 extract_tool_calls_streaming流式解析第 75147 行按生成阶段分三种情况处理工具调用刚开始当useful_textthought_end之后的文本中出现tool_call_start时用正则(\w)\(((?:[^()]*|\([^()]*\))*)\)匹配函数名(参数)支持嵌套括号随后用ast.parse解析为 AST 并交给resolve_ast_call提取函数名与参数产出DeltaToolCall工具调用已结束tool_call_start与tool_call_end同时出现时返回None等待最终收尾生成结束当前 token 落入stop_token_ids时对整个current_text执行fc2dict得到完整工具调用数组作为最终的DeltaMessage返回。5.4 fc2dict从文本到结构化字典fc2dict第 150218 行是解析核心工作步骤包括切分思考与正文按thought_end切分提取|thought_start|与|thought_end|之间的思考文本切分工具调用按tool_call_end切分取|tool_call_start|与|tool_call_end|之间的代码块并兼容python围栏关键词保护遍历 Python 关键字列表把,xxx、xxx、(xxx形式的关键字参数名临时加上下划线后缀如,class→,class_避免ast.parse报语法错误AST 解析ast.parse后对每个ast.Call调用resolve_ast_call得到{函数名: 参数dict}还原关键字将带下划线后缀的参数名还原为原始关键字组装为{name: ..., arguments: {...}}列表兜底解析异常时返回仅含content与thought的字典保证不会因解析失败而中断对话。resolve_ast_call与resolve_ast_by_type第 222284 行源于 gorilla 项目能递归还原嵌套属性调用如module.func(...)、常量、一元运算、列表、字典、布尔值、二元运算、嵌套函数调用、元组、Lambda、切片下标等多种 Python 表达式从而稳健地把模型生成的 Python 风格调用语句转回 JSON 参数。六、工具聊天模板 minicpm_chat_template_with_tool.jinja 原理MiniCPM3 工具调用的独特之处在于工具定义不是以 JSON 形式塞进提示词而是被渲染成 Python 函数签名。模板 minicpm_chat_template_with_tool.jinja 完成了从 JSON Schema 到 Python 类型提示的编译类型映射宏json_to_python_typestring→str、number→float、integer→int、boolean→bool、null→Nonearray递归为List[...]object递归为Dict[str, ...]多类型用Union[...]表达字段渲染宏object_to_fields为每个参数生成 Pydantic 风格字段带enum的参数被展开为Enum类嵌套 object 递归生成BaseModel子类支持description、regexpattern、title、默认值等元信息工具渲染宏tool_parser将每个函数工具渲染为def func(paramdefault):的 Python 函数头docstring 写入函数描述与 Args 说明。最终系统提示词结构如下|im_start|system 系统消息 # Functions Here is a list of functions that you can invoke: python from enum import Enum from typing import List, Dict, Optional from pydantic import BaseModel, Field def 函数签名...Function Call Rule and Output Format无需调用函数时直接回答……信息不足时思考后追问……信息充足时思考后调用函数……Use default parameters unless the user has specified otherwise.You should answer in the following format:|thought_start| {解释……} |thought_end| |tool_call_start|func1(params_nameparams_value, params_name2params_value2...) func2(params)|tool_call_end| {直接回答或追问} |im_end|对话历史部分的渲染同样遵循该协议assistant 消息若带 tool_calls会按 |thought_start| |tool_call_start|python func(...)|tool_call_end| 的格式回放带 thought 的消息则输出思考后接正文。add_generation_promptTrue 时末尾追加 |im_start|assistant\n 等待模型续写。 正是这套模板与解析器的配合实现了以 Python 代码为媒介的稳定工具调用模型先输出 Python 风格调用再由 fc2dict/extract_tool_calls 反向解析为 JSON规避了纯文本工具调用常见的格式漂移问题。 ## 七、总结与实践建议 | 场景 | 推荐路径 | 关键命令 | | --- | --- | --- | | 对外提供 OpenAI 兼容服务 | 方式一vLLM API Server | python -m vllm.entrypoints.openai.api_server ... --enable-auto-tool-choice --tool-call-parser minicpm --tool-parser-plugin minicpm_tool_parser.py | | 本地验证工具调用逻辑 | 方式二本地推理脚本 | python function_calling.py | 实践要点回顾 1. 服务端必须**同时**开启 --enable-auto-tool-choice 与 --tool-call-parser minicpm并加载本仓库的 minicpm_tool_parser.py 插件否则模型不会输出结构化的 tool_calls 2. 客户端 tools 遵循 OpenAI Function 格式tool_choiceauto 是推荐取值 3. 多轮工具调用务必维护好 role: tool 消息与 tool_call_id 的对应关系否则模型无法将工具结果与调用关联 4. 本地脚本依赖 vllm 与 datamodel_code_generator安装见 [requirements.txt](https://link.gitcode.com/i/3a7874a9ea2f138c8ffcf6fb818d5388) 5. 若需查看模型在更高层级的工具调用能力说明与进阶用法可参考 [docs/README-minicpm3-cn.md](https://link.gitcode.com/i/a8a0d7ed3e0fdb9c2ed5afee349a2888) 的进阶功能章节。 MiniCPM3-4B 在 Berkeley Function Calling LeaderboardBFCL上表现出优于多个 7B-9B 参数模型的工具调用水平见 [docs/README-minicpm3-cn.md](https://link.gitcode.com/i/a8a0d7ed3e0fdb9c2ed5afee349a2888)本文介绍的两条实战路径——服务化部署与本地多轮调用——已经覆盖从调试到上线的完整闭环开发者可以直接在此基础上接入真实业务工具。【免费下载链接】MiniCPMMiniCPM5: SOTA on-device LLMs, small yet powerful.项目地址: https://gitcode.com/GitHub_Trending/mi/MiniCPM创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考