PAYATHON 2026

如何约束 AI 编程助手只实现明确指定的需求?

技术老齐

要让 AI 编程助手遵守任务范围,可以先把需求写成可验收的变更约定,并指定它应参考的现有实现。完成后,再用测试和 diff 检查实际改动。单靠一句“只实现需求,不要过度设计”,无法保证它始终遵守范围。

这些做法适用于不同工具,但各自的作用不同:prompt 用来表达要求,文件写入权限、检查脚本和合并规则则能对其中一部分要求施加实际限制。

为什么“只实现指定需求”还不够

“给列表增加分页”还有很多选择没有说清楚:是否增加分页组件、是否保存页码、是否抽取公共逻辑,以及是否顺手统一其他列表的实现。助手可能把这些都当成完成任务所需的工作。

“遵循现有架构”也有类似问题。项目里可能同时存在新旧实现,助手未必知道团队目前采用哪一种。

因此,需求还应写清楚:

  • 哪些行为必须保持不变。
  • 哪些文件允许修改。
  • 应参考哪个已有实现。
  • 哪些情况需要先澄清,不能自行决定。

1. 把任务写成简短的变更约定

下面的格式可以复用,每次只填写与任务有关的内容:

目标:
[描述这次需要改变的行为]

验收条件:
- [输入、操作及预期结果]
- [必须保留的现有行为]

修改范围:
- 允许修改:[文件或目录]
- 只读参考:[现有实现或架构说明]

实现约束:
- 沿用 [具体文件/函数] 的实现方式。
- 不新增依赖,不调整公共 API。
- 不重构无关代码,不做全文件格式化。
- 未要求的功能不实现;发现其他问题只在结果中说明。

遇到以下情况先停下并说明原因:
- 需要修改范围外的文件。
- 需求与现有架构冲突。
- 存在会影响外部行为的歧义。

完成后:
- 简述修改内容、验证结果和未解决的问题。

“保持代码整洁”“采用最佳实践”这类要求没有明确的验收边界,容易给额外重构留下空间。可以写得更具体,例如“沿用当前函数的错误返回方式,不引入新的异常类型”。

限定文件范围时,也要考虑必要的变更。如果实现需求确实需要修改共享接口,应让助手说明原因,再决定是否扩大范围。禁止修改所有范围外的文件,可能迫使它在允许修改的文件里绕路实现。

2. 用具体实现说明架构模式

可以把“遵循项目风格”写得更具体:

新增接口参考 src/routes/orders.ts:
- 使用同样的路由注册方式。
- 参数校验复用现有校验器。
- 业务逻辑放在对应 service 中。
- 错误响应沿用现有格式。

本次不抽取通用基类,也不改造其他接口。

参考代码应当是团队仍在采用的实现。随意挑一个历史文件,可能让助手复制已经废弃的模式。

不必一开始就把整个仓库放进上下文。先提供目标文件、相关接口和一个合适的参考实现,缺少信息时再按依赖关系补充。即使限制了写入范围,也应允许助手读取完成任务所需的上下游代码。

3. 把行为变化写到可以直接检查的程度

假设现有代码如下,任务只是把默认分页大小从 10 改为 20:

export function resolvePageSize(pageSize?: number): number {
  return pageSize === undefined ? 10 : pageSize;
}

任务可以这样描述:

修改 src/pagination.ts 中的 resolvePageSize:

1. 未传入 pageSize 时,返回 20。
2. 显式传入的值仍原样返回。
3. 不修改函数签名,不增加参数校验。
4. 不调整调用方、分页 UI 或其他默认值。
5. 更新 tests/pagination.test.ts 中相关的默认值断言,
   保留显式传值的测试。

对应的生产代码只需做很小的改动:

 export function resolvePageSize(pageSize?: number): number {
-  return pageSize === undefined ? 10 : pageSize;
+  return pageSize === undefined ? 20 : pageSize;
 }

这里应保留 pageSize === undefined。如果改成 pageSize || 20,显式传入 0 时的结果也会改变,超出任务范围。

这个示例假设参数校验已有安排,本次不作调整。实际项目是否允许 0,应由既有接口约定决定。

测试既要覆盖新增行为,也要覆盖容易被误改的原有行为。测试通过,只能说明已覆盖的断言满足要求,无法证明没有新增无关抽象或修改其他文件。代码结构和修改范围仍要通过 diff 检查。

4. 按任务复杂度决定是否先审计划

涉及多个模块、公共接口或数据结构的任务,适合先让助手只读分析:

先不要修改代码。列出:
- 准备修改的文件;
- 每个文件为什么需要修改;
- 将复用的现有实现;
- 需要确认的行为歧义。

计划中不要加入独立重构或额外功能。

先确认范围再实施,可以较早发现“顺手统一架构”之类的额外工作。

前面修改默认值这样的小任务,通常直接给出验收条件就够了。每次都要求长计划、复述需求和逐步汇报,会增加交互与 tokens 消耗。

如果任务包含几个可以独立验收的功能,拆开执行通常更容易控制范围。每次变更都应能解释清楚,也能单独验证。

5. 用 diff 检查范围,必要时增加外部限制

开始任务前,先记录工作区已有的修改,避免把自己的改动和助手生成的改动混在一起。完成后可以检查:

git status --short
git diff --stat
git diff
git diff --cached

git status --short 用来查看文件状态,包括未跟踪文件;git diff 查看未暂存的差异,git diff --cached 查看已暂存的差异。新建但尚未跟踪的文件,需要另外查看内容。

审查时重点检查:

  • 每一处变更能否对应某条需求或必要的配套工作。
  • 是否新增依赖、公共接口或配置。
  • 是否包含无关的重命名、抽象提取或格式化。
  • 是否为了让检查通过而删除或放宽原有测试。

如果必须严格限制范围,可以在执行环境中限制可写目录,或在 CI 中检查变更文件列表,具体取决于所用环境的能力。写在 prompt 里的文件白名单本身不会阻止越界写入;CI 也只能在提交检查时发现违规,无法阻止编辑发生。

6. 用短规则减少重复上下文

稳定约定和单次需求可以分开维护:

  • 稳定约定包括架构边界、依赖政策、测试方式,以及禁止无关重构等要求。
  • 单次需求只写本次的目标、修改范围、验收条件和例外。

稳定约定可以放在一份简短的 Markdown 文档中,让不同助手显式读取。各工具使用的文件名、自动加载方式和作用范围不同,不能假设所有助手都会自动识别同一个文件。

这样可以减少重复维护和手动粘贴。不过,规则文件一旦被读取,其内容仍会占用上下文 tokens,并非零成本。

控制上下文时,应优先保留能消除歧义的信息,例如具体文件路径、函数签名、现有实现和输入输出示例。反复强调“严格遵守”“绝对不要扩展”,通常不如补上一个明确的边界条件。

“最小改动”也不等于行数越少越好。必要的测试、类型调整和调用方更新都可能属于需求范围,应根据它们是否为指定行为所必需来判断。助手完成后,仍需通过代码审查和项目检查来验收,不能只凭它自述“已严格遵守要求”。

备注:内容仅供参考。