news 2026/9/10 4:33:54

oh-my-pi 的 MiniMax Dialect:基于 `<minimax:tool_call>` 的带内函数调用协议实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
oh-my-pi 的 MiniMax Dialect:基于 `<minimax:tool_call>` 的带内函数调用协议实战指南

oh-my-pi 的 MiniMax Dialect:基于<minimax:tool_call>的带内函数调用协议实战指南

【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi

导读

MiniMax Dialect 是 oh-my-pi 编码 Agent 为接入 MiniMax 系列模型(如MiniMax-M3)而定制的一套「带内工具调用(in-band tool calling)」文本协议。它将一次函数调用编码为<minimax:tool_call>包裹的 XML 风格标签、将工具结果回传编码为<function_results>块,从而让模型在普通文本流中直接声明要执行的工具,无需依赖厂商专有的tool_callsJSON 结构。读完本文,你将掌握该协议每个标签的准确写法、参数值编码的底层规则(为什么不能做 HTML 转义)、错误结果的处理方式,以及 oh-my-pi 在 dialect/minimax.ts 中如何以「前缀匹配 + 流式状态机」的方式解析并复原这些调用。

本文主体以 dialect/minimax.md 为骨架,并辅以同目录源码与packages/ai/test/inband-tools.test.ts等测试用例作实现级佐证。

一、协议总览:一次调用与一次回传的完整形态

MiniMax Dialect 把整个工具调用过程拆成两个阶段:模型侧发起的调用工具侧回传的结果。二者在转录文本中的形态完全不同,且都由 Agent 之外的运行时(即 oh-my-pi 的 dialect 渲染层)负责拼装。

1.1 调用(Call):<minimax:tool_call>包裹<invoke>

一次函数调用是一个<minimax:tool_call>块,内部包裹一个或多个<invoke>块,每个<invoke>通过若干<parameter>子元素携带参数:

<minimax:tool_call> <invoke name="tool_name"><parameter name="arg_name">arg value</parameter></invoke> </minimax:tool_call>

要点拆解:

  • <minimax:tool_call>是命名空间前缀化的包裹标签,作用等价于 Anthropic 方言中的<function_calls>,用于把多个并行调用圈成一个整体。在 dialect/minimax.ts 中,MINIMAX_WRAPPER_TAGS只登记了tool_call这一个包裹标签,且扫描器只认minimax:前缀与无前缀两种写法(见MINIMAX_BASE_TAG_PREFIXES)。
  • <invoke name="...">是单次调用的载体,name属性必须精确匹配已登记的工具名(见下文「规则」)。
  • <parameter name="...">值</parameter>是参数载体,name为参数名,标签体为参数值。
  • 多个调用时,在同一个<minimax:tool_call>内连续书写多个<invoke>块,这是并行调用在文本协议里的唯一表示方式。

1.2 回传(Results):<function_results><result>/<error>

调用执行完毕后,结果以<function_results>块返回,每次调用对应一个<result>;失败调用不使用<result>,而是改用<error>子块,且内部以<stderr>承载错误内容:

<function_results> <result> <tool_name>tool_name</tool_name> <stdout>verbatim tool result</stdout> </result> </function_results>

对应失败形态:

<function_results> <error> <tool_name>tool_name</tool_name> <stderr>error message</stderr> </error> </function_results>

从实现看,renderToolResults(dialect/minimax.ts)正是依据每个结果的isError布尔值选择标签:成功时用result/stdout,失败时用error/stderr,并把工具名经escapeXmlText转义后放入<tool_name>。这与 Anthropic 方言的renderToolResults结构完全一致(见 dialect/anthropic.ts),说明 MiniMax 方言在回传侧复用了同一套序列化约定。

二、规则全解:模型侧必须遵守的七条硬约束

2.1name必须匹配已登记函数

<invoke name="...">中的名称必须与提示词中列出的函数(tool listing)精确一致,否则扫描器无法把该块解析为一次有效的toolEnd事件。在 dialect/minimax.ts 的#startInvoke中,只有当tag.attrs.get("name")解析出的名称非空时#started才为true,也才会发出toolStart/toolEnd事件;名称为空或不可识别的<invoke>会被当作普通文本吞掉。

2.2 标量参数按正则读、禁止 HTML 转义

这是本协议最反直觉、也最容易出错的一条:

  • 字符串/标量参数:逐字书写,保留空格。协议解析器读取参数体用的是「正则/定界符匹配(delimiter matching)」,不是真正的 XML 解析器,因此:
    • 不要做任何 HTML 实体转义:写a & b绝不写a &amp; b
    • <>在参数体内保持字面量,照写即可;
    • 唯一被保留的定界符是参数体自己的</parameter>闭合标签——也就是说,值内部出现<>&都没问题,但绝不能出现裸的</parameter>序列,因为它会被当作参数结束。
  • 列表/对象参数:以JSON形式书写。

这一设计在源码中有双重印证。渲染侧renderInvoke(dialect/minimax.ts)用escapeXmlAttr转义的只有name属性与参数name属性,参数则按是否字符串决定原样输出还是stringifyJson;解析侧#peekTag也只对形如</parameter的前缀做定界匹配(dialect/anthropic.ts,MiniMax 复用同一扫描器),参数体里的<&不会被展开。

2.3 多调用:一个tool_call内多个<invoke>

并行调用不重复书写外层标签,而是:

<minimax:tool_call> <invoke name="read"><parameter name="path">src/a.ts</parameter></invoke> <invoke name="glob"><parameter name="pattern">**/*.ts</parameter></invoke> </minimax:tool_call>

测试 inband-tools.test.ts 验证了该写法的流式解析:即使把src/a.ts</parameter>...切成多个 chunk 分片喂给扫描器,最终仍能复原出完整调用,这正是流式场景(模型逐 token 吐出)下的健壮性保障。

2.4 调用前可以写可见文本

<minimax:tool_call>之前,模型可以正常输出思考过程、解释性文字等可见文本,扫描器的outside状态会把这些内容作为text事件透传(dialect/anthropic.ts)。

2.5 禁用 JSON 调用与旧语法

  • 绝不输出tool_callsJSON:MiniMax 方言明确禁止走 OpenAI 风格的tool_calls结构化字段,一切调用必须落到上述文本标签里;
  • 绝不使用<function_calls>或旧的<tool_name>/<parameters>调用语法:这是被淘汰的写法。从扫描器配置看,MINIMAX_BASE_TAG_PREFIXES(dialect/minimax.ts)只登记了minimax:tool_calltool_callinvokeparameter四组开闭前缀,function_calls并不在其列,写了也不会被解析成调用。

2.6 按序读取结果,绝不自行发出function_results

每个<result>/<error>必须严格按照调用顺序阅读;<function_results>块由运行时注入(renderToolResults),模型永远不要自己拼写它。原因在于:转录历史中工具结果天然属于Human:侧回填内容(见renderLegacyTextTranscripttoolResult消息的处理,dialect/rendering.ts),模型若自行伪造结果块,会破坏调用-结果的配对关系。

2.7 停止序列只许在调用完整写完后触发

这是最容易导致「模型瘫痪」的一条:先写完完整的调用,再触发停止序列,然后才停止。禁止出现「宣布要用工具但没写<invoke>就停下」的行为,例如输出完Let's run cargo clippy就戛然而止。正确做法是:

Let's run cargo clippy. <minimax:tool_call> <invoke name="bash"><parameter name="command">cargo clippy</parameter></invoke> </minimax:tool_call>

(随后才输出停止序列并停止。)该约束与 dialect/anthropic.md 等其它方言完全同源,是 oh-my-pi 对所有带内协议的一致要求。

三、实现原理:前缀匹配的流式扫描器

MiniMax 方言没有自己的解析器,而是复用了 Anthropic 的AnthropicInbandScanner,仅替换三组配置(dialect/minimax.ts):

  • wrapperTags = { tool_call: true }:只有tool_call被视为包裹/分节标签;
  • baseTagPrefixes<minimax:tool_call</minimax:tool_call<tool_call</tool_call<invoke</invoke<parameter</parameter共 8 个前缀;
  • allTagPrefixes:在前者基础上追加 Anthropic 的思考标签前缀(<thinking<think<scratchpad等)。

扫描器采用状态机 + 前缀判定而非 DOM 解析:#peekTag(dialect/anthropic.ts)先用couldBeTagPrefix判断当前缓冲是否命中某个登记前缀——若缓冲以某个前缀开头或某个前缀以缓冲开头,且尚未见到>,就返回"partial"并等待更多流式数据。这正是「模型输出到一半、标签还没闭合」时扫描器不会误判为文本的原因,也是上文测试中分片输入能复原完整调用的机制基础。

扫描过程中对外发出四类事件(dialect/types.ts):

  • text:调用外的可见文本;
  • toolStart:遇到带name<invoke>时触发;
  • toolArgDelta:参数体每增加一段内容时触发,支持流式增量;
  • toolEnd:遇到</invoke>时触发,携带完整参数表。

另外,解析器对参数值做了两层规范化(#coerceParameterValue,dialect/anthropic.ts):若参数 schema 声明为纯字符串类型则原样保留;否则先尝试JSON.parse(失败回退为原字符串),从而与渲染侧的「字符串逐字、非字符串 JSON」规则严格对称。

四、Dialect 接线:定义、注册与测试验证

4.1 定义结构

DialectDefinition(dialect/types.ts)要求每个方言提供六项能力,MiniMax 的实现(dialect/minimax.ts)逐一对应:

能力实现职责
dialect"minimax"方言标识,与目录名一致
promptminimax.md(本文档)注入系统提示词,约束模型输出格式
createScanner配置化AnthropicInbandScanner流式解析模型输出中的调用
renderToolCall渲染单个<invoke>单调用渲染(无外层包裹)
renderAssistantToolCalls渲染<minimax:tool_call>包多个<invoke>并行调用渲染
renderToolResults渲染<function_results>结果/错误回传渲染
renderThinking<thinking>…</thinking>思考过程渲染(沿用 Anthropic 风格,dialect/thinking.ts 中明确minimax使用<thinking>开闭标签)
renderTranscriptrenderLegacyTextTranscript整段会话历史的文本化转录

4.2 注册与获取

factory.tsDIALECT_DEFINITIONS表把minimax映射到该定义,外部通过getDialectDefinition("minimax")createInbandScanner("minimax", options)获取(dialect/factory.ts)。

4.3 测试验证

测试 inband-tools.test.ts 对 minimax 方言做了三个方向的验证,可作为自行实现或接入时的回归参考:

  1. 提示词渲染renderInbandToolPrompt(TOOLS, "minimax")必须包含<tools>/</tools>包裹与minimax.md的首行标题;
  2. 渲染-解析往返renderAssistantToolCalls渲染出的调用块再喂回feedText扫描,必须解析出与原始ToolCall一致的结果(inband-tools.test.ts);
  3. 流式分片健壮性:把渲染结果切成'<minimax:tool_call>\n<invoke name="read"><parameter name="path">'"src/""a.ts</para"'meter><parameter name="count" string="false">'等 chunk 顺序喂入,仍能正确复原(inband-tools.test.ts)。

五、配套能力:MiniMax 的用量配额与模型接线

5.1 Token Plan 用量上报

packages/ai/src/usage/minimax-code.ts为国际版minimax-codeapi.minimax.io)实现了 Token Plan 配额查询:请求GET /v1/token_plan/remains,每个model_remains[]桶包含滚动区间窗口与周窗口的剩余百分比、总数、用量与状态码(1正常、2耗尽、3不限量)。值得注意的两个实现细节:

  • MiniMax 即使凭据被拒也会返回 HTTP 200,因此真正的成功信号是响应体base_resp.status_code === 0(minimax-code.ts);
  • 「双窗口均为 0 总量 + 状态 3」的桶被判定为「不在当前套餐中」并放入metadata.unavailableModels,不会渲染成健康的配额(isUnavailablePlan,minimax-code.ts)。

5.2 模型接线

目录 compat/rules/providers/minimax-code.kdl 与minimax-code-cn.kdl(国内站api.minimaxi.com/v1)声明了MiniMax-M3的接线契约:reasoning-deltas-may-be-cumulative(推理增量可能为累积式)、thinking-mode "effort",以及minimal/low/medium/high四档思考强度(minimax-code.kdl)。也就是说,MiniMax 方言的文本调用协议与MiniMax-M3的思考强度配置、Token Plan 配额上报共同构成 oh-my-pi 对 MiniMax 系的完整接入面。

六、常见错误速查

错误写法问题正确写法
<parameter name="q">a &amp; b</parameter>对参数体做了 HTML 转义,解析器按字面量读取得到a &amp; b<parameter name="q">a & b</parameter>
<invoke name="bash"><parameter name="cmd"><bash -c 'x'></parameter></invoke>(值内含</parameter>唯一保留定界符</parameter>提前截断参数改写参数值,避免出现裸</parameter>
输出<function_calls>…</function_calls>tool_callsJSON已被禁止的旧语法/JSON 语法,扫描器不识别统一使用<minimax:tool_call>+<invoke>
写了Let's run cargo clippy.就停止调用未完整书写就触发停止序列,模型被卡死写完完整<minimax:tool_call>块后再触发停止序列
自行输出<function_results>结果块必须由运行时注入,模型伪造会破坏调用-结果配对只按序阅读运行时返回的<result>/<error>

结语

MiniMax Dialect 是 oh-my-pi 带内工具调用体系(glmhermeskimixmlanthropicdeepseekminimax等十余种方言之一,见 dialect/factory.ts)中的关键一环。它的核心价值在于:用一套「正则定界符 + 前缀状态机」就能在纯文本流中稳定解析结构化调用,天然适配流式生成,且对模型侧的书写纪律(不转义、不乱发结果块、先写完整调用再停止)提出了明确而可测试的要求。无论是接入新模型还是调试既有 Agent 的调用失败问题,都可以先回到minimax.md的规则清单与inband-tools.test.ts的往返测试上定位根因。

【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 4:31:44

Modbus调试三层次解剖:物理层、链路层与应用层协同排障

1. 为什么MODBUS至今仍是嵌入式现场的“硬通货”——从蓝桥杯国赛真题说起你有没有在调试一个STM32F103板子时&#xff0c;明明串口波形干净、电平标准、接线无误&#xff0c;但Modbus Poll就是收不到响应&#xff1f;或者更糟——它偶尔能读到寄存器&#xff0c;但一发写命令就…

作者头像 李华
网站建设 2026/9/10 4:31:36

STM32核心寄存器实战指南:23个高频生死线详解

1. 这不是“背诵清单”&#xff0c;而是嵌入式工程师的寄存器操作地图你翻过STM32参考手册第几遍&#xff1f;是不是每次查到某个外设章节&#xff0c;光是寄存器列表就密密麻麻占满十几页&#xff0c;字段名缩写像天书&#xff0c;复位值记了又忘&#xff0c;配置顺序一错整个…

作者头像 李华