汽车电子测试这份工作,干久了你会发现一个规律:大量时间不是花在“测”上,而是花在“写”上。写测试用例、写CAPL脚本、写测试报告、翻诊断规范查DTC定义、对着通信矩阵一个个核对报文信号。我上半年接手了一个某量产车型的网关项目回归测试,光是UDS诊断相关的用例就整理了三天,其中两天半在翻文档。后来我开始尝试用大语言模型(LLM)配合提示词工程来处理这些活,效率提升是实打实的,但前提是——不能像用搜索引擎那样去用一个对话窗口。这个话题值得展开聊聊:汽车电子测试语境下的Prompt工程,跟市面上的通用提示词技巧完全是两码事。
1. 通用提示词技巧错在哪:汽车电子测试是个高语境、低容错的领域
先说说大部分人第一次尝试的样子。很多人拿到ChatGPT、Claude这类工具之后,第一反应是“帮我写一组CAN总线物理层测试用例”,然后AI真的给了一组很工整的用例——有帧格式、有位时序、有错误帧注入步骤。乍看挺像那么回事,但仔细一看全是通用内容,没有针对你手里这个ECU的通信矩阵、没有DBC里真实的信号定义、没有你们项目里特殊的需求约束。这种输出拿去评审,基本会被打回来重写。
通用场景下的Prompt技巧,比如“角色设定”“思维链”“少样本示例”,这些东西本身没有错,但它们默认了一个前提:任务的上下文是常识级的、输出质量偏差是可以接受的。写一段营销文案,AI把角度写偏了,你改一改还能用;生成一份UDS 0x22服务读取VIN的测试用例,如果AI把Session切换的前置条件写错了,这条用例就是废的,执行的时候还会误导你。
我把这两者的差异整理过一张表,基本能说明问题:
| 对比维度 | 通用场景(写文案、做翻译、日常问答) | 汽车电子测试场景(用例、脚本、诊断解析) |
|---|---|---|
| 知识来源 | 依赖模型预训练常识就能回答 | 依赖你喂进去的规范、DBC、项目背景 |
| 输出评价标准 | 读得通、有创意即可 | 必须对应真实规范条款、必须可执行 |
| 上下文长度 | 几百字足够 | 动辄需要数千字甚至上万字的规范摘录 |
| 错误容忍度 | 低后果,润色即可 | 高后果,错误可能导致测试误判 |
| 术语体系 | 通用词汇 | 高度密集:DTC、Sub-function、NRC、P2/Node Delay…… |
所以汽车电子测试人做Prompt工程,核心思路不是“怎么把提示词写得漂亮”,而是“怎么把测试领域的知识结构、验证方法和验收标准,编码成AI能理解和遵循的指令”。说白了,你在设计的不只是一句提示词,而是一条小型的自动化流水线:上下文输入、任务定义、格式约束、结果校验。这四个环节缺一不可,下面我会逐一拆开讲。
2. 上下文喂法:让AI从“知道很多”变成“懂你手里这个项目”
你第一次觉得AI“不够专业”,九成九是上下文没喂够。我见过太多人直接丢一句“帮我分析这条DTC P0121是什么意思”,AI能给你解释故障码逻辑,甚至能提到节气门位置传感器电路范围性能问题,但它不知道你检测到的是哪个供应商的ECU、不知道这个故障码在你项目里对应的降级策略是什么。差别不在AI,在你的输入太单薄。
大语言模型的生成机制是概率预测:你给了多少信息,它就在这个信息构成的条件概率空间里采样。给它两行字,它只能从通用知识里“猜”;给它两页规范摘录、十几条历史用例示例,它才能在真实约束里“推”。所以喂上下文不是走形式,是直接影响输出质量的数学前提。
我后来养成了一个习惯,每次抛任务前都按固定的上下文结构组织信息,相当于一个模板:
- 角色与立场:你是负责某ECU项目的汽车电子测试工程师
- 项目背景:被测对象类型(网关/BCM/域控制器)、总线类型(CAN/CAN FD/LIN)、波特率、节点拓扑关系
- 领域约束:依据的诊断规范版本、公司内部测试规范、客户特殊要求
- 输入数据:相关的DBC字段定义、诊断调查表、DTC码表、历史Bug清单
- 任务目标:明确要产出什么(用例列表、脚本代码、分析结论)
- 输出格式:表格还是纯文本、字段要求、语言要求
- 验收标准:你判断输出合格的依据是什么
这套结构里,最容易被人忽略的是“领域约束”和“验收标准”。有一次我让AI生成一组LIN从节点的调度表测试用例,只告诉它“LIN总线、BCM主节点、有5个从节点”,结果AI给了基于LIN 2.1规范的标准调度表策略。方向没错,但我们项目用的是LIN 2.2A规范,且老平台的调度表是静态固定的,跟新平台不同。我重新补上这两条约束再让它生成,输出就直接命中了项目实际场景。
有个很实用的技巧值得分享:喂完长上下文后,别急着要结果,先让AI用自己的话概括你给的项目背景和约束条件。让它“复述”一下,你就能快速判断它到底“读进去”了哪些内容。我实际操作中,大概有两成概率AI会漏掉关键约束——尤其是你藏在段落中间、没有单独列出的那条。自从我把约束条件全部改成独立编号条目(约束1、约束2、约束3),这个漏读率明显下降了。
3. UDS诊断测试用例生成:把“测试设计”固化成一段Prompt模板
诊断测试是汽车电子测试的大头,UDS(Unified Diagnostic Services)协议里光一个0x19服务就有好几种子功能,每种子功能下还要覆盖DTC状态掩码的各个位,再加上各种NRC(负响应码)条件的组合,用例数量轻松过百。纯手工写,心情是崩溃的。
我试过用一段结构化的Prompt批量生成UDS诊断测试用例,效果最稳的做法如下文所示。你可以直接把这个模板拿去做底稿,替换成自己项目的规范内容就能用。
角色:你是一名资深汽车电子测试工程师,熟悉ISO 14229和OEM诊断规范,擅长编写ECU诊断测试用例。 背景资料: - 被测ECU:某车身域控制器 - 支持的诊断服务:0x10、0x22、0x19、0x2E、0x31、0x85 - 诊断规范版本:基于ISO 14229-1,并满足某OEM诊断调查表补充要求 - 总线类型:CAN FD,波特率500kbps - 会话切换规则:默认会话下仅允许0x10和0x22部分子功能,非默认会话需先切换 任务: 请为0x19服务(读取DTC信息)的ReportDTCByStatusMask子功能设计一组测试用例, 覆盖以下DTC状态掩码组合:0x01、0x02、0x19、0x2B、0x31、0x59。 每组掩码用例需包含: - 前置条件(ECU状态、会话状态、点火状态) - 测试步骤(含CAN报文发送的详细内容) - 预期结果(正响应数据内容、DTC状态字节的各位含义) - NRC异常用例(至少覆盖0x12、0x13、0x22、0x31四种NRC触发条件) 输出格式: 以Markdown表格形式输出,每条用例一个序号,字段为:用例编号、测试目的、前置条件、测试步骤、预期结果、NRC符合性说明。 边界要求: - 如果某个子功能的掩码组合在你的规范知识中无法完全确定,请明确标注“需人工确认”,不要猜测。 - 只覆盖0x19服务,不要扩展生成其他服务的用例。这段提示词看着长,但每一句都有目的。“角色设定”让模型在语义空间里往“懂行”的词分布靠拢;“背景资料”里给的是完整的项目锚点,尤其是“诊断调查表”这类OEM语境词汇,能有效把输出拉到行业语境;“任务”部分不贪多,只锁一个服务的子功能,输出深度才有保证;“边界要求”是后面才加上的,因为我吃过亏——AI会非常自信地给你编造一个NRC条件,而且编得跟真的一样。
说说实际效果。用这个模板生成的用例,覆盖度能达到我手工编写的大概80%,剩下20%的缺口主要来自那些OEM特有的子功能,通用模型确实没法学到。给我的感觉是:与其说它在替代我干活,不如说它把我熟悉的诊断测试场景标准化地复述了一遍,我只需要审一遍,挑出少数不准确的细节,再补充项目特有条件,一份用例初稿就有了着落。这个过程中,人省去的是把规范一条条翻译成用例格式的重复劳动,这恰恰是回报率最高的环节。
我也试过让AI先列出测试设计思路,确认思路可行后再生成用例。比起直接要结果,让它在动笔之前“亮出框架”,相当于多了一层纠偏控制。思路越清晰,细节越准确,这个习惯我现在一直在用。另外,如果你希望AI输出更完整的用例,还可以让它先对“ReportDTCByStatusMask”的每个掩码位做一次逐一解释,确认它没有混淆DTC状态掩码和DTC状态字节——这是UDS里很容易绕晕的高频误解点。
4. CAPL脚本生成:从“语法能过”到“报文能跑”,差的是一轮轮的对话修正
CAPL(Communication Access Programming Language)是Vector工具链里的脚本语言,语法长得像C,但事件驱动的模型非常特殊。有on message、on timer、on key这类事件处理函数,有系统变量、环境变量、诊断对象一大堆,平时写一个发送UDS请求并等待响应的脚本,光查那几个内置函数的签名就得折腾半小时。所以我特别想利用LLM写CAPL,但这条路我走了一段时间才发现,真正的价值不在“一次生成”,而在“人机协同迭代”。
我第一次试水用的需求是这样的:通过CAN发送一个UDS 0x22服务请求(读取VIN),收到ECU正响应后把VIN打印到Write窗口,如果3秒内没响应则记录超时并继续执行下一条用例。
| 需求描述 | 具体内容 |
|---|---|
| 发送报文ID | 0x7E0(Tester物理请求) |
| 响应报文ID | 0x7E8(ECU物理响应) |
| 数据内容 | 02 22 F1 90 00 00 00 00 |
| 触发方式 | 按下键盘按键 ‘a’ 触发 |
| 超时时间 | 3000ms |
我把这个需求原封不动地丢给LLM,第一版CAPL脚本大概长这样(简写示意):
on key 'a' { byte request[8] = {0x02, 0x22, 0xF1, 0x90, 0x00, 0x00, 0x00, 0x00}; message 0x7E0 msg; msg.dlc = 8; for (i = 0; i < 8; i++) msg.byte(i) = request[i]; write("Sending UDS request..."); output(msg); setTimer(tReq, 3000); }语法看着没问题,但真拿去编译就露馅了:on key 'a'触发的字符串键值不合规,需要用on key 'a'的数字写法;局部变量i没声明类型,CAPL里变量声明必须在函数开头;报文类型需要显式定义,不能用裸message。这一堆小毛病,恰恰是CAPL新手最痛苦的坎——语法错误提示还特别模糊。
我后来发现,与其手工修,不如把编译错误全文贴回对话里,让AI自己解释并修正。CAPL的编译器错误信息很多直接指向行号,LLM能根据上下文猜出问题根源。这一轮下来,脚本从“语法能过”进化到“逻辑基本正确”,但离“能跑”还差一步:报文格式。0x02 22 F1 90 这个数据场,在CAN FD里还涉及DLC长度的判断和填充字节策略。你给的帧是8字节标准CAN,换了CAN FD节点测试又得改。所以每次生成之后,我都会把总线类型和DBC里这个报文的真实布局贴给它,而不是让它猜。
更高效的思路是“模板化+参数化生成”。我先让AI基于团队常用风格写一个“发送UDS请求并等待响应”的模板脚本,包含规范的变量声明区、on key触发区、定时器处理区、响应解析区,各区域注释都写好。之后每迭代一个诊断服务,只需要在这个模板基础上替换报文ID、数据和预期响应ID,风险点集中在“要改的地方”而非“整份代码”,审查工作量大大降低。还有一个容易踩的坑:LLM生成的CAPL脚本在缩进和命名风格上,每次都会微妙地变化。如果你需要把代码并入既有测试工程,最好提前在Prompt里明确“变量命名遵循驼峰、函数注释格式按照工程现有风格”,否则代码风格不一致会让后续维护很痛苦。
关于CAPL和提示词工程,我自己的结论是:LLM是一个顶得上半个熟悉CAPL语法的初级工程师,但你仍需要一个人来定验收标准。生成的脚本必须经过编译、跑通、抓包验证三步才可信任,尤其是那些与被测ECU安全功能相关的测试脚本,是必须走评审流程的。
5. 让AI“懂你的历史”:RAG知识库比通用对话更贴合测试场景
再怎么说,通用LLM对你的项目一无所知。你手里有DBC文件、诊断规范、历史Bug清单、上一年度的测试报告,它统统没看过。那怎么让它基于这些资料对话?答案不是把几万字文档一次性塞进提示词——会超token限制,而是用RAG,也就是检索增强生成。
我打的一个比方:RAG相当于给LLM配一个随身带的资料柜,每当你提问,先从这个柜子里检索最相关的几份文档片段,拼在一起再让语言模型组织回答。它不改变模型的知识能力,但改变了模型回答时的信息底座。对汽车电子测试人来说,这意味着你可以这样问它:
“把DTC P0121和我们项目里相关的历史用例找出来,看看以前在哪个模块出现过类似问题。”
通用LLM是不可能回答这个的,但接了知识库之后,它能定位到具体文档的具体片段,并引用来源。这个对测试工作的帮助是实实在在的:查规范、查Bug单、查历史版本差异,这些活本质上都是“先找文档,再读文档”,RAG把“找”和“读”压缩成了一个问答。
落地路径上没有想象中复杂。市面上的知识库工具已经比较成熟,本地部署一套开源的也可以。核心工作量在两步:第一步,把文档整理成适合检索的分块(chunk);第二步,把分块向量化并建索引。
| 文档类型 | 推荐切块策略 | 原因 |
|---|---|---|
| DBC文件 | 按message拆分为独立块 | 每条报文自带ID、周期、信号布局,天然独立 |
| UDS诊断规范 | 按服务(0x10/0x22/0x19/0x2E……)分块 | 每次检索只关心一个服务,跨服务拼接会串味 |
| 测试用例 | 按模块/ECU功能分块 | 方便从功能维度聚合检索 |
| Bug清单 | 按单条Bug记录切分,保留严重等级字段 | 方便按缺陷类型搜索复盘 |
工程中最容易翻车的环节在切块。切太大了,检索出来是一大坨混着多个主题的文本,LLM容易“眼花缭乱”,模棱两可的地方就开始“自由发挥”;切太小了,上下文断裂,检索结果缺乏完整因果链。我自己的经验是每条块大小控制在300-500字左右,并且相邻块之间保留少量的重叠区域,这样既不会丢失关键信息,又不会把不相关内容绑在一起。建好索引之后,先用几个测试问题验证检索质量,比如问“0x19服务的Sub-function有哪些”,如果AI能直接定位到规范对应章节而不是泛泛回答,说明索引可用。
RAG最坑的一个现象是“信誓旦旦的胡话”:AI引用的文档片段确实是真实存在的,但结论跟原文对不上,或者把两个相近DTC的定义混在一起输出。我遇到过不止一次。所以哪怕有知识库兜底,你仍然需要保留人工抽查机制。知识库负责效率,人工抽查负责正确率,这个搭配才健康。
6. 边界与兜底:LLM在汽车电子测试里能做什么、不能做什么
聊到这儿,得把话说透。AI在汽车电子测试领域能做的事很多,但它是有明确边界的。
先说能做的。第一是“设计穷举”,比如某个服务的所有NRC组合、某个信号的边界值组合,AI擅长做组合枚举,并且不容易漏项;第二是“格式转换”,从XML格式的测试数据转换到Excel表格,从旧版测试用例格式迁移到新模板;第三是“模糊检索”,在几千页规范里找出和某个功能相关的所有条款。这三类工作的共同特征是:模式清晰、产出结构明确、错误后果可控。
再说不能做的。第一是“验证逻辑正确性”,AI能给你写一条用例,但它不能告诉你这条用例是否符合你们项目的测试策略;第二是“判断规范原文含义”,当两条规范条款存在歧义时,AI只能给一个概率上最合理的解释,而不是权威结论;第三是“评估安全影响”,一个偶发故障会不会引发降级策略、会不会影响功能安全等级,这不是LLM能回答的。这些事,最终都必须由人拍板。
我自己踩过一个典型坑:让AI总结一份DTC清单,它把两个编号极为相似的DTC描述搞混了。这两条DTC一个是“传感器电压过高”,一个是“传感器电压过低”,AI在总结时把两者的诊断条件互换了。如果你没有逐行对照原始规范,这份总结就会变成测试依据,后果可想而知。从那以后,我给自己定了一条规矩:凡是用AI做的语义压缩型输出,必须保留原始来源编号,并且按比例人工复核。
关于数据合规,也需要在这里提醒一句。很多测试相关的规范文档、DBC、代码,都属于公司内部甚至OEM的机密资料。把这些资料原封不动贴进某个外部在线对话窗口,风险是实打实的。建议优先考虑本地部署或私有化部署的模型方案,至少也要对敏感字段做脱敏处理。别让效率追求踩了合规红线。
如果你也想在团队里推广这套玩法,我建议从一个小范围试点开始:挑一个重复性最高的场景,花半天时间把上面的上下文模板、输出格式和校验清单做成一份团队内部可复用的提示词库,让一两个人先跑熟悉。跑通了,再慢慢把这个“AI测试助手”的覆盖面扩展出去。
最后说点个人体会。做Prompt工程这段时间,我越来越觉得它跟写测试用例是一回事:需求要清晰、输入要完整、预期结果要明确、边界条件要覆盖、怀疑一切未经校验的输出。甚至可以说,提示词工程本质上就是用测试思维去约束一个不可控的“实习生”——你给它画好框,它才有机会在框里帮上忙。AI不能替代测试人的判断力,但它绝对能帮你省下那些本该花在重复劳动上的时间。用好了,它就是你工位上的第二双手。