diff --git a/docs/function_call_guide_cn.md b/docs/function_call_guide_cn.md deleted file mode 100644 index db8d799..0000000 --- a/docs/function_call_guide_cn.md +++ /dev/null @@ -1,482 +0,0 @@ -# MiniMax-M2 函数调用(Function Call)功能指南 - -## 简介 - -MiniMax-M2 模型支持函数调用功能,使模型能够识别何时需要调用外部函数,并以结构化格式输出函数调用参数。本文档详细介绍了如何使用 MiniMax-M2 的函数调用功能。 - -## 基础示例 - -以下 Python 脚本基于 OpenAI SDK 实现了一个天气查询函数的调用示例: - -```python -from openai import OpenAI -import json - -client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy") - -def get_weather(location: str, unit: str): - return f"Getting the weather for {location} in {unit}..." - -tool_functions = {"get_weather": get_weather} - -tools = [{ - "type": "function", - "function": { - "name": "get_weather", - "description": "Get the current weather in a given location", - "parameters": { - "type": "object", - "properties": { - "location": {"type": "string", "description": "City and state, e.g., 'San Francisco, CA'"}, - "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]} - }, - "required": ["location", "unit"] - } - } -}] - -response = client.chat.completions.create( - model=client.models.list().data[0].id, - messages=[{"role": "user", "content": "What's the weather like in San Francisco? use celsius."}], - tools=tools, - tool_choice="auto" -) - -print(response) - -tool_call = response.choices[0].message.tool_calls[0].function -print(f"Function called: {tool_call.name}") -print(f"Arguments: {tool_call.arguments}") -print(f"Result: {get_weather(**json.loads(tool_call.arguments))}") -``` - -**输出示例:** -``` -Function called: get_weather -Arguments: {"location": "San Francisco, CA", "unit": "celsius"} -Result: Getting the weather for San Francisco, CA in celsius... -``` - -## 手动解析模型输出 - -如果您无法使用已支持 MiniMax-M2 的推理引擎的内置解析器,或者需要使用其他推理框架(如 transformers、TGI 等),可以使用以下方法手动解析模型的原始输出。这种方法需要您自己解析模型输出的 XML 标签格式。 - -### 使用 Transformers 的示例 - -以下是使用 transformers 库的完整示例: - -```python -from transformers import AutoTokenizer - -def get_default_tools(): - return [ - { - "name": "get_current_weather", - "description": "Get the latest weather for a location", - "parameters": { - "type": "object", - "properties": { - "location": { - "type": "string", - "description": "A certain city, such as Beijing, Shanghai" - } - }, - } - "required": ["location"], - "type": "object" - } - ] - -# 加载模型和分词器 -tokenizer = AutoTokenizer.from_pretrained(model_id) -prompt = "What's the weather like in Shanghai today?" -messages = [ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": prompt}, -] - -# 启用函数调用工具 -tools = get_default_tools() - -# 应用聊天模板,并加入工具定义 -text = tokenizer.apply_chat_template( - messages, - tokenize=False, - add_generation_prompt=True, - tools=tools -) - -# 发送请求(这里使用任何推理服务) -import requests -payload = { - "model": "MiniMaxAI/MiniMax-M2", - "prompt": text, - "max_tokens": 4096 -} -response = requests.post( - "http://localhost:8000/v1/completions", - headers={"Content-Type": "application/json"}, - json=payload, - stream=False, -) - -# 模型输出需要手动解析 -raw_output = response.json()["choices"][0]["text"] -print("原始输出:", raw_output) - -# 使用下面的解析函数处理输出 -function_calls = parse_tool_calls(raw_output, tools) -``` - -## 🛠️ 函数调用的定义 - -### 函数结构体 - -函数调用需要在请求体中定义 `tools` 字段,每个函数由以下部分组成: - -```json -{ - "tools": [ - { - "name": "search_web", - "description": "搜索函数。", - "parameters": { - "properties": { - "query_list": { - "description": "进行搜索的关键词,列表元素个数为1。", - "items": { "type": "string" }, - "type": "array" - }, - "query_tag": { - "description": "query的分类", - "items": { "type": "string" }, - "type": "array" - } - }, - "required": [ "query_list", "query_tag" ], - "type": "object" - } - } - ] -} -``` - -**字段说明:** -- `name`: 函数名称 -- `description`: 函数功能描述 -- `parameters`: 函数参数定义 - - `properties`: 参数属性定义,key 是参数名,value 包含参数的详细描述 - - `required`: 必填参数列表 - - `type`: 参数类型(通常为 "object") - -### 模型内部处理格式 - -在 MiniMax-M2 模型内部处理时,函数定义会被转换为特殊格式并拼接到输入文本中。以下是一个完整的示例: - -``` -]~!b[]~b]system -You are a helpful assistant. - -# Tools -You may call one or more tools to assist with the user query. -Here are the tools available in JSONSchema format: - - -{"name": "search_web", "description": "搜索函数。", "parameters": {"type": "object", "properties": {"query_list": {"type": "array", "items": {"type": "string"}, "description": "进行搜索的关键词,列表元素个数为1。"}, "query_tag": {"type": "array", "items": {"type": "string"}, "description": "query的分类"}}, "required": ["query_list", "query_tag"]}} - - -When making tool calls, use XML format to invoke tools and pass parameters: - - - -param-value-1 -param-value-2 -... - -[e~[ -]~b]user -OpenAI 和 Gemini 的最近一次发布会都是什么时候?[e~[ -]~b]ai - -``` - -**格式说明:** - -- `]~!b[]~b]system`: System 消息开始标记 -- `[e~[`: 消息结束标记 -- `]~b]user`: User 消息开始标记 -- `]~b]ai`: Assistant 消息开始标记 -- `]~b]tool`: Tool 结果消息开始标记 -- `...`: 工具定义区域,每个工具用 `` 标签包裹,内容为 JSON Schema -- `...`: 工具调用区域 -- ``: 生成时的思考过程标记(可选) - -### 模型输出格式 - -MiniMax-M2使用结构化的 XML 标签格式: - -```xml - - -["technology", "events"] -["\"OpenAI\" \"latest\" \"release\""] - - -["technology", "events"] -["\"Gemini\" \"latest\" \"release\""] - - -``` - -每个函数调用使用 `` 标签,参数使用 `` 标签包裹。 - -## 手动解析函数调用结果 - -### 解析函数调用 - -MiniMax-M2使用结构化的 XML 标签,需要不同的解析方式。核心函数如下: - -```python -import re -import json -from typing import Any, Optional, List, Dict - - -def extract_name(name_str: str) -> str: - """从引号包裹的字符串中提取名称""" - name_str = name_str.strip() - if name_str.startswith('"') and name_str.endswith('"'): - return name_str[1:-1] - elif name_str.startswith("'") and name_str.endswith("'"): - return name_str[1:-1] - return name_str - - -def convert_param_value(value: str, param_type: str) -> Any: - """根据参数类型转换参数值""" - if value.lower() == "null": - return None - - param_type = param_type.lower() - - if param_type in ["string", "str", "text"]: - return value - elif param_type in ["integer", "int"]: - try: - return int(value) - except (ValueError, TypeError): - return value - elif param_type in ["number", "float"]: - try: - val = float(value) - return val if val != int(val) else int(val) - except (ValueError, TypeError): - return value - elif param_type in ["boolean", "bool"]: - return value.lower() in ["true", "1"] - elif param_type in ["object", "array"]: - try: - return json.loads(value) - except json.JSONDecodeError: - return value - else: - # 尝试 JSON 解析,失败则返回字符串 - try: - return json.loads(value) - except json.JSONDecodeError: - return value - - -def parse_tool_calls(model_output: str, tools: Optional[List[Dict]] = None) -> List[Dict]: - """ - 从模型输出中提取所有工具调用 - - Args: - model_output: 模型的完整输出文本 - tools: 工具定义列表,用于获取参数类型信息,格式可以是: - - [{"name": "...", "parameters": {...}}] - - [{"type": "function", "function": {"name": "...", "parameters": {...}}}] - - Returns: - 解析后的工具调用列表,每个元素包含 name 和 arguments 字段 - - Example: - >>> tools = [{ - ... "name": "get_weather", - ... "parameters": { - ... "type": "object", - ... "properties": { - ... "location": {"type": "string"}, - ... "unit": {"type": "string"} - ... } - ... } - ... }] - >>> output = ''' - ... - ... San Francisco - ... celsius - ... - ... ''' - >>> result = parse_tool_calls(output, tools) - >>> print(result) - [{'name': 'get_weather', 'arguments': {'location': 'San Francisco', 'unit': 'celsius'}}] - """ - # 快速检查是否包含工具调用标记 - if "" not in model_output: - return [] - - tool_calls = [] - - try: - # 匹配所有 块 - tool_call_regex = re.compile(r"(.*?)", re.DOTALL) - invoke_regex = re.compile(r"", re.DOTALL) - parameter_regex = re.compile(r"", re.DOTALL) - - # 遍历所有 tool_call 块 - for tool_call_match in tool_call_regex.findall(model_output): - # 遍历该块中的所有 invoke - for invoke_match in invoke_regex.findall(tool_call_match): - # 提取函数名 - name_match = re.search(r'^([^>]+)', invoke_match) - if not name_match: - continue - - function_name = extract_name(name_match.group(1)) - - # 获取参数配置 - param_config = {} - if tools: - for tool in tools: - tool_name = tool.get("name") or tool.get("function", {}).get("name") - if tool_name == function_name: - params = tool.get("parameters") or tool.get("function", {}).get("parameters") - if isinstance(params, dict) and "properties" in params: - param_config = params["properties"] - break - - # 提取参数 - param_dict = {} - for match in parameter_regex.findall(invoke_match): - param_match = re.search(r'^([^>]+)>(.*)', match, re.DOTALL) - if param_match: - param_name = extract_name(param_match.group(1)) - param_value = param_match.group(2).strip() - - # 去除首尾的换行符 - if param_value.startswith('\n'): - param_value = param_value[1:] - if param_value.endswith('\n'): - param_value = param_value[:-1] - - # 获取参数类型并转换 - param_type = "string" - if param_name in param_config: - if isinstance(param_config[param_name], dict) and "type" in param_config[param_name]: - param_type = param_config[param_name]["type"] - - param_dict[param_name] = convert_param_value(param_value, param_type) - - tool_calls.append({ - "name": function_name, - "arguments": param_dict - }) - - except Exception as e: - print(f"解析工具调用失败: {e}") - return [] - - return tool_calls -``` - -**使用示例:** - -```python -# 定义工具 -tools = [ - { - "name": "get_weather", - "parameters": { - "type": "object", - "properties": { - "location": {"type": "string"}, - "unit": {"type": "string"} - }, - "required": ["location", "unit"] - } - } -] - -# 模型输出 -model_output = """我来帮你查询天气。 - - -San Francisco -celsius - -""" - -# 解析工具调用 -tool_calls = parse_tool_calls(model_output, tools) - -# 输出结果 -for call in tool_calls: - print(f"调用函数: {call['name']}") - print(f"参数: {call['arguments']}") - # 输出: 调用函数: get_weather - # 参数: {'location': 'San Francisco', 'unit': 'celsius'} -``` - -### 执行函数调用 - -解析完成后,您可以执行对应的函数并构建返回结果: - -```python -def execute_function_call(function_name: str, arguments: dict): - """执行函数调用并返回结果""" - if function_name == "get_weather": - location = arguments.get("location", "未知位置") - unit = arguments.get("unit", "celsius") - # 构建函数执行结果 - return { - "role": "tool", - "content": [ - { - "name": function_name, - "type": "text", - "text": json.dumps({ - "location": location, - "temperature": "25", - "unit": unit, - "weather": "晴朗" - }, ensure_ascii=False) - } - ] - } - elif function_name == "search_web": - query_list = arguments.get("query_list", []) - query_tag = arguments.get("query_tag", []) - # 模拟搜索结果 - return { - "role": "tool", - "content": [ - { - "name": function_name, - "type": "text", - "text": f"搜索关键词: {query_list}, 分类: {query_tag}\n搜索结果: 相关信息已找到" - } - ] - } - - return None -``` - -### 将函数执行结果返回给模型 - -成功解析函数调用后,您应将函数执行结果添加到对话历史中,以便模型在后续交互中能够访问和利用这些信息,拼接格式参考chat_template.jinja - -## 参考资料 - -- [MiniMax-M2 模型仓库](https://github.com/MiniMax-AI/MiniMax-M2) -- [vLLM 项目主页](https://github.com/vllm-project/vllm) -- [OpenAI Python SDK](https://github.com/openai/openai-python) \ No newline at end of file