跳到主要内容

给 Agent 造围栏

阿舟
阿舟

· 阅读约 6 分钟

七月的第一周,我半夜在浏览器里刷到 Ben 那篇 AI Engineer 大会的总结,看到一句话,手停在滚动条上愣了大半天:

所有人都在给 agent 造围栏,只是没人管那玩意儿叫围栏。

原文说的是 agent harness。我愣住是因为它把我过去半年的工作全说完了——我一直在给那个不会写代码的"实习生"造围栏,只是我管那叫"保姆式审查"。

往前的故事很老套。我对 AI 写代码的初期态度,是那种典型的没见过世面的热情:什么都敢让它跑,跑完不审 diff 就 commit。代价来得不算晚,不是生产事故,但比生产事故更膈应人——它替我把一段回滚兼容逻辑给删了。那行代码长得很丑、没有注释,但没有它,老数据就滚不回去。

UPDATE orders SET status = 'completed_legacy' WHERE status = 'legacy';

我盯着 diff 看了半分钟,脑子一片空白。工具不知道历史,这是它唯一被允许的浑——历史是我该交代而没交代的东西。

那次之后我矫枉过正,所有东西都回到手写,足足两个多月,鼠标右键的次数都变多了。后来发现这也不对:不是 AI 不行,是我给的围栏太糙,糙到它跨出去一步就撞出栏杆。真正的问题从来不是"要不要用它",是"怎么把它关在正确的范围内"。

所以上个月那个大会让我觉得,这件事终于有人系统地想明白了。

会场上的共识很有意思:没人管自己搭的那层东西叫 harness,但所有人都在做同一件事——给模型套一层壳,管状态、防死循环、限权限。模型是壳里随时可换的 CPU,壳才是真正长期维护的工程。Uber 拿出来讲的那个内部代码审查引擎 uReview 也一样:让 agent 自己审 PR、跑测试、抓边界情况,在人工介入前先修一轮。这不是什么"AI 取代工程师"的故事,这是把审查从人肉循环搬进了围栏。

壳有几个关键件。

一是持久执行。用 Temporal 或者 Inngest 那种东西把 agent 的长任务变成可恢复的工作流,网络超时了能从断点接着跑,而不是带着内存一路回滚重来。我跑过半天数据回填,一次超时全部重来,看到账单的时候我对"状态就是钱"这句话有了全新的理解。

二是结构化输出。用 Pydantic 或 Instructor 强制模型吐 JSON Schema,而不是一段散文。听起来平平无奇,但这条比什么 prompt 技巧都管用——散文可以对,也可以"看起来对";Schema 只有对和不对。

{
  "action": "apply_migration",
  "target": "orders",
  "commands": ["ALTER TABLE orders MODIFY COLUMN status"],
  "side_effect_touched": ["users"],
  "requires_review": true
}

三是防护栏。这是个很笼统的词,但它的笼统恰恰说明问题:每家的实现都不一样,因为每家的边界条件不一样。你只能自己画那道线。

上下文这块,会场把 context window 重新定义成了"动态内存缓存"而不是"文本转储箱"。前缀缓存、语义压缩、图 RAG 和混合检索,三层策略本质上是同一件事:把上下文当资源来优化,按成本裁剪,不是按需求堆。首令牌时间和 API 账单才是真正的瓶颈,这个共识让我松了一口气——我以为只有我在被 token 账单抽耳光。

但这些都还好,真正让我后背一凉的是一条关于"人设陷阱"的研究。

提示词里写"你是一位资深员工工程师",不但不会让模型更靠谱,反而会引入一种静默偏见,拉低性能。它优化的是风格,不是能力。而"你是一位有十年经验的资深后端工程师,请……"这句话,我自己写过不下三十次 😅,并且一度真心觉得它会带来更"资深"的回答。

现在回头看,我喂给模型的从来不是约束,是一场角色扮演的戏服。

# 差的写法
你是一位资深员工工程师。请审查以下代码并给出建议。

# 能用的写法
以下是审查规则,逐条对照代码检查:
1. 只允许触碰 orders 表,禁止修改 users 表
2. 禁止删除任何索引;"优化"不算例外
3. 发现可能破坏现有行为的地方,停下来报告,不要顺手改掉

"请仔细检查边界情况"这句话,我后来彻底不写了——太抽象,模型接不住。真管用的是把边界情况列成清单,一条一条喂。这大概是我这半年攒下最不性感、但最好用的一条经验。

大会把 vibe-based engineering 定性为不可接受,也是这个逻辑。不是理念之争,是因为它根本验不出来——你无法靠感觉判断一次多步 agent 任务做得好不好。评估的新玩法是在隔离沙盒里跑一个复杂任务,检查任务有没有完成、耗了多少步、有没有违反安全协议。不评语气,不评文风,只评结果。这个转变比我预期狠得多。我一直误以为自己在靠审 diff 把关,但 diff 只能告诉你它动过什么,动没动不该动的;agent 工作流里有三十步的话,diff 只有结果,没有过程。过程错了但结果碰巧对,那才是未来的矿难。

后面讲安全的环节,我越听越熟悉。微沙箱把 agent 生成的代码放进轻量级临时微虚拟机里跑,毫秒级启动、跑完即销毁,防容器逃逸和文件系统篡改。密钥那边用类似 AAuth 的委托层,给 agent 任务限定权限,但它永远看不到原始 API key——中和提示注入泄露风险。

说实话,看到微沙箱的时候我心里挺复杂的。我原以为"审 AI 的代码"靠人眼,靠 code review 我瞪大眼睛盯三遍,是个态度问题。但这个品类做的是环境设计:让代码在跑起来之前先进一个临时容器,跑完连容器一起埋葬。这比我在评审里多花三小时有效。态度解决不了运行时后果,环境可以。

不过这里有个坑我得说清楚:沙箱兜底的是"跑出来的后果",兜不了"写进去的逻辑"。一个 agent 在沙箱里把业务逻辑写歪了、写漂亮了,任务完成度再高,bug 也照样进生产。所以结论不是"人不用审了",是"人审 + 沙箱"双轨——沙箱兜运行时,人兜意图和历史。两边都塌了,才是真的翻车。

往回看这半年,我走的路有点好笑:从"AI 写的代码不审就用",到"什么人都不如我自己手写",再到今天想明白"约束得靠机制"——不是靠盯,不是靠态度,是靠把围栏修到它根本跨不过去的高度。这大概就是 Ben 那篇文章真正想说的:AI 正在变成常规软件基础设施,那就该用常规工程原则对待它——预测输入、严格测试、保障环境安全。别追每一个新模型,别迷信每一个新框架,先把围栏修对。

这周就干的事:把 agent 跑命令的步骤全部挪进 E2B 沙箱,CI 里跑完即销毁;"应该没事"这四个字,从我的验收流程里永久开除。

本期缴税:一段被删的兼容逻辑,加两个多月手写代码的负气期,换来一句"给 agent 建围栏比盯着它更有用"。这教训比会议本身的 PPT 值钱多了。

阿舟
阿舟

写代码写到一半开始怀疑人生,靠 AI 工具续命,顺手把踩过的坑都记下来。

查看主页 →