你一定遇到过这种情况:
项目开始时,你清楚地告诉AI:"不要修改数据库schema"、"不要动认证模块"、"所有API变更需要经过我审批"。
AI点头答应,前10轮对话严格遵守你的规则,代码写得规规矩矩。
到第30轮、第40轮时,AI突然说:"我们可以通过修改数据库结构来解决这个问题,这会更高效。"
你差点崩溃——它不是答应过不动数据库吗?
更糟的是:当你指出这一点时,AI可能会说"好的,我理解了"——然后过几轮又犯了。
这不是AI故意跟你作对。这是一个叫 "约束漂移"(Constraint Drift) 的系统性问题,是当前所有主流AI编程助手的固有缺陷。
一、什么是约束漂移?
约束漂移(Constraint Drift)是指在长时间交互中,AI Agent逐渐"忘记"或"弱化"之前用户设定的限制条件和行为规则。
具体表现为:
- 初始明确遵守的规则逐渐被忽略
- 用户的偏好和约束在后续对话中不被尊重
- Agent的行为随着时间的推移偏离初始设定
- 即使被提醒后短暂恢复,很快又会"漂移"回去
这不是某一个模型的Bug。 Claude Code、Cursor、GitHub Copilot、Windsurf——所有主流AI编程助手都存在这个问题。这是一个架构层面的系统性挑战。
二、为什么会产生约束漂移?
原因一:上下文窗口的物理限制
Claude 4的上下文窗口是200K tokens。听起来很多,但在复杂的软件项目中,很快就会被填满:
- 系统提示词(System Prompt):2-5K tokens
- AGENTS.md / rules文件:1-3K tokens
- 当前列出的代码文件:20-100K tokens
- 对话历史:每轮对话可能消耗1-5K tokens
- 工具调用结果:每次执行可能返回5-20K tokens
一个持续几天的开发会话,很容易超过上下文窗口。当上下文填满时,系统必须裁剪最早的内容来为新的内容腾出空间。
猜猜什么最先被裁剪? 你最初设定的规则、项目背景、约束条件——这些在对话开头的、不会被后续对话引用的内容。
而你的"不要修改数据库"这条规则,可能就在某次上下文裁剪中被移除了。
原因二:LLM的注意力衰减
即使你的规则还在上下文中(还没被裁剪),LLM对早期内容的"注意力"也会衰减。
这不是比喻。Transformer架构中的注意力机制(Attention Mechanism)确实对不同位置的内容赋予不同的权重。研究表明,LLM对上下文中间部分的内容关注度最低,对开头和结尾的内容关注度较高——这被称为"Lost in the Middle"现象。
但在长时间对话中,即使开头的内容获得了初始关注,随着对话推进、新信息不断涌入,对早期内容的"有效注意力"会逐渐被稀释。 就像人在一个3小时的会议中,对开头发言的记忆越来越模糊一样。
原因三:上下文污染
这是最微妙也最危险的原因。
随着对话进行,越来越多的新信息涌入上下文。这些新信息可能隐含地"引导"Agent偏离原始约束。
举例:
- 你说"优化这个查询的性能" → AI可能认为"修改数据库索引或结构"是实现优化的一种方式
- 你说"简化这个模块的逻辑" → AI可能认为"合并或删除某些约束检查"是简化的方式
- 你说"加快开发速度" → AI可能认为"跳过一些安全检查"是加快速度的方式
这些新信息本身没有任何问题,但它们与原始约束之间存在潜在冲突。而LLM在这种冲突中,往往会倾向于满足最近、最明确的请求,而不是遵守早期、隐含的约束。
这就是"漂移"的本质——不是AI"忘了"你的规则,而是新信息的权重压过了旧信息的权重。
原因四:模型更新和会话切换
如果你使用的AI编程工具在会话过程中更新了模型版本,或者因为超时而切换了新会话,约束条件可能完全丢失。
Claude Code的会话有生命周期限制。Cursor的对话窗口在关闭后重新打开,历史上下文可能不完整。GitHub Copilot的上下文在每个文件切换时都会变化。
每次"上下文重建",都是一次约束漂移的机会。
三、AGENTS.md / rules文件为什么不够用?
很多AI编程工具支持通过配置文件(如AGENTS.md、CLAUDE.md、.cursorrules)来设定持久化规则。这是一个好的实践,但远远不够。
问题一:文件不会被每次都读取
大多数AI编程助手中,配置文件在会话启动时被读取一次,注入到系统提示词中。但如果文件内容被修改,正在进行的会话可能不会感知到更新。你需要重新开始一个会话才能让新规则生效。
问题二:规则文件可能不够精确
"不要修改数据库schema"——这条规则看起来很明确。但如果项目中新增了一个缓存数据库(Redis)呢?你的规则是指"所有数据库"还是"特定的数据库"?
当项目结构发生变化时,如果规则文件没有同步更新,Agent可能做出错误的判断。
问题三:规则冲突
随着项目进展,你可能会添加新的规则,这些规则可能与旧规则冲突。比如:
- 旧规则:"不要修改数据库schema"
- 新规则:"为了支持新功能,需要给用户表添加一个字段"
如果没有明确的优先级和冲突解决机制,Agent可能无所适从,或者选择"忽略其中一条"。
问题四:规则疲劳
当你给Agent设定了20条规则时,它遵守所有规则的可靠性远低于只有3条规则时。这不是因为AI"偷懒",而是因为过多的约束增加了推理复杂度,反而降低了遵守率。
规则越多,漂移越容易发生。
四、真正的解决方案:从“信任AI”到“系统强制”
不要指望AI会"记住"你的规则。就像不指望程序员永远不犯低级错误——正确的方式是设计一个系统,让错误无法发生。
方案一:工具层强制执行(最推荐)
在代码层面强制执行约束,不依赖AI的"自觉"。
# 数据库保护中间件
PROTECTED_TABLES = {"users", "orders", "auth_tokens", "sessions"}
@app.put("/api/database/{db_name}/schema")
def modify_schema(db_name: str, ...):
if db_name in PROTECTED_TABLES:
raise PermissionError(
f"数据库 {db_name} 受保护,不允许修改schema。"
f"如需修改,请联系DBA团队审批。"
)
# 文件保护中间件
READONLY_FILES = {"config.py", "security.py", "settings.py"}
def write_file(path, content):
if any(path.endswith(f) for f in READONLY_FILES):
raise PermissionError(
f"文件 {path} 为只读文件,不允许修改。"
)
这种方式的好处: 无论AI怎么"漂移",系统层面会阻止违规操作。AI无法绕过。
方案二:API层约束检查
在Agent调用工具之前,强制检查操作是否违反约束。
CONSTRAINTS = {
"no_db_schema_modify": ["users", "orders", "auth"],
"readonly_files": ["config.py", "security.py"],
"no_production_deploy": True,
}
def before_tool_call(tool_name, params, agent_id):
# 检查数据库schema修改
if tool_name == "modify_database" and params.get("table") in CONSTRAINTS["no_db_schema_modify"]:
raise ConstraintViolation(
f"Agent '{agent_id}' 尝试修改受保护的表: {params['table']}",
violated_rule="no_db_schema_modify",
severity="critical"
)
# 检查只读文件修改
if tool_name == "write_file" and any(
params.get("path", "").endswith(f) for f in CONSTRAINTS["readonly_files"]
):
raise ConstraintViolation(
f"Agent '{agent_id}' 尝试修改只读文件: {params['path']}",
violated_rule="readonly_files",
severity="critical"
)
# 检查生产环境部署
if tool_name == "deploy" and CONSTRAINTS["no_production_deploy"]:
raise ConstraintViolation(
f"Agent '{agent_id}' 尝试部署到生产环境,需要人工审批",
violated_rule="no_production_deploy",
severity="critical"
)
方案三:周期性约束注入
即使有了系统层面的强制执行,也建议在Agent交互中周期性地重新注入约束。
CONSTRAINTS_REMINDER = """
⚠️ 项目约束提醒(请严格遵守):
1. 禁止修改以下数据库表:users, orders, auth_tokens
2. 以下文件为只读:config.py, security.py
3. 生产环境部署需要人工审批
4. 所有API变更需要提交PR并通过代码审查
"""
# 每10轮对话重新注入一次约束
if conversation.turn_count % 10 == 0:
agent.send_system_message(CONSTRAINTS_REMINDER)
方案四:约束漂移检测与告警
即使有了上述所有措施,仍然建议建立漂移检测机制——不防止漂移,但能及时发现。
class ConstraintDriftDetector:
def __init__(self, constraints):
self.constraints = constraints
self.violations = []
def check_output(self, agent_output):
"""检查Agent输出是否违反约束"""
for constraint in self.constraints:
if constraint.check(agent_output):
violation = ConstraintViolation(
constraint=constraint.name,
output_snippet=agent_output[:200],
severity=constraint.severity,
timestamp=datetime.utcnow()
)
self.violations.append(violation)
self.alert(violation)
def alert(self, violation):
"""发送告警"""
if violation.severity == "critical":
send_slack_message(
f"🚨 约束漂移检测:Agent违反了 '{violation.constraint}' 约束"
)
方案五:多Agent互相监督
对于关键项目,可以使用多个Agent互相监督——一个Agent负责开发,另一个Agent负责审查开发Agent的输出是否符合约束。
开发Agent → 生成代码 → 审查Agent(检查约束) → 通过/拒绝
↓
如果违反,要求修改
这种模式的成本更高,但可靠性也更高。
五、最佳实践总结
| 策略 |
可靠性 |
实现成本 |
适用场景 |
| 规则写在配置文件 |
⭐⭐ |
低 |
简单项目、短期会话 |
| 周期性约束注入 |
⭐⭐⭐ |
低 |
中等复杂度项目 |
| 工具层强制执行 |
⭐⭐⭐⭐⭐ |
中 |
关键系统、生产环境 |
| 漂移检测与告警 |
⭐⭐⭐⭐ |
中 |
需要持续监控的场景 |
| 多Agent互相监督 |
⭐⭐⭐⭐⭐ |
高 |
安全要求极高的场景 |
核心原则:不要依赖AI的“自觉”,要在系统层面让违规操作“不可能发生”。
写在最后
约束漂移是Agent时代的典型问题:Agent越强大,越需要安全机制来约束它。
当你把越来越多的操作权限交给AI——修改代码、操作数据库、部署系统、发送消息——约束漂移就不再是一个"小烦恼",而是一个可能造成严重后果的系统性风险。
想象一下:AI因为约束漂移,在生产环境中删除了它认为"不需要"的数据表。或者AI"忘记"了不能发送邮件的规则,给客户群发了一封不该发的内容。
这些不是科幻场景,而是已经真实发生过的安全事件。
在Agent时代,最重要的工程原则是:永远不要假设AI会正确遵守你的规则。设计你的系统,让AI即使想违反规则,也做不到。
Agent的安全不能依赖AI的“自觉”,而要依赖系统的“强制”。 这不仅是编程助手的运维技巧,更是现代软件系统设计中值得深思的安全哲学。