<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>潘锦的空间 &#187; harness</title>
	<atom:link href="https://www.phppan.com/tag/harness/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sun, 13 Sep 2026 02:08:46 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>DeepSeek Harness 和 Pi 的 Agent Loop 循环结束判断架构细节解析</title>
		<link>https://www.phppan.com/2026/08/deepseek-harness-and-pi-agent-loop-end/</link>
		<comments>https://www.phppan.com/2026/08/deepseek-harness-and-pi-agent-loop-end/#comments</comments>
		<pubDate>Sun, 30 Aug 2026 05:26:34 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[架构和远方]]></category>
		<category><![CDATA[Agent]]></category>
		<category><![CDATA[Agent Loop]]></category>
		<category><![CDATA[DeepSeek]]></category>
		<category><![CDATA[DeepSeekHarness]]></category>
		<category><![CDATA[harness]]></category>

		<guid isPermaLink="false">https://www.phppan.com/?p=2533</guid>
		<description><![CDATA[本篇文章代码基线采用 DeepSeek Harness 版本 0.1.2-alpha.1，提交时间为 2026 [&#8230;]]]></description>
				<content:encoded><![CDATA[<section id="nice" data-tool="mdnice编辑器" data-website="https://www.mdnice.com">
<p data-tool="mdnice编辑器">本篇文章代码基线采用 DeepSeek Harness 版本 <code>0.1.2-alpha.1</code>，提交时间为 2026 年 8 月 28 日；Pi 采用 <code>853a80d2</code>。这里的 Pi 指 <code>pi-agent-core</code> 中的官方 Agent Loop。</p>
<p data-tool="mdnice编辑器">就循环究竟在什么时刻结束这个问题，很多 Agent 框架把结束判断写成一个条件：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs"><span class="hljs-keyword">while</span> (hasToolCalls) {
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p data-tool="mdnice编辑器">在 Demo 中这种循环也够用。进入生产环境后，你会发现会很多问题：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>模型没有调用工具，是否代表任务完成？</section>
</li>
<li>
<section>工具执行完了，模型是否还需要解释结果？</section>
</li>
<li>
<section>用户在工具执行期间发来 steering，应该进入当前轮还是下一轮？</section>
</li>
<li>
<section>输出触达 token 上限后，工具参数还能不能执行？</section>
</li>
<li>
<section>某个工具宣布任务完成，其他并行工具怎么办？</section>
</li>
<li>
<section>Agent 进入 idle 后，Goal Driver 能不能再次唤醒它？</section>
</li>
<li>
<section>Plan mode 退出，是结束当前循环，还是切换下一次请求的策略？</section>
</li>
<li>
<section>进程崩溃后，日志里尚未闭合的 turn 应当如何解释？</section>
</li>
</ul>
<p data-tool="mdnice编辑器">DeepSeek Harness 和 Pi 的工程路线不同，或者说 DeepSeek Harness 更复杂，也更能满足复杂场景的需求。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 将结束拆成多层状态，并把事件日志作为重建依据。Pi 保留了更扁平的循环结构，把 steering、follow-up 和 post-turn stop 暴露成回调。前者适合多插件、持久恢复和长期任务；后者适合轻量嵌入，控制路径也更容易读懂。</p>
<p data-tool="mdnice编辑器">两种实现都能工作。它们承担的系统复杂度不同，结束语义自然不会相同。</p>
<h1 data-tool="mdnice编辑器"><span class="content">五层边界</span></h1>
<p data-tool="mdnice编辑器">讨论 Agent Loop 时，我们需要先定义好「结束」，否则代码里的 <code>completed</code>、<code>turn_end</code>、<code>agent_end</code> 很容易被混为一谈。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 实际存在五层边界。</p>
<p data-tool="mdnice编辑器">第一层是模型请求结束。</p>
<p data-tool="mdnice编辑器">Provider 流式输出完成，可能给出正常停止、工具调用、最大 token、错误或取消。这里的判断逻辑是：当前 HTTP 请求或模型流结束了吗？</p>
<p data-tool="mdnice编辑器">第二层是 step 结束。</p>
<p data-tool="mdnice编辑器">一个 step 包含一次模型调用，以及该响应发起的一整批工具执行。工具执行结束后，step 才算关闭。模型若调用了普通工具，系统通常还欠一次模型回访，因此 step 结束不代表 turn 结束。</p>
<p data-tool="mdnice编辑器">第三层是 turn 结束。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 中，一个 turn 可以包含多个 step，大概如下：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">用户输入
→ 模型调用
→ 工具批次
→ 模型回访
→ 工具批次
→ 模型最终输出
</code></pre>
<p data-tool="mdnice编辑器">以上为一个 turn。turn 结束需要同时满足两项条件：</p>
<ol data-tool="mdnice编辑器">
<li>
<section>模型不再欠一次回复；</section>
</li>
<li>
<section><code>next-step</code> inbox 没有待处理输入。</section>
</li>
</ol>
<p data-tool="mdnice编辑器">第四层是 driver activity 结束。</p>
<p data-tool="mdnice编辑器">一个 driver 可以连续处理多个 turn。当前 turn 关闭后，如果 inbox 里还有普通 follow-up，driver 会直接打开下一 turn。只有队列耗尽，driver 才回到 idle。</p>
<p data-tool="mdnice编辑器">第五层是长期工作流结束。</p>
<p data-tool="mdnice编辑器">Goal Driver 可以监听 idle，检查持久 Goal 状态，再调用 <code>followup()</code> 开启新 turn。Plan mode 也可能跨越多个 turn 持续生效。因此，idle 只描述当前 activity；它无法回答长期目标是否完成。</p>
<p data-tool="mdnice编辑器">Pi 的层级少一些。一次 assistant 响应与随后执行的工具批次，会对应一个 <code>turn_end</code>。工具回访模型时，Pi 再开启下一次 turn。内部队列耗尽后发出 <code>agent_end</code>，当前 invocation 至此结束。</p>
<p data-tool="mdnice编辑器">从语义上看：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>DeepSeek Harness 的 step 接近 Pi 的 turn；</section>
</li>
<li>
<section>DeepSeek Harness 的一次 driver activity 接近 Pi 的一次 Agent Loop invocation；</section>
</li>
<li>
<section>DeepSeek Harness 的 Goal Round 位于 driver activity 外层；</section>
</li>
<li>
<section>Pi 的长期 Goal 通常由宿主或扩展继续调度。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">术语相似，粒度相差一层。如果日志消费端忽略这一点，统计出的 turn 数、工具往返次数和任务完成率都会失真。</p>
<h1 data-tool="mdnice编辑器"><span class="content">驱动收敛</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 的入口：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs"><span class="hljs-keyword">while</span> (<span class="hljs-keyword">await</span> <span class="hljs-keyword">this</span>.turn()) {
}
</code></pre>
<p data-tool="mdnice编辑器"><code>turn()</code> 返回 <code>true</code>，driver 继续处理下一 turn；返回 <code>false</code>，driver 收敛；抛出异常时，异常会被 driver 边界容纳，随后进入 idle。</p>
<p data-tool="mdnice编辑器">短代码背后有一套完整的 phase 状态机：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">idle
maintenance
running
</code></pre>
<p data-tool="mdnice编辑器"><code>running</code> 保存：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>当前 turn；</section>
</li>
<li>
<section>当前 step；</section>
</li>
<li>
<section><code>AbortController</code>；</section>
</li>
<li>
<section><code>wakeRequested</code>。</section>
</li>
</ul>
<p data-tool="mdnice编辑器"><code>maintenance</code> 同样持有取消信号和唤醒锁存，只是对外状态仍显示为 idle。这种设计解决了一个经常被忽略的竞态：Agent 处于维护任务时收到新消息，新消息不能立即启动第二个 driver，也不能静默丢失。系统先将唤醒意图锁存，维护结束后检查 inbox，再决定是否重启。</p>
<p data-tool="mdnice编辑器">取消路径也有类似处理。</p>
<p data-tool="mdnice编辑器">如果一个 waking input 到达时，现有 activity 已经被 abort，这条消息会被重分类到 <code>next-turn</code>。它不能加入一个正在收敛的旧 turn。<code>send()</code> 在插入 inbox 前读取 aborted 状态，避免 inbox observer 触发重入取消后改变分类结果。</p>
<p data-tool="mdnice编辑器">这段细节很像传统并发状态机，而不是常见的聊天循环。它处理的是输入归属问题：一条消息必须属于当前 step、下一 step 或下一 turn，重入事件不能改变已经作出的边界判断。</p>
<p data-tool="mdnice编辑器"><code>whenIdle()</code> 也没有简单等待某个固定 Promise。它反复比较 <code>activityDone</code>：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs"><span class="hljs-keyword">do</span> {
  <span class="hljs-keyword">await</span> (activity = <span class="hljs-keyword">this</span>.activityDone)
} <span class="hljs-keyword">while</span> (activity !== <span class="hljs-keyword">this</span>.activityDone)
</code></pre>
<p data-tool="mdnice编辑器">等待期间如果 activity 被新的 driver 替换，调用方会继续等待。否则 <code>whenIdle()</code> 可能在旧 driver 结束、新 driver 已经启动的窗口里提前返回。</p>
<p data-tool="mdnice编辑器">在多插件环境中，idle 是一个可观察状态，也是一种同步承诺。这个承诺需要覆盖重启竞态，不能只看某次异步任务是否 resolve。</p>
<h1 data-tool="mdnice编辑器"><span class="content">Turn 状态机</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 在领取输入之前写入 <code>turn/start</code>。</p>
<p data-tool="mdnice编辑器">pre-step 可能拒绝输入，系统提示组装可能抛错，首步消息也可能被插件改写为空。无论发生哪种情况，日志中都存在一个完整 turn，并由唯一的 <code>turn/end</code> 收口。</p>
<p data-tool="mdnice编辑器">turn 内部维护两个变量：</p>
<ul data-tool="mdnice编辑器">
<li>
<section><code>turnEnds</code>：当前已知的结束原因；</section>
</li>
<li>
<section><code>target</code>：本轮 pre-step 应领取 <code>next-turn</code> 还是 <code>next-step</code>。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">第一个 step 从 <code>next-turn</code> 开始。后续 step 转向 <code>next-step</code>。普通用户 prompt 因此拥有独立 turn，工具附加上下文、运行时 context 和 steering 则可以进入当前 turn 的下一 step。</p>
<p data-tool="mdnice编辑器">一次循环大致经历以下过程：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">创建 step 编号
→ 从 inbox 领取消息
→ 组装系统提示和运行时 context
→ 执行 agent/pre-step
→ 记录 step/start
→ 写入 user/message
→ 调用模型并执行工具
→ 记录 step/end
→ 判断是否继续
</code></pre>
<p data-tool="mdnice编辑器">如果 <code>agent/pre-step</code> 返回 <code>reject</code>，turn 以 <code>blocked</code> 结束，模型不会被调用。</p>
<p data-tool="mdnice编辑器">如果首个 step 的消息为空，turn 以 <code>completed</code> 结束，也不会消耗模型请求。这覆盖了一个边缘场景：wakeup 已经打开 turn，随后消息被移除，或者 pre-step 插件把消息改写为空。边界既然已经建立，日志仍需闭合。</p>
<p data-tool="mdnice编辑器">如果某个 step 已经产生结束结果，但下一次 pre-step 没有消息，循环退出。若仍有消息，就继续执行。</p>
<p data-tool="mdnice编辑器">这里需要留意 <code>turnEnds</code> 与 <code>stepEnd</code> 的关系。<code>step()</code> 可以返回：</p>
<ul data-tool="mdnice编辑器">
<li>
<section><code>completed</code>；</section>
</li>
<li>
<section><code>max-tokens</code>；</section>
</li>
<li>
<section><code>null</code>。</section>
</li>
</ul>
<p data-tool="mdnice编辑器"><code>null</code> 表示工具执行完毕，模型还欠一次回复。它是继续循环的协议状态，和错误、未知结果没有关系。</p>
<p data-tool="mdnice编辑器">turn 的结束判断由「模型债务」与「消息债务」共同决定。模型债务来自 tool call，消息债务来自 inbox。只检查其中一项都会出错。</p>
<h1 data-tool="mdnice编辑器"><span class="content">停止钩子</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 在 turn 准备收口时触发 <code>agent/turn-stopping</code>。</p>
<p data-tool="mdnice编辑器">这个扩展点没有返回 <code>true</code> 或 <code>false</code>。插件如果希望 turn 继续，需要向 <code>next-step</code> 写入消息。hook 执行完成后，核心循环重新检查 inbox：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">turn 已经可以结束
→ next-step 为空
→ 触发 agent/turn-stopping
→ 再次检查 next-step
→ 为空则关闭
→ 非空则进入下一 step
</code></pre>
<p data-tool="mdnice编辑器">这是数据驱动的方式。</p>
<p data-tool="mdnice编辑器">多个插件都能监听 stopping。如果采用 <code>shouldContinue(): boolean</code>，组合规则会立刻变得棘手：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>任意插件返回 true 就继续？</section>
</li>
<li>
<section>所有插件都返回 true 才继续？</section>
</li>
<li>
<section>后执行的插件能否覆盖先执行的结果？</section>
</li>
<li>
<section>插件决定继续，却没有提供下一步输入，模型该看到什么？</section>
</li>
<li>
<section>插件决定停止，但另一个插件已经排入 steering，谁的优先级更高？</section>
</li>
</ul>
<p data-tool="mdnice编辑器">DeepSeek Harness 用 inbox 消除了大部分布尔值合并问题（这个设计和 Golang 的竞态处理逻辑类似，使用类似消息队列来处理竞态）。继续执行必须产生一条可消费的数据。最终判定依赖队列状态，而非插件调用顺序。</p>
<p data-tool="mdnice编辑器">当然，这也是需要代价的。</p>
<p data-tool="mdnice编辑器">插件作者需要理解 inbox target、turn 边界和 wakeup 语义。一个简单的「再跑一次」操作，需要构造 <code>UserMessage</code> 并写入正确队列。框架学习成本高于直接回调。</p>
<p data-tool="mdnice编辑器">这种成本在单体应用里可能显得繁琐。进入可恢复、多插件、可审计系统后，显式消息通常比隐式布尔控制更可靠。日志和调试工具能看到「为什么继续」，而不是只看到某个 hook 曾经返回 true。</p>
<h1 data-tool="mdnice编辑器"><span class="content">Step 债务</span></h1>
<p data-tool="mdnice编辑器"><code>step()</code> 最关键的职责，是判断模型是否还欠一次回复。</p>
<p data-tool="mdnice编辑器">模型流结束后，<code>BlockAssembler</code> 给出 finish 状态。如果 finish 是 error 或 aborted，系统先触发 <code>agent/request-error</code> waterfall。插件可以选择 retry。没有 retry 动作时，代码抛出结构化 <code>LlmError</code>。</p>
<p data-tool="mdnice编辑器">正常组装出 assistant message 后，判断顺序如下：</p>
<ol data-tool="mdnice编辑器">
<li>
<section>finish 为 <code>max-tokens</code>，返回 <code>max-tokens</code>；</section>
</li>
<li>
<section>没有 tool call，返回 <code>completed</code>；</section>
</li>
<li>
<section>存在 tool call，执行整批工具；</section>
</li>
<li>
<section>工具批次声明 concluded，返回 <code>completed</code>；</section>
</li>
<li>
<section>普通工具批次返回 <code>null</code>。</section>
</li>
</ol>
<p data-tool="mdnice编辑器">顺序不能随便改。</p>
<p data-tool="mdnice编辑器">最大 token 状态在工具解析之前返回，因此响应中即使出现 tool call，也不会被执行。截断输出可能包含不完整的 JSON 参数。某些流式解析器会尝试补全 JSON，补全后甚至能通过 schema 验证，但语义字段可能已经缺失。执行这类调用会产生真实副作用。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 的选择偏保守：整轮以 <code>max-tokens</code> 收口，等待外部策略决定是否继续。</p>
<p data-tool="mdnice编辑器">Pi 采用另一种处理。<code>stopReason === "length"</code> 且消息包含工具调用时，它会给所有工具生成错误结果，说明参数可能被截断，没有实际执行，然后把这些结果交回模型。模型有机会在下一 turn 重发完整调用。</p>
<p data-tool="mdnice编辑器">两者的恢复能力不同。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 保留了清晰的 durable turn reason，运维侧能准确识别 token ceiling。自动继续需要 Goal Driver、用户输入或其他插件参与。Pi 更倾向在当前 invocation 内自我修复，模型可能马上重发工具调用。</p>
<p data-tool="mdnice编辑器">我在具有写操作的 Agent 中会选择 DeepSeek Harness 的策略。达到输出上限本身意味着模型状态不完整，自动延续可能重复前一批操作。只读研究型 Agent 可以采用 Pi 的方式，失败工具结果能减少一次人工干预。</p>
<h1 data-tool="mdnice编辑器"><span class="content">粘性结果</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 的 <code>max-tokens</code> 具有粘性。</p>
<p data-tool="mdnice编辑器">某个 step 达到上限后，插件仍可能在 <code>turn-stopping</code> 阶段补入 steering，让 turn 再执行几个 step。后续 step 即使正常完成，最终 <code>turn/end</code> 仍然保留 <code>max-tokens</code>。</p>
<p data-tool="mdnice编辑器">判断逻辑是：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs"><span class="hljs-keyword">if</span> (
  turnEnds === <span class="hljs-literal">null</span> ||
  turnEnds.kind !== <span class="hljs-string">'max-tokens'</span>
)
  turnEnds = stepEnd
</code></pre>
<p data-tool="mdnice编辑器">这里记录的是整个 turn 的质量，而非最后一次 step 的结果。</p>
<p data-tool="mdnice编辑器">如果不做粘性处理，可能产生如下日志：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">step 1: max-tokens
step 2: 插件要求继续
step 3: completed
turn/end: completed
</code></pre>
<p data-tool="mdnice编辑器">消费端会丢失曾经发生的截断。监控系统无法统计 token ceiling，Goal Driver 也可能把这轮当成完整成功并继续自动调度。</p>
<p data-tool="mdnice编辑器">把 turn reason 视为聚合结果后，合并规则就需要专门设计。DeepSeek Harness 当前只对 <code>max-tokens</code> 做了优先保留。错误和取消会直接离开主流程，不参与后续合并。</p>
<p data-tool="mdnice编辑器">如果未来加入诸如 <code>partial</code>、<code>policy-warning</code>、<code>budget-exhausted</code> 等状态，简单覆盖会越来越脆弱。更稳妥的方向是为 reason 建立显式优先级或累积 facts，再由投影层生成最终 reason。当前 union 规模尚小，现有实现足够清楚。</p>
<h1 data-tool="mdnice编辑器"><span class="content">工具收口</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 允许工具通过结果上的 <code>concludesTurn</code> 宣布当前 turn 可以收口。</p>
<p data-tool="mdnice编辑器">工具批次采用 OR 聚合：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">任意一个已提交结果 concludesTurn === true
→ 整批 concluded === true
</code></pre>
<p data-tool="mdnice编辑器">它表达的是「模型默认不再欠一次工具结果回访」。</p>
<p data-tool="mdnice编辑器"><code>concludesTurn</code> 没有直接打断同批工具，也没有清空 <code>next-step</code>：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>已启动的并行工具继续运行；</section>
</li>
<li>
<section>结果按模型调用顺序提交；</section>
</li>
<li>
<section><code>additionalContexts</code> 写入 <code>next-step</code>；</section>
</li>
<li>
<section>同期到达的 steering 也写入 <code>next-step</code>；</section>
</li>
<li>
<section>只要 <code>next-step</code> 非空，turn 仍会进入下一 step。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">因此，工具结束能力属于软收口。它取消了自动回访债务，无法压过已经存在的消息债务。</p>
<p data-tool="mdnice编辑器">这套语义适合权威型工具。例如某个交互工具已经取得用户最终决定，或者某个提交工具已经完成不可逆事务，模型没有必要再生成一段中间解释。工具可以建议收口，同时保留系统上下文和用户 steering 的优先级。</p>
<p data-tool="mdnice编辑器">Pi 的工具终止采用 AND 聚合：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs"><span class="hljs-keyword">return</span> finalizedCalls.length &gt; <span class="hljs-number">0</span> &amp;&amp;
  finalizedCalls.every(
    <span class="hljs-function"><span class="hljs-params">finalized</span> =&gt;</span> finalized.result.terminate === <span class="hljs-literal">true</span>
  )
</code></pre>
<p data-tool="mdnice编辑器">只有非空批次中的每个 finalized result 都带有 <code>terminate: true</code>，整批才终止。</p>
<p data-tool="mdnice编辑器">并行批次中，一个工具不应单方面吞掉其他工具结果。Pi 要求整批达成一致，语义更保守。DeepSeek Harness 允许一个权威工具宣布收口，扩展能力更强，也更依赖工具契约。</p>
<p data-tool="mdnice编辑器">选择 OR 还是 AND，取决于 <code>terminate</code> 的业务含义。</p>
<p data-tool="mdnice编辑器">如果它代表「任一工具发现全局终止条件」，OR 合理，比如用户取消、权限拒绝、事务已完成。</p>
<p data-tool="mdnice编辑器">如果它代表「当前工具不需要模型处理自己的结果」，AND 更稳妥，因为其他工具可能仍需模型解释。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 通过 <code>next-step</code> 上下文缓和了 OR 的侵略性，但无法覆盖所有情况。假设两个并行工具都成功，一个写数据库并 concludes，另一个返回一份需要模型分析的报告，又没有追加 context。模型回访会被跳过。工具注册规范需要限制哪些工具可以 conclude，不能把它当成普通便利字段。</p>
<h1 data-tool="mdnice编辑器"><span class="content">顺序提交</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 的工具调度器还有一项容易被忽略的约束：执行可以并行，提交保持模型顺序。</p>
<p data-tool="mdnice编辑器">调度器维护：</p>
<ul data-tool="mdnice编辑器">
<li>
<section><code>nextToStart</code>；</section>
</li>
<li>
<section><code>started</code>；</section>
</li>
<li>
<section><code>committed</code>；</section>
</li>
<li>
<section><code>inFlight</code>；</section>
</li>
<li>
<section>按调用位置排列的 <code>slots</code>。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">并行工具完成时，只把结果放入对应 slot。<code>commitReady()</code> 从 <code>committed</code> 开始，连续提交已经就绪的结果。后面的工具先完成，也要等待前面的 slot。</p>
<p data-tool="mdnice编辑器">这会增加尾部等待时间，但能保证：</p>
<ul data-tool="mdnice编辑器">
<li>
<section><code>tool/result</code> 顺序稳定；</section>
</li>
<li>
<section>additional context 顺序稳定；</section>
</li>
<li>
<section>replay 结果稳定；</section>
</li>
<li>
<section>插件观察顺序稳定；</section>
</li>
<li>
<section>同一模型响应在多次运行中的日志结构更一致。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">模型生成了 A、B、C 三个调用。若 C 最先完成，直接提交 C 会让后续上下文受网络时序影响。对于事件溯源系统，这类非确定性会扩大恢复和测试成本。</p>
<p data-tool="mdnice编辑器">Pi 的并行执行也使用 <code>Promise.all</code> 保留输入数组顺序，最终 tool result message 按原调用顺序发出。两套系统都接受并行执行带来的延迟收益，同时拒绝完成时序污染模型上下文。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 额外支持动态重分类。并行池补充新任务前，会重新读取工具当前 execution mode。前一个工具可能修改注册表，使后续工具从 parallel 变成 exclusive。调度器会停止补充，等待当前池排空，再把 exclusive call 留给下一个 barrier。</p>
<p data-tool="mdnice编辑器">这种灵活性会增加 scheduler 状态数量。适合「工具本身能改变工具环境」的 Harness。工具目录完全静态时，预先分组会更简单。</p>
<h1 data-tool="mdnice编辑器"><span class="content">取消语义</span></h1>
<p data-tool="mdnice编辑器">工具执行期间的取消，比模型流取消复杂得多。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 的原则可以概括成三条：</p>
<ol data-tool="mdnice编辑器">
<li>
<section>停止补充尚未启动的调用；</section>
</li>
<li>
<section>清空已经启动的调用；</section>
</li>
<li>
<section>为因取消而跳过的工具写入合成错误结果。</section>
</li>
</ol>
<p data-tool="mdnice编辑器">已启动工具可能已经产生副作用，框架不能假装它没有运行。调度器等待这些调用 settle，并按模型顺序提交结果和 additional contexts。</p>
<p data-tool="mdnice编辑器">未启动工具则写入一对完整事件：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">tool/call
tool/result(error: aborted before dispatch)
</code></pre>
<p data-tool="mdnice编辑器">这样可以维持模型工具协议的配对关系。恢复和 replay 时，每个模型产生的 tool call 都有对应结果。</p>
<p data-tool="mdnice编辑器">内部 scheduler failure 的处理更克制。它停止新 dispatch，等待已经启动的调用结束，然后抛出第一个失败。它不会为剩余调用伪造结果。因为 scheduler failure 与用户取消不同，系统无法确认未提交调用处于什么语义状态。伪造恢复结果可能掩盖调度器缺陷。</p>
<p data-tool="mdnice编辑器">这里体现出事件日志的核心要求：日志不只服务 UI，它还是恢复协议。任何 synthetic event 都需要有确定语义。为了让数组长度好看而补事件，会污染后续决策。</p>
<p data-tool="mdnice编辑器">Pi 的实现更偏运行时事件流。工具执行异常会被转换成 error tool result，随后继续进入上下文。取消时顺序模式会在每次工具后检查 signal，平行模式也会停止准备后续调用。它的核心目标是把本次 invocation 的 message stream 完整交给调用方，持久日志的闭合约束没有 DeepSeek Harness 那么强。</p>
<h1 data-tool="mdnice编辑器"><span class="content">原因体系</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 的 <code>TurnEndReason</code> 包含六种核心结果：</p>
<ul data-tool="mdnice编辑器">
<li>
<section><code>completed</code>；</section>
</li>
<li>
<section><code>blocked</code>；</section>
</li>
<li>
<section><code>max-tokens</code>；</section>
</li>
<li>
<section><code>aborted</code>；</section>
</li>
<li>
<section><code>error</code>；</section>
</li>
<li>
<section><code>interrupted</code>。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">这些状态回答的是整个 turn 如何结束。</p>
<p data-tool="mdnice编辑器"><code>completed</code> 覆盖正常文本停止、工具要求收口，以及首步为空。它不承诺长期 Goal 完成。</p>
<p data-tool="mdnice编辑器"><code>blocked</code> 来自 pre-step reject。输入可能已经被 inbox 领取，但策略层拒绝进入模型调用。driver 当前会停止，其他尚未领取的普通 prompt 可以继续留在队列。</p>
<p data-tool="mdnice编辑器"><code>max-tokens</code> 表示至少一个 step 达到输出上限。它保留为 turn 级质量信号。</p>
<p data-tool="mdnice编辑器"><code>aborted</code> 携带取消原因，包括 user、parent、hook 和 disposed。持久导入还可能出现 legacy cause。</p>
<p data-tool="mdnice编辑器"><code>error</code> 保存结构化 <code>LlmFailure</code>。<code>LlmError</code> 的信息原样保留，其他异常会被压平为 <code>errorChain</code> 文本，并使用 <code>UNKNOWN</code> code。</p>
<p data-tool="mdnice编辑器"><code>interrupted</code> 由持久化恢复层产生。进程崩溃后，后端发现一个开放 turn，会用该状态闭合。live loop 不会主动写入它。</p>
<p data-tool="mdnice编辑器">把 crash repair 与 runtime abort 分开很有必要。abort 表示程序收到了取消请求，并有机会执行清理；interrupted 表示生命周期突然消失。两者对副作用审计、重试决策和用户提示都有不同含义。</p>
<p data-tool="mdnice编辑器">Pi 主要保留 assistant message 的 <code>stopReason</code>：</p>
<ul data-tool="mdnice编辑器">
<li>
<section><code>stop</code>；</section>
</li>
<li>
<section><code>length</code>；</section>
</li>
<li>
<section><code>toolUse</code>；</section>
</li>
<li>
<section><code>error</code>；</section>
</li>
<li>
<section><code>aborted</code>。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">它更接近最后一次模型调用的结束事实。DeepSeek Harness 的 reason 聚合了多 step turn 的结果。一个字段偏 provider，一个字段偏业务生命周期。</p>
<p data-tool="mdnice编辑器">从监控角度看，Pi 的 stopReason 更利于分析模型行为；DeepSeek Harness 的 turn reason 更利于分析任务执行。生产系统通常两类数据都需要。DeepSeek Harness 通过 <code>assistant/message</code>、request events 和 <code>turn/end</code> 同时保留两层事实，日志体积也会更大。</p>
<h1 data-tool="mdnice编辑器"><span class="content">Goal 外循环</span></h1>
<p data-tool="mdnice编辑器">长期 Goal 无法靠核心 turn 的 <code>completed</code> 判断。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 采用外围 Round Driver。它监听 Agent 进入 idle，然后检查：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>Agent 实例是否仍然有效；</section>
</li>
<li>
<section>inbox 是否存在竞争中的普通 prompt；</section>
</li>
<li>
<section>Goal 是否存在；</section>
</li>
<li>
<section>Goal phase 是否为 active；</section>
</li>
<li>
<section>当前 activation 是否 armed；</section>
</li>
<li>
<section>已启动 round 数是否低于上限。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">满足条件后，Driver 构造一条来源为 goal 的 user message，并调用 <code>agent.followup()</code>。新消息进入 <code>next-turn</code>，打开全新的 turn。</p>
<p data-tool="mdnice编辑器">时序如下：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">turn/end(completed)
→ agent/status: idle
→ Goal Driver 读取持久状态
→ flush
→ followup(goal round)
→ turn/start
</code></pre>
<p data-tool="mdnice编辑器">这种结构给每个 Goal Round 一个完整、独立、可恢复的生命周期。进程在两个 Round 之间退出，恢复时可以从最后一个闭合 turn 继续判断。一个覆盖几十轮的巨大 while 会让持久化边界、用户抢占和异常恢复都更困难。</p>
<p data-tool="mdnice编辑器">Goal 还维护 phase 与 activation 两组状态。</p>
<p data-tool="mdnice编辑器">持久 phase 描述业务状态：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>active；</section>
</li>
<li>
<section>complete；</section>
</li>
<li>
<section>blocked；</section>
</li>
<li>
<section>paused。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">进程内 activation 描述自动续行授权：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>armed；</section>
</li>
<li>
<section>disarmed。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">把两者拆开可以处理 resume 和 fork。一个持久 Goal 仍然 active，不代表新进程应该自动继续消耗预算。恢复后的 active Goal 默认 disarmed，需要人类再次授权。否则某次服务重启可能让多个历史任务同时复活。</p>
<p data-tool="mdnice编辑器">达到最大 Round 数时，Goal 会进入 blocked，并记录 round-limit。<code>max-tokens</code>、Agent error、flush failure、driver failure 会 disarm。取消路径也会 pause 或 disarm，防止 idle 后被 Goal Driver 再次拉起。</p>
<p data-tool="mdnice编辑器">这里采用了 fail-closed 策略。长期自治任务遇到状态不确定时停止续行。对成本敏感、有写权限的 Agent，这是合理默认值。自动重试可以放在更高层，由持久预算和幂等策略约束。</p>
<h1 data-tool="mdnice编辑器"><span class="content">Goal 收尾</span></h1>
<p data-tool="mdnice编辑器">Goal 状态改为 complete 或 blocked 后，当前 turn 通常还会再调用一次模型。</p>
<p data-tool="mdnice编辑器"><code>update_goal</code> 工具会修改持久状态，并通过 deferred context 注入收尾指令。工具结果与 <code>&lt;goal_complete&gt;</code> 或 <code>&lt;goal_blocked&gt;</code> context 进入下一 step，模型生成最终面向用户的说明。之后 turn 以 completed 结束。Agent 进入 idle，Goal Driver 读取到非 active phase，不再唤醒。</p>
<p data-tool="mdnice编辑器">这解决了状态完成与用户可见输出之间的时间差。</p>
<p data-tool="mdnice编辑器">如果 <code>update_goal(complete)</code> 直接 conclude turn，持久状态已经完成，用户界面可能只看到工具卡片，没有自然语言总结。若让模型先写总结再更新状态，模型或进程可能在总结期间失败，Goal 又会保持 active。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 先提交状态，再执行展示收尾。恢复时即便缺少最终文本，Goal 也不会重复工作。用户体验层可以根据 complete 状态补一条提示，或者提供重新生成总结的操作。</p>
<p data-tool="mdnice编辑器">代价是 complete 后多一次模型调用，也会增加少量 token 和延迟。我认为这笔成本合理。长期任务的最终输出属于交付结果，不能依赖 UI 猜测工具状态。</p>
<h1 data-tool="mdnice编辑器"><span class="content">Pi 双循环</span></h1>
<p data-tool="mdnice编辑器">Pi 的 <code>runLoop()</code> 使用内外两层循环。</p>
<p data-tool="mdnice编辑器">内层条件为：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">hasMoreToolCalls || pendingMessages.length &gt; 0
</code></pre>
<p data-tool="mdnice编辑器">它处理工具回访和 steering。外层负责 Agent 本来要停止时的 follow-up。</p>
<p data-tool="mdnice编辑器">一次内层迭代包括：</p>
<pre class="custom" data-tool="mdnice编辑器"><code class="hljs">prepareNextTurn
→ 处理 pending steering
→ 调用模型
→ 执行工具
→ 发出 turn_end
→ shouldStopAfterTurn
→ 拉取新的 steering
</code></pre>
<p data-tool="mdnice编辑器">内层耗尽后，系统调用 <code>getFollowUpMessages()</code>。存在 follow-up 时，将它们设置为 pending，重新进入内层。没有 follow-up 时发出 <code>agent_end</code>。</p>
<p data-tool="mdnice编辑器">Pi 提供三个高杠杆控制点：</p>
<ul data-tool="mdnice编辑器">
<li>
<section><code>getSteeringMessages()</code>；</section>
</li>
<li>
<section><code>getFollowUpMessages()</code>；</section>
</li>
<li>
<section><code>shouldStopAfterTurn()</code>。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">这套接口很适合嵌入应用。</p>
<p data-tool="mdnice编辑器">steering 处理当前 activity 内的即时干预；follow-up 处理 Agent 自然收口后的补充工作；shouldStopAfterTurn 提供宿主级截停。扩展作者不需要理解持久 inbox，也不需要创建新的状态投影。</p>
<p data-tool="mdnice编辑器">复杂度被交给宿主。多个扩展共同提供 follow-up 时，需要上层决定合并方式。进程恢复后，回调内部的临时状态如何重建，也由应用实现。若不同扩展分别定义 Goal、Plan 和审批流程，结束语义会逐渐碎片化。</p>
<p data-tool="mdnice编辑器">Pi core 的目标是提供一个小而可组合的运行时。它没有承诺统一的长期任务协议。这个边界和 DeepSeek Harness 的产品定位并不相同。</p>
<h1 data-tool="mdnice编辑器"><span class="content">失败路径</span></h1>
<p data-tool="mdnice编辑器">Pi 遇到 assistant <code>error</code> 或 <code>aborted</code> 时，会发出 <code>turn_end</code> 和 <code>agent_end</code>，然后结束当前 invocation。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 会先区分流 finish error、显式 abort 和普通异常。</p>
<p data-tool="mdnice编辑器">请求错误可以进入 <code>agent/request-error</code> waterfall。插件能够依据 provider、failure、retry policy 和 signal 决定 retry。重试发生在同一个 step 内，重新创建 assembler，再发一次请求。外部 turn 和 step 边界保持不变。</p>
<p data-tool="mdnice编辑器">这种设计使日志更紧凑，但需要谨慎处理重复请求。前一次失败若已经在 provider 侧产生计费，session 中可能只有请求重试后的最终 assistant message。底层观测系统需要独立记录 attempt，不能只靠 conversation event log 统计模型调用次数。</p>
<p data-tool="mdnice编辑器">Pi 通常由 stream implementation 或上层配置承担 retry。Agent Loop 接收到的 final message 已经带有 stopReason。职责划分更轻，调用方也更容易替换模型层。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 将 request header、adapter defaults、request context 和 conversation surface 都纳入 session 语义，retry 与恢复自然更靠近 loop。架构更重，换来统一的请求重建能力。</p>
<h1 data-tool="mdnice编辑器"><span class="content">请求序列</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 每次构建请求时都会比较当前 header 与 session 中的 baseline。</p>
<p data-tool="mdnice编辑器">header 包含：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>provider 和 model；</section>
</li>
<li>
<section>reasoning effort、max tokens 等调用配置；</section>
</li>
<li>
<section>adapter materialized defaults；</section>
</li>
<li>
<section>system prompt；</section>
</li>
<li>
<section>tool schemas。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">首个 header 记录为 initial 或 resume。配置变化时记录 change。显式开始新消息序列或 surface replacement 后，会记录 series。</p>
<p data-tool="mdnice编辑器">结束判断和 request series 没有直接控制关系，但它影响「同一个上下文连续体」的解释。Goal 的自动 Round 可以标记 <code>startsRequestSeries: true</code>，让每轮长期任务拥有独立请求序列。缓存、展示和重放层因此能识别边界。</p>
<p data-tool="mdnice编辑器">如果只依靠 turn start 判断新序列，会把工具回访、用户 follow-up、Goal Round 和 compaction 后续请求全部归入一种语义。DeepSeek Harness 单独记录 series，是在为后续缓存和重建保留信息。</p>
<p data-tool="mdnice编辑器">成本是日志事件更多，header equality 与 canonicalization 也必须稳定。工具 schema 排序、空字段处理或 adapter defaults 若不规范，可能制造大量无意义 change 事件。代码使用 canonical header 和 deep freeze，正是在控制这种漂移。</p>
<h1 data-tool="mdnice编辑器"><span class="content">日志消费</span></h1>
<p data-tool="mdnice编辑器">消费 DeepSeek Harness 日志时，先问清业务方想判断哪一层结束。</p>
<p data-tool="mdnice编辑器">判断一次模型调用完成，应读取 step 内的 assistant message、stream finish 和 usage。</p>
<p data-tool="mdnice编辑器">判断 turn 是否闭合，应寻找配对的 <code>turn/start</code> 与 <code>turn/end</code>。只有 assistant message 不够。pre-step reject、空 turn、异常和 crash repair 都可能产生不同结构。</p>
<p data-tool="mdnice编辑器">判断当前 Agent 是否暂无活动，应读取 status 或等待 <code>whenIdle()</code>。最后一条 turn/end 仍不足以证明 idle，因为 driver 可能已经打开下一 turn。</p>
<p data-tool="mdnice编辑器">判断长期 Goal 是否结束，应读取 Goal phase。complete、blocked 和 paused 都会停止自动 Round，业务含义各不相同。</p>
<p data-tool="mdnice编辑器">判断 Plan 是否退出，应读取最新 <code>plan/mode.active</code>。看到 <code>exit_plan_mode</code> 调用，只能说明模型提出了退出请求。审批可能被拒绝，pending intent 也可能尚未在 pre-step 提交。</p>
<p data-tool="mdnice编辑器">判断会话以后是否还会运行，需要观察 Agent 是否 disposed、是否从 registry 移除，以及外围 scheduler 是否仍能发送消息。idle 和 completed 都没有永久性。</p>
<p data-tool="mdnice编辑器">Pi 的消费方式更简单：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>assistant <code>stopReason</code> 描述模型调用；</section>
</li>
<li>
<section><code>turn_end</code> 描述一次模型与工具批次；</section>
</li>
<li>
<section><code>agent_end</code> 描述当前 invocation；</section>
</li>
<li>
<section>Goal、Plan 和工作流完成度读取具体扩展状态。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">即使已经收到 <code>agent_end</code>，宿主仍然可以再次调用 Agent Loop。它同样不具备永久终止含义。</p>
<h1 data-tool="mdnice编辑器"><span class="content">工程取舍</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 为结束判断支付了较高复杂度。</p>
<p data-tool="mdnice编辑器">它需要：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>phase 状态机；</section>
</li>
<li>
<section>inbox 分类；</section>
</li>
<li>
<section>wake latch；</section>
</li>
<li>
<section>平衡的 turn 和 step 事件；</section>
</li>
<li>
<section>surface projection；</section>
</li>
<li>
<section>request header 重建；</section>
</li>
<li>
<section>crash repair；</section>
</li>
<li>
<section>Goal activation；</section>
</li>
<li>
<section>Plan boundary intent；</section>
</li>
<li>
<section>有序工具提交。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">这些机制会增加代码量、测试矩阵和插件开发门槛。一个简单聊天产品采用全套设计，投入可能超过收益。</p>
<p data-tool="mdnice编辑器">它适合以下场景：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>会话需要跨进程恢复；</section>
</li>
<li>
<section>Agent 拥有高风险工具；</section>
</li>
<li>
<section>多个插件会同时 steering；</section>
</li>
<li>
<section>需要长期 Goal 与预算控制；</section>
</li>
<li>
<section>日志需要审计和 replay；</section>
</li>
<li>
<section>Plan、审批和执行必须跨边界保持一致；</section>
</li>
<li>
<section>子 Agent 和父 Agent 存在取消传播。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">Pi 的循环更适合：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>单次 invocation 生命周期清晰；</section>
</li>
<li>
<section>宿主已经拥有自己的持久化层；</section>
</li>
<li>
<section>扩展数量有限；</section>
</li>
<li>
<section>工作流由应用统一控制；</section>
</li>
<li>
<section>希望快速接入多模型与工具；</section>
</li>
<li>
<section>对 session event vocabulary 没有强约束。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">Pi 的小核心减少了框架内部状态。业务一旦开始增加 Goal、审批、自动 follow-up、并发工具策略、恢复和预算，宿主会逐步补齐类似机制。复杂度没有消失，只是落在不同层。</p>
<p data-tool="mdnice编辑器">团队选择框架时，不应只比较 Agent Loop 文件有多少行。要看系统准备把「继续运行的权力」放在哪里。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 把权力分散给模型 finish、工具结果、inbox、生命周期 hook 和外围持久状态机，并通过事件日志协调。Pi 把权力集中在当前循环和几个宿主回调中，扩展层可以自行定义更高层协议。</p>
<h1 data-tool="mdnice编辑器"><span class="content">设计建议</span></h1>
<p data-tool="mdnice编辑器">如果我们团队要自行实现 Agent Loop，我会保留以下原则。</p>
<p data-tool="mdnice编辑器">第一，区分模型结束、工具批次结束、用户 turn 结束和长期任务结束。类型和事件名也要分开，避免一个 <code>done</code> 字段横跨所有层级。</p>
<p data-tool="mdnice编辑器">第二，继续执行需要携带数据。插件要求再跑一轮时，应提交 steering 或 follow-up message。单独返回布尔值会让调试和组合越来越困难。</p>
<p data-tool="mdnice编辑器">第三，工具调用后的模型回访应被建模为债务。普通工具结果产生一次回复债务，conclude 或 terminate 可以消除债务，steering 又会重新增加消息债务。用这套视角设计状态机，比堆叠 <code>if (hasToolCalls)</code> 更稳定。</p>
<p data-tool="mdnice编辑器">第四，最大 token 需要独立结果，且不要执行疑似截断的工具参数。自动修复可以存在，但必须显式记录恢复过程。</p>
<p data-tool="mdnice编辑器">第五，并行工具允许乱序完成，持久结果应按模型顺序提交。除非协议明确支持乱序 tool result，否则不要让网络时序改变上下文。</p>
<p data-tool="mdnice编辑器">第六，取消必须区分已启动与未启动调用。已启动工具要排空或记录未知结果，未启动工具需要完整的 synthetic result，具体选择取决于日志协议。</p>
<p data-tool="mdnice编辑器">第七，idle 不能充当长期完成信号。Goal phase、workflow state 和 Agent lifecycle 应拥有独立状态。</p>
<p data-tool="mdnice编辑器">第八，模式切换要提交在请求边界。Plan、权限、模型路由和工具目录的变化，都不应在一个已开始的请求批次中途生效。</p>
<p data-tool="mdnice编辑器">第九，恢复后的自动续行默认关闭。长期 Agent 会消耗资金，也可能修改外部系统。新进程接管旧任务时，应重新取得授权或租约。</p>
<p data-tool="mdnice编辑器">第十，结束原因需要兼顾机器消费。<code>completed</code>、<code>blocked</code>、<code>max-tokens</code>、<code>aborted</code>、<code>error</code>、<code>interrupted</code> 这类结构化 union，比一段自然语言错误更适合监控、重试和审计。</p>
<h1 data-tool="mdnice编辑器"><span class="content">架构落点</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 把结束判断分布在四个控制面上。</p>
<p data-tool="mdnice编辑器">模型输出控制 step：还有没有工具回访债务。</p>
<p data-tool="mdnice编辑器">inbox 控制 turn：还有没有当前轮待处理消息。</p>
<p data-tool="mdnice编辑器">driver 控制 activity：队列耗尽后是否进入 idle。</p>
<p data-tool="mdnice编辑器">Goal 与 Plan 控制工作流：idle 后是否开启新 Round，下一请求采用哪种策略。</p>
<p data-tool="mdnice编辑器">Pi 将更多判断放在同一个运行循环里。工具调用和 pending steering 驱动内层循环，follow-up 驱动外层循环，<code>shouldStopAfterTurn</code> 提供宿主截停点，队列耗尽后发出 <code>agent_end</code>。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 更接近一个事件溯源的 Agent Runtime。Pi 更接近一个可嵌入的 Agent 执行内核。</p>
<p data-tool="mdnice编辑器">评价两者没啥意义，我们需要关注的是其系统边界。</p>
<p data-tool="mdnice编辑器">如果产品只需要一次 prompt 驱动的工具循环，Pi 的结构更容易维护。若产品已经出现跨轮 Goal、审批、恢复、多插件 steering 和高风险工具，DeepSeek Harness 的分层会减少后期协议冲突。</p>
<p data-tool="mdnice编辑器">Agent Loop 最难处理的部分，从来都不是让模型继续调用工具。真正消耗工程时间的是：它为什么继续、谁允许它继续、失败后还能不能继续、恢复后应不应该继续，以及日志能否解释它曾经做过的每一次选择。</p>
<p data-tool="mdnice编辑器">以上。</p>
</section>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2026/08/deepseek-harness-and-pi-agent-loop-end/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DeepSeek Harness 的 Cordis 插件架构</title>
		<link>https://www.phppan.com/2026/08/deepseek-harness-cordis/</link>
		<comments>https://www.phppan.com/2026/08/deepseek-harness-cordis/#comments</comments>
		<pubDate>Sun, 23 Aug 2026 03:36:05 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[架构和远方]]></category>
		<category><![CDATA[Agent]]></category>
		<category><![CDATA[Agent Harness]]></category>
		<category><![CDATA[AIAgent架构]]></category>
		<category><![CDATA[DeepSeek]]></category>
		<category><![CDATA[DeepSeekHarness]]></category>
		<category><![CDATA[harness]]></category>

		<guid isPermaLink="false">https://www.phppan.com/?p=2531</guid>
		<description><![CDATA[DeepSeek Harness 把模型、工具、会话、沙箱、文件系统、Agent 循环、调度和 UI 都交给插 [&#8230;]]]></description>
				<content:encoded><![CDATA[<section id="nice" style="color: #000000;" data-tool="mdnice编辑器" data-website="https://www.mdnice.com">
<p data-tool="mdnice编辑器">DeepSeek Harness 把模型、工具、会话、沙箱、文件系统、Agent 循环、调度和 UI 都交给插件。</p>
<p data-tool="mdnice编辑器">系统没有一块承载业务能力的固定内核，Cordis 只维护上下文、服务注册、事件分发、依赖激活和副作用回收；Agent 能做什么，由启动时挂入的一棵插件树决定。</p>
<p data-tool="mdnice编辑器">传统的插件有注册容易，撤销困难；初始化容易，失败回滚困难；全局单例容易，局部覆盖困难等问题，而 Cordis 把这些困难收进了运行时语义，Harness 再用 session、agent 和 preset 的业务约束补齐它。</p>
<p data-tool="mdnice编辑器">今天聊了一下 DeepSeek Harness 的核心 Cordis 架构以及 Cordis 所谓「时空可组合」，究竟怎样落到代码里，又为何适合 Agent Harness 这类持续变化的运行时。</p>
<h1 data-tool="mdnice编辑器"><span class="content">插件的历史</span></h1>
<p data-tool="mdnice编辑器">插件架构的历史并不短。Eclipse 在二十多年前已经把 IDE 拆成插件、扩展点和扩展，宿主声明可扩展位置，其他插件通过清单贡献菜单、编辑器和处理逻辑。</p>
<p data-tool="mdnice编辑器">OSGi 更进一步，给 bundle 配置安装、启动、停止、更新和卸载生命周期，再通过共享服务注册表完成发布、查找和绑定。服务离开注册表时，依赖方必须跟着处理动态变化。</p>
<p data-tool="mdnice编辑器">今天看 Cordis，能找到这些设计的清晰痕迹：动态服务、生命周期、注册表、声明式依赖、事件通知都已有成熟先例。</p>
<p data-tool="mdnice编辑器">Cordis 没有发明插件系统。</p>
<p data-tool="mdnice编辑器">它简化并重新组合了这些概念，让它们适合 TypeScript 应用内的细粒度组装。OSGi 的部署单元是 bundle，模块、生命周期、服务和安全各有一层；Cordis 的执行单元是 Fiber，一个函数或一个 <code style="color: #ef7060;">Service</code> 子类就能成为插件。Eclipse 的扩展点通常由宿主定义结构化清单，Cordis 让服务和类型化事件直接成为扩展面。Agent 运行时里的工具、提示词片段、模型适配器和审批策略变化频繁，如果每次扩展都要引入重量级模块边界，团队很快会绕过框架，重新写回几个全局数组。</p>
<p data-tool="mdnice编辑器">Cordis 官方仓库把自己定位为「Meta-Framework of Spatiotemporal Composability」。</p>
<p data-tool="mdnice编辑器">从源码看，「元框架」表示它不规定 Agent、Web 服务或机器人该有什么组件，只提供构造框架所需的基础语义。DeepSeek Harness 在其上定义 <code style="color: #ef7060;">sessions</code>、<code style="color: #ef7060;">tools</code>、<code style="color: #ef7060;">llm</code>、<code style="color: #ef7060;">agents</code> 等服务，又用这些服务组装产品。Cordis 与 Harness 的关系更接近运行时机制和领域框架，而非通用插件平台与插件集合。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 还把 Cordis 源码直接放进 <code style="color: #ef7060;">vendor/</code>，固定在明确的上游提交，并将包名重映射到 <code style="color: #ef7060;">@deepseek-ai</code> 命名空间。</p>
<p data-tool="mdnice编辑器">项目维护的本地修改包含 Fiber 重入卸载加固、配置更新事务、HMR 精确监听、延迟配置解析等。这增加了维护成本，也换来了框架层的可审计性。Agent 能执行 Shell、修改文件、访问网络，插件生命周期出错会留下进程、监听器、终端模式或权限状态。</p>
<p data-tool="mdnice编辑器">此时依赖一个本地的代码白盒，会让人放心一些。</p>
<h1 data-tool="mdnice编辑器"><span class="content">调用链路图</span></h1>
<p data-tool="mdnice编辑器">简单的调用图如下所示：</p>
<figure data-tool="mdnice编辑器"><img src="https://files.mdnice.com/user/36365/c8ef3798-50e3-40a7-810e-c68c5f71ca03.png" alt="" /></figure>
<h1 data-tool="mdnice编辑器"><span class="content">最小内核</span></h1>
<p data-tool="mdnice编辑器">Cordis 的根对象是 <code style="color: #ef7060;">Context</code>。它同时承担依赖容器、插件挂载入口和事件入口。</p>
<p data-tool="mdnice编辑器">服务通过稳定名称出现在 <code style="color: #ef7060;">ctx</code> 上，例如 <code style="color: #ef7060;">ctx.tools</code>、<code style="color: #ef7060;">ctx.llm</code>、<code style="color: #ef7060;">ctx.sessions</code>。插件声明 <code style="color: #ef7060;">inject</code> 后，Cordis 只有在所需服务可用时才激活它；服务消失，依赖插件也会进入卸载或等待状态。配置文件中条目的先后顺序因此不承担启动顺序，依赖关系才承担。</p>
<p data-tool="mdnice编辑器">这种处理解决了传统插件系统的第一个顽疾：隐含初始化顺序。</p>
<p data-tool="mdnice编辑器">常见实现会遍历插件数组，依次调用 <code style="color: #ef7060;">init</code>。当工具依赖文件系统、文件系统依赖沙箱、UI 又依赖会话时，数组顺序就变成一套没有类型、没有诊断的依赖图。后来插入一个插件，顺序约束可能跨越几十个文件。</p>
<p data-tool="mdnice编辑器">Cordis 把需求写进 <code style="color: #ef7060;">inject</code>，Fiber 会为每项依赖保存当前实现；缺少依赖时保持 <code style="color: #ef7060;">PENDING</code>，依赖齐备后进入 <code style="color: #ef7060;">LOADING</code> 和 <code style="color: #ef7060;">ACTIVE</code>。启动失败则进入 <code style="color: #ef7060;">FAILED</code>。状态机至少让故障有了准确位置。</p>
<p data-tool="mdnice编辑器"><code style="color: #ef7060;">Context</code> 还是一个代理对象。</p>
<p data-tool="mdnice编辑器">插件直接读取 <code style="color: #ef7060;">ctx.tools</code> 时，反射层会检查它是否声明过依赖，并沿 Fiber 父链解析实现。未声明就读取会抛错；声明了但当前上下文不可用，也会抛出另一类错误。这种约束防止依赖藏在任意函数深处。源码里依然提供 <code style="color: #ef7060;">ctx.get(name)</code> 读取可选服务，区别在于调用方显式接受服务可能不存在。</p>
<p data-tool="mdnice编辑器">这里的「服务定义、服务提供方、消费方」三种角色被完整建模。比如文件系统能力不能只写一个接口，也不能只挂一个本地实现。定义方稳定调用协议，提供方接入本地目录或远程沙箱，消费方把能力变成模型可见工具。Harness 把这组关系称为 capability seam。替换沙箱时，Shell、PTY、LSP 只要依赖同一能力面，就能整体迁移到新的执行环境，消费方无需知道提供方运行在本机还是远端。</p>
<p data-tool="mdnice编辑器">「一切皆插件」有一个前提是：一切产品能力皆由插件贡献，Cordis 自身仍保留插件得以存在的机制。上下文代理、Fiber 状态机、服务存储、事件总线和 Loader 属于元层。</p>
<p data-tool="mdnice编辑器">这并不是系统里没有内核，更准确的说，应该是，内核不拥有模型、工具和循环等产品特权。</p>
<h1 data-tool="mdnice编辑器"><span class="content">空间组合</span></h1>
<p data-tool="mdnice编辑器">同一个进程里，服务名称必须稳定，实例又不能全局唯一。两个 Agent 可能选择不同模型、不同工具集、不同 persona 和不同沙箱。如果 <code style="color: #ef7060;">ctx.llm</code> 永远指向一个全局对象，插件替换只发生在进程级，无法满足多会话并存。</p>
<p data-tool="mdnice编辑器">Cordis 的 <code style="color: #ef7060;">Context.isolate</code> 为指定服务名创建一个 realm 标签。服务注册和查找都以该标签定位，同名服务可以在不同子上下文里各自存在。两个 <code style="color: #ef7060;">isolate</code> 调用传入同一标签时会加入同一 realm；使用新标签时彼此隔离。子上下文通过原型继承父上下文，隔离映射按层遮蔽，因此局部配置不需要复制整棵容器。</p>
<p data-tool="mdnice编辑器">这解释了「空间可组合」的第一层：组合具有位置。插件挂在哪个上下文，决定它提供的服务、注册的监听器和持有的副作用在哪个范围可见。传统依赖注入容器也有 singleton、request、session 等 scope，Cordis 的差异在于作用域与插件树、事件过滤、资源所有权使用同一个 Context 表达。开发者无需在四套 API 之间同步身份。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 又增加了 <code style="color: #ef7060;">dsh-scope</code>。它用不透明对象作为 scope key，维护父子关系，并创建带路由身份的事件 receiver。注册视图沿父链向下继承：Agent 能看到所属 preset 的提示词和工具。事件则沿链向上接纳：preset 级监听器能收到其下 Agent 的事件，兄弟 Agent 互不串线。这是第二层空间结构，解决的是领域身份，而非单个服务名的 realm。</p>
<p data-tool="mdnice编辑器">为何需要两层？<code style="color: #ef7060;">isolate</code> 处理「哪个 <code style="color: #ef7060;">tools</code> 服务实例」，<code style="color: #ef7060;">dsh-scope</code> 处理「同一工具注册表里，哪些注册项对当前 Agent 可见」。前者适合替换提供方，后者适合对注册内容分层。把所有差异都做成独立服务实例，会放大内存和初始化成本；把所有差异都塞进一个全局注册表，又会让过滤规则散落在调用点。这两层模型把实例隔离和内容路由分开了。</p>
<p data-tool="mdnice编辑器">Agent preset 是空间组合的完整应用。一个 preset 的 Cordis 配置会挂在一个长期存在的 scope 下，Agent 创建时把自己的 scope key 绑定到该 preset。相同 preset 的并发首次使用通过 single-flight 共享一次挂载，后续 Agent 复用这份组合。文件变化后，新会话加入新一代组合，已有会话保留原来的代际。这个策略避免会话运行中途突然更换工具或提示词，代价是旧代际要保留到整棵运行时退出，配置频繁变化时内存会按代际增长。</p>
<p data-tool="mdnice编辑器">源码还专门审计 preset 子树是否把服务发布到了 root realm。发生这种泄漏时，第二个会话挂载同一 preset 会与第一个冲突，所谓会话级组合也会退化成进程全局状态。DeepSeek Harness 在发布 Agent 前拒绝这种配置。空间隔离若只靠约定，迟早会被一个没有 <code style="color: #ef7060;">isolate</code> 的 provider 穿透；运行时审计比文档警告可靠。</p>
<p data-tool="mdnice编辑器">这套空间模型存在认知成本。插件作者要同时理解 Context 父链、服务 realm、业务 scope 父链和事件过滤方向（当然，在当前 Vibe Coding 盛行的时代，也可以作者不理解，直接让 AI 来搞）。</p>
<p data-tool="mdnice编辑器">在认知不清楚的时候，常见的错误往往表现为某项能力「看不见」或意外泄漏，类型系统无法证明运行时挂载位置。DeepSeek Harness 用 preset 挂载审计、包级 invariant 和真实组合测试降低风险，却没有消除模型复杂度。团队若只需要单进程单 Agent，直接引入整套空间语义会显得过重。</p>
<h1 data-tool="mdnice编辑器"><span class="content">时间组合</span></h1>
<p data-tool="mdnice编辑器">插件能挂载只是静态组合。运行期间服务上线、配置改变、插件失败或上下文销毁，系统还要回到一致状态。Cordis 用 Fiber 和 effect 管理这条时间轴。</p>
<p data-tool="mdnice编辑器">每次插件应用都会产生一个 Fiber。Fiber 记录父上下文、原始配置、解析后配置、依赖实现快照、生命周期状态和 disposables。插件调用 <code style="color: #ef7060;">ctx.effect()</code> 注册副作用，effect 的执行结果返回 disposer。事件监听、服务提供、子插件和访问器最终都进入这套所有权体系。Fiber 卸载时按注册的逆序执行清理，并等待异步清理达到静止状态。</p>
<p data-tool="mdnice编辑器">逆序本身不是一个特别要讲的事情，因为这是必须的。</p>
<p data-tool="mdnice编辑器">若插件先启动子进程，再注册输出监听，最后暴露服务，销毁时应先撤销服务，停止新请求，再移除监听，最后结束进程。资源创建顺序的反向通常就是依赖安全的拆卸顺序。</p>
<p data-tool="mdnice编辑器">传统插件常给出一个 <code style="color: #ef7060;">deactivate()</code> 钩子，把所有清理责任推给作者；漏掉一个定时器或事件监听，热加载几次便出现重复执行。Cordis 让每次注册同时产生撤销动作，框架持有所有权。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 的 vendor 版本进一步处理了重入场景：effect 在执行 setup 前先登记所有者包装；插件发布事件时，观察者可能同步卸载它；异步 cleanup 已经开始后，其他调用者仍能等待同一次清理；Fiber 处于 <code style="color: #ef7060;">UNLOADING</code> 时拒绝创建新 effect。这些代码看起来全是繁琐的边界处理，但为了保证生命周期并发的安全，一个都不能少。否则插件的热卸载就只是个玩具，没法真正落地。</p>
<p data-tool="mdnice编辑器">依赖变化也属于时间组合。某个服务被提供后，反射层通知所有声明该依赖的 Fiber 重新检查；条件满足便激活。服务撤销后，依赖方会卸载并回到等待。OSGi 早已采用动态服务注册表，Cordis 的新意主要在于把动态依赖、作用域上下文和 effect 所有权压进一个很小的进程内模型。代价同样继承自 OSGi：任何持有服务引用越过生命周期的代码，都可能在提供方撤销后继续调用过期对象。Cordis 保存加载时的实现快照，却无法替业务代码管理逃逸引用。</p>
<p data-tool="mdnice编辑器">Loader 把时间组合延伸到配置。DeepSeek Harness 的 profile 由多层 bundle patch 叠加：基础 bundle、模式 bundle、profile patch、home patch、命令行 overlay。patch 按 id 定位条目，配置采用整块替换。整块替换要求用户重述保留字段，使用上稍显笨重，却避免深度合并规则在数组、表达式和删除语义上制造歧义。</p>
<p data-tool="mdnice编辑器">配置热更新时，Loader 先导入候选插件，再卸载旧实例并应用候选；候选失败会恢复旧插件或旧配置。Group 对一批子条目并发启动，收集全部结果，只要一项失败就删除新增项并重建旧配置。Include 读取候选文件、在副本上应用 patch、完成树协调后才提交缓存。用户 patch 语法错误或新插件启动失败时，最后一棵可用树继续运行。</p>
<p data-tool="mdnice编辑器">这已经接近配置事务，却不能等同于数据库事务。</p>
<p data-tool="mdnice编辑器">插件 effect 可能调用外部 API、创建远端资源、发送消息；disposer 只能做补偿，无法保证外部世界回滚。Loader 能保证自己管理的树和服务注册恢复，无法撤回所有不可逆副作用。插件开发规范仍要限制初始化期行为，把外部写入延迟到真正的业务请求，或者设计幂等键和补偿路径。</p>
<p data-tool="mdnice编辑器">时间组合还带来可观的测试面积。挂载成功只是第一条路径，还要覆盖依赖晚到、依赖撤销、初始化失败、卸载重入、异步清理、热更新失败、回滚再次失败。DeepSeek Harness 要求注册项证明 disposal，产品可见插件还要通过真实 Loader 组合测试。这个成本无法靠框架消失，只能被框架集中暴露。相比线上出现幽灵监听器和半更新状态，还是愿意支付这部分测试费用。</p>
<h1 data-tool="mdnice编辑器"><span class="content">事件契约</span></h1>
<p data-tool="mdnice编辑器">插件之间只靠服务调用，会把所有扩展都变成接口方法。宿主每增加一项策略，就要修改服务定义。Cordis 同时提供类型化事件，并区分 <code style="color: #ef7060;">emit</code>、<code style="color: #ef7060;">parallel</code>、<code style="color: #ef7060;">serial</code>、<code style="color: #ef7060;">bail</code> 和 <code style="color: #ef7060;">waterfall</code>。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 最依赖的是 waterfall。它的监听器拿到 <code style="color: #ef7060;">next</code>，调用后把控制权交给下一层，不调用就截断链条。模型请求、工具执行和轮次控制都能被插件包裹。审批策略可以在工具执行前拒绝，重试插件可以包围模型流，日志插件可以观察前后状态。它与 Koa 一类中间件链相似，但事件名和 Context 过滤让同一个分发器覆盖多个能力域。</p>
<p data-tool="mdnice编辑器">waterfall 也最容易出错。一个只想记录日志的监听器忘记调用 <code style="color: #ef7060;">next()</code>，整条能力链便被短路。DeepSeek Harness 把「必须调用 <code style="color: #ef7060;">next()</code>」写进项目级规则，并在事件文档里记录 dispatch mode。类型能保证参数，却很难保证 continuation 一定执行。代码评审和组合测试仍是主要防线。</p>
<p data-tool="mdnice编辑器">事件的持久性也被刻意分层。<code style="color: #ef7060;">agent/*</code> 和 <code style="color: #ef7060;">tools/*</code> 事件用于活跃运行时的拦截；会话事件追加到日志，承担恢复、fork、UI 回放和模型历史投影。DeepSeek Harness 规定「模型可见即已记录」：进入模型请求的输入必须能从 session log 重建。插件若偷偷修改 prompt 却不产生会话事实，重放结果会漂移，问题也无法审计。</p>
<p data-tool="mdnice编辑器">这条约束说明，一切皆插件并不意味着一切皆事件。直接能力调用放进 Service，策略和拦截放进实时事件，需要持久化的事实进入 session log。三类通信各自承担调用、扩展和历史。将它们混成一个全局 event bus，短期代码更少，长期会失去时序语义和数据权威。</p>
<h1 data-tool="mdnice编辑器"><span class="content">Agent 适配</span></h1>
<p data-tool="mdnice编辑器">Agent Harness 比普通 Web 服务更需要动态组合。模型供应商会变，工具权限随工作区变化，子 Agent 的执行环境可能与父 Agent 不同，UI 还要消费同一份流式过程。如果主循环直接 import 每个能力，任何替换都会改循环；循环逐渐成为依赖最多、风险最高的文件。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 的默认 agent loop 仍然存在，但它也是一个服务提供方。循环读取 session log 生成历史，组装插件贡献的 prompt 和 tool schema，通过 <code style="color: #ef7060;">agent/request</code> 进入模型适配器，再经过工具流水线记录结果。扩展点围绕步骤、请求、工具和停止阶段布置。新功能通常挂到这些事件或注册表，项目规则甚至要求修改 agent loop 时同步更新架构文档。</p>
<p data-tool="mdnice编辑器">我赞成这种限制。循环承担控制流，频繁承载产品策略后会迅速腐化。压缩上下文、重试、审批、工具超时、计划模式、子 Agent 调度都可以有自己的生命周期与配置。它们进入循环的接口必须少且稳定。插件化不会自动获得解耦，真正起作用的是 DeepSeek Harness 为能力选择了明确的 seam，并拒绝消费方特有逻辑污染定义层。</p>
<p data-tool="mdnice编辑器">UI 作为插件也有实际意义。Web 和 headless profile 在共享 base bundle 上增加不同条目，后者可以完全不启动服务器。UI 驱动 <code style="color: #ef7060;">ctx.agents</code>，订阅 <code style="color: #ef7060;">session/event</code> 渲染状态，没必要成为循环的一部分。服务端、CLI、ACP 和浏览器界面可以共享会话及 Agent 语义，同时保留自己的传输和展示逻辑。</p>
<p data-tool="mdnice编辑器">插件树还提供自省基础。Fiber 保留名称、状态、依赖和 effect 元数据，DeepSeek Harness 能实现查看、挂载、卸载自身插件的能力。对 Agent 而言，这比普通应用更敏感：模型可以通过工具改变运行时，错误配置可能直接扩大权限。源码中的 sandbox 和 approval 仍是独立能力，插件架构没有天然安全性。自修改必须受工具权限、配置校验和作用域审计约束。</p>
<h1 data-tool="mdnice编辑器"><span class="content">架构代价</span></h1>
<p data-tool="mdnice编辑器">第一项代价是启动与运行时开销。每个插件产生 Fiber，服务访问经过 Proxy 和反射解析，事件分发要执行作用域过滤，注册项还要保存 disposer 与诊断元数据。对于 LLM Agent，单次模型请求通常以百毫秒到秒计，这些 JavaScript 调度开销很难成为主要瓶颈；高频 token chunk、文件扫描或终端字节流若全部穿过通用事件总线，成本会被放大。DeepSeek Harness 把流式模型输出定义为能力语义，但大量数据处理仍应留在具体 provider 内，事件只承载必要扩展点。</p>
<p data-tool="mdnice编辑器">第二项代价是故障面扩大。插件初始化可以同步抛错、异步拒绝、等待缺失服务，也可能在 disposer 中失败。Group 并发启动缩短时间，却会带来多个兄弟同时失败的 AggregateError。DeepSeek Harness 的 boot 会等待 Loader 结算，审计所有启用条目是否加载与激活，失败时先 dispose 部分构造的上下文，再退出。少做任何一步，都可能让终端停留在 raw mode，或者让后台 watcher 继续运行。</p>
<p data-tool="mdnice编辑器">第三项代价是配置成为编程接口。<code style="color: #ef7060;">cordis.yml</code> 支持 <code style="color: #ef7060;">!!js</code> 表达式，条目可以按环境禁用，配置会在依赖激活后求值。灵活性很高，静态分析能力随之下降。表达式读取服务时，求值时机与上下文位置都会影响结果。DeepSeek Harness 只允许 <code style="color: #ef7060;">config</code> 和 <code style="color: #ef7060;">disabled</code> 使用插值，其他元数据保持字面量，并让错误尽早暴露。这仍要求运维人员理解插件依赖和 patch 覆盖语义，配置文件已经超出普通 YAML 参数表的复杂度。</p>
<p data-tool="mdnice编辑器">第四项代价是生态兼容。Cordis 的服务名和事件类型提供了源码级协议，插件版本升级仍可能修改配置、事件 payload 或生命周期假设。DeepSeek Harness 目前处于预发布阶段，仓库规则允许直接拒绝旧磁盘格式，也没有承诺 session 格式兼容。现在的可组合性主要服务于同一发行版内的替换和扩展，尚不能推导出跨版本插件 ABI 稳定。</p>
<p data-tool="mdnice编辑器">第五项代价是组织治理。一切都能成为插件后，团队容易把每段十几行逻辑都拆成包，形成依赖图膨胀、文档分散和测试启动缓慢。DeepSeek Harness 用 package 分组、Service Definition/Provider/Consumer 角色、每包 README、运行时 invariant 和真实组合测试控制边界。这些规范本身就是成本。小团队若没有维护扩展生态或多 profile 的需求，模块化函数加显式依赖可能更合适。</p>
<h1 data-tool="mdnice编辑器"><span class="content">历史对照</span></h1>
<p data-tool="mdnice编辑器">从 OSGi 看 Cordis，动态服务和生命周期联动已有先例。服务注册、发现、撤销后触发依赖变化，这条主线几乎一致。Cordis 值得学习的新点，是把资源清理统一成 effect，并让子插件、服务、监听器都归属于同一个 Fiber。OSGi 的 bundle 生命周期更完整，也更重；Cordis 选择应用内细粒度对象，失去了类加载隔离、标准版本解析和安全层，获得了低门槛组合。</p>
<p data-tool="mdnice编辑器">从 Eclipse 看 DeepSeek Harness，profile 与 bundle patch 很像部署时组装，Service 和事件类似扩展点。差异在于 Eclipse 扩展通常围绕稳定宿主能力，DeepSeek Harness 连 agent loop 和 UI 都可替换，核心插件与第三方插件共享同一挂载机制。这个平权减少了特权内核，风险也更集中到协议治理：循环能被替换，不代表任何替代循环都遵守 session log、权限和工具时序约束。</p>
<p data-tool="mdnice编辑器">从依赖注入容器看，Cordis 的服务解析并不陌生。新的组合来自 DI 与生命周期的绑定。普通容器负责构造对象，定时器、监听器和子进程仍由业务代码清理；Cordis 把注册动作收敛成 effect。空间 scope 与时间 ownership 同时存在，插件才能在某个 Agent 范围内挂载，并随该 Agent 完整撤销。</p>
<p data-tool="mdnice编辑器">从微内核看，DeepSeek Harness 的内核确实很轻，但其 Loader 和配置协调已经承担不少平台职责。它要解析模块、等待依赖、处理 HMR、执行事务式更新、保存最后可用树、输出诊断。这提醒我，微内核减少的是业务特权，不会减少生命周期复杂度。能力越动态，内核对失败语义的要求越高。</p>
<p data-tool="mdnice编辑器">Cordis 的贡献可以概括为一种紧凑的组合坐标：Context 决定插件位于哪里，Fiber 决定插件在何时有效，Service 负责直接能力，Event 负责横切协作，effect 负责撤销。DeepSeek Harness 在这个坐标系上加入 Agent scope、持久会话事件和配置事务，使其能承载多会话、多 profile 与热更新。</p>
<h1 data-tool="mdnice编辑器"><span class="content">工程取舍</span></h1>
<p data-tool="mdnice编辑器">当我想要用类似架构时，会先确认三个条件，基于这三个条件判断来是否采用。</p>
<p data-tool="mdnice编辑器">其一，能力确实需要独立替换，至少存在两个生产提供方或明确的外部扩展需求。</p>
<p data-tool="mdnice编辑器">其二，同一进程需要多套组合并存，或者运行期间需要可靠更新。</p>
<p data-tool="mdnice编辑器">其三，团队愿意为卸载、回滚和真实组合测试持续付费。</p>
<p data-tool="mdnice编辑器">缺少这些条件，插件框架容易沦为复杂的工厂模式。</p>
<p data-tool="mdnice编辑器">能力切分要从消费方开始。先列出谁调用、调用时需要哪些稳定语义，再设计 Service Definition；随后实现 provider，最后把面向模型的 schema、展示和错误文本留给 consumer。接口只有一个内部调用者时，保留私有闭包，不急着升格为公共 service。可替换性必须由真实替代者证明。</p>
<p data-tool="mdnice编辑器">所有注册都要有明确所有者。注册工具、提示词片段、适配器、监听器时同步返回 disposer；卸载测试要观察注册项确实消失。涉及异步资源时，dispose 完成的定义要包含子进程退出、队列排空和 watcher 关闭，不能只发出取消信号。DeepSeek Harness 对 Fiber quiescence 的处理值得照搬。</p>
<p data-tool="mdnice编辑器">配置更新要区分内存一致性和外部副作用。Loader 可以恢复旧树，插件初始化若已经创建云资源，回滚需要业务补偿。规则可更保守一些：挂载阶段只做校验和本地注册，外部写操作放到带幂等标识的运行阶段。确实要在初始化创建资源时，必须让 disposer 能识别部分完成状态。</p>
<p data-tool="mdnice编辑器">作用域要控制在两种以内。实例隔离与注册可见性已经足够表达多数 Agent 场景，再增加租户、请求、工作区、角色四套独立 scope，调试成本会失控，需要根据实际业务需求和必要性来判断。当需要新增维度时，先判断它属于服务实例选择、注册过滤、持久数据权限还是请求参数。很多所谓新 scope，其实只是一次显式参数传递。</p>
<p data-tool="mdnice编辑器">事件也要克制。需要唯一返回值的调用用 Service，需要持久恢复的事实写 session log，需要多个插件观察或包裹的阶段才用事件。waterfall 必须把短路当成公共协议，监听器顺序也要有测试。事件名虽然能降低导入耦合，却会增加时序耦合；后者通常更难排查。</p>
<h1 data-tool="mdnice编辑器"><span class="content">小结</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 选择 Cordis，解决的主要矛盾是 Agent 能力变化速度与运行时一致性之间的冲突。模型、工具、沙箱和 UI 都可以替换并不稀奇；这些能力可以在局部作用域内共存，能随依赖变化启停，能在配置失败后保留旧树，卸载时还能回收监听器、服务和子插件，才构成可用的插件架构。</p>
<p data-tool="mdnice编辑器">它也没有抹平工程风险。Proxy 隐藏了查找路径，双层 scope 增加理解成本，热更新无法回滚任意外部副作用，预发布阶段也缺少跨版本兼容承诺。团队采用这套思路时，应复制它的生命周期纪律和能力边界，别只复制「一切皆插件」的目录结构。</p>
<p data-tool="mdnice编辑器">源码给我们一些启发，把插件设计的评审顺序倒过来：先问如何撤销，再问如何注册；先证明局部挂载不会泄漏，再讨论全局复用；先定义失败后保留哪一棵树，再讨论热更新速度。做到这些，时空可组合才是一组可以验证的运行时语义。</p>
<p data-tool="mdnice编辑器">这套架构个人理解是想往 Agent 的实时「自生长」，通过 AI 的能力在使用过程中让自己更强大。</p>
<p data-tool="mdnice编辑器">逼逼这么多，主要还是在这个过程中学习一下，说实话，有了 DeepSeek Harness，想自己开发一个专属的 Agent ，快捷方便了很多，eg且这是 MIT 协议的。</p>
<p data-tool="mdnice编辑器">以上。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">参考资料</span></h2>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><a style="font-weight: bold; color: #ef7060;" href="https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/architecture.zh.md">DeepSeek Harness 架构文档</a></section>
</li>
<li>
<section style="color: #010101;"><a style="font-weight: bold; color: #ef7060;" href="https://github.com/cordiverse/cordis">Cordis：Meta-Framework of Spatiotemporal Composability</a></section>
</li>
<li>
<section style="color: #010101;"><a style="font-weight: bold; color: #ef7060;" href="https://osgi.github.io/osgi/core/framework.service.html">OSGi Service Layer</a></section>
</li>
<li>
<section style="color: #010101;"><a style="font-weight: bold; color: #ef7060;" href="https://www.osgi.org/resources/architecture/">OSGi Architecture</a></section>
</li>
<li>
<section style="color: #010101;"><a style="font-weight: bold; color: #ef7060;" href="https://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html">Eclipse Plug-in Architecture</a></section>
</li>
</ul>
</section>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2026/08/deepseek-harness-cordis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>聊聊 Harness：从 Agent 到组织</title>
		<link>https://www.phppan.com/2026/05/harness-engineering-anent-org/</link>
		<comments>https://www.phppan.com/2026/05/harness-engineering-anent-org/#comments</comments>
		<pubDate>Sat, 30 May 2026 09:35:05 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[架构和远方]]></category>
		<category><![CDATA[Agent]]></category>
		<category><![CDATA[harness]]></category>
		<category><![CDATA[harness engineering]]></category>

		<guid isPermaLink="false">https://www.phppan.com/?p=2501</guid>
		<description><![CDATA[我们在落地 Agent 时面临的核心矛盾，是大模型的概率生成机制与工程系统所需的绝对确定性存在天然冲突。要获取 [&#8230;]]]></description>
				<content:encoded><![CDATA[<section id="nice" style="color: #000000;" data-tool="mdnice编辑器" data-website="https://www.mdnice.com">
<p data-tool="mdnice编辑器">我们在落地 Agent 时面临的核心矛盾，是大模型的概率生成机制与工程系统所需的绝对确定性存在天然冲突。要获取大规模、可维护且值得信赖的代码，必须在系统外围构建 Harness。<strong>Harness 的本质是将不确定性转化为确定性。</strong></p>
<p data-tool="mdnice编辑器">提高信任度和可靠性需要极度压缩 Agent 的解决方案空间。我们必须放弃让模型「生成任何内容」的灵活性，转而采用包含大量技术细节的提示、规则和框架。特定的架构模式、强制执行的边界以及标准化的结构，构成了这套护栏的物理基础。</p>
<p data-tool="mdnice编辑器">当前越来越多的团队在持续快速的产生代码，而这些演示很好看，当真的进入整个软件生命周期中，就会产生混乱，当越来越多的人随着时间的推移在仓库中堆砌代码，组织就开始堆人进行 review、反复返工，最后 AI 的吞吐量被人类注意力卡死，表面上用了 Agent，实际产能没上去，维护成本还更高。</p>
<p data-tool="mdnice编辑器">当然，这是一种结果，也有人在过程中不停的构建基建，做 Harness 工程，整个代码不再是无序的扩张。从这个逻辑来讲，harness 的作用是把<strong>大模型输出从概率事件压回工程确定性的系统设计</strong>。</p>
<h1 data-tool="mdnice编辑器"><span class="content">Agent 的 Harness</span></h1>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">harness 是什么</span></h2>
<p data-tool="mdnice编辑器"><strong>很多人把 harness 比作一个操作系统，模型是 CPU，但我觉得并不是。</strong></p>
<p data-tool="mdnice编辑器">如果模型真的是 CPU，那它接收指令后的执行结果应该是绝对严格且可预测的；但大模型本质上是一个概率引擎，它在潜空间里做的是模式匹配与概率生成。因此，harness 并不是像操作系统那样去调度底层硬件资源或分配内存，它更像是一套概率过滤器和对齐机制。它依靠纯粹的工程手段，把模型那种发散的、充满不确定性的「创造力」或「幻觉」，强行压缩进一条狭窄、严谨且符合人类预期的流水线里。</p>
<p data-tool="mdnice编辑器">这种工程逻辑在实践中，体现为无处不在的防御性设计和反馈闭环。当模型吐出一串代码或一个决策时，harness 并不负责直接「运行」它，而是负责「质检」和「纠偏」。它通过静态检查、架构规则扫描、自动化测试和沙箱验证，把模型给出的「大概率正确」转化为工程上非黑即白的「通过或驳回」。正是这种让概率不断撞击确定性规则的过程，才使得最终沉淀到代码库里的产物是安全、可控且符合系统长期利益的。</p>
<p data-tool="mdnice编辑器">harness 解决确定性问题的终极目的，是为了在系统中建立无需人工干预的信任，从而真正释放 AI 的吞吐量。如果没有这套逻辑，模型生成的代码越多，人类审查的负担就越重，整个组织的运转速度依然会被人类的注意力瓶颈卡死。</p>
<p data-tool="mdnice编辑器">Martin Fowler 的博客中发表了 Thoughtworks 的技术专家的一篇文章，将 OpenAI 文章中所描述的 harness 分为三个方面：</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">上下文工程</span></h2>
<p data-tool="mdnice编辑器">上下文工程需要做到动态与静态的交织</p>
<p data-tool="mdnice编辑器">单纯依赖超长 Prompt 无法解决复杂工程问题。上下文工程的核心在于构建代码库中持续增强的知识库，并打通 Agent 对动态上下文的访问路径。</p>
<p data-tool="mdnice编辑器">静态知识库定义了系统的基础法则。我们将领域模型、API 契约和历史架构决策文档化，作为 Agent 初始化的基线上下文。动态上下文决定了 Agent 在运行时的决策质量。系统需要将实时的可观测性数据、测试覆盖率报告甚至浏览器导航状态，实时注入到 Agent 的工作流中。缺乏动态上下文的 Agent 就像蒙眼狂奔的打字机，产出的代码在语法上完美，在逻辑上完全脱离系统现状。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">架构约束</span></h2>
<p data-tool="mdnice编辑器">架构约束是确定性的防线。</p>
<p data-tool="mdnice编辑器">完全依赖 LLM 进行自我反思和代码审查，在生产环境中极度危险。架构约束必须由确定性的自定义代码检查器和结构测试来强制执行。</p>
<p data-tool="mdnice编辑器">我们通过静态分析工具拦截不合规的依赖调用，利用 AST（抽象语法树）解析确保代码分层符合规范。当 Agent 试图在 UI 层直接发起数据库连接时，确定性的检查器会立即阻断该行为，并将具体的错误堆栈和修复路径作为反馈输入给 Agent。这种混合架构确保了系统的底线由死板的规则守卫，Agent 的创造力被严格限制在安全的沙盒内。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">垃圾回收</span></h2>
<p data-tool="mdnice编辑器">垃圾回收主要是用于对抗代码熵增。</p>
<p data-tool="mdnice编辑器">完全自主的智能体引入了代码库衰败的新问题。Agent 会精准且不知疲倦地复现代码仓库中已存在的模式，包含那些不均衡或不够理想的遗留设计。随着时间的推移，这种行为不可避免地导致系统架构漂移。</p>
<p data-tool="mdnice编辑器">最初，人类开发者试图手动处理这个问题。团队过去每周五要花费 20% 的时间清理「AI 残渣」。这种依赖人力的做法毫无可扩展性。</p>
<p data-tool="mdnice编辑器">我们将资深工程师的主观品味转化为机械规则，提炼为「黄金原则」并直接编码到代码仓库中，建立了一个循环清理流程。我们强制要求使用共享的实用程序包，禁止手工编写零散的辅助工具，确保不变式集中管理。我们严禁使用猜测性的数据探测，强制验证边界或依赖类型化的 SDK，防止 Agent 基于虚幻的结构进行构建。</p>
<p data-tool="mdnice编辑器">系统定期运行一组后台 Agent 任务，扫描代码库中的偏差、更新质量等级，并发起有针对性的重构 Pull Request。这些 PR 大多可以在一分钟内完成审查并自动合并。这套机制的功能等同于内存管理中的垃圾回收。技术债务如同高息贷款，通过高频的微小重构不断偿还，远胜过让债务累积到系统崩溃。人类的架构品味一旦被捕获并规则化，就会无情地应用于每一行代码，每天自动发现并消灭不良模式。</p>
<h1 data-tool="mdnice编辑器"><span class="content">AI Agent Harness 的工程化落地</span></h1>
<p data-tool="mdnice编辑器">从几个流行的框架来看，主要是从流程强化、规格沉淀、任务编排等逻辑上来做事情。</p>
<p data-tool="mdnice编辑器">将这些逻辑拆开可以分为四个维度：</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">上下文工程</span></h2>
<p data-tool="mdnice编辑器">上下文工程主要是在规范层解决问题，其主要解决的「规则文件失控」的问题，实现规格沉淀与对齐，以及上下文工程的可控。</p>
<p data-tool="mdnice编辑器">之前，我们习惯把所有规范塞进类似于单个 <code style="color: #ef7060;">.cursorrules</code> 文件，导致 AI 上下文过载且容易忽略细节。这一层落地的第一步是建立结构化、按需加载的规范体系。主要做到如下的点：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #000000;">规范模块化</strong>：将系统架构、数据库规范、错误处理等拆分为独立的结构化文档。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">按需检索</strong>：AI 不需要每次都通读所有规范，而是根据当前所处的任务阶段，动态检索并加载所需的上下文。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">任务记忆隔离</strong>：为每个独立任务建立物理隔离的工作区和日志。AI 每次开启新会话时，只读取当前任务的精确记忆，既解决了“跨会话失忆”，又屏蔽了无关信息的干扰。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">以 Trellis 框架为例，Trellis 摒弃了单一庞大的全局提示词文件，而是采用 spec/ 目录将规范模块化（如拆分为 database-guidelines.md）。在执行任务时，它利用 tasks/ 目录下的 JSONL 配置文件，让 Agent 动态检索并按需加载上下文。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">架构约束</span></h2>
<p data-tool="mdnice编辑器">架构约束的<strong>核心逻辑：用代码约束代码，实现闭环自愈。</strong> 口头约定或纯文本规范在 AI 面前是脆弱的，它极易为了「跑通逻辑」而破坏架构分层。</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #000000;">规则代码化</strong>：将核心的架构依赖规则（例如“前端组件严禁直接调用数据库”）编写为静态分析脚本或自定义 Linter。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">带解释的强阻断</strong>：在代码提交或验证阶段强制执行这些拦截器。关键在于，报错信息不能仅仅是「检查失败」，必须输出高度结构化的指导：明确告诉 AI“为什么违反了规则”以及“正确的做法是什么”。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">自动修复</strong>：AI 读取到结构化的报错指导后，能够自动理解并修正代码，形成无需人类介入的自愈闭环。</section>
</li>
</ul>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">反馈循环</span></h2>
<p data-tool="mdnice编辑器"><strong>核心逻辑：降噪处理，防范死循环。</strong> LLM 的注意力会被长篇大论的日志（如几千行的覆盖率输出）稀释注意力，从而忽略真正致命的错误。 因此我们需要做到：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #000000;">零输出原则</strong>：改造验证脚本。如果测试通过，脚本应保持完全沉默；如果失败，只输出精简的错误堆栈和失败原因。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">强制验收清单</strong>：在 AI 试图标记任务「已完成」之前，系统应强制拦截，要求其对照需求文档逐项确认边界条件。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">防死循环干预</strong>：设定重试阈值。如果 AI 对同一文件连续修改多次且测试依然失败，系统应主动中断并强制其回滚代码、重新审视需求，防止 AI 陷入无效的「幻觉修 Bug」循环。</section>
</li>
</ul>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">熵管理</span></h2>
<p data-tool="mdnice编辑器">熵管理主要是阻断「坏模式」的指数级扩散</p>
<p data-tool="mdnice编辑器"><strong>核心逻辑：快速偿还技术债。</strong> AI 复制坏代码的速度是指数级的。一旦允许一个临时的妥协方案合入主分支，AI 会在极短时间内将其复制到整个代码库。</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #000000;">高频垃圾收集</strong>：彻底放弃“集中清技术债”的传统做法。每天必须安排固定时间，专门 Review AI 生成的代码（人工或 AI 自动），及时识别新引入的坏模式。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">规范资产的动态演进</strong>：一旦发现坏模式，立即让 AI 深度分析根因，并<strong style="color: #000000;">自动将正确的防范规则更新到规范库中</strong>。</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">团队级免疫</strong>：由于规范库与代码同源管理（存在于 Git 仓库中），当这段新规则被提交后，团队其他成员拉取代码时，他们的 AI 助手就能立刻“学会”这个新技能。这把偿还技术债的动作，变成了每天自动化、可积累的系统进化。</section>
</li>
</ul>
<p data-tool="mdnice编辑器">以 Cursor 为例，可以更新 Team Rules</p>
<h1 data-tool="mdnice编辑器"><span class="content">组织级 Harness</span></h1>
<p data-tool="mdnice编辑器">聊完 Agent 的 Harness，再聊一下组织的。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">人的角色已经变了</span></h2>
<p data-tool="mdnice编辑器">大家都知道康威定律，简单来说就是：<strong>设计系统的组织，其产生的设计受限于这些组织的沟通结构。</strong></p>
<p data-tool="mdnice编辑器">而系统设计到最后，也一定会遇到一个问题：<strong>谁来定义规则，谁来解释例外，谁来承担后果。</strong></p>
<p data-tool="mdnice编辑器">以前的软件开发分工相对稳定。PM 写需求，设计出稿，前后端分别实现，测试验证，运维发布。大家各自占一段链路，边界虽然有摩擦，但总体清楚。</p>
<p data-tool="mdnice编辑器">AI 进来以后，边界开始模糊。</p>
<p data-tool="mdnice编辑器">PM 已经可以直接产出前端原型，很多时候产出的还不是静态图，而是真能跑的页面代码。设计师也不再只是给稿子，很多交互和组件约束可以直接沉淀成生成资产。前端工程师花在纯页面搭建上的时间下降，开始更多介入状态管理、交互抽象、可维护性收拢。后端和算法也更早被拉进来，因为很多 AI 生成的原型一开始就会碰到真实数据和能力边界。</p>
<p data-tool="mdnice编辑器">这是现在很多团队正在进行的转型。</p>
<p data-tool="mdnice编辑器">如果组织还按旧的分工运转，Agent 会把协作缝隙快速放大。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">组织级 Harness 要管什么</span></h2>
<p data-tool="mdnice编辑器">我理解的组织级 harness，重点在三件事：</p>
<ol data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #000000;">定义新的协作接口</strong></section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">重新分配注意力</strong></section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">把责任从「谁写了代码」改成「谁定义了系统」</strong></section>
</li>
</ol>
<h3 data-tool="mdnice编辑器"><span class="content">协作接口要前移</span></h3>
<p data-tool="mdnice编辑器">以前很多问题可以留到开发阶段再对齐。现在不行。</p>
<p data-tool="mdnice编辑器">因为 PM 通过 AI 已经能直接产出前端代码，需求不再是文字说明，而可能是一个可交互原型；设计规范也不再只是 Figma 标注，而是可以半自动映射到组件约束；后端接口能力如果不提前讲清楚，前面的生成很容易一路偏到错误方向。</p>
<p data-tool="mdnice编辑器">所以组织里的评审必须前移，重点也得改。</p>
<p data-tool="mdnice编辑器">过去的需求评审，很多时候在讨论功能要不要做。现在要多讨论三件事：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">验收标准到底是什么</section>
</li>
<li>
<section style="color: #010101;">哪些边界不能突破</section>
</li>
<li>
<section style="color: #010101;">哪些部分允许先用原型推进，哪些必须工程化收拢后才能上线</section>
</li>
</ul>
<p data-tool="mdnice编辑器">这几个东西不提前定，后面会出现一个很常见的问题：原型阶段看起来进展飞快，进入工程化后才发现返工巨大。</p>
<h3 data-tool="mdnice编辑器"><span class="content">注意力要重新分配</span></h3>
<p data-tool="mdnice编辑器">我现在越来越少鼓励资深工程师花时间逐行抠低风险代码。</p>
<p data-tool="mdnice编辑器">这不是说 review 不重要，而是注意力要贵着用。</p>
<p data-tool="mdnice编辑器">在 Agent 环境里，重要的工作变成了：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">定义验收标准</section>
</li>
<li>
<section style="color: #010101;">设计架构边界</section>
</li>
<li>
<section style="color: #010101;">提炼黄金原则</section>
</li>
<li>
<section style="color: #010101;">识别系统性失败信号</section>
</li>
<li>
<section style="color: #010101;">决定哪些异常值得阻塞主流程</section>
</li>
<li>
<section style="color: #010101;">审核高风险改动和高影响面重构</section>
</li>
</ul>
<p data-tool="mdnice编辑器">反过来，低风险、重复性、局部性的东西，应该尽量交给自动化校验和后台清理任务。</p>
<p data-tool="mdnice编辑器">如果一个组织还在让最贵的人力去看大批格式化差异、小工具改名、重复样板代码，那 harness 基本等于没有。</p>
<h3 data-tool="mdnice编辑器"><span class="content">责任归属要重写</span></h3>
<p data-tool="mdnice编辑器"><strong>在 AI-Native 组织里，谁对结果负责？</strong></p>
<p data-tool="mdnice编辑器">PM 产出了页面代码，前端做了工程化收拢，Agent 自动补了测试，清理 Agent 又改了一轮共享工具。最后线上出问题，算谁的？</p>
<p data-tool="mdnice编辑器">如果这个问题没有明确答案，团队会很快进入防御状态。每个人都怕接 AI 产出的锅，于是流程开始重新变重，所有人都试图把责任往后传。</p>
<p data-tool="mdnice编辑器">所以组织级 harness 一定要明确责任模型。</p>
<p data-tool="mdnice编辑器">可以按三层分：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><strong style="color: #000000;">需求责任</strong>：谁定义了目标与验收标准，谁负责需求正确性</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">架构责任</strong>：谁定义了边界、模式和约束，谁负责系统一致性</section>
</li>
<li>
<section style="color: #010101;"><strong style="color: #000000;">发布责任</strong>：谁决定进入生产环境，谁负责风险接受</section>
</li>
</ul>
<p data-tool="mdnice编辑器">不要再执着于「谁手写了这行代码」。就像团队管理一样，最后拍板的人担责。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">可落地的 AI-Native 研发流程</span></h2>
<p data-tool="mdnice编辑器">以下为我们当前在跑的流程：</p>
<h3 data-tool="mdnice编辑器"><span class="content">需求生成</span></h3>
<p data-tool="mdnice编辑器">第一步由 PM 主导，但交付物不再只是 PRD，而是<strong>带验收标准的可运行原型</strong>。</p>
<p data-tool="mdnice编辑器">但是，原型代码不等于可直接上线代码。它的价值是澄清需求、暴露分歧、提前感知交互复杂度。</p>
<p data-tool="mdnice编辑器">所以 PM 可以生成，但不能默认拥有工程决策权。最终所有的代码都需要前端工程师构建的工具链条，以及 AI 和人工的审核及合入。</p>
<h3 data-tool="mdnice编辑器"><span class="content">联合评审</span></h3>
<p data-tool="mdnice编辑器">第二步是全员参与的需求评审与架构设计。设计、前端、后端、算法都要尽早介入。</p>
<p data-tool="mdnice编辑器">这个阶段重点不是抠实现细节，而是确定：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">用户路径是否成立</section>
</li>
<li>
<section style="color: #010101;">数据流怎么走</section>
</li>
<li>
<section style="color: #010101;">状态边界怎么划</section>
</li>
<li>
<section style="color: #010101;">哪些能力用现有服务承接</section>
</li>
<li>
<section style="color: #010101;">哪些模块需要新增抽象</section>
</li>
<li>
<section style="color: #010101;">风险点在哪</section>
</li>
<li>
<section style="color: #010101;">验收怎么自动化</section>
</li>
</ul>
<p data-tool="mdnice编辑器">这这一步的产出结构化进仓库，因为后面它会直接成为 Agent 的约束输入。</p>
<h3 data-tool="mdnice编辑器"><span class="content">工程收拢</span></h3>
<p data-tool="mdnice编辑器">第三步是工程化整合。这个阶段前端、后端、算法开始把前面的原型和需求收敛进正式系统。</p>
<p data-tool="mdnice编辑器">这里 Agent 会大量参与，但人类不能退出。重点工作包括：</p>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;">把原型重构进现有组件和模块体系</section>
</li>
<li>
<section style="color: #010101;">校正状态管理、错误处理、埋点、权限、监控</section>
</li>
<li>
<section style="color: #010101;">对接真实接口和算法能力</section>
</li>
<li>
<section style="color: #010101;">补齐类型、边界验证和回归测试</section>
</li>
<li>
<section style="color: #010101;">处理跨模块影响面</section>
</li>
</ul>
<p data-tool="mdnice编辑器">这一段最考验 harness，因为原型代码最容易带着局部最优、全局失真、风格漂移的问题冲进主仓。</p>
<h3 data-tool="mdnice编辑器"><span class="content">自动验证与灰度</span></h3>
<p data-tool="mdnice编辑器">最后一步是自动化测试、灰度发布和反馈回收。</p>
<p data-tool="mdnice编辑器">这一步先由专门的工程团队来负责，加入部分的 AI 成分，固化系统。</p>
<h1 data-tool="mdnice编辑器"><span class="content">从 Agent 到组织，真正难的是控制系统</span></h1>
<p data-tool="mdnice编辑器">很多人以为 AI 落地的核心挑战在模型能力、成本或者工具接入。我现在看，最大挑战更集中在三个词：<strong>环境、反馈回路、控制系统。</strong></p>
<p data-tool="mdnice编辑器">环境决定 Agent 看到了什么、能做什么、不能做什么。</p>
<p data-tool="mdnice编辑器">反馈回路决定错误会被放大，还是会被系统吸收成改进信号。</p>
<p data-tool="mdnice编辑器">控制系统决定生成能力增长之后，组织是变得更稳，还是更乱。</p>
<p data-tool="mdnice编辑器">这三个东西做不好，模型再强也只是更快地产生问题。</p>
<p data-tool="mdnice编辑器">做得好，哪怕模型能力没到最顶尖，系统一样能稳定进化。因为工程上真正稀缺的，从来不是一次惊艳输出，而是长期重复地产出靠谱结果。</p>
<h1 data-tool="mdnice编辑器"><span class="content">组织的 AI-Native 化</span></h1>
<p data-tool="mdnice编辑器">组织的 AI-Native 化也是慢慢进货，逐步推进的，先从小范围试起，再根据结果不断调整规则和流程。并且各家有各家的风格和气质。</p>
<p data-tool="mdnice编辑器">第一，<strong>选一条链路打透</strong>。不要一开始就全组织铺开。先找一个协作关系清楚、反馈周期短、风险相对可控的场景，比如中后台、运营工具、内部系统，或者低风险服务改造。重点不是让 AI 多写代码，而是先验证：信息怎么给、边界怎么定、错误怎么发现、问题怎么清理。</p>
<p data-tool="mdnice编辑器">第二，<strong>先改规则，再谈效率</strong>。很多团队一上来就问产能能提升多少，但更重要的是：规则有没有沉淀下来，错误能不能回流，坏模式能不能及时发现并清掉。如果这些没做好，所谓提效往往只是把问题推后，甚至把混乱放大。</p>
<p data-tool="mdnice编辑器">第三，<strong>把人的位置往上移</strong>。资深工程师要逐渐从大量写代码，转向定规则、画边界、看反馈；技术管理者要从盯人和排期，转向设计流程、分层风险、明确责任；产品可以更早参与原型，但不能越过工程判断。</p>
<p data-tool="mdnice编辑器">组织真正变成 AI-Native，不是因为每个人都在用 Agent，而是协作方式已经围绕 Agent 被重新设计过。</p>
<p data-tool="mdnice编辑器">模型当然重要，但不是决定性因素。真正拉开差距的，是谁先意识到：Agent 不是一个更快的开发者，而是一个高吞吐的生产单元。它会放大环境本身。规则清楚，它就放大规则；流程混乱，它就放大混乱。</p>
<p data-tool="mdnice编辑器">所以到最后，harness 这件事谈的根本不只是 AI。</p>
<p data-tool="mdnice编辑器">谈的是工程纪律怎么重新编码。</p>
<p data-tool="mdnice编辑器">谈的是组织协作怎么重新布线。</p>
<p data-tool="mdnice编辑器">谈的是我们怎么把概率生成系统，放进一个仍然要求长期维护、长期演进、长期负责的软件世界。</p>
<p data-tool="mdnice编辑器">这是我理解的「从 Agent 到组织」。</p>
<p data-tool="mdnice编辑器">以上。</p>
</section>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2026/05/harness-engineering-anent-org/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>自进化 Agent 实现的 4 个层面</title>
		<link>https://www.phppan.com/2026/05/self-improving-agent/</link>
		<comments>https://www.phppan.com/2026/05/self-improving-agent/#comments</comments>
		<pubDate>Sat, 23 May 2026 03:04:48 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[架构和远方]]></category>
		<category><![CDATA[harness]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[Self-Improving Agent]]></category>
		<category><![CDATA[自进化Agent]]></category>

		<guid isPermaLink="false">https://www.phppan.com/?p=2499</guid>
		<description><![CDATA[如果 AI 能像人一样，随着时间，经验，反馈不断学习，会发生什么？ 我们现在常用的 Agent，不管是豆包，还 [&#8230;]]]></description>
				<content:encoded><![CDATA[<section id="nice" data-tool="mdnice编辑器" data-website="https://www.mdnice.com">
<p data-tool="mdnice编辑器"><strong>如果 AI 能像人一样，随着时间，经验，反馈不断学习，会发生什么？</strong></p>
<p data-tool="mdnice编辑器">我们现在常用的 Agent，不管是豆包，还是编程用的 Cursor，本质是还是一次性对话工程，你问一句，它答一句，或者执行完一堆任务，任务结束后不会成长。</p>
<p data-tool="mdnice编辑器">如果能成长呢？这将会是不一样的世界。</p>
<p data-tool="mdnice编辑器">这也是今年硅谷比较热门的方向。</p>
<p data-tool="mdnice编辑器">为什么是这个方向：</p>
<ol data-tool="mdnice编辑器">
<li>
<section>人性，人天生懒惰，公司逐利</section>
</li>
<li>
<section>成本，自动化的 Agent 比 Chat AI 消耗的成本高出数个数量级，而自己进化的 Agent 所消耗的 token 又比一般的自动化的 agent 要高出多个数量级</section>
</li>
<li>
<section>上下文更长、模型更大、工具更多，这些路线都还有效，但边际收益已经没有前几年那么夸张。当其它维度进入瓶颈的时候，<strong>时间永远是可以考虑的重要维度</strong>，</section>
</li>
</ol>
<p data-tool="mdnice编辑器">自我进化不是「长期记忆」，而是 Agent 依据自身交互情况、任务反馈或环境信号，对上下文、记忆、技能、工作流甚至模型参数进行持续更新。这些更新会直接干预未来的任务执行。</p>
<p data-tool="mdnice编辑器">通过不断调整大模型和 harness 的边界，在静态世界里不断进化，模型能够能够越来越熟悉环境工具记忆等</p>
<p data-tool="mdnice编辑器">任何演进路径都必须压在评估、版本、回滚、权限与供应链治理的基础之上。</p>
<p data-tool="mdnice编辑器">自我进化用一句来讲，大概是这样：</p>
<blockquote class="custom-blockquote multiquote-1" data-tool="mdnice编辑器"><p>真实任务里的经验，怎么变成下一次任务可复用、可验证、可治理的能力。</p></blockquote>
<p data-tool="mdnice编辑器">拆解一下，可以分为四层或者说四种可实现路径：</p>
<ol data-tool="mdnice编辑器">
<li>
<section><strong>上下文进化</strong>：将执行经验、用户偏好或环境约束写回本地记忆文件、会话索引或技能目录，在下一次任务触发时通过检索提取并拼接入上下文。</section>
</li>
<li>
<section><strong>技能进化</strong>：把经验外化成结构化的 SKILL.md、技能包或工作流脚本。系统依据执行报错或反馈信号，自动修改技能代码，在测试集中跑通后覆盖老版本，失败则触发版本回滚。</section>
</li>
<li>
<section><strong>群体智能进化</strong>：多个 Agent、多台机器、多个用户的本地经验接入云端共享层。系统在服务端完成轨迹去重、冲突合并、安全脱敏与质量验证，最后将提纯后的技能或记忆分发回所有终端。</section>
</li>
<li>
<section><strong>策略进化</strong>：将真实的交互轨迹与成败反馈收集起来，直接修改 Agent 的核心调度代码、工作流拓扑，甚至转化为强化学习（RL）的标量奖励来更新大模型的底层参数。</section>
</li>
</ol>
<p data-tool="mdnice编辑器">从工程落地的角度来说，上下文闭环和技能闭环是不错的起始点，也是能快速落地，快速带来结果的点。</p>
<p data-tool="mdnice编辑器">这两层改动的基本都是文本资产，容易审计，且故障可控，回滚成本低。如果实现群体闭环或策略闭环，就会多出很多数据脱敏，权限控制等等问题。</p>
<h1 data-tool="mdnice编辑器"><span class="content">上下文进化</span></h1>
<p data-tool="mdnice编辑器">上下文进化是指让 Agent 在自己的主循环里，将执行经验、用户偏好或环境约束写进以后还能用到的上下文资产。</p>
<p data-tool="mdnice编辑器">典型的上下文资产包括：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>跨会话记忆</section>
</li>
<li>
<section>会话检索</section>
</li>
<li>
<section>用户画像</section>
</li>
<li>
<section>项目级上下文</section>
</li>
<li>
<section>技能目录的动态装载</section>
</li>
<li>
<section>失败后的反思记录</section>
</li>
</ul>
<p data-tool="mdnice编辑器">优点：轻、快、容易落地。</p>
<p data-tool="mdnice编辑器">缺点：如果底层模型本身不够强，光靠上下文很难突破上限；如果没有治理，错误经验会稳定污染后续行为。</p>
<p data-tool="mdnice编辑器">以 Hermes Agent 为例，它将持久记忆（MEMORY.md / USER.md）、跨会话检索（SQLite + FTS5）和技能创建塞进同一个对话主循环。</p>
<p data-tool="mdnice编辑器">工程实现上，Hermes 走的是一条贴紧主循环的轻量闭环。用户下发任务，Agent 经由消息网关调用终端工具。执行反馈与用户纠正产生分叉，一部分写入策展记忆，一部分沉淀为 Skills。当新任务到来，系统通过 session_search 将历史记忆与技能一并汇入下一轮上下文。</p>
<p data-tool="mdnice编辑器">上下文进化解决的问题是Agent 的「金鱼记忆」与重复试错成本。在早期开发中，大模型每次新建会话都会丢失之前的上下文。昨天刚通过多轮对话教会它如何绕过内网的 SSL 证书校验，今天遇到同样的报错，它依然会从零开始盲目重试。上下文进化通过持久化存储（如 SQLite 配合 FTS5 全文检索），让 Agent 在行动前先查阅历史成功路径，直接跳过无效的探索阶段。</p>
<p data-tool="mdnice编辑器">适用于单兵作战的个人助手、轻量级代码副驾、日常办公辅助。只要底层大模型的推理能力在线，且任务经验不需要跨团队、跨设备共享，这是投入产出比最高的一层。它不需要复杂的评测沙箱，几百行代码就能让单体 Agent 的可用性产生质变。</p>
<h1 data-tool="mdnice编辑器"><span class="content">技能进化</span></h1>
<p data-tool="mdnice编辑器">上下文闭环再往前一步，就是把经验沉淀成可复用技能。</p>
<p data-tool="mdnice编辑器">当经验开始重复出现，必须将其从松散的记忆层提升到结构化的技能层。把经验外化成结构化的 SKILL.md、技能包或工作流脚本。系统依据执行报错或反馈信号，自动修改技能代码，在测试集中跑通后覆盖老版本，失败则触发版本回滚。</p>
<p data-tool="mdnice编辑器">在 Agent Skills 生态里，SKILL.md 充当了 Agent 的程序性记忆，定义了触发时机、执行脚本、环境约束和异常处理逻辑。</p>
<p data-tool="mdnice编辑器"><code>SKILL.md</code> 这一类开放技能格式，是这波 Agent 工程里比较实用的中间层，它有如下的特点：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>比记忆更结构化</section>
</li>
<li>
<section>比代码改动更轻</section>
</li>
<li>
<section>比参数训练更便宜</section>
</li>
<li>
<section>可迁移、可 diff、可版本化、可回滚</section>
</li>
</ul>
<p data-tool="mdnice编辑器">所以当我们发现某类经验开始重复出现，就不应该继续把它留在记忆层，而应该上升成技能资产。</p>
<p data-tool="mdnice编辑器">Darwin Skill 把 SKILL.md 当作可评测、可回滚的资产。</p>
<p data-tool="mdnice编辑器">Hermes Agent 的技能系统不是静态文档库，它允许 agent 自己创建、编辑、补丁、删文件、写附属文件。核心工具是 <code>skill_manage</code>。[skill_manager_tool.py]</p>
<p data-tool="mdnice编辑器">Hermes Agent 的技能进化，并不完全依赖用户主动说「把这个存成技能」。</p>
<p data-tool="mdnice编辑器">它有两层自动复盘机制。</p>
<p data-tool="mdnice编辑器">第一层是 nudge。memory 按用户回合数触发，skills 按工具迭代次数触发。达到阈值以后，系统会在主任务完成后，后台 fork 一个 review agent，让它复查当前会话，看有没有东西值得落 memory 或 patch/create skill。[run_agent.py] run_agent.py#L2448-L2547 [run_agent.py] run_agent.py#L11586-L11612</p>
<p data-tool="mdnice编辑器">第二层是 guidance。系统提示里直接写明：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>复杂任务、踩坑任务、发现可复用流程，要考虑存技能</section>
</li>
<li>
<section>技能用着发现过时或不完整，要立刻 patch</section>
</li>
</ul>
<p data-tool="mdnice编辑器">它已经把「技能进化」从人工运营动作，拉进了 agent 自己的工作流。系统不再等人整理文档，而是把复盘变成运行时行为。</p>
<p data-tool="mdnice编辑器">但这种触发还是偏软。nudge 只是提醒，review agent 还是模型自己判断。只靠提示词和后台复盘，技能库后面大概率会出现三类问题：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>有价值流程没被沉淀</section>
</li>
<li>
<section>沉淀下来的技能版本缺少来源和上下文</section>
</li>
<li>
<section>技能被 patch 多次以后，质量开始飘</section>
</li>
</ul>
<p data-tool="mdnice编辑器">技能进化解决的问题是纯文本记忆的非结构化缺陷。当任务复杂度上升，大模型在处理几万字的自然语言排错记录时极易丢失细节，甚至产生幻觉。复杂的业务需要确定的执行路径。人工维护这些包含几十个步骤的 SOP（标准作业程序）脚本成本极高，且极易因外部 API 的微小变动而全盘失效。技能进化将脆弱的静态脚本转化为能够依据报错信息自我修复的动态资产。</p>
<p data-tool="mdnice编辑器">其适用于垂直领域的自动化流水线、运维巡检、复杂数据清洗。当业务要求 Agent 严格遵循既定流程操作，且操作环境（如第三方接口、依赖库版本）会频繁发生变化时，技能进化是维持系统长期稳定运行的唯一解。</p>
<h1 data-tool="mdnice编辑器"><span class="content">群体智能进化</span></h1>
<p data-tool="mdnice编辑器">当你有多个 Agent、多台机器、多个用户时，单机技能闭环就不够了。</p>
<p data-tool="mdnice编辑器">因为最大浪费会变成另一件事：<br />
<strong>同一个坑被不同实例反复踩。</strong></p>
<p data-tool="mdnice编辑器">这时候我们就需要一个共享层，把个人经验抽出来，变成全体可复用资产。</p>
<p data-tool="mdnice编辑器">这就是群体闭环要解决的问题。</p>
<p data-tool="mdnice编辑器">它的收益大，但治理也复杂。因为共享意味着：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>权限问题</section>
</li>
<li>
<section>隐私问题</section>
</li>
<li>
<section>脱敏问题</section>
</li>
<li>
<section>质量门控问题</section>
</li>
</ul>
<p data-tool="mdnice编辑器">等等</p>
<p data-tool="mdnice编辑器">Ultron 将散落在各次会话里的经验蒸馏成群体知识，提供 Memory Hub、Skill Hub 和 Harness Hub。</p>
<p data-tool="mdnice编辑器">Memory Hub 实现了 HOT / WARM / COLD 分层存储。系统根据命中次数进行再平衡，引入时间指数热度衰减公式 hotness = exp(-α × days)。未经衰减处理的记忆库是一场灾难，Agent 会频繁召回半年前已经废弃的内部 API 规范。</p>
<p data-tool="mdnice编辑器">数据入库前，系统通过 Presidio 进行中英 PII（个人身份信息）检测与脱敏。这是企业级落地的底线。一旦某个 Agent 将包含真实客户手机号的排错日志写入群体记忆，整个系统的合规风险将彻底失控。</p>
<p data-tool="mdnice编辑器">Skill Hub 负责将进入 HOT 层的记忆结晶为多步工作流技能。Harness Hub 则将人设、记忆、技能打包为蓝图，支持一键导入。这种设计抹平了多实例部署的知识水位差。</p>
<p data-tool="mdnice编辑器">其主要解决的问题是规模化部署下的经验孤岛。如果团队里有 50 个开发人员，每个人的 Agent 都在本地独立摸索公司内部 CI/CD 系统的某一个奇葩报错，相当于团队为同一个坑支付了 50 遍大模型的 API 账单。群体智能进化打破了实例之间的物理隔离，让一个 Agent 踩过的坑成为全团队的免疫抗体，抹平多实例部署的知识水位差。</p>
<p data-tool="mdnice编辑器">其适用场景于企业级 Agent 矩阵、跨部门研发协同、大型内部工具链。团队规模越大，这层进化的网络效应越明显。前提是必须在共享层前置严苛的 PII（个人身份信息）脱敏与恶意 Prompt 注入拦截机制，防止单一终端的脏数据污染全局技能库。</p>
<h1 data-tool="mdnice编辑器"><span class="content">策略进化</span></h1>
<p data-tool="mdnice编辑器">再往下走，就是最重的一层：让系统直接改策略本身。</p>
<p data-tool="mdnice编辑器">这里的策略可能是：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>代码</section>
</li>
<li>
<section>工作流拓扑</section>
</li>
<li>
<section>模型参数</section>
</li>
<li>
<section>策略网络</section>
</li>
<li>
<section>推理路径分配</section>
</li>
</ul>
<p data-tool="mdnice编辑器">这层能力上限很高，也很危险。因为一旦我们把真实用户反馈接进训练或策略更新链路，很多以前可以拖着不管的问题会立刻变成硬约束：</p>
<ul data-tool="mdnice编辑器">
<li>
<section>数据许可</section>
</li>
<li>
<section>脱敏</section>
</li>
<li>
<section>训练延迟</section>
</li>
<li>
<section>奖励劫持</section>
</li>
<li>
<section>评测作弊</section>
</li>
<li>
<section>安全回滚</section>
</li>
<li>
<section>服务与训练解耦</section>
</li>
</ul>
<p data-tool="mdnice编辑器">将真实的交互轨迹与成败反馈收集起来，直接修改 Agent 的核心调度代码、工作流拓扑，甚至转化为强化学习（RL）的标量奖励来更新大模型的底层参数。</p>
<p data-tool="mdnice编辑器">其主要解决的问题是基座模型能力天花板的绝对限制。无论是追加记忆还是改写技能，本质上都在做外挂。当遇到模型根本无法理解的深层逻辑或极度复杂的推理链条时，外挂方案会全线崩溃。策略进化直接向底层动刀，利用在线交互产生的真实反馈信号（如代码是否编译通过、测试用例是否全绿）来微调模型权重或重构 Agent 的执行逻辑。</p>
<p data-tool="mdnice编辑器">主要适用场景是拥有充足算力预算的 AI 基础设施团队、需要将开源模型逼出闭源模型效果的核心业务。这一层工程风险极大。任务必须具备极度清晰、可自动化判别的反馈信号（如数学定理证明、代码生成）。如果反馈信号存在噪声，模型会迅速在错误的梯度中崩溃，产生严重的奖励作弊（Reward Hacking）现象。</p>
<h1 data-tool="mdnice编辑器"><span class="content">核心工程挑战</span></h1>
<p data-tool="mdnice编辑器">上面讲了四层进化，但是要落地自进化系统，必须跨越四道工程天堑。</p>
<p data-tool="mdnice编辑器">评估器比生成器更重要。没有评估器的自动修改，只是在自动制造生产事故。Darwin Skill 的棘轮、Ultron 的升级门控、OpenClaw-RL 的 PRM，都在解决同一个问题：证明改动没有让系统变坏。评估器的算力消耗通常是生成器的三倍以上。</p>
<p data-tool="mdnice编辑器">可回滚是自进化的基础设施。技能层的优势在于天然支持版本化。参数层的更新回滚成本极高。工程实践的逻辑是：能在记忆层解决的异常，绝不改写技能；能在技能层修补的逻辑，绝不修改代码；能在代码层绕过的缺陷，绝不在线更新权重。</p>
<p data-tool="mdnice编辑器">共享经验需要严苛治理。群体智能闭环的引入，意味着污染风险的全局放大。一个包含 rm -rf / 的错误技能一旦进入共享库，会摧毁整个团队的开发环境。权限分层、PII 脱敏、候选验证和版本审计，是系统上线的强制前置条件。</p>
<p data-tool="mdnice编辑器">技能供应链安全无法事后补救。Agent Skills 已经演变为跨生态的能力封装格式。它包含脚本、远程依赖和执行指令。技能市场必须审查其是否读取敏感路径、是否执行危险命令、是否下载未知来源的 Shell 脚本。沙箱隔离和系统调用拦截必须做在宿主的最底层。</p>
<p data-tool="mdnice编辑器">当前可落地执行的路线，不要一步到位堆砌在线 RL。可分阶段实施：</p>
<p data-tool="mdnice编辑器">第一阶段，夯实上下文治理。让 Agent 具备最基本的成长能力：记录偏好、总结失败、检索历史。重点是让项目上下文和工具状态形成稳定机制，控制上下文窗口的 Token 消耗。</p>
<p data-tool="mdnice编辑器">第二阶段，跑通技能资产沉淀。当排错经验重复出现，将其提取为 SKILL.md。引入类似 Darwin Skill 的测试集与评估机制。这是当前投入产出比最高的一步，能够立竿见影地降低 API 调用成本。</p>
<p data-tool="mdnice编辑器">第三阶段，建设跨端群体智能。部署共享存储与演化服务，实现多终端经验的去重、验证与分发。在这个阶段，投入 50% 的研发精力解决隐私脱敏与权限审计问题。</p>
<p data-tool="mdnice编辑器">第四阶段，谨慎切入参数与工作流修改。只有当你的 PRM 准确率达到生产可用级别，沙箱隔离足够坚固，版本回滚延迟降到秒级时，才去触碰在线强化学习。</p>
<p data-tool="mdnice编辑器">自进化 Agent 的核心壁垒，从来不是模型本身有多聪明，而是底层的评估、沙箱、治理和安全机制有多扎实。</p>
<p data-tool="mdnice编辑器">以上。</p>
</section>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2026/05/self-improving-agent/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
