OMP 中的 OpenAI Harmony 方言:gpt-oss 函数调用线格式与流式解析实战

OMP 中的 OpenAI Harmony 方言:gpt-oss 函数调用线格式与流式解析实战 OMP 中的 OpenAI Harmony 方言gpt-oss 函数调用线格式与流式解析实战【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-piHarmony 是 OpenAI 为其开源权重模型 gpt-oss 系列gpt-oss-20b、gpt-oss-120b训练的响应格式它定义了对话信封、多通道推理/回答分离与函数调用的线语法。本文以 oh-my-piOMP项目中实际注入系统提示词的方言指南 harmony.md 为骨架结合 harmony.ts 的流式扫描器、完整格式说明 与配套测试完整讲解 Harmony 消息格式、工具目录渲染、流式解析实现与泄漏防护读完即可读懂 OMP 的harmony方言如何把模型输出还原成标准 ToolCall也能在自己的推理循环中正确实现该格式。Harmony 是什么gpt-oss 的原生响应格式Harmony 是 OpenAI 训练其开放权重模型 gpt-oss 系列时使用的响应格式覆盖三个层面对话信封conversation envelope、多通道的推理/回答分离analysis/commentary/final以及函数调用的线上语法。不使用该格式提示模型模型将无法正常工作。它刻意模仿 OpenAIResponsesAPI 的角色、通道、接收方结构而不是更早的 Chat Completions 形态。在 OMP 中Harmony 是 factory.ts 注册的十一种方言之一glm、hermes、kimi、xml、anthropic、deepseek、minimax、harmony、qwen3、gemini、gemma。方言定义由四部分组成prompt注入系统提示词的格式指南——正是 harmony.md在 harmony.ts 中以import dialectPrompt from ./harmony.md with { type: text }的方式内联createScanner返回HarmonyInbandScanner负责把流式输出还原成结构化事件渲染函数renderToolCall、renderAssistantToolCalls、renderToolResults、renderThinking、renderTranscript元信息dialect: harmony。消息信封与三通道结构Harmony 中每条消息都是统一信封|start|{header}|message|{content}|end|{header}总是以角色开头可携带可选的接收方to...、通道channel与内容类型content-type。完整消息以|end|结束正在生成的 assistant 消息则以停止 token|return|或|call|结束。五种角色指令冲突时按systemdeveloperuserassistanttool的层级裁决角色用途system身份、知识截止/当前日期、推理强度、合法通道声明、内置工具。不是面向用户的 system prompt。developer常规的 system prompt指令 # Tools函数声明 可选结构化输出 schema。user终端用户输入。assistant模型输出。携带通道工具调用时携带接收方。tool工具执行结果。消息的作者/角色是工具自身的名字如functions.get_current_weather而不是字面量tool。三种通道仅 assistant 输出使用且每条 assistant 消息强制携带通道用途analysis原始思维链推理过程。安全要求低于final不得展示给终端用户内置python/browser调用通常也走这里。commentary函数工具调用以及多工具调用前的用户可见 前言行动计划。final面向用户的最终回答。推理强度在 system 消息中以Reasoning: high或medium/low默认medium设置。模型把 CoT 写入analysis把答案写入final。CoT 携带规则下一轮对话时仅当上一轮 assistant 以final消息结束时才丢弃先前的analysis消息如果上一轮是进行中的工具调用轮次则紧邻工具调用之前的analysis必须连同工具结果一起回喂给模型否则多步工具推理会断裂。函数调用的线格式核心格式来自 harmony.md 的 Format guide——每条函数调用是commentary通道上的一条 assistant 消息以文本形式发出指向具体函数|start|assistant|channel|commentary tofunctions.function_name|message|{arg:value}|call|接收方可能出现在role 区段或channel 区段两种写法都是合法的 Harmony解析器都接受。OMP 渲染器采用后者接收方在 channel 区段见 harmony.ts 的renderToolCall|start|assistant|channel|commentary tofunctions.get_current_weather|message|{location:San Francisco, CA}|call|部分 Harmony 序列化器会显式携带 JSON 内容类型并把接收方放在 role 区段|start|assistant tofunctions.get_current_weather|channel|commentary |constrain|json|message|{location:San Francisco, CA}|call|参数体是原始 JSON 对象可选的|constrain|json内容类型标记 JSON也是受限/文法解码的挂载点内容类型也可能是裸词如code内置工具常见。内置工具的区别只在通道与接收方通常渲染在analysis通道接收方为browser.search/browser.open/browser.find或固定的python。OMP 的取舍OMP 发出的正是第一种形式——无|constrain|标记、接收方在 channel 区段、紧凑 JSON 参数。由于 Harmony 本身不携带调用 IDOMP 在收到调用时用mintToolCallId()合成见 coercion.ts形如ptc_时间戳36进制_计数器36进制。私有推理放在analysis消息中|start|assistant|channel|analysis|message|private reasoning|end|工具结果以函数署名的消息回传指向 assistant位于commentary通道|start|functions.function_name toassistant|channel|commentary|message|verbatim tool result|end|Rules 逐条解读harmony.md 的 Rules 部分给出九条硬性约束OMP 将其整体注入系统提示词约束模型输出接收方必须是functions. 已列出的函数名。扫描器在解析头部时会剥离前缀functions.得到暴露给上层的工具名harmony.ts。正文是单个符合 schema 的 JSON 对象未设置的参数直接省略。字符串值只用普通 JSON 转义\、\\、\n绝不做 HTML 转义——写a b不写a amp; b。这是 OMP 在渲染工具调用时用stringifyJson直出 JSON 的原因。多条调用 连续的消息。Harmony 没有独立的 parallel 包装结构。可选的前言是commentary消息以|end|结尾——与analysis不同前言是给用户看的行动计划。绝不把工具调用放进analysis——工具调用必须走commentary通道。绝不用 Markdown/代码围栏包裹调用——否则扫描器会把整段当作可见文本。按调用顺序读取每条工具结果消息绝不自行发出工具结果消息——工具结果只能由宿主回填。只有在调用完整写完之后才输出停止序列——先完整写完|call|消息再停止严禁只宣布要调用工具如停在 Lets runcargo clippy却不发出|call|消息。第 9 条对应停止 token 语义|call|与|return|是仅有的两个合法生成停止 token宿主必须在两者之一处停止推理。特殊 token 与 o200k_harmony 编码所有 Harmony 控制 token 的字面形式都是|type|ASCII 竖线|U007C不能是 Unicode 变体。在o200k_harmony编码中它们是真正的单 tokeno200k_baseBPE 词表加上一块 Harmony 特殊 token不是会被 BPE 切分的文本。结构上有意义的 token 如下ID 范围来自o200k_harmonyToken原文Token ID用途\|start\|200006消息开始后紧跟头部角色、可选接收方/通道/内容类型。\|end\|200007结束一条完整消息。\|message\|200008头部 → 内容的过渡其后的所有内容直到停止/结束 token都是消息体。\|channel\|200005引入头部中的通道字段analysis/commentary/final。\|constrain\|200003在工具调用头部标记内容类型/受限解码格式如\|constrain\|json。\|return\|200002停止 token模型完成最终回答。仅解码期使用。\|call\|200012停止 token模型正在发出工具调用等待执行。同一编码块还定义了|startoftext|199998、|endoftext|199999以及 199998–200013 区间的保留槽位与一段大范围保留区|reserved_200014|…|reserved_201088|。渲染器还认识|refusal|、|untrusted|、|end_untrusted|、|meta_end|这些名字但它们不属于已提交的 gpt-oss 词表正常流量中不会出现。编码时务必把|...|当作原子特殊 token若按普通文本编码得到的 rank 不同会污染整条流。工具定义namespace functions 目录函数工具在developer消息的# Tools区块中以 TypeScript 风格namespace functions { ... }声明内置browser/python工具则声明在system消息自己的# Tools/## browser/## python标题下。渲染器把每个 JSON Schema 转成 TS 类型规则如下无参函数 →type name () any;有参函数 → 唯一参数命名为_对象类型内联type name (_: { ... }) any;返回类型恒为anydescription属性变成字段上方一行的//注释JSON Schema 的title渲染成// TITLE后接一行//空注释examples渲染成// Examples:加逐行// - value非required字段带尾部?default渲染成尾部// default: value注释enum变成a | b联合oneOf变成多行|联合JSONinteger映射为 TSnumber函数定义之间空一行区块以} // namespace functions收尾。若 developer 消息没有指令文本则省略# Instructions标题消息只剩# Tools区块。只要定义了任何函数system 消息就会获得路由行Calls to these tools must go to the commentary channel: functions.。这一渲染逻辑在仓库中有两处落点inventory.ts 的renderToolInventory调用jsonSchemaToTypeScript(toolWireSchema(tool), { style: harmony })把工具目录渲染成## functionsnamespace functions { ... }形式供 verbose system-prompt 目录与/dump共用typescript.ts 的jsonSchemaToTypeScriptstyle: harmony输出扁平约定——//行注释、,分隔符、无缩进与默认风格的 JSDoc 注释/;分隔符/缩进体区分开。渲染器发出的 developer 消息原样示例指令 三个函数|start|developer|message|# Instructions Use a friendly tone. # Tools ## functions namespace functions { // Gets the location of the user. type get_location () any; // Gets the current weather in the provided location. type get_current_weather (_: { // The city and state, e.g. San Francisco, CA location: string, format?: celsius | fahrenheit, // default: celsius }) any; // Gets the current weather in the provided list of locations. type get_multiple_weathers (_: { // List of city and state, e.g. [San Francisco, CA, New York, NY] locations: string[], format?: celsius | fahrenheit, // default: celsius }) any; } // namespace functions|end|OMP harmony 方言的渲染实现harmony.ts 定义了一组与格式指南严格对齐的渲染函数renderToolCall${START}assistant${CHANNEL}commentary to${harmonyRecipient(call.name)}${MESSAGE}${stringifyJson(call.arguments)}${CALL}——无constrain标记、接收方在 channel 区段、紧凑 JSON 参数renderAssistantToolCalls多条调用逐条拼接天然满足 多条调用 连续消息renderToolResults${START}${harmonyRecipient(result.name)} toassistant${CHANNEL}commentary${MESSAGE}${result.text}${END}——完整的规范结果头部result.text原样透传renderThinking${START}assistant${CHANNEL}analysis${MESSAGE}${text}${END}renderTranscript按消息流顺序渲染——assistant 消息依次输出完整的analysisthinking、完整的final可见文本再对每个工具调用输出一条commentary调用消息因此伴随工具调用的可见文本渲染成final而非 commentary 前言。工具结果则把连续的工具结果消息合并为逐条规范信封。harmonyRecipient定义在 rendering.ts名字已带functions.前缀则原样返回否则补上保证发送与回传两侧的接收方命名一致。流式解析HarmonyInbandScanner 状态机接收侧的核心是HarmonyInbandScanner一个三状态outside/header/body的流式扫描器暴露feed(text)与flush()两个入口harmony.ts产出InbandScanEventtext、thinkingStart/Delta/End、toolStart、toolEnd等事件类型见 types.ts。解析规则要点头部解析找到|message|后切出头部分别提取 role、channel、recipientto...正则见parseRecipient。有状态扫描器同时接受接收方出现在任一头部区段。工具调用判定任何非空且不等于assistant的接收方都被视为工具调用包括browser.search这类内置工具名字带functions.前缀则剥离。#enterBody在头部完成时立即发出toolStart事件并合成调用 ID。参数累积参数文本累积直到|call|、|end|或|return|然后用parseJsonWithRepair做 JSON 修复解析#parseArgsharmony.ts。空参数或修复后仍无法解析的输入降级为{}而不是扫描器报错。事件分派analysis消息体以thinkingDelta增量流式输出普通 assistant 的commentary/final消息体以text流式输出非 assistant 消息包括工具结果信封被跳过。边界处理feed用partialSuffixOverlapAny保留可能是不完整 token 的尾部字节避免多字节 UTF-8 或 token 在分块边界被切断复用 coercion.ts 的偏后缀重叠检测。一个与规范 Harmony 不同的所有权边界情况文档明确标注在带接收方头部到达|message|之后OMP 已经发出了toolStart如果普通流式路径把消息体字节耗尽后流在没有|call|、|end|、|return|的情况下结束flush()不会发出toolEnd也不会撤回toolStart。由于 Harmony 扫描器不产生参数增量即使看到未终止的正文文本保留的规范调用参数仍是{}。正常停止时 OMP 会把该轮改为toolUse并可能派发这个空调用——这是宽容但非安全的恢复行为不是合法的 Harmony 终止规则。扫描器在 owned-stream.ts 中被接入流式管线wrapInbandToolStream把 provider 的原始文本增量喂给扫描器遇到RESPONSE_OPEN_TOKENS[harmony]即[|start|functions.]owned-stream.ts即判定模型开始伪造工具结果在 abort 模式下立即截断轮次防止 provider 继续为幻觉输出烧 token。parseInbandToolMessage则把已完成的消息一次性投影为结构化 ToolCallrawBlock保留原文供审计。思考流修复与泄漏防护Harmony 的analysis标签同时出现在通用思考修复器的恢复列表中thinking.ts 把|start|assistant|channel|analysis|message|...|end|渲染形态与|channel|analysis|message|...|end|裸泄漏形态都识别为推理段落把模型泄漏进可见文本通道的推理修复回 thinking 事件。此外 demotion.ts 在需要降级渲染思考时对harmony方言使用think\n${text}\n/think包装。针对 gpt-5.x / gpt-oss 服务端会拒绝请求中出现的保留控制 token 拼写invalid_promptharmony-leak.ts 实现了两层防护传输层转义escapeHarmonyControlTokens把|start|、|end|等保留拼写转义为惰性反斜杠形式\|start\|让不可信数据用户文本、工具结果能作为数据到达 harmony 模型而不触发校验拒绝JSON 文档内使用escapeHarmonyControlTokensInJson双写反斜杠保持文档合法。调用方以isHarmonyDialectModel模型identity.class gpt-oss为开关且只转义传输副本持久化记录保留逐字节原文。泄漏检测与恢复detectHarmonyLeak融合多路信号——H控制 token 拼写、Mtofunctions.*标记、C通道词邻接、G故障 token如changedFiles/RTLU/Jsii_commentary/Japgolly、S脚本混杂、B正文级联、R伪结果框架。触发规则是H单独触发或M至少带一个协同信号孤立的M不触发文档与测试本身就会合法携带该标记。工具参数面tool_arg采用更严的门控只有结构合法解析边界之后的标记T信号才触发避免误杀合法的代码/数据内容。recoverHarmonyToolCall对edithashline DSL以开头与eval工具支持截断 追加*** Abort哨兵的恢复其余工具回落到 abort-and-retry由 agent 循环处理。端到端示例与轮次边界完整的天气多轮交换——system developer 提示 → 用户提问 → assistant analysis 思维链 → assistant commentary 工具调用 → 工具结果 → assistant final 回答消息在流中紧密拼接、无分隔符换行仅为可读性|start|system|message|You are ChatGPT, a large language model trained by OpenAI. Knowledge cutoff: 2024-06 Current date: 2025-06-28 Reasoning: high # Valid channels: analysis, commentary, final. Channel must be included for every message. Calls to these tools must go to the commentary channel: functions.|end||start|developer|message|# Instructions Use a friendly tone. # Tools ## functions namespace functions { // Gets the current weather in the provided location. type get_current_weather (_: { // The city and state, e.g. San Francisco, CA location: string, format?: celsius | fahrenheit, // default: celsius }) any; } // namespace functions|end||start|user|message|What is the weather like in SF?|end||start|assistant|channel|analysis|message|User wants the weather in San Francisco. Use get_current_weather.|end||start|assistant|channel|commentary tofunctions.get_current_weather|message|{location:San Francisco, CA}|call||start|functions.get_current_weather toassistant|channel|commentary|message|{sunny: true, temperature: 20}|end||start|assistant|channel|final|message|Its sunny and about 20°C in San Francisco right now.|return|轮次边界与规范化宿主在|call|处停止生成解析commentary调用执行get_current_weather追加functions.get_current_weather toassistant结果消息然后追加|start|assistant继续生成。前一条analysis消息被保留上一轮以工具调用结束而非final模型得以继续推理生成在|return|处停止。当该轮被持久化到历史供后续轮次使用时把尾部的|return|规范化为|end|保证每条存储消息都是完整的|start|{header}|message|{content}|end|监督训练目标除外训练目标以|return|结尾是正确的。部署形态原生路径与 OpenAI 兼容桥接通过 OpenAI 兼容端点服务时服务器替你处理 HarmonyOllama / LM Studio / HuggingFace内部应用 Harmony你照常发送 OpenAI 风格 JSONvLLMvllm serve openai/gpt-oss-120b --enable-auto-tool-choice --tool-call-parser openai --reasoning-parser openai_gptoss。注意工具调用解析器标志是openai不是harmonyvLLM 也通过/v1/responses端点暴露 Harmony 原生路径SGLangpython3 -m sglang.launch_server --model-path openai/gpt-oss-20b --reasoning-parser gpt-oss --tool-call-parser gpt-ossNVIDIA Dynamo 分离模式下用--dyn-tool-call-parser harmony --dyn-reasoning-parser gpt_oss。gpt-oss 权重自带的聊天模板会把标准messages/tools数组渲染成同样的 token 序列。Chat Completions JSON 映射vLLM/SGLang/Ollama 桥接时finish_reason停在|call|→tool_calls停在|return|→stopmessage.tool_calls[]每条commentarytofunctions.*调用一条function.name是去掉functions.命名空间后的接收方function.arguments是JSON 字符串|message|正文原样不是解析后的对象tool_call_idHarmony 没有原生调用 ID服务器合成一个如call_abc123并负责把后续role:tool消息关联回工具结果信封tofunctions.name/ 调用顺序工具结果消息渲染为|start|{toolname} toassistant|channel|commentary|message|{content}|end|服务器把tool_call_id映射回原始函数名以构造{toolname}作者推理analysis通道文本作为reasoning_contentvLLM/SGLang或reasoning/thinking字段暴露通常不回显final通道是正常message.content原生路径下请求的tools/tool_choice由服务器聊天模板编译进 developer 消息的namespace functions { ... }块system 消息追加 commentary 路由行。OMP 的 owned-dialect 广告路径略有不同选定harmony方言后OMP 移除 provider 原生工具改在系统提示词中追加其通用紧凑toolsJSON 目录与本文讲解的 Harmony 格式指南而不走规范的 developer 消息 namespace 作为工具广告。解析注意事项与常见坑两个停止 token|return|与|call|都要停。只停return会越过工具调用只停end对 assistant 生成是错的。接收方位置可变tofunctions.name可能在 role 区段|start|assistant to...|channel|commentary或 channel 区段|channel|commentary to...解析器必须两者都接受。通道必填assistant 消息强制携带通道system 消息甚至提醒模型Channel must be included for every message.缺通道的输出是畸形输出。工具作者名而非tool工具结果消息的角色是工具名functions.get_current_weather不是字面量tool把functions.x拆成命名空间 函数名是解析器的职责。CoT 丢弃是有条件的只有上一轮 assistant 以final结束时才丢弃analysis丢弃紧邻|call|的analysis会破坏多步工具推理。arguments是字符串不要双重编码|message|之后的正文已是序列化 JSON原样作为arguments字符串透传。内容类型变体|constrain|json是可选的出现也只表示元数据不保证 JSON 合法要用受限解码或自己的文法保证 schema 遵循对结构化输出的# Response Formats同样成立。流式解析务必使用有状态解析器让不完整 UTF-8 与 header/channel/recipient/content-type 字段增量重建朴素子串扫描会搞砸多字节切分与可选头部字段。不要把尾部停止 token 传给解析器。编码使用o200k_harmony把|...|当作原子特殊 token编码为普通文本会得到不同 rank 并破坏流。测试验证仓库测试直接印证了上述行为inband-tools.test.tsexpectRawBlock验证 harmony 工具调用完整原文|start|assistant|channel|commentary tofunctions.read|message|{path:src/a.ts}|call|parseInbandToolMessage把该原文投影为结构化ToolCallrawBlock保留原文renderToolResults输出规范的|start|functions.read toassistant|channel|commentary|message|FILE|end|harmony-leak.test.ts覆盖isHarmonyLeakMitigationTarget策略门控、负样本不得误触发含分块边界切分、正样本带协同信号必须触发、tool_arg的T信号门控以及editDSL 的*** Abort截断恢复与幂等性issue-6913-harmony-marker-escaping.test.ts 与 json-schema-typescript.test.ts 分别覆盖保留标记转义与 schema→TS含 harmony 风格渲染。综上harmony.md 既是注入模型的格式指南也是 OMPharmony方言渲染与解析两侧的共同契约渲染侧严格产出 无constrain、接收方在 channel 区段、紧凑 JSON 的第一种调用形式解析侧用有状态扫描器容错地还原工具调用、思维链与文本再配合泄漏检测与传输转义使 gpt-oss 系列模型在 OMP 的 agent 循环中可靠地完成多步工具调用。如需在自己的推理循环中集成 gpt-oss按本文的线格式、停止 token 与规范化规则实现即可若要参考 OMP 的完整落地可继续阅读 toolconv/harmony.md、harmony.ts 与 owned-stream.ts。【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考