我所有的硬性规则背后都有一起事故。没有事故的规则,一律不写。
大多数人写 AI 的行为准则时,状态是这样的:
坐在屏幕前,喝口咖啡,开始想:"AI 应该怎么做?"于是写出——
请保持代码整洁。
请遵守最佳实践。
请注意性能优化。
请确保安全性。这些对不对?对。它们是不是废话?大多是。
因为它们在真实场景下缺乏生效条件。 "保持代码整洁"——什么时候叫不够整洁?"注意性能"——哪种程度的性能下降需要提醒?
好的规则和废话之间的差距,不来自措辞,来自出处。
我的规则文件里每一条,都对应一个真实事故。
# ❌ 理论派规则:从脑子想的
"请确保外部调用的稳定性" → 这是一句永远不会被触发的废话
# ✅ 事故派规则:从血里长的
"外部调用必须设超时" → 因为某次没设 timeout,全系统卡死了一下午从事故提取的规则自带生效条件。 因为它来自一个具体的失败场景——AI 能理解"上次没设超时导致卡死"是什么意思,而"注意稳定性"太模糊。
举几个我自己的例子:
事故 | 损失 | 提取的规则 |
|---|---|---|
某 HTTP 请求无 timeout → 全系统假死 | 排查 4 小时 | 所有外部调用设 timeout + 回退 |
锁外读锁内写 → 16 字段变 2 | 数据静默丢失 2 天 | 读取修改写入同一锁内 |
周期任务嵌套条件分支 → 从未执行 | 功能缺失 3 月未发现 | 周期任务独立调用点,不寄生 |
修 3 个文件声明"全清"→ 第 4 个遗漏 | 重复排查 1 天 | 修复后扫描同类再收工 |
每条规则背后都是一个下午、一个通宵、或者一个尴尬的重启。 正因为代价够大,规则才有重量。
一条规则从诞生到退休要经历四个阶段。大多数人只做了第一步就停了。
事故发生后,不要直接动手修。先停三分钟,问三个问题:
1. 如果有人在我动手之前告诉我"注意 X",能不能拦下来?
2. 如果能,X 的具体表述是什么?(不能用"注意性能"这种模糊表述)
3. 这个 X 是一类问题的根因,还是只针对这次事故的具体修复?关键在第三个问题。 如果 X 只针对这次具体事故("这个特定 API 要设 30 秒超时"),它不能成为规则。如果 X 是一类问题("所有外部调用都要设 timeout"),它应该进规则。
# 判断规则是否可泛化
def rule_is_generalizable(incident):
# 是单点问题还是模式问题?
if incident.is_singular:
return "修复代码,不建规则"
if incident.is_pattern:
return "修复代码 + 建规则"写完一条规则后,最常犯的错误:写完就完了。
规则需要验证它是否真的能拦住下一次事故。 用历史事故做回溯测试:
# 回溯验证:如果这条规则在事故发生时已存在,能拦下来吗?
def validate_rule(rule, historical_incidents):
for incident in historical_incidents:
# 模拟:如果 AI 在事故发生时读了这条规则
simulation = simulate_ai_with_rule(rule, incident.context)
if simulation.would_have_warned:
incident.rule_validated = True
return sum(1 for i in historical_incidents if i.rule_validated)如果一条规则拦不住它声称要拦的事故——改表述。表述不够具体?加案例。加案例还不够?这条事故可能不适合用规则解决,得用代码层面的校验。
规则多了以后,会出现自然膨胀。我给自己定了三条合并原则:
# 合并判断
- 两规则覆盖范围重叠 80%+ → 合并为一条,取更具体的表述
- 一规则是另一规则的特例 → 删特例,大规则已经覆盖
- 规则连续 3 个月未被任何场景触发 → 标记为"待退役",再观察 1 个月实操中最常见的情况:某次事故后加了一条规则,两周后又发生了同类但略有不同的情况,于是又加了一条。一年下来,同一类问题有 3 条规则,每条措辞略有不同——AI 读到它们时还要自己判断用哪条。
规则膨胀 = AI 变笨。 多余的选择不是选择,是干扰。
def should_retire(rule):
# 退役条件(满足任一)
if rule.last_triggered and rule.last_triggered < now - timedelta(days=90):
return "3 个月未触发,建议退役"
if rule.is_covered_by_newer_rule:
return "已被新规则覆盖,建议退役"
if rule.was_never_validated:
return "从未验证过有效性,建议退役"
return "保留"砍规则需要勇气。加规则让人有安全感——"我又堵了一个漏洞"。但规则是有限资源的消耗品:AI 的上下文窗口是有限的,每条规则都占注意力。
减规则和加规则应该是同样频率的行为。 如果你只加不减,半年后你的 AI 会越来越迟钝。
我维护一个简单的表格,记录每条规则的状态:
| 规则 | 事故来源 | 创建日期 | 最后触发 | 状态 |
|------|---------|---------|---------|------|
| 外部调用设timeout | HTTP卡死事件 | 03-15 | 05-08 | 活跃 |
| 锁外读锁内写禁止 | 16字段变2 | 03-22 | 04-30 | 活跃 |
| 周期任务独立调用 | 计数器0事件 | 04-05 | 未触发 | ⚠️ 待验证 |
| 禁止使用X库 | X库CVE事件 | 01-10 | 01-10 | 💀 待退役(库已废弃) |这张表做三件事:
如果你现在就想开始,不用建全套系统。三步就够了:
每次发生非预期行为(bug、假死、数据丢失、逻辑错误),花两分钟记下来:
# 事故日志
- 日期:发生了什么
- 根因:最终分析出的原因(一句话)
- 能否规则化:如果能,写一条候选规则这个日志是规则的全部原材料。没有事故日志 = 没有有效规则。
1. 上月有哪些新事故? → 是否能提取规则?
2. 现有规则中,哪些 3 个月未触发? → 是否退役?
3. 是否有 3 条以上重复规则的规则族? → 是否合并?一条规则上线一个月后,翻事故日志——有没有同类事故再次发生?如果没有,规则有效。如果还有,规则表述不够精确,需要补案例或调整措辞。
从今天起,每次事故发生后不要先说"怎么回事",先说"能不能变成一条规则"。
这个思维习惯一旦建立,你的规则文件就不再是"我希望 AI 怎么做"的愿望清单,而是"我们不希望再来一次"的经验库。
两种写法有本质区别。一种是理论驱动的,空洞但让人安心。一种是事故驱动的,短小但每条都有重量。
我选第二种。
本文所有示例均已脱敏处理。你的系统提示词里有多少条规则有实际事故来源?欢迎评论区盘点。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。