

同一段提示词递给模型三遍,第一遍它老老实实写短函数,第三遍就开始堆三百行的巨兽。模型的记性靠不住,靠嘱咐没用,这是写代码的助手身上最老的一个毛病。
CodeAgent 是一个开源的编码助手,骨架是39个基本模块,这一版在三件事上补了课,一部宪法,一条接单线,一套自己安排活儿的办法。三个东西各管一段,宪法管写成什么样,接单线管谁来干、干完说一声,编排管先干什么后干什么,这一版就是 0.8.0。

PART 01

提示词管不住的那段,交给实物

提示词就是每次递给模型的那段话。指望它替你把纪律记住,等于每次开工前跟工人念一遍安全手册,念得再熟,也架不住有人走神。这套系统换了个做法,把纪律做成三件实物。
第一件是一份短文档,正文980字,分成三层。常驻的有五条,不许编造,不许越权,边界内做到底,只认一个现行说法,说了就做。
按数字判的有11条,函数不超过50行,嵌套不超过3层,圈复杂度不超过10,另外还有四类东西要求为零,死代码、被悄悄吞掉的错误、空壳函数、明文写的密钥。剩下五条只在审查环节加载,讲审查时该看什么。
分层的理由是省,写代码的人不必背审查口径,审查的人也不必背那几个数字。
第二件是把这份文档真的送到模型眼前。系统在三个地方把它接上,写代码的入口,循环写码的入口,代码审查的入口。
接上多少能数出来,写码提示里多出1549个字符,循环的入口多出2612个。万一加载失败,它不会悄悄少一段,会在提示里留下一个显眼的记号,让人一眼看出这份文档没进去。
这一条看着笨,却是整套东西立不立得住的地方。文档写得再细,没送到它眼前就等于没有。
第三件是一个能跑起来的脚本,读同一份阈值文件,把仓库里的 Python 文件逐个看一遍,给出超线的清单和退出码。数字只有这一个出处,文档里写的必须和它一样,另有一段自检专门核对两边,免得改了代码忘了改文档。
三件实物之外,还有两处设计值得说。
一处是例外,规矩太硬会逼着人绕着走,所以超线的地方可以写一行注释说明理由,写了就放行,同时记进一本账,这本账的意思是例外要留下名字,不能默默存在。
另一处是只给旧的记账,只拦新出现的。第一次把这个脚本对着整个仓库跑,出来的数字是809条超线,226条提醒,13条已登记的例外。
这些都是积下来的欠账,一次清完不现实,先把它们写进一本底账,再规定往后只看这次改动新添的,取不到底账就明说判不了,不假装通过。这条规矩单独写成了一个脚本,也接入了每次提交都会自动跑的检查。
PART 02

派活最费神的一步,是替它想清楚怎么做

在这之前,往这套系统里派活,得先想清楚调哪个能力,参数怎么填,产物落在哪。活一多,每次派单都在重复同一遍思考。
现在派活的人只写要什么,写进一本队列文件,每一项包括任务名、目标、验收命令。系统那边有一个每十五分钟看一遍队列的轮询,见到待办就领走。领走的时候先把状态改成进行中,再动手,这样即使中途崩了,也不会无限地重领。
同一时间只允许一个轮询在跑,用锁文件卡住。做完在任务下面追加结果,成功失败都写,失败就写阻塞和原因,不粉饰。接手的人不用追着问进度,打开那份文件就能看到它做到哪。
领走之后怎么干,有两条路,能自己判断的,走规则层的选链,关键词命中一张表,直接给出该按哪几步做,这一步不花钱叫模型。任务里写明步骤的,就按写明的来,一步一步调,前一步的产物交给后一步。
这条线第一次真跑,领到的活是修它自己的一个毛病,就是下面第三个。
PART 03

它会自己排先后,跑不动会停

编排说的是先干什么,后干什么,干到什么程度停。
现成备好的路线有6条,修缺陷、补功能、审代码、看依赖、写测试、查根因,这六种最常见的活各有各的走法。每条路线是一串能力,前一步的产物会变成后一步的输入,比如写码产出的文件直接递给审查那一步。
写码那一步最花心思,它不叫生成代码,叫循环。流程是这样,先想一遍再动手,产出一个计划,然后把文件真的写出来,接着跑一条事先指定的验收命令,看它过不过。
不过就照着报错改,改完再跑,直到过了,或者到了次数上限。验收命令是派活的人给的,比如编译某个文件。
这圈循环还带三道刹车,步数上限、重复动作上限、模型调用上限,任何一条触到就停下来,状态写明 halted 和原因,而不是一直烧下去。
底下还有两个面在记账,一个是事件账本,每次动作可以追加,可以回放,可以拉一条时间线,出了事能倒着查。一个是任务状态,两边读的是同一份文件,外面看到的进度和里面做的事情是同一件,不会各说一套。
PART 04

这一版修掉的三个毛病

三处都属于跑了以后才知道坏的那类。
第一处
管纪律的脚本认不出自己那份写坏的样本。仓库里放着几个故意写坏的文件,用来试它灵不灵,按事先的约定,文件名以 bad_sample 开头就跳过。实际跑起来,它们照样被当成超线报出来。
根子在比较的方式上,不带通配符的名字要求一字不差,badsample 和 badsample.py 不是同一个字符串,于是那条约定等于从来没生效。改法是按开头几个字判断,写坏的样本回到该在的位置。
第二处
自检自己的样本撞上了这个名字。改完第一处,自检开始报写坏的样本应当失败,可它没失败。查下去才发现,这段自检用来造违规样本的文件名,恰好也是 bad_sample 开头,整个文件被跳过,一条违规都没看到,自然就不会失败。
改法两步,样本改个名,同时补一条断言,专门验证那条跳过约定本身还有效,免得以后又悄悄退化。
第三处
它是自己修的,改的是它自己的命令行入口。循环写码这个能力带一个命令行的自测入口,直接跑会报错,说这个能力不收参数 edits,它收的是 task、path、outputdir、verify、language、maxiterations、fakemodel、modelconfig、write_root。
根子在命令行那一层,edits 只有出补丁的能力才收,命令行却把它一起传给了写码能力。改完只在需要的时候传,命令行就能跑通了。这一处正是接单线派出去的第一单,也是它第一次动手改自己的入口。

PART 05

怎么上手

地址是 https://github.com/zhengjinjun1975/codeagent-minimal ,版本号 0.8.0,仓库根目录的 CHANGELOG 里有这一版的条目。
gitclonessh://git@ssh.github.com:443/zhengjinjun1975/codeagent-minimal.git
python scripts/verify_code_constitution.py# 自检文档和代码对不对得上,29 项断言 python scripts/constitution_gate_changed.py# 只看这次改动有没有超线 python -m pytest tests/ -q# 全部单测,212 个
该说的还有没做完的部分,一起摆在这儿。管纪律的脚本对整个仓库跑出来的809条超线,这一版只记了账,没有清,四类要求为零的东西里也还有旧账。
接单线目前只有写得动代码的那条路是循环,写报告这类任务还得靠写明步骤,还没到它自己想清楚该报什么那种程度。基本模块39个,管的是写码、审查、测试、依赖、安全这些环节,不是什么都干得了。
模型的能力还在涨,这一版管的是另一头,把它的产出、它的越界、它的沉默,摆到能被跑起来、能被记账、能被拦住的地方。