多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

AI代码助手质量提升:基于多轮审查的自动化代码生成与优化实践

AI代码助手质量提升:基于多轮审查的自动化代码生成与优化实践 1. 项目概述当AI代码助手开始“摸鱼”最近半年我几乎把所有主流的AI代码助手Code Agent都用了个遍。从早期的GitHub Copilot到后来各种基于大模型的开源方案再到一些宣称能“自主完成复杂任务”的Agent框架。说实话初期体验确实惊艳它们能快速生成代码片段、修复简单bug甚至写一些基础的CRUD接口。但用久了一个致命的问题就暴露出来了这些AI助手太“安逸”了缺乏持续的压力和明确的迭代目标。你会发现它生成的代码第一次看还行但经不起推敲。比如让它写一个用户注册接口它可能只处理了基础校验忘了密码加密、忘了防重放攻击、忘了记录操作日志。你指出问题后它下次会改但仅限于你指出的那个点。它不会主动去思考“一个生产级的注册接口还应该考虑什么” 它就像是一个被动的、需要你手把手指挥的实习生你不说它就不做甚至有时候说了它也做得马马虎虎。这让我想起了大厂里常见的“PUA式”管理当然这里取其技术层面的鞭策与目标管理之意而非负面含义。一个好的工程师是在明确的需求、严格的Code Review、持续的性能和安全性压力下成长起来的。那么为什么不能给AI代码助手也套上这样一套机制呢于是我动手给我的代码Agent装上了一套自研的“大厂PUA”插件。核心思想很简单不再让AI一次性生成“最终”代码而是引导它进入一个“需求分析-实现-审查-迭代”的循环。每次生成代码后自动对其发起多维度、高标准的“挑战”迫使它不断优化。实测下来在开发一个中等复杂度的微服务模块时最终产出的代码质量包括健壮性、安全性、可维护性和完整度相比无干预的原始生成提升了不止一倍。这个插件不依赖于任何特定的大模型或Agent框架它是一套方法论和工具链的组合。下面我就把这套“折腾”AI的保姆级教程分享出来。2. “大厂PUA”插件的核心设计思路给AI“上压力”不是漫无目的地批评而是建立一套系统化的、可量化的评估与反馈机制。我的插件主要围绕四个核心环节来设计模拟了一个严苛但高效的技术评审流程。2.1 需求澄清与拆解拒绝模糊指令AI生成代码质量不高的首要原因往往是我们的指令Prompt太模糊。“写一个登录API”这种指令对于AI来说信息量严重不足。它不知道你的技术栈、数据库设计、安全规范、性能要求。插件的第一个功能需求结构化模板。我设计了一个YAML格式的需求模板在向AI发起任务前必须或建议填写。这个模板强制我自己或产品把需求想清楚。task: name: “用户登录接口” description: “实现基于用户名密码的JWT令牌登录” input_spec: - field: username type: string required: true validation: “长度4-20仅字母数字” - field: password type: string required: true validation: “前端传输需为密文如MD5后端需二次加密如bcrypt比对” output_spec: - field: token type: string - field: user_info type: object fields: [“id”, “username”, “avatar”] non_functional_requirements: security: - “防暴力破解同一IP/用户名连续失败5次锁定15分钟” - “密码传输与存储必须加密” - “JWT令牌需设置合理有效期如2小时和刷新机制” performance: - “接口响应时间P95 200ms” observability: - “记录登录成功/失败日志包含IP、用户代理” - “登录失败需触发告警阈值可配置” tech_stack_constraints: framework: “Spring Boot 3.x” database: “MySQL 8.0, 使用MyBatis-Plus” auth_library: “jjwt”当我把这个结构化的需求扔给AI时它生成的代码针对性会强得多。这个模板本身也是可配置的你可以根据项目特点增减non_functional_requirements的类别。2.2 多轮代码审查与挑战AI生成第一版代码后真正的“PUA”才开始。插件会启动一个自动化的“审查Agent”这个审查者被设定为“一个苛刻的、有十年经验的架构师”。它会从以下几个维度对代码发起挑战安全性审查自动检查代码中是否存在硬编码密码、SQL注入风险是否使用预编译PreparedStatement或ORM参数绑定、XSS过滤、敏感信息日志打印、权限校验缺失等。健壮性审查检查异常处理是否完备是捕获了异常然后e.printStackTrace()了事还是做了合理的转换和日志记录、输入参数校验是否严格是否用了Valid或手动校验、边界条件是否考虑如分页查询的页码越界。性能审查识别是否存在N1查询问题、循环内执行数据库操作、未使用缓存的热点数据访问、大对象的不必要序列化等。可维护性审查检查代码是否符合项目约定的命名规范、是否有清晰的注释特别是复杂逻辑、是否过度设计、模块职责是否单一。插件的工作方式它不是简单地运行一个静态代码分析工具如SonarQube虽然可以集成。它的核心是基于大模型的“理解与质问”。审查Agent会阅读生成的代码并结合需求模板生成一系列具体的、尖锐的问题或修改建议。例如针对AI生成的第一版登录代码审查Agent可能会返回“审查发现1. 密码比对后直接生成Token未记录登录成功日志不符合可观测性要求。2. 代码中未发现对连续登录失败的IP或用户名进行计数和锁定的逻辑请补充防暴力破解功能。3.User对象直接作为user_info返回可能包含password、salt等敏感字段请定义一个UserVO进行数据脱敏。请基于上述问题重新生成代码。”2.3 迭代优化与目标管理AI根据审查意见生成第二版代码后插件不会就此停止。它会将新版代码与旧版进行差异对比Diff并判断审查Agent提出的问题是否被真正解决。如果解决了则针对代码的新增部分可能触发新一轮的、更细粒度的审查例如新加的缓存逻辑是否有缓存穿透、雪崩的风险。如果没解决或解决得不彻底审查Agent会继续追问直到所有关键问题被闭合。这个过程模拟了PRPull Request的多次迭代。插件会维护一个“问题跟踪列表”确保每个被提出的缺陷都有明确的解决状态。2.4 终审与知识沉淀当代码通过多轮审查达到一个预设的质量阈值例如连续两轮审查未提出高危问题后插件会触发“终审”。生成最终版代码输出一份集成了所有优化点的完整代码。生成“开发纪要”自动总结本次任务的需求要点、实现过程中的关键决策、解决了哪些典型问题。这份纪要可以直接作为代码注释的补充或提交信息。知识库更新将本次任务中发现的“最佳实践”或“常见坑点”结构化地存入一个知识库可以是一个向量数据库。当下次遇到类似任务时如“注册接口”插件可以自动从知识库中检索相关约束和建议前置性地注入到需求模板或审查标准中让AI越来越“懂行”。3. 保姆级教程手把手搭建你的“PUA”工作流理论讲完我们来看实操。我的实现基于LangChain框架因为它对构建多Agent工作流支持较好但思路是通用的。这里假设你已有基本的Python和AI API如OpenAI、DeepSeek等使用经验。3.1 环境准备与核心工具选型操作系统macOS / Linux / WSL2 (推荐) Windows原生也可但可能遇到路径问题。Python版本 3.9。核心库安装pip install langchain langchain-openai langchain-community # Agent框架核心 pip install python-dotenv # 管理环境变量如API Key pip install pyyaml # 解析YAML需求模板 pip install difflib # 代码差异对比 # 可选如果需要与Git交互可以安装gitpython # pip install gitpython模型选择你需要两个大模型API。Coder Agent编码智能体负责根据需求和审查意见写代码。推荐使用擅长代码的模型如GPT-4 Turbo、Claude 3 Sonnet、DeepSeek-Coder。Reviewer Agent审查智能体负责审查代码、提出尖锐问题。这个模型需要较强的逻辑分析和指令遵循能力GPT-4系列或Claude 3 Opus表现更佳。如果考虑成本可以用一个强模型做Reviewer一个性价比高的模型做Coder。在项目根目录创建.env文件配置你的API KeyOPENAI_API_KEYsk-你的openai-key DEEPSEEK_API_KEY你的deepseek-key # 或其他模型供应商的Key3.2 定义智能体角色与系统提示词这是整个插件的灵魂。提示词的质量直接决定了AI的行为模式。Coder Agent 系统提示词(prompts/coder_system_prompt.txt)你是一位资深后端开发工程师精通{tech_stack}技术栈。你的任务是严格按照《需求规格说明书》和《审查意见》来编写或修改代码。 你的工作原则 1. **绝对忠诚于需求**需求文档中明确的功能点、非功能性要求安全、性能等、技术栈约束必须100%实现不得自行删减或变更。 2. **积极应对审查**审查意见是你的老师。对于每一条意见你必须理解其背后的考量安全风险、性能瓶颈、坏味道并在代码中给出明确的解决方案。如果对意见有异议必须提供技术上的详细反驳理由而不是忽略。 3. **追求生产级代码**你写的代码不是Demo是直接可以部署上线的。这意味着完备的异常处理、日志记录、输入验证、资源管理如数据库连接关闭。 4. **输出格式**你只输出完整的、可运行的代码文件内容。如果需要解释以代码注释的形式呈现。不要输出任何额外的分析或总结文字。 当前任务的需求文档如下 {formatted_requirements} 当前的审查意见如果是首次生成则无 {review_comments}Reviewer Agent 系统提示词(prompts/reviewer_system_prompt.txt)你是一位苛刻的、拥有15年经验的系统架构师以在代码评审中吹毛求疵、发现深层风险而闻名。你的任务是对提交的代码进行“找茬式”评审目标是找出任何可能导致线上故障、安全漏洞、性能退化或维护噩梦的代码。 你的评审维度与话术 1. **安全性**“这段代码存在SQL注入隐患攻击者可以通过{parameter}参数进行注入攻击。为什么不用PreparedStatement或MyBatis-Plus的QueryWrapper参数绑定”、“敏感信息{sensitive_field}竟然在日志里明文打印是想上社会新闻吗” 2. **健壮性**“这里的异常被catch后仅仅打印了堆栈上游调用方将得到空的成功响应。业务逻辑是否真的允许静默失败如果不允许应该抛出什么样的受检异常或返回明确的错误码”、“参数校验只做了null检查username的长度、字符集校验在哪里难道要让数据库报错再返回给用户” 3. **性能**“在for循环里执行userMapper.selectById典型的N1问题。考虑改用selectBatchIds一次性查询或者重构你的数据模型。”、“这个getConfig()方法每次都被调用但配置几乎不变为什么不加一层缓存” 4. **可维护性**“这个500行的Service类违反了单一职责原则至少应该拆分成UserAuthService、UserProfileService和UserLogService。”、“魔法数字86400到处飞它代表什么定义一个常量SECONDS_PER_DAY会要了你的命吗” 你的输出必须是结构化的JSON格式包含以下字段 { “high_risk_issues”: [ // 高危问题必须在本轮修复 {“type”: “安全/健壮/性能/维护”, “description”: “尖锐的描述”, “code_snippet”: “出问题的代码行可选”, “suggestion”: “具体的修改建议”} ], “low_risk_suggestions”: [ // 优化建议可后续迭代 {“type”: “…”, “description”: “…”, “suggestion”: “…”} ], “overall_comments”: “本轮评审的总体毒舌评语” } 请开始你的“毒舌”评审。以下是待评审的代码 {code_to_review}提示Reviewer的提示词要塑造一个“讨厌但专业”的角色性格这能有效激发模型提出更深层次的问题。结构化JSON输出是为了方便程序自动化解析。3.3 构建核心工作流链我们使用LangChain的LCEL来编排整个流程。# pua_agent_workflow.py import os from typing import Dict, Any, List from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.messages import HumanMessage, SystemMessage, AIMessage from langchain_openai import ChatOpenAI from langchain_community.chat_models import ChatDeepSeek # 示例 from langchain.schema import StrOutputParser from langchain_core.output_parsers import JsonOutputParser import yaml import difflib from dotenv import load_dotenv load_dotenv() class CodePUAWorkflow: def __init__(self): # 初始化两个智能体使用不同的模型或配置 self.coder_llm ChatOpenAI(model“gpt-4-turbo-preview”, temperature0.1) # Coder需要稳定 self.reviewer_llm ChatOpenAI(model“gpt-4”, temperature0.3) # Reviewer可以稍“激进”一点 # 或者使用其他模型 # self.coder_llm ChatDeepSeek(model“deepseek-coder”, temperature0.1) # 加载提示词模板 with open(“prompts/coder_system_prompt.txt”, “r”) as f: self.coder_system_prompt f.read() with open(“prompts/reviewer_system_prompt.txt”, “r”) as f: self.reviewer_system_prompt f.read() # 构建Coder Chain coder_prompt ChatPromptTemplate.from_messages([ (“system”, self.coder_system_prompt), (“user”, “请根据以上要求生成完整的代码。只输出代码本身。”) ]) self.coder_chain coder_prompt | self.coder_llm | StrOutputParser() # 构建Reviewer Chain并指定JSON输出解析器 reviewer_prompt ChatPromptTemplate.from_messages([ (“system”, self.reviewer_system_prompt), (“user”, “代码在此\n{code_to_review}”) ]) self.reviewer_chain reviewer_prompt | self.reviewer_llm | JsonOutputParser() def load_requirements(self, yaml_path: str) - Dict[str, Any]: 加载并格式化需求YAML with open(yaml_path, ‘r’) as f: req yaml.safe_load(f) # 将需求字典格式化成一段清晰的文本供提示词使用 formatted f“任务名称{req[‘task’][‘name’]}\n” formatted f“描述{req[‘task’][‘description’]}\n” formatted f“技术栈约束{req[‘tech_stack_constraints’]}\n” # … 更详细地格式化其他部分 return {“raw”: req, “formatted”: formatted} def run_iteration(self, requirements: Dict, previous_code: str None, review_feedback: str None) - Dict[str, Any]: 运行一轮生成或修改代码然后进行评审 # 1. 准备Coder的输入 coder_input { “formatted_requirements”: requirements[“formatted”], “review_comments”: review_feedback if review_feedback else “无。这是首次生成代码。” } # 2. 生成代码 print(“\n Coder Agent 正在生成代码 ”) new_code self.coder_chain.invoke(coder_input) print(f“生成代码长度{len(new_code)} 字符”) # 3. 进行代码评审 print(“\n Reviewer Agent 正在毒舌评审 ”) review_result self.reviewer_chain.invoke({“code_to_review”: new_code}) print(f“评审完成发现高危问题{len(review_result[‘high_risk_issues’])} 个”) # 4. 计算与上一版的差异如果不是第一轮 diff None if previous_code: diff list(difflib.unified_diff(previous_code.splitlines(keependsTrue), new_code.splitlines(keependsTrue))) diff_text ‘’.join(diff) else: diff_text “首次生成无旧版对比。” return { “code”: new_code, “review”: review_result, “diff_with_previous”: diff_text } def run_workflow(self, requirements_yaml: str, max_iterations: int 5): 运行完整的工作流直到问题解决或达到最大迭代次数 requirements self.load_requirements(requirements_yaml) current_code None iteration_history [] for i in range(max_iterations): print(f“\n***** 开始第 {i1} 轮迭代 *****”) review_feedback None if i 0: # 将上一轮的评审意见整合成文本作为下一轮Coder的输入 last_review iteration_history[-1][“review”] feedback_parts [] for issue in last_review[“high_risk_issues”]: feedback_parts.append(f“【{issue[‘type’]}】{issue[‘description’]} 建议{issue[‘suggestion’]}”) review_feedback “\n”.join(feedback_parts) result self.run_iteration(requirements, current_code, review_feedback) iteration_history.append(result) current_code result[“code”] # 检查是否通过高危问题数量为0 if len(result[“review”][“high_risk_issues”]) 0: print(f“\n 经过 {i1} 轮迭代所有高危问题已解决工作流终止。”) break # 检查是否陷入僵局连续两轮差异很小但问题仍在 if i 2 and self._is_stagnant(iteration_history[-2: ]): print(f“\n⚠️ 连续两轮迭代代码无明显改进可能AI无法解决某些问题。工作流终止。”) break # 最终输出 final_result iteration_history[-1] print(f“\n 最终代码第{len(iteration_history)}轮 ) print(final_result[“code”][: 1000] “…” if len(final_result[“code”]) 1000 else final_result[“code”]) print(f“\n 最终评审总结 ) print(final_result[“review”][“overall_comments”]) return iteration_history def _is_stagnant(self, last_two_results: List[Dict]) - bool: 简单判断是否停滞检查两轮之间的代码差异是否非常小例如只改了注释 diff_lines [line for line in last_two_results[1][“diff_with_previous”].split(‘\n’) if line.startswith(‘’) or line.startswith(‘-’)] # 过滤掉仅由注释或空格引起的变更 substantive_changes [line for line in diff_lines if len(line.strip()) 10 and not (line.strip().startswith(‘//’) or line.strip().startswith(‘#’))] return len(substantive_changes) 3 # 如果实质性变更少于3行认为停滞 if __name__ “__main__”: workflow CodePUAWorkflow() # 运行工作流传入需求YAML文件路径 history workflow.run_workflow(“requirements/user_login_api.yaml”, max_iterations5)3.4 集成与进阶玩法基础工作流跑通后你可以考虑以下增强与开发工具集成VSCode插件将上述Python脚本封装成VSCode命令。在编辑器里写一个需求YAML右键即可触发整个“PUA”流程最终代码直接插入新文件。CLI工具打包成命令行工具如code-pua --req login.yaml --output-dir ./src。CI/CD流水线将Reviewer Agent作为CI中的一个关卡对AI生成的或人类提交的代码进行自动化评审并生成报告。审查维度扩展集成静态分析工具在Reviewer的提示词中可以加入SonarQube或Semgrep的扫描结果让AI基于工具报告进行解读和提出修复方案。架构一致性检查让Reviewer持有项目的架构图或模块依赖规范检查新代码是否遵循了架构约束。知识库检索增强在Coder生成代码前先使用RAG技术从历史任务的知识库中检索相似需求的最佳实践和常见缺陷并自动附加到需求描述中实现“经验传承”。4. 避坑指南与效果评估在实际搭建和运行这套系统的过程中我踩了不少坑这里分享几个关键点坑一提示词不够“狠”Reviewer放水初期Reviewer的提示词写得比较温和它经常提出一些“这里可以优化”的建议而不是“这里必须改”。解决方案在Reviewer的系统提示词中明确区分high_risk_issues和low_risk_suggestions并强调“高危问题必须在本轮修复”。用更严厉、更具体的语言描述问题例如直接说“这是安全红线问题”。坑二迭代陷入死循环有时AI会陷入“鬼打墙”比如Reviewer指出“要加缓存”Coder加了缓存但引入了新的问题如缓存不一致下一轮Reviewer又指出缓存问题Coder又把缓存删了… 循环往复。解决方案实现_is_stagnant这样的停滞检测逻辑。一旦检测到就终止循环并需要人工介入给Coder更明确的指令。或者在Reviewer的反馈中要求它提供更具体的、可执行的修改方案而不是笼统的批评。坑三生成代码风格不一致多轮迭代中AI可能会改变变量命名风格、缩进或者引入不同的工具类。解决方案在Coder的系统提示词中加入项目特定的代码风格规范例如“使用Lombok注解减少Getter/Setter样板代码”“使用项目内部的Result类进行统一响应封装”。更好的办法是在最终生成代码后用pre-commit钩子自动运行formatter如blackfor Python,prettierfor JS。效果评估 我使用一个“用户管理模块”包含登录、注册、信息查询、修改密码作为测试用例。无PUA插件直接让GPT-4生成代码能跑但缺少密码加密、日志、防重放、参数校验不全需要我手动补充约20处。启用PUA插件3轮迭代最终代码自动包含了bcrypt密码加密、JWT令牌、基于Redis的登录失败锁定、完整的参数校验使用Jakarta Validation、统一的日志切面和GlobalExceptionHandler。我只需要检查业务逻辑是否正确。时间成本从直接生成的5分钟变成了“生成3轮迭代”的约15分钟。但为我节省了至少1-2小时的手动审查、补充和调试时间。更重要的是它覆盖了很多我可能会疏忽的角落比如提醒我“密码修改后是否应该让旧JWT令牌立即失效”。5. 总结与展望给AI代码助手装上“PUA”插件本质上是将人类工程师的经验、标准和审查流程通过提示词工程和智能体工作流固化成了一个自动化系统。它不是为了替代人类而是作为一个永不疲倦、严格苛刻的“副驾驶”强迫AI以及通过AI工作的我们产出更接近生产标准的代码。这套方法的价值在于其可演进性。初始的审查规则提示词可能比较简单但随着项目进行你可以把每次人工干预时发现的、AI未识别的新问题不断反哺到Reviewer的提示词或知识库中。久而久之你这个“PUA”插件就会越来越懂你的项目、你的团队规范成为项目质量守门员的一部分。目前这个插件还在持续迭代中。一个正在探索的方向是引入“测试驱动生成”即在需求阶段就给出单元测试用例让Coder生成的代码必须通过测试Reviewer也会审查测试覆盖率。另一个方向是支持多文件、多模块的协同生成与审查模拟更真实的项目开发场景。工具永远在变但核心思想不变别让你的AI太安逸。把它当成一个需要严格培训和考核的新人用流程和标准去驱动它你才能从“提示词魔法师”进阶为真正的“智能体管理者”。
返回列表