生成式AI进软件工程:先用LLM优化需求与测试
简介《软件工程基于生成式AI的需求与测试优化》是一份面向汽车电子、嵌入式系统与工业自动化领域需求工程师、测试工程师及网络安全专家的技术PDF资料聚焦生成式AI在需求工程与测试环节的工程化落地。内容基于Vector Consulting Services的真实实践案例展示利用GenAI优化需求一致性、可测性与完整性自动化生成高覆盖测试用例及边界场景并借助小型语言模型、语义搜索和RAG技术实现IP保护下的私有化部署。同时结合功能安全ISO 26262与网络安全ISO/SAE 21434要求讨论AI辅助的TARA分析、漏洞识别与安全标准符合性验证强调工程师对AI输出进行审查与控制的人机协作闭环。该PDF共1个文件大小仅1.77MB内容紧凑且更加偏重实际应用场景适合希望将AI融入现有工具链如CANoe、vTESTstudio、PREEvision的团队参考并可用于团队快速入门AI辅助研发落地。资源已有96人学习浏览对关注AI治理与责任边界的技术管理者具有实用价值。1. 生成式AI进软件工程先落在需求与测试别急着改代码生成软件工程里生成式AI真正该先插手的环节不是写代码而是需求与测试优化。原因很实际需求规格书写不清开发返工三周测试用例跟不上上线心惊胆战。这两块恰恰是项目里最费人、最容易被糊弄过去的环节。基于生成式AI的需求清洗、用例生成、质量门禁能把“人读人写的文档”和“机器跑的用例”之间的断口焊上。这篇笔记按需求侧、测试侧、工程化落地三个层面讲完适合被需求变更压着的QA、项目经理和一线开发照着改着用。2. 用LLM做需求质量优化从“写文档”到“可检核的需求规格”2.1 需求质量的黑匣子模糊词、隐性假设与不可验收一份看起来写满了的需求规格书在开发眼里可能全是坑。“响应要快”“界面友好”“适当优化”——这种句子在软件工程导论里叫非功能性需求没量化在实际项目里叫吵架导火索。需求质量差往往不是因为写的人不认真而是“写得全”和“写得可检核”是两件事。需求可检核至少要有三样东西唯一编号、明确主语、可验证的验收标准。缺了这三样测试就没法从需求直接推用例只能凭接口文档脑补。生成式AI在这里的价值不是“帮你写需求文档”而是当质检员把模糊词标出来把隐性假设追问出来把一个自然语言长句拆成带编号的条目。这个步骤做完后面的测试生成才有地基。我一般会先把需求原文按条目拆开每条交给模型做两类输出一是问题清单二是一条建议的验收标准。问题清单里必须标注它来自哪一行便于人工复核。这里有一个关键认知不要指望模型一次输出就是最终结果它的作用是“把黑匣子变成灰匣子”让质量问题早暴露而不是隐藏在段落里。2.2 批量检核需求规格一份可直接跑的python脚本把需求原文丢给LLM逐条检查是常见做法但在公司环境里我更建议先做一层正则预筛。一方面省token另一方面给模型一个“已知问题候选”的提示让它别漏。下面这份python脚本可以在本地跑通接口以OpenAI兼容服务为例换成本地部署的模型服务也一样。import json import re from openai import OpenAI # 常见模糊词表命中即进入 LLM 精检不直接判死刑 FUZZY_WORDS [快速, 友好, 适当, 完善, 高效, 尽量, 等, 相关] def pre_filter(spec_text: str) - list: hits [] for idx, line in enumerate(spec_text.splitlines(), 1): for w in FUZZY_WORDS: if w in line: hits.append({line_no: idx, word: w, text: line.strip()}) return hits def check_spec(spec_text: str, model: str qwen2.5:7b, base_url: str http://127.0.0.1:11434/v1): client OpenAI(base_urlbase_url, api_keylocal) fuzzy pre_filter(spec_text) user_msg ( 你是需求质量分析员。对下面的需求条目逐条检查只输出 JSON不要输出解释。\n 输出格式{\items\: [{\id\: \REQ-001\, \fuzzy_words\: [], \hidden_assumption\: \\, \acceptance_criteria\: \\}]}\n 要求每一条验收标准必须可验证禁止出现模糊词。\n\n f已知模糊词位置{json.dumps(fuzzy, ensure_asciiFalse)}\n\n f需求原文\n{spec_text} ) resp client.chat.completions.create( modelmodel, temperature0.1, # 质检场景低温度减少随机漂移 max_tokens2000, response_format{type: json_object} ) return json.loads(resp.choices[0].message.content) if __name__ __main__: # 实际使用从需求文档里按章节切块传入 sample REQ-001 用户登录后应快速跳转到首页。\nREQ-002 系统应提供完善的报表导出功能。 result check_spec(sample) print(json.dumps(result, ensure_asciiFalse, indent2))逻辑说明pre_filter先定位模糊词所在行把行号和原句作为上下文喂给模型让模型知道“这里可能有问题请重点看”。temperature0.1是质检场景的标配因为我们需要稳定输出而不是创意发散如果温度拉高同一条需求每次检查结果都会变根本没法做回归。response_format强制 JSON 输出方便后面直接落表。参数上最容易忽略的是max_tokens。一条需求拆出来的问题清单加建议验收标准可能超过 1000 token给太短会被截断JSON 直接坏掉。实践里我会按输入长度的 2 到 3 倍设置宁多勿少。本地部署时用 int8 量化的小模型跑这种批量检查完全够用对话式追问才上 fp16 以上的大模型成本和效果都能兼顾。2.3 从规格描述生成用户故事与验收条件给测试开个好头需求检核通过后下一步是把条目转成用户故事和验收条件。这一步本质上是给测试用例生成铺路。很多团队跳过用户故事直接让模型生成测试结果就是测试用例和需求之间没有可追溯关系需求一变更用例瞬间失效。def to_user_story(spec_item: dict, model: str qwen2.5:7b) - dict: prompt 你是业务分析师。把下面的需求规格改写成用户故事和验收条件。 必须满足 1. 每个验收条件可验证禁止出现良好快速等模糊词 2. 每个用户故事包含角色、目标、收益 3. 额外列出 3 条边界或异常场景 4. 只输出 JSON格式为{role: , goal: , benefit: , acceptance: [], edge_cases: []} 需求原文{text} .format(textjson.dumps(spec_item, ensure_asciiFalse)) client OpenAI(base_urlhttp://127.0.0.1:11434/v1, api_keylocal) resp client.chat.completions.create( modelmodel, temperature0.2, max_tokens1500, response_format{type: json_object} ) return json.loads(resp.choices[0].message.content)逻辑说明要求“先列边界和异常”是我特别加的一条。默认情况下模型只会顺着正常流程写比如登录成功就完事不会想到密码错误五次锁账号。把 edge_cases 单独放进输出结构等于强迫模型走一遍攻击视角。后面测试人员拿到的就不是一段叫做“用户能登录”的废话而是一张可以直接转用例矩阵的清单。这里输出的 JSON 结构就是所谓的“用例建模表”雏形和大多数软件需求规格说明书里的用例建模思路一致只是原先靠人工填现在靠模型先起草再人工修。验收条件里的动词必须是“显示”“返回”“写入”这类可观察行为而不是“支持”“可以”这类应然描述。3. 用LLM生成测试用例与测试骨架把需求变成可回归的资产3.1 从验收标准到用例矩阵边界、异常与攻击视角需求分析做完测试用例的生成就有了输入。常见误区是直接把整个需求文档塞给模型让它一口气生成几十条用例这种做法的产物看着很全实际没法用。我是按“一条验收标准对应一组用例矩阵”的方式拆正常路径、反向路径、边界值、权限场景、数据状态场景各一列。用例矩阵是测试管理的老工具格式上建议至少包含这六列用例编号前置条件操作步骤预期结果优先级是否自动化TC-001用户已注册且未锁定输入正确账号密码点击登录跳转首页且写入会话P0是TC-002用户已连续输错4次密码第5次输入错误密码提示账号锁定锁定时间显示P0是生成矩阵之前我会让LLM先做一步“失败假设”针对这条验收标准列出它可能以哪些方式坏掉。这一步的作用参考的是测试设计里的错误推测法。模型不会主动暴露系统设计缺陷但它能根据业务常识列出“超时”“数据不存在”“权限不足”这类通用风险点这些点转成用例正好补齐矩阵里的非主流分支。实际跑的时候可以用一条长提示词把“角色设定 输出格式 失败假设要求 需求条目”一次问完。注意提示词里的“角色设定”不是玄学它是在约束模型调用哪部分常识QA角色和业务分析角色生成的用例风格差别很大QA会更关注异常流和断言。生成完成后按用例矩阵格式落表字段缺失时宁可让模型补空也不要让它编造前置条件。3.2 自动生成pytest骨架先能跑起来再谈填断言用例矩阵落在文档里只是第一步真要让它在迭代里起作用得把它转成自动化测试骨架。下面这个python函数读取上一步的用例矩阵生成可被 pytest 收集的测试文件。注意这里只生成骨架断言由人工填充这是为避免模型幻觉断言埋雷。import json import re def sanitize(title: str) - str: # 只保留字母数字下划线中文转拼音会麻烦直接用用例ID保证唯一 return re.sub(r[^0-9a-zA-Z_], _, title).strip(_) def build_pytest(spec: dict, cases: list, module_name: str) - str: lines [import pytest, ] for i, case in enumerate(cases, 1): cid f{spec[id]}_{str(i).zfill(3)} title sanitize(case.get(title, fcase_{i})) or fcase_{i} lines.append(fdef test_{cid}_{title}():) # 模型只负责生成骨架和注释不生成断言逻辑 lines.append(f # {case.get(precondition, TODO)}) lines.append(f # 步骤: {case.get(steps, TODO)}) lines.append(f # 预期: {case.get(expected, TODO)}) lines.append( assert True # TODO: 替换为真实断言) lines.append() return \n.join(lines) if __name__ __main__: spec {id: CRM_LOGIN_001} cases [ {title: login_success, precondition: user exists, steps: open home, input valid password, expected: redirect to dashboard}, {title: login_locked, precondition: 5 failed attempts, steps: input wrong password, expected: show lock message} ] code build_pytest(spec, cases, test_login) print(code)逻辑说明函数名里带用例ID和短标题好处有三个。第一pytest 运行时能在失败信息里直接定位到需求条目不用再翻文档第二用例ID跨项目不重复后续做回归筛选时按ID前缀过滤即可第三assert True占位让测试至少能通过pytest --collect-only收集不会因为语法错误把整个测试任务阻塞。实际填断言时我会让测试人员参考模型注释里的“预期”自己写而不是让模型直接生成。参数上要留意的是sanitize处理中文标题。中文不是不能用但文件路径和CI脚本对中文的兼容性差跨平台跑起来经常翻车。我的习惯是一律用英文短标题加中文注释注释里保留完整业务描述既保证可读性又避免编码问题。3.3 复杂迭代下测试用例的管理复用用ID和标签串起跨项目协作多项目组并行时最头疼的不是用例不够而是用例重复且没人敢改。不同项目组各自维护一套登录用例A组改了锁定策略B组还在用旧预期跑最后上线前才发现。这个问题靠AI生成解决一半靠用例ID规范解决另一半。我的做法是给每条用例打上三层标签需求域、变更源、自动化状态。需求域对应系统模块CRM、ORDER变更源对应需求条目IDREQ-001自动化状态标明是人工还是脚本。当需求变更时按需求条目ID反查所有受影响用例只重新生成和复核这部分而不是全量重跑。模型在这里的价值是“变更影响分析”把需求差异描述丢给模型让它列出可能受影响的既有用例ID人工确认后进入回归批次。复用的前提是生成时强制要求模型输出“用例ID前缀 需求ID 场景类型”的命名结构。场景类型我固定用正常、边界、异常、权限四类这样在回归报告里可以一眼看出覆盖率偏在哪。跨团队协作时谁改用例就在ID后缀加责任人缩写冲突马上能查出来这也是“测试用例在不同项目组的复杂迭代需求中的管理复用和维护”真正落地的方式。4. 把生成结果收进工程流程审核、度量与质量门禁4.1 人审节点怎么插三查一测一归档AI生成的需求分析和测试用例不能直接流到开发和QA手里中间必须过人。这不是对模型不信任而是质量责任必须落在人身上。我见过的最大失控就是团队把AI输出当第一稿结果第一稿里的错误约束顺着需求管道一路漏进代码最后测试真按这个错误约束去验整条链路白忙。我的落地节奏是“三查一测一归档”。三查需求分析师查需求条目是否可验收测试负责人查用例矩阵是否覆盖验收条件开发代表查技术可行性。一测挑三条关键用例先在测试环境手工预跑验证预期结果不是模型编的。一归档把原始模型输出、人审修改后的版本、模型版本号一起存档。归档是经常会跳过的一步但它是后面排查问题的后悔药。环节责任角色检查重点输出物一查需求分析师需求编号、模糊词、隐性假设检核后的需求条目二查测试负责人用例矩阵与验收条件的映射关系用例矩阵三查开发代表技术约束、性能指标的可测性风险清单预跑QA关键用例在真实环境能否跑通预跑记录归档流程Owner模型版本、提示词版本、人工diff版本记录入口门禁也要设。没有唯一编号的需求条目不进开发没有关联用例矩阵的验收标准不算完成。这条门禁不靠模型自动判靠流程工具在合并请求上检查文件清单。AI只负责把产出速度提上来门禁负责把质量基线守住。4.2 别拿“像不像人写的”当指标无效率、召回率与变更命中率给AI生成产物定指标时团队常犯的错是拿“看起来靠谱”当标准。这种主观指标没法回归。我一直在用的是三个可数字化的指标无效率、需求点覆盖率、变更命中率。无效率 人工否决的生成条数 / 生成总条数。这个数字能直接反映提示词质量。比如一条提示词产出的用例里有一半被执行人否决那问题大概率在输入需求太模糊而不是模型不行。需求点覆盖率 已生成用例的需求条目数 / 需求总条目数。覆盖率低于80%说明需求分析或用例生成存在漏项要回头查是不是需求条目本身不可解。变更命中率 需求变更后成功定位到受影响用例的数量 / 实际受影响用例数这个指标反映的是用例与需求的关联质量关联做得差命中率会很难看。有一类指标要慎用BLEU 或 ROUGE 这类文本相似度。AI生成的用例表达和人工写的本来就是两种风格语义对但字面全不同相似度低不代表质量差。与其天天盯相似度不如按周统计无效率和覆盖率趋势往下走就是有效。4.3 模型、提示词与量化版本让生成结果可以回放生成式AI在需求与测试场景里最容易被忽略的是可回放性。模型升级、提示词微调、温度参数改动都会让输出变化。如果这些变化没有记录某天质量突然下降排查起来只能靠猜。我一般会在项目里维护一份配置清单记录当前使用的模型版本、提示词版本、推理参数和量化精度。批处理检核场景用低精度量化模型就足够比如 int8 量化版速度快显存小交互式追问和复杂用例设计用高精度版本逻辑更稳。fp16 和 fp32 之间在短文本上的差异不明显但在多轮、长上下文场景下高精度版本的回答更少出现前后矛盾。llm: model: qwen2.5:7b quant: int8 temperature: 0.1 max_tokens: 2000 prompt_version: v20240501 reviewer: 需求分析师-张 / 测试负责人-李这份配置随每次生成结果一起归档。下次任何人拿到一份用例都能知道它是哪一版模型、哪一版提示词、谁审的而不是面对一个来路不明的黑匣子。真出现漂移时把配置回滚到上一版同时把新旧配置各自跑一遍基线集对比数据比争论谁对谁错有用得多。5. 避坑清单我在需求与测试生成上踩过的五个真实问题5.1 幻觉约束混进验收标准把需求写“厚”了现象某条需求写的是“用户登录后跳转首页”模型生成的验收标准里多了“且跳转时间不超过2秒”。开发看到这个默认是产品要求真去做了性能优化产品却说没提过这个指标。原因模型在生成时把常识里的“性能良好”脑补成了具体数值需求原文根本没有这个约束。这类幻觉约束比漏词更隐蔽因为它看着很专业。解决在提示词里加一条硬约束“验收标准中的任何数值或条件必须能在需求原文中找到出处找不到就输出为待确认项。”同时人审时逐条核对验收标准里的数字凡是带“秒”“毫秒”“次数”“百分比”的都要圈出来问一遍产品。这条我现在已经写进团队的审核清单。5.2 生成用例全是happy path异常场景要靠逼问现象让模型生成登录模块的用例一次出来十五条十四条都是账号密码正确、页面正常跳转这一类唯一一条异常用例还是“密码错误提示”。边界、锁定、并发、数据不存在全都没有。原因模型默认沿着“用户能完成目标”的方向生成不会主动想破坏路径。如果不明确要求异常场景它就会给你一个看起来非常完美的正常流。解决在用例生成的提示词里强制加一步先输出十个“这里可能会怎么坏”的假设再基于假设生成用例。这一步是单独一问不是和用例生成放在同一个 prompt 里否则模型会偷懒。第二个办法是给模型塞边界定义比如“为空、超长、超时、重复提交、权限不足”作为候选场景逼它挨个套用。5.3 长需求被截断后半段规则静默丢失现象把一份包含三十条需求点的完整需求文档直接丢给模型生成的用例只覆盖前十条后二十条完全没出现而且没有报错。原因输入超过了模型上下文窗口中间或末尾内容被截断。模型不会告诉你它没看完它会基于看到的部分继续生成结果就是后半段规则全部丢失输出结构还保持完整非常具有迷惑性。解决大文档必须切块处理。我按需求条目为单位切每条单独调用最后再汇总合并。如果上下文长涉及跨条的约束就先做一层摘要把摘要和当前条目拼在一起入参。此外在代码里检查输入长度超过模型窗口的80%就直接报错而不是静默截断。5.4 同一套提示词两周后效果明显漂移现象同一个生成脚本上周输出质量很好这周同一批需求生成的用例开始出现重复还有些用例预期结果明显不合逻辑。代码没改提示词没改数据没改。原因模型服务端升级了版本或是调度到了不同参数的实例。SaaS接口和本地服务的模型权重都可能被更新输出分布随之变化。这不是提示词写得不好是模型版本不受你控制。解决本地部署可以锁定模型版本镜像SaaS 则在配置里注明调用日期和端点版本。更关键的是建一条“基线回归集”每次换模型前把五十条典型需求跑一遍只看输出JSON的结构完整率、无效率、重复率有没有明显波动。这条基线集规模不用大五十条足够暴露大多数漂移问题。5.5 把模型当黑匣子直接出稿没有留后悔药现象需求分析师让模型直接生成整个需求规格说明书再导出给全体开发评审。开发按这个版本开始设计后来发现其中一条约束是错的但所有人已经在这个基础上建了一堆方案返工成本非常高。原因模型输出被当成了“最终版”而不是“草稿版”。中间缺失了一个强制的人工复核节点更致命的是没人留存模型给的原始版本问题出现后根本没法定位是模型错还是人改错。解决任何AI产物进流程前必须经过三查一测的审核关卡并且原始输出、人审修改、最终定稿三份文件都归档。我把这个习惯类比成写代码时保留 diff如果你不能回答“这一版为什么和上一版不同”你就没有资格把它合入主干。AI生成也一样它加快了产出的速度但责任边界不会因此消失。6. 最后的技巧给AI生成的需求与测试建一条回归基线前面反复提到“基线回归集”这里把它落成一个可执行的最小方案。基线回归集不需要很大我从历史项目里抽出六十条典型需求片段覆盖模糊词检核、用户故事改写、验收条件生成、异常用例生成四类任务每类十五条。每条标注“预期输出中必须存在的字段”比如“acceptance 数组中至少包含一条”“edge_cases 数组长度大于等于3”。每次调整提示词或更换模型版本前跑一遍基线集并记录分数。下面这个脚本是简化的基线检查流程import json def run_baseline(golden_set: list, run_llm): report [] for item in golden_set: out run_llm(item[input]) keys item[expect_keys] score sum(1 for k in keys if k in out) / len(keys) report.append({id: item[id], score: score, missing: [k for k in keys if k not in out]}) # 结构完整率所有条目的 key 命中率平均值 total_score sum(r[score] for r in report) / len(report) return total_score, report调用时传入不同模型或提示词的包装函数就能得到一个可比较的数值。分数掉十个百分点就要警惕掉二十个百分点说明这个改动大概率不该上线。基线集要定期增补每次线上发现一个新问题类型就把它的输入和期望字段加进去让这条防线越滚越厚。我自己的习惯是每次改动提示词后都会跑一遍基线并截存档等哪天真遇到输出质量突然下滑第一件事就是翻基线分数和当时的存档 diff。这个小动作省了很多次“上周还好好的”这种排查也算是我在这个方向上做过性价比最高的一笔投入。希望帮到你。本文还有配套的精品资源点击获取