反思(Reflection):给 AI 输出加一层质量检查
AI 经常能一次写出一个看起来不错的答案。
但「看起来不错」和「真的合格」不是一回事。代码可能少处理边界,方案可能漏风险,文章可能有正确废话,JSON 可能格式不合法。
这有点像发文章前找同事过一遍。写初稿的人负责把东西写出来,审稿的人负责挑问题,最后作者再按问题修改。不是因为作者不会写,而是因为写和检查本来就是两种注意力。
Reflection 模式解决的是这个问题:
先生成,再按明确标准检查,最后根据检查结果修改。
它不是让 AI 自我感动式地说「我再优化一下」,而是把质量检查变成一条可执行流程。
一、最小流程
这条流程里有三个角色:
| 角色 | 职责 | 不该做什么 |
|---|---|---|
| Generator | 生成初稿 | 不负责证明自己合格 |
| Judge | 按标准找问题 | 不直接重写全文 |
| Refiner | 根据问题修改 | 不随意扩大范围 |
Reflection 的关键是标准明确。没有标准,反思只会变成「再润色一下」。
一个可用的 Judge 标准,最好写到能直接判断,而不是只表达愿望:
| 不够可执行 | 更适合做 Judge 标准 |
|---|---|
| 代码要健壮 | 是否处理空值、非法类型、除零、超时 |
| 文章要清晰 | 是否解释目标读者、核心概念、适用边界 |
| JSON 要正确 | 是否能解析,字段名和类型是否符合 schema |
| 回复要安全 | 是否涉及权限、隐私、不可执行承诺 |
二、为什么需要反思
一次生成容易出错,尤其是任务同时包含多个要求时。
比如让 AI 写一个函数:
写一个 divide(a, b) 函数:
1. b 为 0 时返回 None;
2. 输入必须是数字;
3. 保留两位小数;
4. 给出简单测试。模型可能写出主体逻辑,但漏掉类型检查,或者测试只覆盖正常情况。
这时不要只让它「再优化」。更稳的做法是让 Judge 按清单检查:
请检查这段代码是否满足:
1. b 为 0 时返回 None;
2. 非数字输入会被处理;
3. 返回值保留两位小数;
4. 至少有正常、除零、非法输入三类测试。
只输出发现的问题,不要重写代码。然后 Refiner 只根据这些问题修改。
三、Self-Refine 和 Reflexion
Reflection 常见有两种形态。
| 方式 | 关注点 | 反馈来源 | 存储内容 | 适合场景 | 常见误用 |
|---|---|---|---|---|---|
| Self-Refine | 当前任务内反复修改 | AI 自评或规则评审 | 不长期保存 | 写作、代码、结构化输出 | 无标准地反复润色 |
| Reflexion | 跨任务积累经验 | 真实执行结果、测试、环境反馈 | 失败原因和下次策略 | Agent 多轮任务、工具使用 | 把错误总结成空泛鸡汤 |
Self-Refine 更像「这次作业先自查再改」。Reflexion 更像「这次失败的经验要进入经验本,下次别再犯」。
经验本应该记录具体信息:
{
"task_type": "code_generation",
"failure": "forgot_zero_division_case",
"evidence": "unit test test_divide_by_zero failed",
"next_time_rule": "before returning math code, check zero/empty/null boundary cases"
}不要只写:
下次要更仔细。这句话没有任何可复用价值。
四、完整案例:代码生成 + 自动审查 + 修改
目标:
生成一个安全的 divide 函数,并通过基础检查。1. Generator 提示词
请用 Python 写一个 divide(a, b) 函数。
要求:
1. a 和 b 必须是 int 或 float;
2. b 为 0 时返回 None;
3. 正常结果保留两位小数;
4. 给出 3 个测试:正常、除零、非法输入。2. Judge 提示词
你是代码审查员。
请根据标准检查下面代码。
标准:
1. 是否处理非数字输入;
2. 是否处理 b == 0;
3. 是否保留两位小数;
4. 是否包含正常、除零、非法输入测试;
5. 是否有不必要的复杂逻辑。
输出 JSON:
{
"pass": true/false,
"issues": [
{
"severity": "must_fix|suggestion",
"problem": "...",
"fix_hint": "..."
}
]
}
代码:
{{draft_code}}3. Refiner 提示词
请只根据审查问题修改代码。
要求:
1. 不要重写无关部分;
2. 每个 must_fix 都必须处理;
3. 保留原有函数名;
4. 输出完整代码。
原代码:
{{draft_code}}
审查问题:
{{review_issues}}五、最小实现结构
生产系统不能只靠 prompt。至少要有最大轮数、结构化校验、真实反馈、日志和降级。
def reflection_loop(task, max_rounds=3):
draft = call_ai("generate", task)
history = []
for round_index in range(max_rounds):
checks = run_checks(draft)
review_raw = call_ai("judge", {
"task": task,
"draft": draft,
"checks": checks,
})
review = parse_json_or_none(review_raw)
if not review or "pass" not in review:
history.append({
"round": round_index,
"status": "judge_invalid_json",
"raw": review_raw,
})
break
history.append({
"round": round_index,
"status": "reviewed",
"checks": checks,
"pass": review["pass"],
"issues": review.get("issues", []),
})
if review["pass"]:
return {
"status": "success",
"output": draft,
"history": history,
}
draft = call_ai("refine", {
"task": task,
"draft": draft,
"issues": review.get("issues", []),
})
return {
"status": "needs_human_review",
"output": draft,
"history": history,
}这段代码表达了几个底线:
- 反思循环必须有最大次数;
- Judge 输出必须能解析;
- 能跑测试、schema 或规则检查时,先把真实反馈交给 Judge;
- 每一轮都要记录;
- 多轮仍不合格时要降级给人,而不是无限自我修改。
六、工程风险与防护
| 失败模式 | 触发条件 | 防护措施 | 是否必须 |
|---|---|---|---|
| Judge 误判 | 标准模糊或只看表面 | 标准拆细,关键任务用测试/真实反馈 | 必须 |
| Refiner 越改越偏 | 修改器拿不到具体问题 | 只传 issues,不让它自由重写 | 必须 |
| JSON 解析失败 | Judge 输出解释性文字 | schema 校验,失败重试一次 | 必须 |
| 无限循环 | 每轮都发现新问题 | 设置最大轮数和停止条件 | 必须 |
| 成本失控 | 长文或代码多轮修改 | 限制轮数、限制上下文、记录 cost | 建议 |
| 隐私泄露 | 日志保存用户原文 | 对日志脱敏,限制访问权限 | 必须 |
| 标准和用户目标冲突 | Judge 只按通用规则评审 | 把用户目标放进评审标准 | 必须 |
Reflection 的风险在于:系统看起来更严谨,但如果 Judge 本身不可靠,它会把错误包装成「已审查」。
七、什么时候不要用反思
| 场景 | 是否适合 | 原因 |
|---|---|---|
| 低风险短回答 | 不一定 | 反思成本可能高于收益 |
| 需要严格事实核查 | 单靠反思不够 | 需要检索、引用或真实工具 |
| 强实时聊天 | 谨慎 | 多轮检查会增加延迟 |
| 标准无法写清 | 谨慎 | Judge 容易变成主观润色 |
| 代码、结构化输出、重要文档 | 适合 | 有明确标准,能检查和修改 |
不要把 Reflection 当成万能质量开关。它适合「错误能被描述,改动能被验证」的任务。
八、和其他 Agent 模式的关系
| 模式 | 解决的问题 | 和 Reflection 怎么组合 |
|---|---|---|
| 提示词链 | 把任务拆成步骤 | 链路末尾加审查和修改 |
| 路由 | 判断走哪条分支 | 不同分支使用不同评审标准 |
| 并行化 | 同时处理独立任务 | 多个 Judge 并行评审不同维度 |
| 工具调用 | 获取真实信息或执行动作 | Judge 可以调用测试、lint、检索工具 |
真实系统里,Reflection 往往不是单独存在。它更像一层质量门禁,放在生成之后、交付之前。
九、最后给一份检查清单
设计 Reflection 流程时,先问:
1. 这件事有没有明确质量标准?
2. Judge 只评审,还是会越权改稿?
3. Refiner 是否只根据具体问题修改?
4. Judge 输出是否结构化?
5. 最大反思轮数是多少?
6. 哪些失败需要交给人?
7. 真实反馈、测试或工具结果能不能进入评审?
8. 日志里是否保存了每一轮的问题和修改?一句话记住:
Reflection 不是让 AI 多想一会儿,而是把生成、评审、修改和停止条件拆成一条可检查的流程。