我的 harness engineering 工程实践

2026-04-20

现在比较火的一个词叫 harness engineering。从 prompt engineering,到 context engineering,到 harness engineering。

我自己写了一个 coding agent,那篇文章写的时候还比较早期,而当前又经又过去了两个月。 而我写代码的主力工具,已经完全是使用自己实现的这个 coding agent 了。

所以与其说叫"我的 harness engineering 工程实践",不如叫:我日常是怎么样使用我自己的 ai coding agent 的。

coding agent vs claw agent

在我的项目中,我把 picoclaw 的接各个渠道的代码 import 进来,把最核心的 agent loop 替换成了我的实现,于是就得到一个 claw agent。 这样我就可以在微信/飞书之类的 IM 里面连接上我的 agent,还有用 picoclaw 的 web 前端也可以连上我的 claw。

但是...我其实不用 claw 类的 agent 的。其实我也不知道别人用 openclaw 或者其它的龙虾是怎么玩的,因为我基本都在电脑前干活,所以交互方式直接就是在我的编辑器里面,启动 agent 并与它交互。 编辑器也是当前自己在维护一个 fork 了。

使用姿势也比较原始,就是开多个 terminal 的 tab 页,每个 tab 下面都会启动一下 ad 编辑器,然后在 ad 编辑器里面会启动 coding agent,通过对话的方式在使用。

在我看来,不管是 claw 或者是终端,它们都只是一个交互界面。而真正重要的是如何通过对话这种交互,还完成任务。 在我的编辑器中使用,是因为我可以很方便地像操作 emacs 一样的操控。即使现在不敲代码了,但是不离开终端,编辑器作为控制入口,这个习惯是一直没变的。

关于记忆

如果是 claw 类的 agent,通常它们的一个群组,或者一个话题,或者一个跟 claw bot 对话的消息历史,就是一个 session。 所以对话历史会越来越长,这时就会触发 compaction,然后就会丢失上下文信息。所以会需要记忆系统来将有价值的部分保留下来。

而在我的使用场景中,我不怎么使用 claw,以 coding 为主,使用习惯就是一个任务开一个新的 session。 并且不要长时间只使用同一个 session。保持交互会话是短的,这就是最佳实践,这个原则放在任何 coding agent 上都适合。

据说 openclaw 比较烧 token,它如果一直要用同一个会话,那么上下文自然是越积越长的,每一次 agent 跟 llm 交互,需要需要带上完整的对话历史, 那自然会比较烧 token 了。

在我这边会使用一个叫 session-analyzer 的技能,它是一个离线的 session 分析技能。 我会自动周期性地,或者手动地调用这个技能。它会分析我执行过的会话的 session 和 trace,从中提取有价值的信息。

然后,分析的结果会用于优化我的 coding agent 的代码实现,优化工具,优化项目下的 AGENTS.md 文件,优化技能等等。 某种程度上,这就是一个实现记忆系统类似的功能,让 agent 越用越好用。

这只是在线 vs 离线的区别。有一个差异就是,离线对于 agent 的心智负担更小。 在线的 memory 记忆,会告诉 agent 要每次完成一些什么,最后加入一个学习阶段,去更新和维护记忆。 还有在查询一些东西时,RAG 或者注入去召回记忆,其实都属于在 agent 的主任务里面,让它分心的 prompt。

claude code 代码泄漏出来,它里面也有一个叫 dreaming 的东西,就是在用户睡觉的时候,去整理白天发生的 session,然后更新记忆等信息, 这就跟我这边的 session-analyzer 技能是类似的情况。

上下文管理

在我自己实现的 coding agent 里面,有一处理念上比 codex 和 claude code 更先进的地方,是我的上下文管理系统。

它的介绍可以看这里,在知乎上面记录过。

codex / claude code 或者开源的比较 goose 等等其它 agent,它们的上下文管理很精密,但是是基于人类的经验来优化 agent 的实现,来控制上下文管理的。 而我的理念,是倾向于让 agent 自己来管理自己的上下文。理念很先进,但是这个做法还不好说谁好谁坏。

因为 codex / claude 那边大量的使用和 tuning 下来的系统,它们在触发时机的选择,和消息压缩或者 truncate 类的操作上,都已经是打磨得很充分的。 稳定性通常更好。而我这边,把这件事情放能 agent 来做,就是有点赌未来的味道,我认为 LLM 是有能力来管理自己的上下文,比人类告诉它做什么的会上限更高。

但是现实很快啪啪啪把我的脸打肿了~

中间会遇到各种问题,比如 compaction 得太激进了,token 使用没那么高的情况下,它就发生 compaction,然后丢失重要性。 或者 truncate 得太迟缓了,导致大量工具输出留在上下文中,污染对话。在我的 agent 中,这些决策都是由 LLM 自己来决策的。

有一个印象很深的场景是,glm5.0 版本在上下文使用到 50% 左右,如果中间有生成过大量比例的代码类的输出,就会让 LLM 开始说胡话。 当时的 session 甚至是稳定复现的,因为我这边有保留 session 切换到期间任意对话时间点,重新 fork 出一个新 session 来的基础设施能力。 而这个问题在 glm4.7 则反而更好一些,不容易被触发到。到 glm5.1 版本的时候,不确定受模型那边的影响,还是我代码这边的改动,基本没见到再触发。

这个点也是我为什么吐糟 pi agent 做得太简陋的,我的 coding agent 最早就是抄 pi 的,不过后期基于是研究各个 agent 取大家的长处,抄百家艺。 关于 pi,学之者生,用之者死!它的思想我大部分都非常认同,但是上下文管理这块太简陋了,或者叫没啥管理策略,实用会不太行(这些都是历史经验,不确定最新的版本有没啥改进,免责声明一下,以免误导读者)。 直接用它是用不好的,但是学习它之后,用它去做定制,却可以用好。

说回上下文管理,一个很大的问题就是,我要求 LLM 自己去管理 context,我在 system prompt 里面给了它很复杂的指令。 复杂的 turn protocol,告诉它每一轮都要先去看 context 的 token 使用比率,离上一轮已经过了多久,是否应该触发管理操作。 而触发以后,是做 truncate 一些消息,还是去 compact。具体 truncate 的时候,是去 truncate 哪些信息,我还在 agent 里面给消息标记了 id,以及新旧程度。

这套做法太复杂了!最大的一个麻烦是,当 context 使用率升高以后,LLM 就不遵守 system prompt 中写的那些上下文管理的指令了!

于是我又做了一个更加复杂的系统。我在 agent 中引入了提醒机制,还引入了给 LLM 的行为打分的机制。每隔一定的轮数,当我发现 LLM 没有根据 system prompt 中的指示去管理上下文, 我就会在 agent 中插入提醒指令,告诉 agent 需要去做上下文管理。而打分机制是,如果它主动去调用上下文管理的工具,它的评分就会高。 而反之如果它忘记做这些事情,提醒就越频繁,在 agent 中插入的信息,告诉 LLM 它表现得不好。

简直把复杂度推向了一个极端,结果是一个很脆弱的系统。我问 LLM,把我的 coding agent 的上下文管理和 codex 等其它 agent 对比,它怎么看。 它告诉我,这个设计很先进,但是它不喜欢。它更喜欢 codex 的做法,理由是对于 LLM 的心智负担低。 这就是典型的 over-engineering hurt performance。所以反思之后,我重新设计了一版。

理念倒是没变,我还是会让 LLM 自己管理上下文。在新版的实现中,我拆分成了 normal 模式,和 context management 模式。在 context management 下,LLM 还是需要自主决策。 我会给它 llm context update 的工具,给它 truncate message 工具,给它 compaction 工具。它自己决策执行什么样的行动。 llm context update 会维护结构化的上下文,而不是维护对话历史。truncate 会清理和截断工具输出,由 LLM 来决定哪些保留,哪些不再需要。 而 compact 则和常规的 agent 中的 compaction 差不多。我会更频繁地让它进入到 context management 模式中,做一些上下文维护的决策。

这里我学到的经验就是,不要通过 prompt 给 LLM 很复杂的指令去控制。

不要让它完成任务的同时,还要分心关注非任务相关的内容。它是很难遵守的,而为了让它遵守,去引入提醒机制,引入打分机制, 这都是在增加熵。哪怕模型越来越聪明,它也不喜欢这种形式的规则约束。

spec driven development

spec driven development,或者有些 agent 里面叫 plan mode。这是一个非常有价值的东西。

我最初被惊艳到,是在我只给我的 coding agent 实现了基础的 compaction 功能,还没有做太多的打磨和优化的基础, 套上 spec drive development 之后,它居然可以自主干 2 3 小时不停下来,直到完成任务。

我基于早期版本的微软的 spec-kit 改了改,做了个技能。 使用的时候就 /speckit "帮我开发了个 xxx feature" 这样,它就会一步一步地先写 spec,再到 plan,再拆分 tasks。

前期我会较多地跟 agent 交互,以明确需求。而到后面 task 拆分完毕的阶段,就可以 agent 自动干活了。

然后 superpowers 那边的 brainstorming 技能,也是我非常喜欢的。 可以前面先通过 brainstorm 的方式来明确需要,产出 spec。

为什么 spec drive development 有用?为什么我们直接让 agent 做一些事情,做到后面会做偏?

我认为其实核心在于实现 tasks 的步骤中,有一个很好的机制:每完成一项 task,更新 tasks.md 文件,将 - [ ] 勾选成 - [X]。 这是一个非常强大召回机制,即使发生过 compaction,只要 compaction 还保留了任务信息,只要它还知道去更新 tasks.md 文件, 它就会再次读取任务信息,于是把任务的内容召回到当前上下文中。于是总体更不容易走偏。

如果没有这种机制的时候,很容易在长的复杂的任务中迷失,比如某次 compaction 后,agent 就忘记自己的 tasks 做了哪些还剩下哪些。 通过 speckit 的 prompt 去引导它完成任务后更新,这样间接是实现了一种提醒机制,使得稳定性大大地提高。

tmux 和 subagent

在我的 coding agent 里面,提供的工具是极其稀少的,跟 pi 一样,走极简路线。我只提供了 read / write / edit / grep / bash 几个工具。 最重要的是提供了 bash,而有了 bash 之后就有了一切的外部交互的基础,可以调用任何 cli 命令行了。

后台任务和长时间执行的任务,我在 system prompt 写了不要 bash & 去做,都走 tmux。这些在许多其它的 agent 中都会提供工具来处理,而我这边则坚持不提供。

tool 不足的能力,用技能来补全。技能其实就有几类,描述做一件事情怎么做,或者描述一个 cli 工具怎么用。这样几乎绝大部分需要用 tool 形式提供的功能,都可以改用 cli 来提供。 这样做的好处就是不侵入 agent core。我有一个 tmux 技能就是告诉 agent 怎么使用 tmux 命令工具。

再然后是 subagent,其实就是 ai -mode headless 就行了。然后有命令行支持 -system-prompt 可以换不同的系统 prompt,从而支持不同的 persona。 特定的事情可以起特定的 subagent,设定一个人设。

tmux 和 subagent 这样的技能,尤其是 subagent,提供了我的 coding agent 的基础。 勿在浮沙筑高台,基础打牢了才能去做一些更高级的功能。

在此之上,我又做了 review 技能和 explore 技能,它们都是通过 subagent 赋予特定的 persona 去完成的。 比如我可以写 /review "帮我 review http://github.com/tiancaimao/ai/xxx 这个 pr" ai 就会启用 subagent 去 review 这个 pr 了。

我迟迟都没有引入 team 或者更复杂的 agent 编排,是我一直想要需要把单 agent 先做好,地基要先打牢。 在单 agent 时代,我已经可以通过 spec drive development 的方式让 agent 自主工作几小时级别。我还没想好 agent 编排怎么做,但是旧的这个阶段已经是相对稳定的。

引入 subagent 打下了一个很好的基础。其实原理还是在上下文管理这一层。假设我们要做一些任务,这些任务都由主 agent 来做, 那么执行过程中留下的任务信息,就会污染上下文。当上下文使用率越高,agent 的表现就会越差。就是注意力总是有限的。

所以当我们使用 subagent 去执行任务,任务过程中的这些上下文,都随着 subagent 的退出而结束了。我们只保留下了结论性的内容到主 agent 中, 这样主 agent 的上下文就会干净很多,于是效果也会变好。

work-judge loop

除了 spec driven development 以外,我还有用到的一个特别有效的东西,是 work-judge loop。

这也是一个非常好的 pattern,LLM 经常自己认为自己做完了,或者没有什么问题了。然而缺乏检查的机制下,总是容易漏掉一些东西。

我有在我的 system prompt 里面强调完成标准,包括参考 codex 那边的 system prompt 它也是有相关的描述的,比如要求返回给用户之后,确认测试是真的测试过,或者证明自己的改动是验证过的。 但是即使写在 system prompt 中的强调,LLM 也不一定遵守。

我们需要一些其它的模式,典型的比如一个 agent 写代码,我们就不能让它自己来 review 代码,必须由一个干净的新的 subagent 来做 review。 经常都会观察到,写代码的 coder agent 认为完成了,而 review 的 subagent 又可以揪出一堆问题来。 于是这个模式可以设计是一个常见的 pattern 循环下去,这个就 work-judge loop。

这里还有一些关键点,比如需要有办法来验证任务是完成的,有明确的可检查的结果。我记得自己第一次烧到 1B 的 token 的时候,那个任务就是持续了几天级别,我要把一个大型的 MMORPG 的编译修复掉。 agent 能持续地自主工作,是因为这里有非常明确的关于"完成"的验证标准 -- 就是编译通过。

像 TDD (test driven development) 也是属于这种,能明确去验证完成标准的。测试先行,这样就可以验证 agent 说自己做完了,如果实际没做完,就会被拦下来。

还有就是 ralph loop,注意,这里也是用干净的环境,在外部脚本去设置完成条件的判断,只要判定是工作未实际完成,就去驱动下一轮的继续循环。

小改动,可组合

在探索 agent 编排的过程中,我犯过一个错误。当我看到一个其它的做法,我就让 agent 抄过来。 由于 agent 抄代码抄得太快了,我很容易就能够把一些功能能抄过来。

但问题是,每一个实现方案,都有它背后的理念。这些理念并没有谁是对的,谁是错了。只是不同的人,喜欢不同的理念罢了。 这就好比编程泛式中,有的人喜欢面向对象的,有的人喜欢函数式的,或者有的人觉得 actor 模型更好。 所以 agent harness 这块也正是这样,没有所谓唯一正确做法,大家都是在探索。

然而当我东一抄,西一抄,抄出来一坨的代码之后,我发现它根本就跑不起来,用不好!

为什么呢?后来我就意识到了,真正重要的是,学习理念,而不是抄袭代码。 有了 ai 的加持,抄代码的成本很低的。但是抄过来的代码,想要用好,并不容易,用好的前提是需要理解背后的设计理念的。

反之,如果理解了一个东西的设计理念,根本不用参考代码,自己让 ai 写一个也写得出来。而且写出来的东西,经过微调,它就是最适合自己的。

举个例子,当我理解了一些方法论之后,我甚至可以完全不使用技能,来做一个功能。 我可以跟 agent 说,"我想知道某个功能怎么做的,你并发使用 subagent 去探索 A / B / C 这三个库,分析后做一个总结"。 我知道使用 subagent 不会污染上下文。这就是 /explore 技能。

下一步,我可以跟 agent 说,"通过刚才的探索,我们已经了解到了一些背景信息了,现在我们一起讨论一下具体到我这个项目中,应该怎么实现它。你可以通过向我提问的方式,来明确实现方案"。 这样 agent 就会向我提问来细化需求了。这就是 /brainstorm 技能。

当我跟 agent 交流明确之后,我就会告诉 agent,"你把我们讨论的这些,整理到一个 plan.md 文件"。这就是 /speckit 技能的 spec 阶段。 再接着,"把具体任务拆小到多个阶段,细化子任务,每个子任务都可以独立完成。生成到一个 tasks.md 文件,文件的格式要记录 - [ ] task1 - [ ] task2 ..."。嗯,/speckit 的 plan 阶段。

然后我再告诉 agent,"对于 tasks.md 中的每个子任务,你使用一个 subagent 去完成。注意完成以后需要更新 tasks.md 中的任务进度,勾选 - [ ] 变成 - [X]"。 我还可以告诉它,"每完成一个 phase 之后,启动一个 code review 的 subagent 来 review 当前的工作,如果 reivew 通过,则提交保存并进入到下一个 phase,否则继续 worker-judge 的循环"。

纯纯的 prompt engineering!可以在不用任何技能的情况下,完成整个开发流程。这就是理解理念,而不是停留在使用工具阶段。

这是在我知道怎么做一些最佳实践之后得出来的经验。等我知道怎么样写 prompt,也就知道怎么把这些东西变成可复用的技能,下次就可以不用敲这么多的 prompt,直接告诉 agent 用什么技能来做什么。

可组合是非常重要的,通过技能的组合,就可以从基础 block 搭建更复杂的工作流出来。而且小的自己写过的技能,自己能理解理念,并且方便单个做验证。 反之,从其它地方抄过来的一大坨东西,则会由于没理解而消化不良。

从使用工具,到构建工具

有时候看到别人做的东西很惊艳,而再看自己的 coding agent,依然是一坨的时候,无数次想要放弃过。但是都坚持下来了。

这个东西就跟 emacs 很像,世界上有两种人,一种是使用封装好的工具,比如 vscode 搭配现成的许多插件。很容易上手,也很好用。

另一种是坚持造自己的轮子,让工具适配自己,而不是自己去适配工具,我选择了后者。有些场景确实别人开发的很成熟的东西,比如 codex 比如 claude code,然后又围绕它们有非常多的插件,拿来就可以用。但是这种过程是不创造复利的。

现在 ai 已经将自己维护自己顺手的工具,这件事情的成本压得很低很低了。而自己造的这些工具,是用来解决自己的问题的,一定是最顺手的。这个过程中可以学习和理解到“怎么做”,而不单纯是“怎么用”。更重要的是这个过程会掌握背后的理念,这才算是学会。

当我把 tmux,把 subagent 做稳定好,就再往上一层构建日常的技能,一个一个加,一个一个打磨。于是有了 /speckit 的技能,有了 /session-analyzer 技能等等其它的很多东西。

不过要注意的是不能闭门造车,要时常去探索一些其它的东西,看看其它人解决一些问题是怎么做的。探索的过程可能就需要去学习别人的工具的使用,通过使用过程去理解背后的设计理念。

auto research 和 wiki

卡帕西的一些东西是真的很酷,非常多不错的 idea。比如说 auto reserach 和 wiki。

auto research 可以把实验过程非常多重复性的劳动压缩掉。比如,我自己优化我的 coding agent 的过程,可能就是想一个 idea,然后跟 agent 讨论一下是否可行,如果可行,就实践一版。 然后需要测试去验证一下是否有效。

而使用 auto reserach 之后,我会这样做,比如优化 context management 实现。我先让 agent 从我的历史 session 中去挑选一些,构建测试集。我会让 agent 分析,哪些 session 哪些 context managemt 的触发是好还是坏, 触发前后的上下文内容分别是怎么样的,然后引入 agent 来打分。构造一组的测试 case 之后,就可以来验证 context management 的实现到底好不好了。

然后,把上一轮的结果评价喂给到一个 coding agent,让它根据反馈去优化代码。整个过程就可以做成一个循环的脚本:跑测试集验证 -> agent 打分和反馈 -> 根据历史决策进入下一轮代码优化 -> 下一代的验证。

如果优化后的效果好于之前,则保存成新的 baseline,反之则继续探索优化方向。这样就可以开启 agent 的自进化之路。

在我实际的操作中,感觉进化其实比较低效,并没有自主探索到一些架构层的优化,而只是代码层和 prompt 层的修修改改。 Anyway,这个东西也没那么好做,但至少经历这样的实验过程,我可以知道当前的实现的稳定性是怎么样的。

网上有那种,比如 claude code 源代码泄漏,然后 vibe coding 一天就搞一个复刻品出来,这种不用信,没意义。 因为我写 agent,我知道抄一份代码去 demo 是特别容易的,而让它真的能用则需要不少的打磨。 最不一样的点,关于 agent 的稳定性这种东西,它不像是 C 语言编译器那样,有一个海量的测试集可以验证实现的正确性,要想真正做一个日常能完全替代 claude 的产品,尤其是使用的稳定性打磨,这背后根本离不人 human in the loop。

wiki 也挺好用的,我弄了个 wiki 技能,这样就可以 /wiki "把这个文章入库", 以及 /wiki "帮我查一查 xx 概念"。这也是会随着越用越多,而越来越好用,变成复利。

symphony

openai 那边有一个项目叫 symphony,原版是用 erlang 写的。它里面是有一个 SPEC 的,这个项目说 “你可以选择你使用的编程语言,让你最喜欢的 coding agent,去自己构建一个 symphony”。

于是让 ai 给弄了一个 Go 语言版本的。用着还行,只是我把其中的 linear 部分改成弄了一个极简易的 kanban。这个项目就是你告诉它做啥,先一个任务过去,它自主地一步一步推进, 我加的状态转换是 inbox -> todo -> running -> self review -> address coment -> done 这样的链路。只要丢一个任务进去,它就会自动地一步一步往前推进,会自己实现并 review 完之后,等待人工 review。

可以把低级的重复劳动给避免掉,我一般只是用在比较小和 pr 改动或者 bugfix。我做了一个额外的 /symphony 技能,然后我还是在编辑器里面,有时候会跟 agent 说,"/symphony 你提交一个任务丢给 symphony 去做吧,不要自己处理"。 相当于是有一个后台的程序,可以实现自己完成任务并提 pr,而我的 coding agent 作为一个前端交互界面。

只适用于比较简单的改动,如果复杂的,我还是会在终端里面跟 agent 对话,讨论清楚方案,在前期做许多事情。

关于 ai coding,我觉得有两个点是始终不能放手的:

  • 第一个是设计阶段
  • 第二个是 review 阶段

设计阶段一定要重度参与,把控好方向,只要自己重度参与过设计阶段的,才能能理解项目大的脉络。然后就是 review 阶段,就是代码还是要看一眼的。不是为了挑出 bug 或者什么,ai 可以来做这个事情。 在 ai coding 时代的 review code 最最重要的目标,是只有自己看代码,才能够把控实现。否则到了后期,软件会维护不下去。

我就犯过这样的错误,最初觉得 ai 无所不能,还说 "ai 写的代码,老子一行不想看。跑得过就跑,跑不过换个 prompt 再搞搞,反正莽过去就行了"。这么做,到了后期会带来巨大的反噬,经常 ai 改一个 bug,送两个 bug。 然后 bug 就改不完了,没完没了,产出的项目非常脆弱。

并且由于一开始在代码量少的时候没读,后面代码量大了,再想读也没机会搞了。这个时候就只能靠“许愿”编程,许愿 ai 能够修复问题。但是有时候 ai 会回应这个愿望,也有时候不回应,总之,走到这一步就已经完全失去控制力了。

纯粹的 coding 被消灭了,毕竟 ai 写东西的速度快 10 倍,快 100 倍,那么"古法"编程方式去手写东西是完全没有性价比的。 但是软件工程并没有被消灭,软件工程有它固有的复杂性,ai 生成代码的速度很快,同样地,它生成技能债务的速度也很快。 如果没有人类的把控,这个地方很容易就复杂性爆炸,无法维护。而人类去想办法控制 ai 按要求产出,变成了一项系统性工程,这就有了 harness engineering。

DAG vs 聊天室

在研究多 agent 编排如何一起协作完成任务的时候,我看到两个不一样的方向。

其中一派倾向于把确定的东西都代码化,脚本化,把流程构建成一张确定的 DAG 图,agent 只是充当其中的节点,去填空的地位。而外层驱动是由确定性的程序去驱动。 以 symphony 为例,它的任务状态变更就是很明确的 DAG,agent 拿到某一步的任务状态,就是把任务推动到下一个状态,那么这步就完成了。agent 不负责全链路的流程。langchain,langgraph 就是属于典型的这一派的。

再比如 spec driven 那边,从 spec 到 plan 到 implement 的各阶段,也是很明确的不同阶段状态变更,这个时候细节上有两种做法,一种是用 markdown 以 prompt 的形式描述整个流程,让 agent 来驱动各阶段的变化。 而另一个做法是,可以写成特定格式的模板,记录各状态下的一些信息,给 agent 提供一些 cli 来调用驱动,cli 背后会写确定格式的文件记录状态信息。有个差异是,后者把能确定的部分都确定化, 于是像其中有崩溃恢复等,都是可以做到的。就是偏 DAG 的流派。

至于另一个流派,他们倾向于把 agent 当人类来看待,给 agent 不同的角色,给它们一个聊天室可以相互交流,碰撞出灵感的火花,以这种方式来协作任务的完成。比如 gstack,比如说 "三省六部",这种东西就授予了 agent 不同的角色。

slock.ai 也属于后一个流派的代表,可以让 agent 自己去聊天室交流和协作,而人类也可以加入其中去参与讨论。这种方式上的灵活性很高,但同时也很容易不稳定。

不是所有任务都是确定性流程的,可以容易做到 DAG 化的。还是举 spec driven development 的例子,spec plan implement 这些阶段性的东西是可以固化的。 当我们 plan 阶段,要把 plan 拆解出小的 task,并且 task 之间的依赖关系,这其实就会生成一个 DAG。但是呢,这个 DAG 就是一个动态化的,不是能提前确定形态的。 如果我们换一个视角,把 agent 当人来看,就可以拆成有 agent 发布任务到一个任务队列,又有 agent 从任务队列中提取任务并执行。 更是还可以有消息中心去发布,某个任务完成,下一个 xxx 任务被解锁这样的消息。

agent 自主驱动的形态下,有一个不稳定的地方是,它不一定都按照 prompt 描述来,尤其是当上下文使用率比较高之后。 比如说,spec driven 上下文用得比较多了之后,我就有遇到 agent 不再按照它原本的 tasks 的阶段来,也不去勾选 tasks.md 更新进度,并且倾向尽快收场草草完成。 slock.ai 它在本地的代码是可以看到的,就是一个 nodejs 脚本实现的 daemon。它的 agent 的 prompt 里面其实就是一个循环,它让用 mcp 协议从 channel 接受到消息,完成任务,再 block 去等待下一条消息。 这个东西是纯 prompt 实现的循环,所有就有可能出现,比如它不再走这个 prompt 描述的循环,然后 agent 就会卡死不响应了。

我自己的 coding agent 这边还是处理早期的探索,还没有把编排做清楚,但是从我当前掌握到的知识,会更倾向于有一个 orchestrate 或者说 coordinator 节点的 agent,来负责和人类对话,并协调其它的 agent。 感觉 team 的形态会更不稳定一些,所以相比于让 agent 之间可以端到端直接对话,我会倾向于都走 coordinator 中心节点这种消息通道。能够固定化的部分,尽量偏 DAG 化,由程序来确定性的驱动。

关于 token 焦虑

ai coding 时代,现在 token 是硬通货了。最焦虑的事情莫过于,5 小时用量马上耗尽了,而任务还在跑还没完成。又或者用量刷新的第一天,一周的 token 都耗尽了。焦虑接下来咋办。

我这边是用的 GLM 的 pro 的 coding plan (老版的 pro,据说是比新版 pro 实际用量给得足),然后再叠加 gpt plus 或者 team。 实际使用的体验上,模型能力方面 GLM 5.1 当前阶段就差不多是国内最强了,但是离国际水平还有明显的差距。有些 bug 就是修不好,换更强的模型就可以。不过总体上可以解决 80% 的场景。 以前试过一阵子 minimax 的套餐,从 2.5 到 2.7,感受都不太行,模型能力不足以搞定 coding 的大多场景,可能只养龙虾比较适合。不得不说的是,响应速度是真的挺快的,比 GLM 要快太多了。

现在的这些 coding plan,倒是越来越难抢了,算力紧张的结果吧。如果好抢我倒是挺想多维护一些各家的模型,主要是通过使用更多的模型来打磨我的 coding agent 的模型接入的能力。 这块真的是一个协同进化的过程,就是 agent 的 harness 跟模型本身,其实需要整体来评估。

如果只单走 gpt plus 用量,完全不够看。而升级下一档的成本又是挺高的,所以就是国产模型搭配着用,国产的主打一个量大管饱。现在每天到下午了简直卡得不行,服务太烂了。受限于 GLM 那边的限流,team 模式很多时候都是玩不好,更稳定的方式也就是固定模板的 workflow 了。

很多烧掉的 token 都浪费掉的,比如每天半夜在睡觉前跑一轮 benchmark,第二天早上起来看看结果,分析一下自己写的 coding agent 是否有一些测试回退。再比较前面的 evolve 自进化实验,也是放差烧 token 但是不保证回报的。 大概就是比较重要的事情,或者国内模型搞不定的,上国外模型,总体性价比较高。

AIharness engineering