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最好独立审查效果最好——因为上一篇讲了同一个人批自己卷子有确认偏差。但对于日常任务角色扮演模式性价比最高。完整实现packagemainimport(bytesencoding/jsonfmtionet/httposstringstime)typeMessagestruct{Rolestringjson:roleContentstringjson:content}typeSelfReflectiveAgentstruct{apiKeystringmaxReflectionsint// 最大反思次数}funcNewSelfReflectiveAgent(apiKeystring)*SelfReflectiveAgent{returnSelfReflectiveAgent{apiKey:apiKey,maxReflections:3,}}func(a*SelfReflectiveAgent)callLLM(messages[]Message,temperaturefloat64)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)iferr!nil{returnfmt.Sprintf(调用失败: %v,err)}deferresp.Body.Close()data,_:io.ReadAll(resp.Body)varresultstruct{Choices[]struct{Messagestruct{Contentstringjson:content}json:message}json:choices}json.Unmarshal(data,result)iflen(result.Choices)0{returnresult.Choices[0].Message.Content}return}// ──────────── 核心反思循环 ────────────typeReflectionResultstruct{FinalOutputstringjson:final_outputIterationsintjson:iterationsIssuesFound[]stringjson:issues_foundImprovements[]stringjson:improvements}// GenerateWithReflection 生成 → 反思 → 修正 → 再反思func(a*SelfReflectiveAgent)GenerateWithReflection(taskstring,qualityCriteriastring,)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 轮反思 修正循环fori:0;ia.maxReflections;i{fmt.Printf( 第 %d 轮反思审查输出...\n,i2)// 反思找问题reviewResult:a.review(currentOutput,task,qualityCriteria)if!reviewResult.HasIssues{fmt.Println(✅ 未发现问题输出通过审查)break}fmt.Printf(⚠️ 发现 %d 个问题:\n,len(reviewResult.Issues))for_,issue:rangereviewResult.Issues{fmt.Printf( - %s\n,issue)reflection.IssuesFoundappend(reflection.IssuesFound,issue)}// 修正根据审查意见改进fmt.Println( 修正中...)improvedOutput:a.revise(currentOutput,reviewResult.Issues)reflection.Improvementsappend(reflection.Improvements,fmt.Sprintf(第%d轮修正了%d个问题,i1,len(reviewResult.Issues)))currentOutputimprovedOutput}reflection.FinalOutputcurrentOutput reflection.Iterationslen(reflection.IssuesFound)returnreflection}// ──────────── 反思 Prompt ────────────typeReviewResultstruct{HasIssuesboolIssues[]string}func(a*SelfReflectiveAgent)review(output,task,criteriastring)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)ifstrings.Contains(result,NO_ISSUES){returnReviewResult{HasIssues:false}}varissues[]stringfor_,line:rangestrings.Split(result,\n){ifstrings.HasPrefix(strings.TrimSpace(line),ISSUE:){issuesappend(issues,strings.TrimPrefix(strings.TrimSpace(line),ISSUE: ))}}returnReviewResult{HasIssues:len(issues)0,Issues:issues}}func(a*SelfReflectiveAgent)revise(outputstring,issues[]string)string{issuesList:strings.Join(issues,\n- )revisePrompt:fmt.Sprintf(修复以下输出中的问题。 原始输出 %s 发现的问题 - %s 请输出修正后的完整代码。不要解释修改了什么。,output,issuesList)returna.callLLM([]Message{{Role:system,Content:你是代码修复专家。输出修正后的完整代码不要包含解释性文字。},{Role:user,Content:revisePrompt},},0.1)}functruncateForReview(sstring,maxLenint)string{iflen(s)maxLen{returns[:maxLen]\n...输出超过长度限制已截断}returns}// ──────────── 对比实验 ────────────funcmain(){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:rangeresult.IssuesFound{fmt.Printf( ❌ %s\n,issue)}}实测数据我对同一个任务上面的折扣计算函数不加反思和加反思各跑了 5 次统计结果指标不加反思加反思编译通过率3/560%5/5100%错误处理完整1/520%5/5100%边界条件正确2/540%4/580%平均 token 消耗350950加反思的 token 消耗多了近 3 倍但换取的是 100% 编译通过率和接近 100% 的错误处理完整性。值得吗取决于场景。如果输出会直接部署到生产环境——值的。如果只是草稿——不值得。什么时候用反思场景用反思理由API 响应生成不推荐太慢用户等不起代码提交前检查强烈推荐编译错误是硬伤文章/报告撰写推荐事实错误和逻辑漏洞很常见数据处理脚本推荐数据错了很难发现聊天回复不需要过度设计一个实用的阈值如果输出错误会导致大于 1 小时的修复时间——加反思。反思的三种 Prompt 模式1. 通用审查检查输出中的事实错误、逻辑漏洞和遗漏2. 逐条核对逐条确认以下要求是否满足1.XXX 2.XXX 3.XXX3. 反向检查如果你是这段代码的使用者你会对哪些地方不满意第三种特别有用——让 AI 从「作者」视角切换到「用户」视角往往能发现意料之外的问题。总结自我反思不是让 Agent 变聪明是让它多了一次检查的机会。人写代码要 reviewAgent 写代码也要 review。区别在于——人的 review 靠同事Agent 的 review 可以自己做。下一篇我们给 Agent 加上最后一道防线——Human-in-the-Loop人机协作的正确姿势。关注我别错过。 一只用 AI Agent 搭副业产线的程序员全平台同名虾哥不加班需要定制 AI 工具来聊聊 → lob_ai源码GitHub - lobster-bujiaban