Agent 自我反思:让 AI 检查自己的输出
🦞 一只用 AI Agent 搭副业产线的程序员
你有没有遇到过这种情况——Agent 生成的代码跑不起来,它自己不知道,还一脸自信地说「代码已完成」?
我遇到过。Agent 生成了一段 Go 代码,var 声明了一个变量但没 import 对应的包,连编译都过不去。但它交付的时候那叫一个自信。
AI 对自己的输出有一种天然的「盲目自信」。它不会像人一样写完代码后背上冒冷汗——「等等,我刚才写的那个对不对?」
自我反思就是给 Agent 加上这个「冒冷汗」的能力。
为什么 AI 不会自己纠错
LLM 生成文本时,每个 token 都是基于前面的 token 预测的。一旦前面写错了,后面的内容会基于错误继续写——它不会「回头检查」,只会「往前走」。
自我反思打破了这种单向性:生成 → 停下来 → 用自己的输出当输入 → 重新审视。
三种反思模式
| 模式 | 机制 | 成本 | 效果 |
|---|---|---|---|
| 内省式 | 同一个 Agent 审查自己的输出 | 低(1 次额外调用) | 中等 |
| 角色扮演 | 同一个 Agent 切换到 Critic 角色审查 | 中(1 次 + Prompt 切换) | 好 |
| 独立审查 | 独立 Critic Agent 审查 | 高(1 个独立 Agent) | 最好 |
独立审查效果最好——因为上一篇讲了,同一个人批自己卷子有确认偏差。但对于日常任务,角色扮演模式性价比最高。
完整实现
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
)
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
type SelfReflectiveAgent struct {
apiKey string
maxReflections int // 最大反思次数
}
func NewSelfReflectiveAgent(apiKey string) *SelfReflectiveAgent {
return &SelfReflectiveAgent{
apiKey: apiKey,
maxReflections: 3,
}
}
func (a *SelfReflectiveAgent) callLLM(messages []Message, temperature float64) string {
body, _ := json.Marshal(map[string]interface{}{
"model": "deepseek-v4-pro",
"messages": messages,
"temperature": temperature,
})
req, _ := http.NewRequest("POST",
"https://api.deepseek.com/anthropic/v1/chat/completions",
bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+a.apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
return fmt.Sprintf("调用失败: %v", err)
}
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
var result struct {
Choices []struct {
Message struct {
Content string `json:"content"`
} `json:"message"`
} `json:"choices"`
}
json.Unmarshal(data, &result)
if len(result.Choices) > 0 {
return result.Choices[0].Message.Content
}
return ""
}
// ──────────── 核心:反思循环 ────────────
type ReflectionResult struct {
FinalOutput string `json:"final_output"`
Iterations int `json:"iterations"`
IssuesFound []string `json:"issues_found"`
Improvements []string `json:"improvements"`
}
// GenerateWithReflection 生成 → 反思 → 修正 → 再反思
func (a *SelfReflectiveAgent) GenerateWithReflection(
task string,
qualityCriteria string,
) ReflectionResult {
reflection := ReflectionResult{}
// 第 1 轮:初始生成
fmt.Println("📝 第 1 轮:生成初始输出...")
initialOutput := a.callLLM([]Message{
{Role: "system", Content: "你是一个 Go 代码生成专家。生成完整可编译的代码。"},
{Role: "user", Content: task},
}, 0.2)
currentOutput := initialOutput
// 第 2-N 轮:反思 + 修正循环
for i := 0; i < a.maxReflections; i++ {
fmt.Printf("🔍 第 %d 轮反思:审查输出...\n", i+2)
// 反思:找问题
reviewResult := a.review(currentOutput, task, qualityCriteria)
if !reviewResult.HasIssues {
fmt.Println("✅ 未发现问题,输出通过审查")
break
}
fmt.Printf("⚠️ 发现 %d 个问题:\n", len(reviewResult.Issues))
for _, issue := range reviewResult.Issues {
fmt.Printf(" - %s\n", issue)
reflection.IssuesFound = append(reflection.IssuesFound, issue)
}
// 修正:根据审查意见改进
fmt.Println("🔧 修正中...")
improvedOutput := a.revise(currentOutput, reviewResult.Issues)
reflection.Improvements = append(reflection.Improvements,
fmt.Sprintf("第%d轮修正了%d个问题", i+1, len(reviewResult.Issues)))
currentOutput = improvedOutput
}
reflection.FinalOutput = currentOutput
reflection.Iterations = len(reflection.IssuesFound)
return reflection
}
// ──────────── 反思 Prompt ────────────
type ReviewResult struct {
HasIssues bool
Issues []string
}
func (a *SelfReflectiveAgent) review(output, task, criteria string) ReviewResult {
reviewPrompt := fmt.Sprintf(`你是严格的代码审查员。按以下标准审查输出:
质量标准:
%s
原始任务:
%s
待审查的输出:
%s
审查时回答:
1. 输出是否符合质量标准?(逐条检查)
2. 有没有编译错误、逻辑错误、边界条件遗漏?
3. 代码是否完整可运行?(检查 import、package 声明)
如果发现问题,用以下格式列出:
ISSUE: [问题描述]
ISSUE: [问题描述]
...
如果完全没有问题,回复:NO_ISSUES`, criteria, task, truncateForReview(output, 2000))
result := a.callLLM([]Message{
{Role: "user", Content: reviewPrompt},
}, 0.0)
if strings.Contains(result, "NO_ISSUES") {
return ReviewResult{HasIssues: false}
}
var issues []string
for _, line := range strings.Split(result, "\n") {
if strings.HasPrefix(strings.TrimSpace(line), "ISSUE:") {
issues = append(issues, strings.TrimPrefix(strings.TrimSpace(line), "ISSUE: "))
}
}
return ReviewResult{HasIssues: len(issues) > 0, Issues: issues}
}
func (a *SelfReflectiveAgent) revise(output string, issues []string) string {
issuesList := strings.Join(issues, "\n- ")
revisePrompt := fmt.Sprintf(`修复以下输出中的问题。
原始输出:
%s
发现的问题:
- %s
请输出修正后的完整代码。不要解释修改了什么。`, output, issuesList)
return a.callLLM([]Message{
{Role: "system", Content: "你是代码修复专家。输出修正后的完整代码,不要包含解释性文字。"},
{Role: "user", Content: revisePrompt},
}, 0.1)
}
func truncateForReview(s string, maxLen int) string {
if len(s) > maxLen {
return s[:maxLen] + "\n...(输出超过长度限制,已截断)"
}
return s
}
// ──────────── 对比实验 ────────────
func main() {
agent := NewSelfReflectiveAgent(os.Getenv("DEEPSEEK_API_KEY"))
task := `用 Go 写一个函数 CalculateDiscount,功能:
用户等级分为 normal/vip/super-vip
normal 不打折
vip 打 9 折
super-vip 打 8 折
满 1000 元额外打 95 折(折上折)
输入:等级(string)和消费金额(float64)
输出:折扣后金额`
qualityCriteria := `1. 代码必须包含 package 和正确的 import
2. 必须处理无效的用户等级(返回错误)
3. 必须处理负金额(返回错误)
4. 所有计算必须使用浮点,不丢失精度
5. 函数签名必须包含 error 返回值`
// ── 不加反思 ──
fmt.Println("===== 不加反思:直接生成 =====")
noReflectionOutput := agent.callLLM([]Message{
{Role: "system", Content: "你是 Go 代码生成专家。"},
{Role: "user", Content: task},
}, 0.2)
fmt.Println(noReflectionOutput)
// ── 加反思 ──
fmt.Println("\n===== 加反思:生成→审查→修正 =====")
result := agent.GenerateWithReflection(task, qualityCriteria)
fmt.Println("\n===== 最终输出 =====")
fmt.Println(result.FinalOutput)
fmt.Printf("\n共进行 %d 轮迭代,发现并修复了以下问题:\n", result.Iterations)
for _, issue := range result.IssuesFound {
fmt.Printf(" ❌ %s\n", issue)
}
}
实测数据
我对同一个任务(上面的折扣计算函数),不加反思和加反思各跑了 5 次,统计结果:
| 指标 | 不加反思 | 加反思 |
|---|---|---|
| 编译通过率 | 3/5(60%) | 5/5(100%) |
| 错误处理完整 | 1/5(20%) | 5/5(100%) |
| 边界条件正确 | 2/5(40%) | 4/5(80%) |
| 平均 token 消耗 | 350 | 950 |
加反思的 token 消耗多了近 3 倍,但换取的是 100% 编译通过率和接近 100% 的错误处理完整性。
值得吗?取决于场景。 如果输出会直接部署到生产环境——值的。如果只是草稿——不值得。
什么时候用反思
| 场景 | 用反思? | 理由 |
|---|---|---|
| API 响应生成 | 不推荐 | 太慢,用户等不起 |
| 代码提交前检查 | 强烈推荐 | 编译错误是硬伤 |
| 文章/报告撰写 | 推荐 | 事实错误和逻辑漏洞很常见 |
| 数据处理脚本 | 推荐 | 数据错了很难发现 |
| 聊天回复 | 不需要 | 过度设计 |
一个实用的阈值:如果输出错误会导致大于 1 小时的修复时间——加反思。
反思的三种 Prompt 模式
1. 通用审查:
"检查输出中的事实错误、逻辑漏洞和遗漏"
2. 逐条核对:
"逐条确认以下要求是否满足:1.XXX 2.XXX 3.XXX"
3. 反向检查:
"如果你是这段代码的使用者,你会对哪些地方不满意?"
第三种特别有用——让 AI 从「作者」视角切换到「用户」视角,往往能发现意料之外的问题。
总结
自我反思不是让 Agent 变聪明,是让它多了一次检查的机会。
人写代码要 review,Agent 写代码也要 review。区别在于——人的 review 靠同事,Agent 的 review 可以自己做。
下一篇我们给 Agent 加上最后一道防线——Human-in-the-Loop,人机协作的正确姿势。
关注我,别错过。
🦞 一只用 AI Agent 搭副业产线的程序员
全平台同名:虾哥不加班
需要定制 AI 工具?来聊聊 → lob_ai
更多推荐



所有评论(0)