“基于大语言模型的代码自动生成与Bug修复助手”这个选题,这几年在高校毕设里几乎成了“显学”。我前前后后带过好几个做类似方向的项目,也帮人审过不少方案,发现一个共性问题:大家都能把“调用大模型生成代码”这步跑通,但一旦涉及系统架构设计、Bug修复闭环、结果可靠性评测,就明显底气不足。这篇文章就围绕这类助手的完整实现展开,从需求拆解、技术选型、提示词工程到后端服务、前端交互、模型调参与评测方法,把我实际操作中的经验和踩过的坑一次讲清楚,适合做毕设、做课程项目或想入门LLM应用的开发者参考,照着能落地。
1. 整体设计与思路拆解
1.1 核心需求到底拆成什么
很多同学拿到这个题目,第一反应就是把大模型接口一封装,做个聊天窗口就交差。但如果你把这套东西当作一个正经系统来设计,需求其实要拆成两条主线和三个角色。
两条主线分别是“代码自动生成”和“Bug自动修复”。生成这边,用户输入一段自然语言描述(比如“写一个Python函数,读取CSV文件并返回按第二列排序的列表”),系统输出完整可运行的代码和必要的使用说明;修复这边,用户粘贴报错信息、堆栈或者有问题的代码片段,系统返回定位原因之后的修正代码和解释。
三个角色则对应了不同的使用场景。普通用户只需要网页交互,把需求丢进去拿结果;开发者可能需要批量接口,把生成能力嵌入自己的脚本或本地工具;维护者(也就是你)需要能看清每一次请求的输入输出、模型参数、耗时和失败原因,否则论文里的实验数据根本编不出来。
这里有个容易被忽视的关键点:如果只做“生成”,项目深度不够,因为本质上就是一个带UI的API转发器。真正有技术含量、能撑起毕设工作量的是“修复”这条线——它需要解析错误、构造诊断上下文、设计修复循环,还要做回归验证,里面每一步都有可写的内容。所以我建议架构上从一开始就把生成和修复做成两个独立模块,而不是一个聊天页面糊到底。
1.2 方案选型:商用API还是本地模型
这是项目启动后第一个需要拍板的问题,也是被问得最多的一个问题。两种路线各有适用场景,我直接按四个维度对比:
表:商用API与本地化模型部署路线对比
| 对比维度 | 商用大模型API | 本地部署开源模型 |
|---|---|---|
| 代码能力 | 强,对长上下文和复杂逻辑理解好 | 取决于模型尺寸,中小模型差距明显 |
| 硬件成本 | 按Token计费,前期投入低 | 需要至少一张消费级显卡,显存紧张 |
| 部署复杂度 | 低,申请密钥即可 | 需要模型下载、推理框架配置 |
| 数据隐私 | 代码会发往服务端 | 完全本地,适合敏感代码 |
| 毕设展示效果 | 交互流畅,但答辩时容易被认为“只是调API” | 本地推理过程可展示,技术深度更直观 |
我个人的倾向是:如果目标是毕业设计,优先选商用API做主干功能,因为开发周期短、效果好,你省下时间可以去做评测、修Bug闭环和论文实验;但建议预留一个模型层抽象接口,让“本地模型”可以作为可选项接入,答辩时既能演示完整功能,又能解释清楚选型理由和适配过程。纯走本地路线不是不行,只是7B级别的开源模型写简单脚本还行,处理复杂业务逻辑时错误率明显高,修复效果也打折,你会花大量时间在模型效果不理想这个不可控因素上。
1.3 系统架构分层
整个系统我建议做成三层:Web前端、后端服务、模型适配层。前端负责对话交互、代码展示、复制和提交反馈;后端负责解析用户请求、构造提示词、调用模型、解析响应、执行修复流程;模型适配层把所有模型调用封装成统一接口,换模型只改配置不改业务代码。
这个分层的价值在于解耦。我见过有人的实现直接把Prompt模板、模型调用和业务逻辑全写在同一个文件里,前期改起来很爽,后期加一个“代码执行验证”功能就要动所有代码。分层之后,每一层都可以独立测试,出了问题也能按层定位。尤其是模型适配层,我强烈建议多花一点时间做,它决定了后续切换成本。
另外要补充一点:后端一定要留日志表,记录每条请求的模型名称、输入输出、Token消耗、耗时、是否成功。这不是为了给老师看,而是你后续做效果对比和写论文必备的数据来源。没有日志,所有评测只能靠感觉,那是毕设的大忌。
2. 提示词工程与模型调用细节
2.1 提示词模板才是核心竞争力
很多人以为大模型项目最难的是代码,其实真正拉开差距的是提示词。同一个模型,用一句话提示词和用结构化的系统提示词,输出质量能差出一大截。代码生成这个场景,我整理的提示词骨架大体是这样的:
系统角色部分要明确“你是一名资深软件工程师,擅长编写高质量、可读性强、可直接运行的代码,并会给出必要的说明”。这听起来像废话,但实测下来角色设定对输出风格影响很大,不设定的话模型容易给出“概述式”回答,而不是直接给代码。
然后是输出格式约束。每次请求我都会强调:先给出完整代码块,再给出简要说明;代码块标注语言类型;不要输出与问题无关的内容。为什么要这样?因为后处理解析的时候,只要模型严格按“代码块+说明”的结构输出,你就能稳定地从Markdown代码块里提取代码,而不是靠正则满天飞地猜。
用户输入部分,生成模块要求用户按“任务描述 + 可选约束”的方式填写。任务描述就是“实现什么功能、输入是什么、输出是什么”,约束包括语言、依赖、风格等。在拼装这段时我会做一个简单的模板填充,而不是让用户随便打字,这样能最大程度保证提示词的质量稳定。
Bug修复的提示词又是另一套逻辑。它的关键不是让模型“看代码”,而是让模型“先诊断再下结论”。我的模板固定了三段式:第一段是报错信息(优先给堆栈)、第二段是代码上下文、第三段是“请按以下步骤回答:列出可能原因,然后给出修正后的完整代码,最后简要说明修改点”。强制模型经历“分析-修复-总结”三个步骤,修复准确率会明显比直接给代码高。这里的原理很简单:让模型逐步推理比让它一口给出答案更可靠,这在实践中反复得到验证。
2.2 模型参数该怎么调
参数这块是大家最容易忽略、又最能体现项目质量意识的地方。代码生成场景里,最常调的是温度(temperature)、单次输出上限(max_tokens)和top_p。
温度控制随机性。代码生成我建议温度设置为0到0.2之间,最好是0.1左右。因为代码是确定性任务,你不想让模型每次生成的结果都不一致,温度太高会带来随机错误。我个人测试过,同一个函数描述,温度设为0.7时,连续调用几次偶尔会出现编译不过的垃圾代码;设为0.1时,输出结构稳定很多,基本只有功能实现层面的小差异。
max_tokens要按任务类型设置。简单代码生成256到512就够,复杂项目级别可能要到2048甚至更多。但要注意,max_tokens设置过大会拖慢响应,设置过小代码会被截断——这是最常见的失败原因之一,后面专门讲。
至于top_p,我通常保持默认或者和温度配合微调,一般固定为1或者0.9即可。根据实际经验,在代码生成的场景里,temperature对结果的影响远大于top_p,优先调temperature就够了。
2.3 响应的后处理与容错
调用模型拿到的响应是文本,尤其是用商用API时,它可能带各种格式瑕疵。最典型的是代码块里外混着解释文字,或者模型在代码块末尾多加了一个多的闭合括号。我的做法是写一个独立的解析函数,专门做几件事:
第一步,优先用正则匹配Markdown代码块,提取第一个语言标注匹配的代码块内容。如果匹配不到,就退化为直接返回全文——这种情况说明模型没有按格式输出,需要记录到日志里作为失败样本。第二步,对提取到的代码做括号配对检查,如果明显不配对,标记为“需要人工确认”而不是直接拒绝。第三步,把解析后的代码单独存一份,为后面的运行验证做准备。
这里有个细节:解析函数不要试图“修复”代码,它只负责提取和标记。修复交给修复模块,解析层越简单越不容易出错。我见过有人在后处理里写复杂的正则替换去修代码,结果越改越乱,最后把本来能用的代码改坏了。后处理层保持克制,是成熟的做法。
3. 核心模块实现与实操要点
3.1 后端服务框架与路由设计
后端我建议用Python生态,开发快、模型SDK支持好。整体用异步Web框架(比如FastAPI这一类),写一个服务端接口接收前端的请求。接口设计上分两个路由比较清晰:一个用于文本生成,接收任务描述和约束参数,返回生成结果;另一个用于代码修复,接收代码和报错信息,返回诊断结论和修复代码。两个接口内部共享同一套会话管理与日志逻辑,但Prompt构造完全分离。
异步接口还有一个好处:大模型调用耗时通常在数秒到十几秒,同步接口会长期占用连接池,前端体验也会卡死。异步接口配合前端的轮询或流式返回,体验会好很多。如果做流式输出,SSE(Server-Sent Events)协议是首选方案,实现简单,前端用EventSource就能接。
3.2 代码生成模块的实现
生成模块的核心流程是:接收请求 → 组装提示词 → 调用模型适配层 → 解析响应 → 返回结果。这里最容易出问题的是“会话上下文”的处理。很多人会把所有历史消息一股脑发给模型,结果上下文越来越长,费用越来越高,而且模型被之前无关的对话干扰,生成质量反而下降。我的建议是:如果只是单次生成任务,只把当前任务描述+系统提示词发过去,不要带历史记录;只有确实需要多轮修改时,才把最后两轮对话带上,而且要做截断。
在调用模型时,我习惯把“生成”和“解析”分两步处理,先拿原始响应,再走解析函数。不要直接在模型回调里解析,因为一旦解析失败,原始数据就丢了,排查问题只能抓瞎。
代码生成示例这里给一个简化版的调用逻辑:
async def generate_code(description: str, language: str = "python"): messages = [ {"role": "system", "content": CODE_GEN_SYSTEM_PROMPT}, {"role": "user", "content": build_gen_user_prompt(description, language)} ] response = await model_adapter.chat( messages=messages, temperature=0.1, max_tokens=1024 ) return parse_code_response(response)这段逻辑里最值得说的是model_adapter。它是一个类,内部封装了具体API的鉴权、请求、超时和重试。业务代码里永远不直接出现具体API的调用语句,这样后面想换成本地模型,只需要新增一个适配器实现类就行。
3.3 Bug修复模块的闭环设计
如果说生成模块是“直路”,修复模块就是“环路”。我的实现是三步循环:
第一步,诊断。把报错信息、堆栈和代码片段拼装进修复提示词,让模型输出可能的原因和修复代码。第二步,验证。调用系统的代码执行器,在受控环境里跑一遍修复后的代码,检查是否能通过编译或运行。这一步很关键,它把“模型说修好了”变成“我们确认修好了”。第三步,反馈。如果执行失败,把新的报错信息再次喂给模型,让模型继续修复,最多重试两轮。
为什么要做这个循环?因为大模型的修复本质是概率性的,一次修复成功率可能只有六到八成,但经过两三轮迭代,成功率能显著提升。而且这个“迭代修复”的过程本身就是毕设里很好的创新点阐述素材——它和论文里常见的“自动程序修复”研究思路是对齐的。
代码执行器要注意安全边界,这个一定要强调:不能在服务器上直接裸跑用户提交的代码,否则就是给自己埋雷。我建议用容器隔离,或者在受限子进程内执行并设置超时、内存限制,禁止写文件、网络请求等危险操作。即便是毕设项目也必须做这层防护。
3.4 前端交互与结果展示
前端不用做得多花哨,但要保证三类信息清晰展示:生成/修复结果代码、模型给出的解释说明、执行验证的状态。代码展示组件要支持语法高亮和复制按钮,这是最基本的要求。
我比较推荐一个“双栏”交互布局:左侧是参数面板,让用户选择语言、温度、是否启用验证;主区域是对话流式的输入输出。修复场景下,输出区要分层展示:原始报错、诊断原因、修复后的代码、验证结果。这样评委一眼就能看到系统的完整能力链,而不只是一个聊天框。
还有一个加分项:展示Token消耗和耗时。这两项数据来自后端日志,展示到前端可以体现系统的可观测性,对答辩尤其有利。
4. 常见问题与排查技巧实录
4.1 代码被截断
这是我在实际使用中遇到频率最高的问题。生成一个较长的函数或类时,输出突然在某个不完整的地方断掉,代码根本没法运行。原因通常是max_tokens设置不够,或者模型输出时被内部上限截断。排查方法很简单:看日志里响应的finished_reason字段,如果是“length”而不是“stop”,说明是截断导致的。
解决办法有三个方向:调大max_tokens;在提示词里要求“代码要完整,不要省略”;或者拆解任务,让模型一次只生成一个函数。我实测下来,最有效的是拆解任务,哪怕多调用一次模型,也比硬撑一个超长输出稳定得多。
4.2 模型输出格式漂移
提示词明明写了“先代码块后说明”,但模型偶尔还是会输出一段话再代码块,甚至代码块的markdown标记缺失。这类格式漂移是概率性的,无法完全根除。我的对策是解析器做三层降级:第一层匹配带语言标注的代码块,第二层匹配不带标注的代码块,第三层把整个响应当作代码处理。同时,每次格式漂移都记入日志,累计多了就去调整提示词。经过两三轮反馈调整,格式漂移率能压到很低。
4.3 生成代码能看不能用
这是比格式漂移更头疼的问题:代码语法没毛病,逻辑却是错的,或者依赖没写清楚。这类问题靠提示词和解析都解决不了,唯一有效的办法是执行验证。这也就是为什么我强调修复模块里要有执行器——生成模块同样建议加一个“一键运行验证”的开关,如果验证失败,自动把错误信息转给修复模块做一轮修复。这就把“生成”和“修复”两个模块串成了一条完整的自动闭环,整个系统的能力一下子就立体了。
4.4 API成本和限额控制
商用API调用多了,费用和限流都是实际问题。我的经验是做好三层控制:第一层,前端做输入长度校验,过长的需求提醒用户精简;第二层,后端做缓存,对完全相同的请求直接返回历史结果,实测能省掉不少重复调用;第三层,日志里记录Token消耗,设置每日消费上限,避免失控。另外,测试阶段建议用低档位模型参数做快速验证,等关键实验再用完整配置跑一遍,能省下一大笔测试费用。
5. 效果评测与论文支撑
5.1 怎么证明系统有效
答辩最怕的是评委问“你这个系统效果到底怎么样”,而你的回答只有“感觉还行”。所以一定要建立一套可量化的评测方案。生成任务,我建议用“通过率”作为核心指标:准备一组任务描述,运行系统后,对每个生成结果做语法检查和执行验证,统计通过的比例。修复任务,用“修复成功率”:准备一组带Bug的代码和对应的报错信息,统计系统输出的代码能通过执行验证的比例。
评测集不需要太大,20到30个典型任务就够起步,但覆盖要全:简单脚本、数据处理、算法实现、Web接口等不同类别各放几个。把每个任务的输入、输出、是否通过、经过几轮修复都记录下来,整理成表格和图表,这就是论文里最有说服力的实验数据。
5.2 对比实验怎么做
另一种常见的问法是“你和大模型直接对话有什么区别”。这个对比正好可以做文章:同一组任务,一组直接用“请你写一个XX”的朴素提示词,一组走你系统里的结构化提示词+后处理+验证闭环,对比通过率和用户操作成本。实测下来,结构化流程的通过率会比裸提示词高不少,尤其是复杂任务,区别非常明显。这个结果直接说明了系统设计本身是有价值的,而不是单纯包装了一个API。
5.3 别忘了记录失败样本
最后一个小建议,也是我自己的习惯:所有评测中的失败案例不要删,单独建一个目录存起来。答辩时遇到评委追问,拿出一两个失败样本分析原因,比展示完美案例更能体现你的工程能力和对问题的理解深度。我当时就靠一个“模型不理解特殊业务术语”的失败案例分析,把“系统当前的局限与改进方向”这部分写得特别扎实,反而成了答辩的亮点。
关于这个项目,我个人在实际操作中最深的体会是:大模型应用类项目,拼的不是“有没有调用模型”,而是“模型之外的那一层工程”。提示词设计、输出解析、验证闭环、日志数据、评测方法,这些才是决定系统成色的关键。最后再分享一个扩展方向:如果时间有余,可以在系统里加一个“测试用例生成”按钮,让模型为生成的代码自动补单元测试,再接入执行器统一跑一遍。这个功能不仅实用,而且能把项目的技术深度再推上一个台阶,做毕设收尾时尤其出效果。