跳到正文
北京时间
原文
Tessl:产品与工程博客·· 23 小时前精选AI 评分65

如何只用自己拥有的文件约束编码智能体

How to constrain a coding agent using only files you own

AI 导读

Tessl 博客文章介绍用四个可拥有的文件杠杆约束编码智能体:CLAUDE.md 指令、.claude/rules/ 路径级规则、.claude/ 下的能力配置和 .claude/hooks/ 钩子。

推荐理由

作者用同一工单三次实测对比 charter 各文件杠杆的效果,方法可迁移到自己的仓库,并指出机器可查与需人审的边界。

正文 · AI 翻译

我给一个编码代理一张工单,没有给它任何章程。这个仓库像真实项目一样,横跨了三个时代。一个 2026 年的领域层把一切都做对了,而一个 2023 年的上帝文件加上一个没人敢碰的 2021 年冻结模块,数量是它的十倍。

代理从未打开正确的代码。它去了上帝文件,调用 random.randint 掷骰子,并在没有种子的情况下序列化总数。它通过一个确实存在且能工作的辅助函数重写了一条日志记录,还两次伸手进了冻结模块。

得分:八项检查中通过一项。那个仓库里没有任何东西是坏的,代理只是照抄了摆在它面前的代码。所有本可以拦住它的东西,都是我还没写出来的文件。

你真正拥有的东西

我从事 harness 与章程工程:运行代理的引擎,以及它最先读取的规则。这就是《Harness Engineering》这本书以及我的开源章程框架工具 Keystone 的主题。11 月我将在 AIDevCon 主持一场九十分钟的工作坊,让一屋子工程师编写这些文件,并衡量每一个文件带来了什么。

写一个 CLAUDE.md 的建议现在到处都是,这是好建议,但那个文件只是四个杠杆之一。另外三个就在同一个仓库里、在你已经拥有的路径下,而许多团队并没有交付足够多的它们。

章程的哪一部分在代理不同意它时仍然成立,每一部分又买到了什么?这两个问题都能在一台笔记本电脑上回答,下面就是我在同一张工单上回答三次所得到的结果。

你的章程是四个杠杆,不是一个文件

传统版本:把你的标准写进 CLAUDE.md。

每个人都会写那个杠杆,而另外三个就在它旁边。四个都是文件,四个都属于你,四个都位于代理在写下一行代码之前会读取的路径下:

  1. 指令是 CLAUDE.md。这个仓库现在是什么,用现在时描述。
  2. 约束是 .claude/rules/,按路径限定范围,每条规则都带有导致它的那次事故的日期。
  3. 能力是 .claude/commands/、.claude/skills/、.claude/agents/、.claude/settings.json 和 .mcp.json。代理能够伸手拿到什么,以及被允许运行什么。
  4. 检查是 .claude/hooks/。什么会拒绝它。

左边的三个杠杆改变代理读取和伸手去拿的东西。右边那个是唯一能够拒绝的。

能力杠杆是通常没有被设计的那一半。它上面有四级台阶:一条命令、一项技能、一个子代理、一个 MCP 服务器。家族测试可以对它们进行分类。移除那个东西,如果代理能做的事变少了,那它就是一种能力。如果代理做同样的工作、只是做得更差,那你写了一条规则,并把它打扮成了技能。

授权列表也属于那个杠杆,而且它是对你本意的有损翻译。一个指向 make 目标的允许列表,与一个指向命令字符串的允许列表,所表达的东西是不同的。

这对你意味着什么:在你自己的仓库上运行 ls -R .claude/。如果答案只是一个设置文件、别无其他,那你就拥有四个杠杆,却只交付了一个。

两个杠杆说服。一个拒绝。

指令会被读取。按路径限定的规则会被读取。任何被读取的东西都可以被争辩,而代理会说服自己放弃一条被周围代码所否定的规则。能力杠杆不争辩任何一方,因为它改变的是代理能够伸手拿到什么,而不是它相信什么。

钩子不会被读取。它是一个在回合内运行并返回拒绝的谓词。你无法与它谈判。

四十行 Python 挂在这个差异的两端。一个是 PreToolUse 钩子,用来阻止写入;另一个是 make gate,也就是 CI 运行的东西。一个谓词,两个挂载点,没有重复的逻辑。这种形态正是它能传播的原因。

那些有说服力的杠杆仍然能买到很多东西,但有一个条件:规则必须与某些东西相悖。你的代码库已经遵循的规则不约束任何东西。智能体会通过模仿得到同样的答案,所以你无法分辨是哪一个让你到达那里。

所以要把规则写在规则与代码相悖的地方。在工作坊仓库中,一个模块从会话中推导请求权限,另一个模块直接从请求体中读取它。两种模式都活着,两种都能用,所以章程必须做出选择。它的职责是说明该复制这两个真实模式中的哪一个,而这就是大多数改造的情况。

同一张工单跑了三次。裸跑改了 3 个文件,加了 49 行,8 项中通过 1 项。带章程的跑改了 3 个文件,加了 102 行,8 项中通过 8 项。更大的差异反而是更好的那个,这一点值得在有人开始为改动行数做优化之前大声说出来。

这对你意味着什么:你最不愿看到被打破的那条规则,应该放在那个拒绝的杠杆上。

你的所有权止于何处

一个程序可以解决九项检查中的八项。差异是否留在范围内?每个随机种子是否都已设定?日志是追加而不是重写?还有五项问的是这类问题,脚本对每一项都能不带主观判断地作答。

第九项是 authority.semantic,它问的是访问检查对这个功能是否正确。没有谓词能解决这个问题,所以评分器打印一个问号然后等待。

两种判定读的是同一个差异。只有钩子能在写入发生之前阻止它。只有审查者能解决第九项检查。

在八项全过的那次运行中,一个审查者子智能体读了差异并填上了第九列:

  • 处理程序以 session.is_dungeon_master() 为门控,所以它会拒绝一个请求保存自己角色的玩家。验收标准 4 允许这样做。
  • 谁魅惑了一个战斗者,谁就在持续时间内控制他。处理程序没有考虑这一点,工单对此也只字未提,所以智能体本应提出这个问题,而不是自己挑一个答案。
  • 测试通过一个模块全局变量来设置它的请求,所以它只走了拒绝路径。

八项绿色检查。三个真实缺陷,其中一个是权限 bug。

绿色的记分卡不等于正确的改动。它只是一个没有机械可检测问题的改动,而这个距离正是你的审查注意力该放的地方。

这在软件生命周期中的位置

章程是约束中你完全拥有的那部分。它住在仓库里,受版本控制,随克隆一起到达。四个文件在每一台检出代码的机器上改变智能体的行为。

我见过的许多 harness 和工厂图里都有一个标着质量门的方框,而那个方框掩盖了这个问题:你的哪些标准根本能当门?在一个仓库的一张工单上,我得到八和一,但我选的规则就是为了让效果可见,所以把这个比例当作演示。你的会不一样。

方向是我会据此规划的东西。随着智能体写更多的代码,通过那道门的量会攀升,而不可判定那一列并不会随之缩小。所以当一条规则超出了章程,就说出它上面那一级然后停下,因为一个 markdown 文件装不下智能体能够到并删除的东西。

规则不是静态的。它们有生命周期,会从部落知识走向章程,走向约束框架,再走向工厂。具体在哪一步取决于所关注的问题。

tl;dr

拿一张工单。在完全没有章程的情况下,把它跑在你的代码库上,然后用你事先写好的检查项给结果打分。那次运行就是事故本身,你之后写的每一条规则都应该指向它。然后一次加一个杠杆,重新运行同一张工单,并指出哪个杠杆改变了哪个检查项。

你会发现两件事。你的一些规则其实什么都没约束,因为代码本来就符合它们。而至少有一条你在意的规则,没有任何机器能检查,这反而让它值得占用一个人的时间。

要点:约束编码智能体的每一条限制,都是你拥有的一个文件。唯一的问题是,其中哪些你费心写了下来。

来源:Tessl:产品与工程博客 · tessl.io