为什么 Harmony 是成为完美的Agents的必经之路

一、前置

OpenAI前段时间开源了 gpt-oss ,我的感受是,在使用模型解决一些我现有任务上时,能力是有明显缺陷的(尤其是与qwen比较),但最让我惊喜的是伴随着它一起开源的一种“设计思想”,即 Harmony Chat Format

先按照我的视角来捋清一切的思路。

1.1 Base LLM(基础模型)

假设我训练了一个数据集仅且仅有一本《小王子》的 小王子AI基础模型(Base)。此时,作为语义因果模型的它来说,对人类最大的作用就是可以补全文本信息。

例如,像这样向 小王子AI基础模型 输入《小王子》原文中的一段话:

小王子抱歉地说:“我不是有意的。我长途跋涉,没有睡眠……”\n

理应得到输出:

“既然如此,”国王对他说,“我命令你打哈欠。我已经多年没看见别人打哈欠了。依我看,打哈欠挺好玩的。快!打吧!这是命令。”

显然,现在的 小王子AI基础模型 只是一个因训练数据受限,而能百分百准确的补全《小王子》全书的一个AI模型罢了。它不“懂”任务,只“懂”在给定上下文后,什么文本出现的概率最高。它只会补全《小王子》的原文,因为它见过的因果关系(训练数据)仅限于此。

但如果将训练数据量从一本书扩展到一万本、一个博客扩展到一万个博客、一个人的聊天记录扩展到所有人的聊天记录。那么,这个新的AI模型就是一个具有不论好坏且不论情景的所有直接或间接的来自人类创造的信息及其背后因果关系的 大模型 了。一个通用的基础大模型,就是见识过世面的、更泛化的“小王子AI”。

人类的贪心不会止于仅仅只是补全文本而已,即使“让非生物体获得从概率上模拟出因果关系的能力”已经是窃取了 造物主 的部分权柄。

基础大模型 的基础上,通过人为制造特定的数据集,变相引导这种 补全之力 流向具体的应用场景。就像是在海滩上的湿沙子处挖出一个小坑,在浪冲过来时,总会有相当程度的概率有水涌进坑中。

1.2 instruction-tuned LLM(指令遵循模型)

继续用例子演示。

现在贪心的我不满足一个小小的仅能够补全《小王子》全书的破模型了,我想要的更多!

假如我设计并准备了相当多的如下格式的数据集:

<|q|>《小王子》书中的国王是个怎样的人?<|end_q|>
<|a|>一千个读者就有一千个哈姆雷特,...(我人工省略的)<|end_a|>

将其用某种方式与 小王子AI基础模型 融合之后,就得到了 小王子AI指令模型(QA特化版本)。进化后的它从此就具备了一定的QA解答能力,但仍受限于基础训练数据/训练方法、指令训练数据/指令训练方法等诸多因素。

聪明的人类想到了通过在指令数据集中模拟角色,让模型通过学习角色分隔,从而学会了对话:

<|im_start|>system
你是小王子AI<|im_end|>
<|im_start|>user
《小王子》书中的国王是个什么样的人?<|im_end|>
<|im_start|>assistant
一千个读者就有一千个哈姆雷特,...(我人工省略的)<|im_end|>

再进一步,制造一些特殊的行为放入数据集中,使模型学会更多的本事,例如如下的 <think> XML标签:

<|im_start|>user
如果我有 3 个苹果,再买 5 个,然后送出 2 个,我一共有多少个?<|im_end|>
<|im_start|>assistant
<think>
从 3 个苹果开始
再加 5 个:3 + 5 = 8
送出 2 个:8 - 2 = 6
所以最终结果是 6 个苹果。
</think>

你将有 6 个苹果。

具体计算如下:你从 3 个苹果开始,再买 5 个(3 + 5 = 8),然后送出 2 个(8 - 2 = 6)。<|im_end|>

设计一道 思考推理环节,就像是在沙坑与海水中见挖出一道小径,水将更容易流进正确的坑中。

这种<|im_start|> 角色+文本 <|im_end|> 的格式就是大部分开源模型(比如qwen3)所使用的ChatML Chat Format。相似的还有 Alpaca、Llama3、Cohere Command R 等,在此不一一列举。

思考” 的能力就是一个经典的通过改变模型指令训练数据集,使其能够通过CoT(思维链)的方式,更好的发挥 补全之力 的例子。通过这种指令训练数据集训练出来的模型,就拥有了模拟出 “思考” 的能力。

再然后,人们根据要处理的任务种类,分别为AI赋予了:多轮对话、角色扮演(遵循系统指令)、使用工具(Function Calling / Tool Use)、复杂的思维链 等能力。模型也就从 <|q|><|a|> 这种为单一任务(问答)挖的一个 专用小沙坑 进阶为了 水渠。

这种“水渠”确实比“沙坑”强大得多,但其所有的信息,包括模型的内心独白(<think>)、与外部工具的交互(<tool_call>)、以及最终呈现给用户的答案全都混杂在同一条水渠(通道)中。开发者就像一个水利工程师,不得不在水渠的末端费力地搭建各种过滤器和分流阀,才能把“思考的泥沙”、“工具调用的工业废水”和“干净的饮用水”分离开。这种方式不仅笨拙,而且在面对需要多步骤、多工具协作的复杂任务时,整条水渠会变得愈发浑浊,难以管理和追溯。在复杂到一定程度后,甚至模型本身的指令遵循能力也会受到影响。

这就是Harmony带来的革命性变化:

它不再满足于一条单体水渠,而是成为了一套多角色、多通道的信息处理格式。

如果说 ChatML等格式 是修了一条功能强大的主干渠,那么 Harmony 就是构建了一座复杂的城市级处理中心。它从根本上接受了在面对愈来愈复杂的任务时数据格式也必须变得复杂这件事,其内部状态和外部交互是多层次、多目的的。

二、Harmony

Harmony 聊天格式 (Harmony Chat Format) 是一种专为 gpt-oss 模型设计的自定义对话格式。主要侧重于实现更高级模型代理功能、工具使用和安全控制。

2.1 从单水渠到多专用管道

Harmony 通过特殊的标记符,设计了 5个角色 (Roles)3个通道 (Channels) 来组织与模型的交互以及模型与内外部工具的交互。

5个角色 (Roles) – 建立了用于解决指令冲突的指令层级 (Instruction Hierarchy),按层级顺序排列:

  • System (系统)
  • Developer (开发者)
  • User (用户)
  • Assistant (助手)
  • Tool (工具)

通道 (Channels) – 用于标明每条消息的用途和可见范围。

  • analysis:内部思考管道。用于存放模型的思维链。这里是模型最原始、未经审查的思维草稿,可长可短。
  • commentary:工具交互管道。用于记录函数或工具调用的相关信息,包括正式调用前的引导起手式和具体的工具调用指令。它就像是连接主处理中心与其他工厂(外部API)的工业管道。
  • final:最终用户管道。用于存放最终的输出,相当于净化后可直接饮用的水。

2.2 为工业管道(commentary)安装智能阀门

例如,当模型决定调用天气查询工具时,它的输出会是这样的:

<|start|>assistant<|channel|>commentary to=functions.get_weather<|constrain|>json<|message|>{"city": "Tokyo"}<|call|>

这里的 to=functions.get_weather 清晰地表明,这条消息是 assistant 发送给 functions.get_weather 这个工具的。

而当工具执行完毕返回结果时,消息格式为这样:

<|start|>functions.get_weather to=assistant<|channel|>commentary<|message|>{"temperature": 22, "condition": "partly cloudy"}<|end|>

这里的 functions.get_weather to=assistant 表示消息从工具流回了助手。

这种设计将原本混杂在单一文本流中的交互,变成了一个清晰、可追溯的执行图谱。开发者可以精确掌握每一次信息交换的源头、目的地和内容。

甚至,我们可以将工具模型本身的前因后果在训练时就让模型记住,结合智能框架来打造近乎无缝的Agent体验。

2.3 更简洁精准的定义:Json SchemaTypeScript

Harmony带来的另一个重大革新是工具(函数)的定义方式。ChatML沿用了主流的JSON Schema格式,虽然严谨但非常冗长。Harmony则采用了类TypeScript的语法

让我们直观地对比一下:

ChatML (JSON Schema):

{
  "type": "function",
  "function": {
    "name": "get_weather",
    "description": "Get weather for a city",
    "parameters": {
      "type": "object",
      "properties": {
        "city": {"type": "string"},
        "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
      },
      "required": ["city"]
    }
  }
}

Harmony (TypeScript-style):

namespace functions {
  // Get weather for a city
  type get_weather = (_: {
    city: string,
    unit?: "celsius" | "fahrenheit", // default: celsius
  }) => any;
}

ChatML (Qwen3) 的复杂函数/工具调用链:

<|im_start|>system
# Tools

You may call one or more functions to assist with the user query.

<tools>
{"type": "function", "function": {"name": "get_weather", "description": "Get weather for a city", "parameters": {"type": "object", "properties": {"city": {"type": "string"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}}, "required": ["city"]}}}
</tools>

For each function call, return a json object within <tool_call></tool_call> XML tags.<|im_end|>
<|im_start|>user
What's the weather in Tokyo?<|im_end|>
<|im_start|>assistant
<think>
User wants Tokyo weather. Need to call get_weather function.
</think>

I'll check the current weather in Tokyo for you.

<tool_call>
{"name": "get_weather", "arguments": {"city": "Tokyo", "unit": "celsius"}}
</tool_call><|im_end|>
<|im_start|>user
<tool_response>
{"temperature": 22, "condition": "partly cloudy", "humidity": 65}
</tool_response><|im_end|>
<|im_start|>assistant
The current weather in Tokyo is 22°C with partly cloudy skies and 65% humidity.<|im_end|>

Harmony的复杂函数/工具调用链:

<|start|>developer<|message|># Tools
## functions
namespace functions {
// Get weather for a city
type get_weather = (_: {
  city: string,
  unit?: "celsius" | "fahrenheit", // default: celsius
}) => any;
} // namespace functions<|end|>
<|start|>user<|message|>What's the weather in Tokyo?<|end|>
<|start|>assistant<|channel|>commentary<|message|>I'll check the current weather in Tokyo for you.<|end|>
<|start|>assistant<|channel|>commentary to=functions.get_weather<|constrain|>json<|message|>{"city": "Tokyo", "unit": "celsius"}<|call|>
<|start|>functions.get_weather to=assistant<|channel|>commentary<|message|>{"temperature": 22, "condition": "partly cloudy", "humidity": 65}<|end|>
<|start|>assistant<|channel|>final<|message|>The current weather in Tokyo is 22°C with partly cloudy skies and 65% humidity.<|return|>

优势是显而易见的:

  • 简洁性:代码量减少了约70%,有效信息密度大幅度上升。
  • 表现力:可选参数、默认值、联合类型等在TS语法中表达得更自然。
  • LLM友好:大模型在其训练数据中见过海量的代码,对这种格式的理解和生成能力远超于繁琐的JSON Schema。

基于这种思想,我们可以启发式的思考一些更进阶的设计。

三、未来的Agent

从ChatML到Harmony的转变:

  • ChatML 依然将LLM视为一个更聪明的对话文本生成器。我们通过各种指令和标签(<think>, <tool_call>)来“哄骗”或“引导”它在一条线性的文本流中,模拟出思考和行动。
  • Harmony 则从一开始就将LLM定位为一个分布式系统的核心调度器。它不再将一切都发生在对话格式中,而是将内部思考、外部通信和最终输出分离开来,并通过一套类似计算机网络的协议(角色、通道、路由)来管理这一切。

Harmony大概率不是最终能成功的大模型指令格式,但一定是最值得尝试的一步。

对于致力于构建稳健、可扩展且可审计的Agent的企业而言,选择变得异常清晰。企业总会去寻求更优秀的解决方法。Harmony的架构带来了企业级应用最渴求的几样东西:

  1. 可观测性: 当Agent行为异常时,开发者不再需要去解析一团混乱的文本。他们可以像分析结构化日志一样,清晰地审查analysis通道的思维链、commentary通道的工具交互,迅速定位问题。这让Agent从一个神秘的“黑箱”变成了一个透明的“玻璃箱”。
  2. 可靠性与安全性: 多通道设计天然地构建了安全隔离区。analysis可以成为模型进行无限制推理的“推理沙箱”,final通道可以部署严格的安全审查,确保输出的内容是安全、合规且可靠的。
  3. 可扩展性: 真实世界的业务流程往往是并行且复杂的。Harmony的结构原生支持并发任务调度,能更从容的应对多工具、多步骤的复杂工作流,而这是ChatML的线性结构难以企及的。

留下评论

From the blog

About the author