Agent 场景

用反思机制构建会自我纠错的 AI Agent

Cover image for 用反思机制构建会自我纠错的 AI Agent

如何用反思模式和持久记忆构建会自我纠错的 AI Agent。一个可运行的 Python 循环,Agent 批判自己的输出、修正错误并记住它们。

TL;DR — 自我纠错 Agent 比普通 Agent 多两样东西:一个反思步骤(提交前批判自己的输出),以及一份过往错误的记忆(不再重复犯)。反思在任务内抓错误;记忆跨任务防错误。本文用纯 Python 把两者都搭出来——不需要框架——并指出每个到底在哪有用、在哪只是烧 token。

“自我纠错”到底是什么意思

这词被随便用。具体说,自我纠错 Agent 做两件不同的事:

  1. 反思(任务内): 在敲定答案前,Agent 对照目标审查自己的草稿、找出缺陷、修订。这抓的是单个任务的错误。这个技术在 Self-RefineReflexion 论文里有正式表述。
  2. 失败记忆(任务间): 当 Agent 搞错了并学到修法,它记下这个教训,在未来任务里回忆它。这防的是跨任务重复同一个错误。

它们解决不同问题。大多数”自我纠错 Agent”教程只做反思就收工了。记忆那一半才是真正让 Agent 随时间进步的东西。存储那一面我们在 Agent 记忆架构讲过;这里把它接进一个纠错循环。

反思循环

核心模式是 生成 → 批判 → 修订。这是一个能跑的最小版本。

from openai import OpenAI

client = OpenAI(base_url="https://api.sandbase.ai/v1", api_key="sk-...")
MODEL = "anthropic/claude-sonnet-4"

def generate(task: str, prior_feedback: str = "") -> str:
    prompt = task
    if prior_feedback:
        prompt += f"\n\nA previous attempt had this problem:\n{prior_feedback}\nFix it."
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "user", "content": prompt}],
    )
    return resp.choices[0].message.content

def critique(task: str, draft: str) -> tuple[bool, str]:
    """返回 (is_good, feedback)。Agent 评判自己的工作。"""
    prompt = (
        f"Task: {task}\n\nDraft answer:\n{draft}\n\n"
        "Critique this draft. If it fully satisfies the task, reply exactly 'PASS'. "
        "Otherwise, list the specific problems to fix."
    )
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "user", "content": prompt}],
    )
    feedback = resp.choices[0].message.content.strip()
    return feedback == "PASS", feedback

def solve(task: str, max_iterations: int = 3) -> str:
    feedback = ""
    for i in range(max_iterations):
        draft = generate(task, feedback)
        ok, feedback = critique(task, draft)
        if ok:
            return draft
    return draft  # 达到最大迭代后返回尽力而为的版本

结构比 prompt 更重要。从生产里跑出来的三条规则:

给迭代设上限。 没有 max_iterations,挑剔的批判者会永远循环。三次通常够;超过三次你在以全额 token 成本打磨递减收益。

批判者需要目标,不只是草稿。 只看草稿的批判步骤会臆造问题。把原始任务给它,让它对照真实需求评判。

让 PASS 是一个精确 token。 模糊的”看着不错!“很难解析。强制一个字面的 PASS,让你的控制流确定。

反思何时有用、何时没用

反思不免费——它至少让你的 token 成本和延迟翻倍。它的回报不均匀:

任务类型反思有用吗?为什么
代码生成强有用批判者抓 bug、漏掉的边界情况
数学/逻辑强有用自检发现算术和推理的滑误
结构化抽取中等抓 schema 违规、漏字段
创意写作”更好”是主观的;批判者加不了多少
简单查询没用没什么可反思的;纯浪费

教训:用任务类型给反思设门。别每次调用都反思。琐碎的分类不需要自我批判;代码生成步骤需要。这跟把可靠、低成本的 Agent 和烧钱的区分开来的选择性花费纪律是同一个。

加记忆:跨任务学习

反思修当前任务。它对下一个任务毫无作用。如果 Agent 一直犯同一个错(日期格式错、忘了校验输入、读错 API),反思每一次都重新发现并重新修。那很浪费。

解法:当批判者发现一个真实问题,存下教训。未来任务里把相关教训加载进 prompt。

import json
from pathlib import Path

LESSONS_FILE = Path("lessons.json")

def load_lessons() -> list[str]:
    if LESSONS_FILE.exists():
        return json.loads(LESSONS_FILE.read_text())
    return []

def save_lesson(lesson: str):
    lessons = load_lessons()
    if lesson not in lessons:
        lessons.append(lesson)
        LESSONS_FILE.write_text(json.dumps(lessons, indent=2))

def extract_lesson(task: str, feedback: str) -> str:
    """把一个具体批判变成可复用规则。"""
    prompt = (
        f"A task had this problem: {feedback}\n"
        "Write one short, general rule (one sentence) to avoid this in future tasks."
    )
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "user", "content": prompt}],
    )
    return resp.choices[0].message.content.strip()

def solve_with_memory(task: str, max_iterations: int = 3) -> str:
    lessons = load_lessons()
    lesson_text = "\n".join(f"- {l}" for l in lessons)
    augmented_task = task
    if lesson_text:
        augmented_task = f"{task}\n\nLessons from past tasks:\n{lesson_text}"

    feedback = ""
    for i in range(max_iterations):
        draft = generate(augmented_task, feedback)
        ok, feedback = critique(task, draft)
        if ok:
            return draft
        # 持久化教训,让未来任务受益
        save_lesson(extract_lesson(task, feedback))
    return draft

关键变换在 extract_lesson:它把一个具体批判(“你用了 MM/DD/YYYY 但 API 要 ISO 8601”)变成一个通用规则(“API 调用永远用 ISO 8601 日期格式”)。具体反馈不可迁移;通用规则可以。

这是个刻意简单的记忆:一个加载进每个 prompt 的扁平 JSON 列表。它能用到教训列表增长超过上下文能舒服容纳的量,那时你切到检索——给教训做 embedding,每个任务只取相关的。那就是温-冷记忆划分的实战。

老实说的取舍

自我纠错不是免费升级。代价:

  • Token 乘数。 反思大约让每个任务的 token 翻 2-3 倍。记忆加一个更小的恒定开销(加载教训)。
  • 延迟。 每次反思迭代是又一个往返。3 迭代循环能让墙钟时间翻三倍。
  • 批判者会出错。 有缺陷的批判者拒绝好答案或批准坏答案。你的纠错只跟你的批判步骤一样好。
  • 教训污染。 坏教训会堆积。一个过度通用的规则(“永远复查一切”)加噪音不加价值。修剪教训库。

从中获益的团队不会到处用它。他们把反思用在高风险、易错的步骤(代码、结构化输出、多步计划),让便宜、低风险的调用只跑一次。

FAQ

反思跟 chain-of-thought 一样吗?

不。Chain-of-thought 是答案之前的推理,在一次里。反思是批判一个已完成的答案并修订它,跨多次。你能组合它们——一步步推理,然后对结果反思——但它们是不同技术。

批判者该用跟生成器一样的模型吗?

通常是,但用不同模型当批判者能抓到生成器看不见的错误。一个实用模式是用强模型生成、用同一个或更便宜的批判。批判者的活(找缺陷)有时比生成器的活(产生正确答案)更容易。

怎么阻止 Agent 永远循环?

硬上限迭代(3 是好默认),到上限就返回最佳尝试。自我批判者总能找到某些可改进的,所以无界循环永不终止。上限不可商量。

生产环境教训该存哪?

从 JSON 文件或每用户/Agent 一行数据库起步。一旦教训超过上下文能容纳的量,移到向量库,每任务只取相关教训。检索设计见 Agent 记忆架构

这适用任何模型吗?

适用。这个模式与模型无关——只是结构化 prompt 加一个控制循环。更强的模型产生更好的批判、需要更少迭代。通过 OpenAI 兼容网关你能换模型不改循环。

关键要点

  • 自我纠错有两部分:反思修任务内的错误,记忆防跨任务重复。大多数教程跳过了记忆那一半。
  • 反思循环是 生成 → 批判 → 修订,带硬迭代上限,批判者要看到原始目标而不只是草稿。
  • 用任务类型给反思设门。它强烈帮助代码和逻辑,对简单查询毫无用处,大约让 token 成本翻 2-3 倍。
  • 记忆靠把具体批判转成通用规则起作用。从 JSON 列表起步,超出上下文窗口时移到检索。

猜你喜欢