拓冰建站拓冰建站
首页 / 资讯中心 / 正文

oh-my-pi 的 GLM 方言工具调用协议:`<tool_call>` 标签格式、流式解析与自愈机制全解

oh-my-pi 的 GLM 方言工具调用协议tool_call标签格式、流式解析与自愈机制全解【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi导读在 oh-my-pi 这个“把 IDE 接进 Agent”的编码代理项目中packages/ai通过“方言dialect”层把统一的内部消息模型翻译成各家模型厂商各自的工具调用语法。本文聚焦 GLM 系列模型方言完整解读其格式指南glm.md并结合 glm.ts 的流式状态机与参数值自愈实现讲清楚tool_call怎么写、为什么arg_value不能被当成真正的 XML 解析、流式返回如何被逐步拆解成toolStart/toolArgDelta/toolEnd事件以及模型写错闭合标签时系统如何自动修复。读完你既能写出被 GLM 方言正确识别的工具调用文本也能理解 oh-my-pi 在流式工具调用上的底层容错设计。一、GLM 方言在 oh-my-pi 中的定位packages/ai/src/dialect/目录下每个模型家族对应一份.md格式指南和一份.ts实现anthropic、deepseek、gemini、gemma、glm、harmony、hermes、kimi、minimax、qwen3、xml 等。所有方言统一收敛到 factory.ts 的DIALECT_DEFINITIONS注册表中其中glm条目对应 glm.ts 导出的DialectDefinition。一份DialectDefinition由五部分组成见 types.tsprompt注入给模型的格式指南文本即glm.mdcreateScanner构造流式扫描器GLMInbandScanner负责把模型流出的文本逐步解析为结构化事件renderToolCall/renderAssistantToolCalls把内部ToolCall渲染成tool_call文本renderToolResults把工具执行结果渲染成observation观测块renderThinking/renderTranscript渲染思考块与完整对话转录。因此glm.md既是写给模型的指令也是这套渲染/解析逻辑的行为契约模型按它输出扫描器按它解析两端必须严格对齐。二、工具调用格式一个tool_call一个调用glm.md规定的工具调用格式非常简洁每个调用是一个tool_call块函数名必须写在开标签的同一行之后每个参数一对arg_key/arg_value最后以/tool_call收尾tool_callget_weather arg_keylocation/arg_key arg_valueBeijing/arg_value arg_keydays/arg_key arg_value3/arg_value /tool_call对照源码扫描器为这些标签定义了精确的常量glm.tsconst TOOL_OPEN tool_call; const TOOL_CLOSE /tool_call; const ARG_KEY_OPEN arg_key; const ARG_KEY_CLOSE /arg_key; const ARG_VALUE_OPEN arg_value; const ARG_VALUE_CLOSE /arg_value; const RESPONSE_OPEN tool_response; const RESPONSE_CLOSE /tool_response; const THINK_OPEN think; const THINK_CLOSE /think;函数名规则名称必须与已列出可用的函数完全一致且与tool_call处于同一行扫描器在name状态下用换行、arg_key或/tool_call三个定界符中的最先出现者截断函数名#consumeNameglm.ts随后#beginCall会对名称做trim()空名直接丢弃该调用。参数书写规则每个参数恰好一对arg_key名称/arg_keyarg_value值/arg_value顺序即参数顺序未设置的可选参数不要写出直接省略整对标签多次调用是连续的多个tool_call…/tool_call块块与块之间直接拼接无需额外分隔符。渲染侧的印证内部ToolCall被渲染成文本时遵循同样结构glmInvocationglm.tsfunction glmInvocation(call: ToolCall, shape: ToolArgShape | undefined): string { let body ${TOOL_OPEN}${call.name}; for (const key in call.arguments) { const value call.arguments[key]; const rendered shape?.stringArgs.has(key) typeof value string ? value : stringifyJson(value); body \n${ARG_KEY_OPEN}${key}${ARG_KEY_CLOSE}\n${ARG_VALUE_OPEN}${rendered}${ARG_VALUE_CLOSE}; } return ${body}\n${TOOL_CLOSE}; }这里有一个与格式指南呼应的关键设计被工具 schema 声明为纯字符串的参数按原文输出其他参数一律序列化为 JSON 字符串。判定逻辑位于 coercion.tsisStringOnlySchema收集 schema 的类型集合展开anyOf/oneOf/allOf、enum、const剔除null若唯一类型是string则该参数属于stringArgs集合。这正是原文档“非字符串值是合法 JSON”这一规则的实现依据。三、工具结果observation观测块工具执行结果通过观测块返回给模型observation tool_response verbatim tool result /tool_response /observation渲染侧由 rendering.ts 的renderToolResponseResults完成每个结果渲染为一个tool_response多个结果用换行拼接整体再包进observation外壳glm.ts。扫描器在outside状态遇到tool_response时glm.ts直接清空缓冲区并停止解析——响应体是透传文本不属于模型需要生成的结构。四、规则逐条拆解与源码印证glm.md的 Rules 是本文最核心的实操约束逐条展开如下1.arg_value由正则/定界符匹配读取不是真正的 XML 解析器这是 GLM 方言与标准 XML 协议最本质的区别。原文档明确字符串值要写成原始字面文本绝不 HTML 转义——写a b而不是a amp; b/原样保留整个值体内只有自己的/arg_value闭合标签是保留的。从实现看扫描器的value状态通过this.#buffer.indexOf(ARG_VALUE_CLOSE)查找闭合定界符#consumeValueglm.ts并配合partialSuffixOverlap处理流式分块当缓冲区结尾恰好是闭合标签的前缀如/arg_val时先暂存不吐出等后续 chunk 到达再确认避免把标签碎片当作值内容流出。2. 字符串值原样、非字符串值是 JSON值收集完成后#endValueglm.ts做分派若该参数在stringArgs集合中valueRaw原样作为字符串否则交给decodeValuecoercion.ts——先trim()能JSON.parse就返回解析结果解析失败则回退为原始字符串。所以数字3、布尔值、对象、数组都要写合法 JSON而字符串参数即便包含、、也直接写原文。3. 思考块与工具调用互斥私有推理放在think…/think中绝不允许把工具调用放进think内部。扫描器在thinking状态只积累thinkingDelta事件遇到/think才回到outside#consumeOutside匹配到think时glm.ts会推入thinkingStart事件并转入思考状态期间任何tool_call都不会被识别。构造选项parseThinking: false可关闭思考解析OUTSIDE_TAGS_NO_THINKglm.ts适用于不输出思考块的模型配置。4. 按调用顺序读取响应绝不自行生成tool_response模型的职责是消费返回的观测块并继续调用或给出最终答案而不是模拟工具返回。扫描器对tool_response的处理清空缓冲区也印证了这一点该标签是系统侧资产。5. 停止序列只能跟在完整调用之后“不要先宣布再停止”——必须把整个tool_call写完整再输出停止序列然后终止。这是为了防止截断的调用块污染下一次请求的历史转录renderTranscript会把历史消息重新拼装glm.ts半截的tool_call会导致后续请求解析错乱。五、流式解析的状态机从字节流到结构化事件GLMInbandScanner是 GLM 方言的流式引擎其状态定义见 glm.tstype State outside | thinking | name | body | key | afterkey | value;状态流转的核心循环#consume按状态分派outsidefindFirstTag在OUTSIDE_TAGS中找最早出现的标签glm.ts。标签前的文本作为text事件吐出命中tool_call转入name命中think转入thinking命中tool_response清空缓冲停止。缓冲结尾若只是标签的部分前缀则用partialSuffixOverlapAny暂存thinking累积思考增量/think后推thinkingEnd事件name读取函数名定界符为换行/arg_key//tool_call中最早者创建OpenCall并推toolStart事件工具 id 由mintToolCallId生成格式ptc_时间戳36进制_计数器36进制见 coercion.tsbody / key / afterkey / value按arg_key…/arg_key、arg_value…/arg_value的序列逐步消费值内容通过toolArgDelta事件增量流出#streamValueglm.ts/tool_call后推toolEnd事件携带完整arguments与rawBlock。对外暴露的InbandScanEvent联合类型定义在 types.tstext、thinkingStart/thinkingDelta/thinkingEnd、toolStart、toolArgDelta、toolEnd。上层拿到这些事件即可逐 token 更新 UI 或累积完整参数对象。转录层的角色标签renderTranscript渲染完整历史时glm.ts使用 GLM ChatML 风格的角色标签以[gMASK]sop开头助手轮次为|assistant|观测轮次为|observation|developer角色映射为|system|其余为|user|。工具结果被collectToolResultRun合并成连续一轮rendering.ts。六、参数值自愈healing模型写错闭合标签也能救流式场景下模型经常手滑最典型的两类错误是闭合标签写错把/arg_value写成了/arg_key后面跟arg_key、/tool_call或/arg_value漏写闭合标签直接开始下一个arg_key…/arg_keyarg_value对。如果不修复当前value状态会一直吞掉后续所有参数对直到流里出现下一个/arg_value导致参数整体错位。scanValueHealglm.ts正是为此设计在值体内从每个位置开始调用matchHealSignature探测修复签名。两条修复路径glm.tswrongCloser命中/arg_key且其后容忍最多HEAL_WS_MAX 32个空白紧跟arg_key、/tool_call或/arg_value则判定前值结束于该位置resumeAt指向后续标签trimValue: falsenextKey值体内出现完整的arg_key…/arg_key键名最长HEAL_KEY_MAX 128字符后紧跟arg_value说明上一值漏了闭合值截至此处trimValue: true此时尾随空白属于语法而非值内容解析后会trimEnd。修复结果分三类heal可立即修复返回valueEnd/resumeAt、partial签名可能正在形成暂存等待后续 chunk、none不处理。这套机制保证了 GLM 方言在真实流式输出中的鲁棒性相关行为可进一步在仓库的流式相关测试如 inband-tools.test.ts、tool-argument-coercion.test.ts中验证。七、实操要点速查场景正确写法说明字符串含、、arg_valuea b/arg_value原样输出绝不 HTML 转义数字/布尔/对象/数组arg_value3/arg_value、arg_value{a:1}/arg_value必须是合法 JSON可选参数未设置直接省略该对标签不要填null或空值并行多次调用连续多个tool_call块块间无需分隔符私有推理think…/think工具调用严禁放进 think 内停止前先写完整个tool_call再停防止截断污染历史转录八、结语格式指南即协议契约oh-my-pi 把“给模型的指令”与“解析模型的代码”放在同一个 dialect 目录下glm.md 与 glm.ts 一一对应glm.md的每一条规则都能在状态机、coercion 逻辑或渲染函数中找到落点不转义对应decodeValue的 JSON 尝试、字符串参数对应stringArgs的 schema 推导、思考块隔离对应parseThinking状态切换、闭合标签修复对应scanValueHeal的自愈签名。理解了这份格式指南就同时理解了 GLM 方言在 oh-my-pi 中的完整数据通路模型按格式产出文本GLMInbandScanner将其解析为事件流工具结果再以observation观测块回灌对话。对于任何需要接入 GLM 类模型的工具调用实现这套“定界符匹配 状态机 自愈容错”的范式都具有直接的参考价值。【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门