最近用 ChatGPT、Codex 跑复杂开发任务时,我越来越少把主要精力放在:

“Prompt还能不能再写详细一点?”

因为任务越复杂,真正决定Agent会不会跑偏的,往往不是Prompt长度。

而是:

有没有几条始终不能被破坏的规则。

比如你让Agent优化支付流程。

Prompt可以写得很详细:

分析代码。

检查调用链。

补测试。

优化异常处理。

验证并发场景。

这些都没问题。

但如果没有明确告诉它:

同一个支付事件只能产生一次业务副作用
旧API必须保持兼容
权限范围不能扩大
历史订单必须继续可读

那Agent在处理某个局部问题时,很可能为了“把当前问题解决掉”,顺手破坏这些更重要的边界。

所以复杂任务开始前,我现在更关注一个概念:

Invariant——不变量。

也就是:

无论实现怎么改、计划怎么变、Agent执行多少步,这些条件始终必须成立。


一、Requirement和Invariant不是一回事

很多人会把两者混在一起。

比如Requirement是:

增加订单部分退款能力

这是:

要做到什么。

但Invariant可能是:

退款总金额不能超过原订单金额
旧版客户端仍然能够读取订单
同一退款事件不能重复产生副作用

它回答的是:

做的过程中,什么绝对不能被破坏。

所以两者的区别可以简单理解成:

Requirement
告诉Agent往哪里走

Invariant
告诉Agent哪些边界永远不能跨

复杂任务里,这两个都需要。

但很多Prompt只写了前者。


二、为什么任务越长,不变量越重要?

因为长任务里:

方案可能改变。

计划可能重建。

文件范围可能扩大。

中间假设也可能被推翻。

例如一开始准备:

直接调用RefundService

后来发现更适合:

Event Driven

实现方式已经完全变化。

但无论哪种方案:

同一退款只能成功一次

这个规则都不能变。

所以相比:

“必须按照方案A执行”

更稳定的表达其实是:

“方案可以变化,但这些条件始终必须成立。”

这会给Agent更多实现自由,

同时保留真正重要的工程边界。


三、Prompt写得再长,也可能被后续上下文稀释

复杂任务跑几十轮以后,

上下文里会不断加入:

日志。

错误。

测试结果。

代码修改。

新发现的问题。

这些信息会越来越多。

最初Prompt里的某些要求,

可能慢慢变成上下文中的一小部分。

尤其当Agent正在处理一个很具体的失败时,

注意力很容易集中到:

怎么把眼前这个错误解决。

而不是重新回看:

几十轮之前写的所有要求。

所以真正关键的约束最好不要埋在几千字Prompt里。

而应该单独提炼成:

一小组高优先级Invariant。


四、一个好的不变量,应该足够具体

比如:

保证系统稳定。

这不算好的Invariant。

因为Agent根本不知道:

什么叫稳定。

更好的写法是:

任何重试都不能产生重复订单

或者:

现有API字段不能删除或改变语义

再比如:

普通用户不能获得管理员权限

这些条件有一个共同特点:

可以验证。

如果一个Invariant无法验证,

它最终很容易退化成一句口号。


五、哪些东西最适合定义成Invariant?

我一般会从几个方向找。

第一类:数据不变量

例如:

账户余额不能小于0
退款金额不能超过支付金额
同一业务ID必须唯一

第二类:兼容性不变量

例如:

旧客户端仍然能够调用现有API
历史数据必须继续可读
旧事件格式在迁移期内必须兼容

第三类:权限不变量

例如:

普通用户不能读取管理员数据
Agent新增功能不能扩大现有权限范围

第四类:副作用不变量

例如:

同一支付事件最多产生一次扣款
数据库回滚不能被误认为外部操作也已回滚

第五类:架构不变量

例如:

领域层不能直接依赖基础设施实现
外部调用不能放进核心数据库事务

这些规则比具体文件结构更稳定。


六、为什么Agent特别容易破坏不变量?

因为Agent通常优先处理:

当前错误。

比如测试失败。

它可能发现:

把一个校验删掉以后,

测试就能通过。

从局部看:

问题解决了。

但那个校验可能恰好保护着:

退款金额不能超过订单金额

这时候:

Local Fix破坏了Global Invariant。

Agent不一定会自动意识到这一点。

尤其是当Invariant没有被明确写出来时。


七、所以测试也应该围绕Invariant设计

很多测试只验证:

某个函数输出。

某个接口状态码。

某个类有没有正常运行。

但对于复杂Agent任务,

还应该增加一类:

Invariant Test。

例如:

不管重试几次:

最终只能产生一条退款记录

不管新旧版本怎么混跑:

旧客户端始终能读订单

不管Agent如何重构:

普通用户始终无法访问管理员接口

这些测试不关心:

内部怎么实现。

只关心:

边界有没有被破坏。

这对Agent特别重要。


八、不变量应该比实现更稳定

例如当前实现是:

Redis分布式锁

用来保证:

同一个任务只能执行一次。

后来可能改成:

数据库唯一约束。

或者:

幂等Key。

实现可以换。

但真正需要保持的是:

同一业务操作只能生效一次

所以不要把:

“必须继续使用Redis锁”

当成Invariant。

真正的Invariant应该是:

业务或系统必须始终成立的事实。

实现只是实现。


九、复杂任务开始前,我会先让Agent提炼Invariant

比如一个需求:

重构订单退款流程。

不要马上让Codex开始改代码。

可以先让它回答:

请先识别这次任务中必须始终保持成立的关键不变量。

包括:
- 数据一致性
- API兼容
- 权限
- 副作用
- 历史数据

不要开始修改代码。

最后可能得到:

INV-01
同一退款请求最多成功一次

INV-02
累计退款金额不能超过订单支付金额

INV-03
旧客户端API行为保持兼容

INV-04
历史订单无需迁移即可读取

确认以后,

再开始执行。

这比一开始直接加一句:

“请谨慎修改。”

有效得多。


十、给Invariant编号,会更适合长任务

比如:

INV-01:支付幂等
INV-02:API兼容
INV-03:权限不扩大
INV-04:历史数据可读

后面的每个重要修改都可以问:

是否影响INV-01?
是否影响INV-02?

测试结果也可以绑定:

INV-01 PASS
INV-02 PASS
INV-03 PASS
INV-04 PASS

这样长任务跑到后面,

不变量仍然非常清晰。


十一、多Agent场景里,不变量更加重要

假设:

Agent A改数据库。

Agent B改API。

Agent C补测试。

如果三个人只知道自己的子任务,

就很容易局部最优。

但如果所有Agent共享同一组:

INV-01
INV-02
INV-03

那至少它们有共同边界。

比如Agent A想改变数据结构,

必须检查:

是否破坏历史兼容。

Agent B改接口,

必须检查:

是否破坏旧客户端。

Agent C测试时,

也知道:

哪些规则是必须覆盖的。

所以多Agent协作里,

Invariant其实是一种:

Shared Constraint。


十二、需求变化时,不变量也应该重新检查

不变量并不是永远不变。

业务规则本身如果变化,

Invariant也可能更新。

但重点是:

必须显式变化。

例如原来:

API必须100%兼容旧客户端

后来产品明确决定:

新版本允许Breaking Change。

那就应该:

INV-02 DEPRECATED

再建立新的边界。

而不是让Agent在执行过程中,

默默把旧Invariant破坏掉。

这和Plan版本管理其实很像。


十三、不要定义太多Invariant

这里也不能走极端。

如果一次任务定义:

30条Invariant。

Agent每改一步都要检查30条,

工作流会变得非常重。

真正关键的是:

少而关键。

通常复杂任务保留:

3—7条核心Invariant

已经非常有价值。

重点覆盖:

最严重的业务风险。

最难回滚的变化。

最容易被局部修改破坏的边界。


十四、什么时候说明你的Invariant写得不好?

有几个信号。

第一:

太抽象。

例如:

保持高质量

无法验证。

第二:

太像实现。

例如:

必须使用Redis

它限制的是方案,不是边界。

第三:

太多。

几十条全部都是最高优先级。

最后等于没有优先级。

第四:

互相冲突。

比如:

不能改变API

同时又要求:

必须新增一个强制字段

这种任务应该先解决约束冲突,

而不是直接执行。


十五、我更推荐这样的复杂任务启动模板

例如:

目标:
重构退款流程,提高幂等可靠性。

关键不变量:

INV-01:
同一退款事件最多产生一次业务副作用。

INV-02:
累计退款金额不能超过原支付金额。

INV-03:
现有API保持兼容。

INV-04:
历史订单数据必须继续可读。

要求:
每完成一个关键修改,都检查是否影响以上Invariant。
如果某个方案会破坏Invariant,先暂停并说明原因,不要直接执行。

这段并不长。

但它比继续增加:

背景介绍。

解释文字。

大量实现细节

更能稳定长任务。


十六、给自己看一个指标:不变量保持率

这篇我建议只看一个指标:

Invariant Preservation Rate——不变量保持率

可以简单理解为:

任务执行过程中始终保持成立的关键Invariant数量 ÷ 全部关键Invariant数量

例如一次任务定义:

5条Invariant。

最后有4条一直保持。

1条在中途被破坏,

直到Review才发现。

那么:

不变量保持率 = 80%。

对于真正关键的不变量来说,

理想状态当然应该尽量接近:

100%。

因为这些本来就是:

不能轻易被破坏的工程边界。


十七、不变量保持率低,先检查什么?

我一般会看:

第一:

Invariant是不是太模糊。

第二:

有没有给每条规则明确编号。

第三:

执行过程中有没有定期重新验证。

第四:

测试是不是覆盖Invariant,而不是只覆盖实现。

第五:

中间方案是不是未经确认就继续被后续继承。

第六:

多Agent之间有没有共享同一套Invariant。

如果这些没建立起来,

再长的Prompt也很难稳定住复杂任务。


十八、Plus和Pro怎么判断?

如果你的复杂Agent任务现在经常出现:

代码能跑。

测试能过。

任务也完成了。

但最后才发现:

兼容性破坏了。

权限变了。

历史数据读不了了。

副作用重复了。

那当前真正限制效率的,

通常不是 ChatGPT、Codex 容量。

而是:

关键工程边界没有被显式定义。

这种阶段Plus通常已经够用。

更值得先把:

Invariant定义。

Invariant测试。

Checkpoint验证。

共享约束

建立起来。


如果这些机制已经很成熟:

复杂任务开始前有清晰Invariant。

Agent每次关键修改都会重新检查。

测试能自动验证。

多Agent也共享同一组边界。

不变量保持率长期稳定。

同时还有大量复杂任务等待执行,

这时候Pro才更容易放大效率。

因为更多AI容量是在:

明确边界内自由执行。

而不是:

跑得更快以后,才发现把系统底线也一起改掉了。


最后

复杂任务开始前,

很多人第一反应是:

Prompt是不是还应该再详细一点?

但Prompt越长,

并不自动意味着任务越稳。

真正稳定复杂Agent Workflow的,

往往是几条非常明确的问题:

什么一定要做到?

以及:

什么无论如何都不能被破坏?

前者是Goal。

后者就是Invariant。

实现可以变。

计划可以变。

文件可以变。

甚至架构方案都可以变。

但只要关键Invariant始终成立,

Agent就拥有足够大的执行自由,

又不会轻易跨过系统真正不能跨的边界。

所以复杂任务开始前,

与其继续给 ChatGPT、Codex 加几百字Prompt,

不如先花几分钟写清楚:

这次任务里,哪几件事必须永远保持成立?

很多长任务的稳定性,

真正就是从这里开始的。

持续分享 Codex、大模型开发与 AI 编程实战内容。
长期深度使用各类代码大模型,也整理了
稳定的Plus/Pro会员订阅渠道,有需要可自取。

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐