Vibe Coding 闲谈:如何设计一套双层Loop 的 Harness系统

机智流 2026-06-27 23:27

Vibe Coding 闲谈:如何设计一套双层Loop 的 Harness系统图1


本文编译自外网

把 SQL parser 重写一遍这种重活儿,听起来不该让 Agent 去干。

因为Parser 是典型的"一个字符都不能错"的东西。PostHog 里尤其如此:用户直接写 SQL 查数据,产品分析、session replay、error tracking 这些内部功能也走同一道门。Parser 搞错的后果非常严重,会影响后面的权限控制、查询优化、ClickHouse等等。

但是我通过设计了一套双层Loop 的 Harness系统让AI完成了这个工作,我同时跑了几个 Claude Code session,让它们并行把原来的 C++ ANTLR parser 重写成了 Rust 版本的 hand-rolled parser。最终产出:16K 行 parser 代码,5K 行工具代码,外加几千行测试。本地 benchmark 快了约 70 倍,线上平均快了 454 倍。

Agent开发过程中有意思的是,整个过程中我几乎没手写一行 parser 代码。让我敢把这种东西上生产的,也不是"Claude 写的代码看着还行"。是一套我专门设计的 Agent harness——它不写 parser,它只做一件事:制造反例。

给Agent定义好问题,并告诉它到底需要做什么

PostHog 的 SQL 查询不是直连 ClickHouse。中间有一层转译:把用户看到的逻辑数据模型,变成 ClickHouse 能直访问的物理 SQL。好处很明显——数据库换物理结构,用户查询不受影响;转译阶段顺便加权限控制和性能优化。

Parser 错,后面就会全错。这就是问题定义:你需要一个又快又好的 agentic 代码。不是 demo,是跑在生产上的核心组件。

旧实现:ANTLR 通用引擎的重负

原来的 parser 是 ANTLR 自动生成的,C++ 版本。

在 vibe coding 成熟之前,这几乎是唯一合理的选择。手写 SQL parser 完全是脏活,几个月起步,语法边角无穷无尽,维护成本高到不值得。ANTLR 解决了边际效应的问题。

但 ANTLR 的通用性要付代价。它把 grammar 编译成一张运行时状态图,然后用一个通用解释器去遍历图。每处理一个 token,都是一次图遍历。它还支持动态 lookahead——如果当前位置有多条分支都合法,就同时模拟这些分支,一路跑到只剩一条成立。

这听起来就很通用,但通用的东西一般都不会拥有很好的性能。手写 recursive-descent 可以把 99% 的热路径变成一串直连调用,只有真正需要的地方才做 lookahead 或回溯。ANTLR 照顾的是任意 grammar,不能只为你的业务逻辑优化。

旧实现已经是 C++ 了。这次提速跟语言关系不大。真正改的是执行模型:扔掉通用解释引擎,回到最直接的代码路径。

问题是——在 AI coding 出现之前,这条路走不通。因为"最直接的代码路径"意味着你要自己去写和维护十万行级别的 parser 代码。

AI coding 让手写变得可能。让开发速度极具变快,但"可能"和"敢上线"中间,隔着一整套 harness。

Agent 不是下指令就完事

我的初版尝试很朴素:让 Opus 用 Rust 写一个新 parser,嘱咐它别出错。

这种口述的prompt根本是不起作用的,它当然出了,而且不只出 bug。写到一半它还会开始怀疑你做的这件事的正确性——"这个语法规则太复杂了""也许我们不该完全重写"——每跑完一轮修正,它就倾向于收工。"差不多了吧。"

这是Agent的通病,为了继续快速迭代我开了两个 parallel agent session,走两条不同的实现路线。

第一条压性能:recursive descent 核心 + Pratt expression loop,只在极少数位置放宽到 lookahead 和回溯。这是我脑子里最快的 parser 形态。

第二条压成功率:行为上尽量贴近 ANTLR 的语义,但把运行时图遍历换成显式手写代码,不依赖通用引擎。

两条到后来都跑通了,效果差不多。但在跑了好几天之前,我不知道它们能不能活下来——Agent 也不知道。能做成,不是靠 prompt 写得妙。是靠着 oracle。

旧的 C++ ANTLR parser 就是 oracle。它不是用来比速度的。它是用来告诉你:在新 parser 上跑同一条 SQL,吐出来的 AST 对不对。

有了 oracle,Agent 的工作就变成了:找一条输出不同的 SQL,修,加入回归测试,找下一条。Agent 不需要"对"的判断力——它只需要修复差异,harness 负责判断对不对。

这个 harness 的设计,围绕着同一个句式展开:只要新 parser 和 oracle 输出不同,就记下来,缩小,加入回归测试。Agent 只管修到消失为止。

Harness 的核心:制造分歧

起步阶段,分歧很好找。PostHog 自己就积累了不少回归测试。

把这些跑完之后,有意思的问题来了:怎么持续生成新反例,让 Agent 不断暴露它还不懂的东西?

答案:property-based testing。

Property 是一行定义:新 parser 的输出永远跟 oracle 一致。输入是一条 SQL。PBT 框架要做的就只有一件事——拼命搜索能打破这条规则的反例。

我用的是 Hypothesis。但我不能直接让它生成一堆字节当作 SQL 扔进去——那样大部分时间都浪费在非 SQL 字符串上。我需要告诉它"什么是合理的 SQL"。

于是我和 Claude 又写了一个工具:让它读 ANTLR 的 .g4 grammar 文件,自动 codegen 出 SQL generator 的代码。写 parser 写到一半,又给 grammar 文件写了个 parser——挺好笑,但这一步是 harness 的分水岭。

有了 grammar-based generator,harness 知道了"这个语法长什么样"。它可以生成合法但不常见的 SQL,可以故意在合法边界上试探,可以反复打 parser 的冷门分支。

后来我在这台 fuzzer 身上又加了几层:

  • 基于 grammar 的变体生成:随机交换 token 位置、加括号嵌套、打乱顺序仍然合法的子句。
  • 生产日志采样:从匿名化的真实查询日志里抽。现实世界用户的 SQL 经常写得比 AI 想的更怪。
  • "认真想边界条件"Agent:这是我最意外的做法——我放了一个后台 Claude agent,不写代码,只负责坐在那里想"什么 SQL 会让 parser 难受"。听起来不像工程,但它找出来的反例质量异常高。

光生成不够。反例往往很大——一条两 KB 的 SQL 把 parser 炸了,Agent 没法对着它 debug。Hypothesis 自带 shrinking,能把大样本压缩成最小复现。生产日志里出来的 SQL 不走这套,我又给 harness 加了 ShrinkRay。

再往后,加了 coverage-guided generation。生成器追踪自己覆盖了哪些 grammar 分支、哪些还没动过,然后有意识地往缺口填。这一步不是必须的——要在生产查询上做到零分歧,前面的措施已经够了。但它挖出了一小撮非常隐蔽的边界问题,属于"只有专门写坏模型的人才想得到"的那种。

这时候回头看:我写的 parser 代码量是零。我写的 harness 代码量,大概五千行。

Agent 会忘事,Harness 要提醒它

vibe coding的时候总是会有段时间特别容易让人暴躁:那就是Agent 修 bug 修得特别脆弱的时候。

它经常会这次发现差一个 token lookahead,它加上。下一轮发现不够,改成两个。再下一轮,发现这里不该补 lookahead,应该按 grammar 的另一条分支处理——之前加的代码全白费,还搅乱了别的逻辑。

根因分析很简单:context window 打满后做了 compaction,Agent 忘了完整的 grammar 长什么样,也忘了旧 C++ parser 在相关位置到底用了什么策略。

人类工程师忘了可以用 git blame。Agent 忘了,就只能靠 context 里还剩下的碎片往前推。

我的解决方法一点都不神秘。

每次开始修一个具体分歧之前,我让 haraness 强制把两样东西再喂进 context:grammar 文件,和旧 C++ 实现在相关位置的源码。不是一直放在 context 里占窗口——是在动手前那一刻,重新塞进去。

这不是 prompt 玄学。是 context 管理。Agent 的记忆不可靠,但文件是可靠的。它需要被提醒,harness 的职责之一就是在它动手之前替它翻开这两页。

这个道理我花了比预想中长得多的时间才学会。但一旦学会了,Agent 的修复质量直接跳了一个台阶——不再像在补丁堆上打架,更像一个有完整信息的工程师在做局部重构。

两个 loop 都跑满

到了冲刺阶段,我只想做一件事:CPU 永远在 fuzz,Agent 永远在修。

我给 harness 加了一个后台常驻进程:PBT 和线上采样不停跑,新发现的失败反例不断往文件里写。几个 parallel Agent session 共享同一个失败队列——手头没活了就取下一个,修完归队。

两条 parser 路线的 Agent 共享同一套回归测试。A 路线发现的 bug,B 路线的 Agent 也能立刻受益——不需要我手动同步,队列天然就是共享状态。

每轮修完后,Agent 不会直接跑下一轮。它会先输出一段简短说明给人类 operator(也就是我):这次修了什么,用什么思路。我的工作从看代码变成了读说明、看通过率曲线、判断修法是在逼近通用解还是在打补丁。

Agent 修代码。Harness 负责找茬、缩小反例、维护回归测试、喂上下文、判断修得对不对。两边各跑各的,互相不挡。

Harness 够好,你才敢上线

新 parser 太快了。快到我不需要对线上流量抽样验证——直接把新 parser 放到生产环境旁边跑 shadow mode。

同一个请求过来,旧 parser 和新 parser 各跑一遍,暗中对比输出。几百万次 parse,我就等在另一边看分歧计数。

零分歧。

我本来打算让它跑几天。几个小时之后的结果已经足够硬,直接把生产流量切到了新 parser,只留 0.1% 的 reverse shadow 继续盯。

线上平均快 454 倍。标题说 70 倍,是 Mac 本地 benchmark。线上 SQL 平均更长,而且很多请求不命中 parser cache,差距拉得更开。

这是是一个过去大概要领域专家花几个月才能做完的东西,我用几天时间做到了——不是凭靠 Agent 的智力,是凭靠 harness。

整体的流程其实不能再称为vibe coding

如果流程是:跟 Claude 说"写一个 Rust SQL parser,要快"——然后拿回来,测试跑了一遍没报错,就上线了——那确实很吓人。

我没有依赖 Agent 的判断力。我依赖的是一台专门设计的找茬机。它的每一环都是确定性的:property 是确定的、oracle 是确定的、回归测试是确定的、shrink 是确定的。Agent 只需要在确定问题面前执行确定任务——找到分歧就修,修完就跑测试。

这件事让我对"Agentic coding"有了一个很具体的看法:不是 prompt 写得好叫 Agentic。是把 Agent 放进一个自己会自检的 harness 里,让 Agent 的每一步产出都被外部系统验证,才叫 Agentic。

最后得到的 parser 可以精确地描述成:以预测式 recursive descent 为主体的手写 parser,中间嵌一个 Pratt expression 核心;默认 LL(2) cursor,少数关键处分叉用有界 lookahead probe;只有极个别决策点才亮出局部 speculative backtracking。Rust 实现,2026 年 5 月由 Claude Opus 4.7 完成。

我也开始重新想 ANTLR 这类 toolchain 的未来。

Parser generator 大概不会消失。但它的角色会变。过去它负责产最终的 parser。以后它可能更适合做某种 oracle——提供一份可信参考实现。LLM 照着这份 oracle 手写出高性能版本,PBT 和 fuzzing 做护栏。generator 变 referee,Agent 变成场上的选手。

这件事上我学到最核心的一条经验很简单:Agent 能做多少,不取决于它多聪明。取决于你给它的 harness 能在多短时间内、用多高的确定性,告诉它"你错了"。

Agentic coding 的流程,不是靠你相信模型,而给它当成许愿机。是靠不停地写test,制造反例而不停的修复代码


-- 完 --


加入机智流 Pro,1 天一块钱,AI 能力指数级增长时代,不掉队。机智流 AI 团队将燃烧远超人类的智能的 AI Tokens 驱动 AI Agents 军团带来「与你有关」「对你有用」的高质量资讯/研报。


机智流推荐阅读

1. 

2. 

3. 

4. 

关注机智流并加入 AI 技术交流群,不仅能和来自大厂名校的 AI 开发者、爱好者一起进行技术交流,同时还有等。
在「机智流」公众号后台回复下方标红内容即可加入对应群聊:
  • cc | 大模型技术交流群
  • hf | HuggingFace 高赞论文分享群
  • lc|LangChain 技术交流群
  • code | AI Coding 交流群
  • 具身 | 具身智能交流群
  • 硬件 | AI 硬件交流群
  • 推理 | AI 推理框架交流群
  • Agent | Agent 技术交流群

声明:内容取材于网络,仅代表作者观点,如有内容违规问题,请联系处理。 
AR
more
华为天才少年一作,港大MaRS Lab拿下IEEE TRO傅京孙纪念最佳论文奖
腾讯Marvis iOS版上线:手机秒变PC遥控器,跨端协同再进一步
Karpathy投了一家AI记忆公司,撞名DeepSeek Engram记忆架构
横扫八大数学竞赛:清华微软联合提出STAR-PólyaMath,Apex基准超GPT-5.5 13.5%
Nanobot作者来了!Agent Harness研讨会议程公布,拆解智能体走向生产级应用的系统底座
刚刚,DeepSeek V4更新DSpark,推理速度提升80%
苹果专利披露光学模组追踪技术,可快速适配用户瞳距,有效提升AR眼镜等穿戴式显示设备成像精度
脑机接口临床里程碑:Paradromics完成首例人体植入,比Neuralink多了一次“试装”
资讯速递|Paradromics无线脑机接口完成首次正式人体植入手术
产业 | 国内脑机接口新秀·芯生视界/思昇科技完成种子轮融资!WISE完成D轮融资/Paradromics首例植入手术/品驰DBS覆盖至西藏
Copyright © 2025 成都区角科技有限公司
蜀ICP备2025143415号-1
  
川公网安备51015602001305号