1. 规则引擎先兜底,AI 再补深度:为什么“水用例”总在重复出现
测试用例生成这件事,很多人第一反应是“直接让大模型写不就行了”。我一开始也这么想,直到把一份商品管理需求丢给模型,拿回来的用例标题是“验证商品功能正常”,步骤是“进入页面 → 操作 → 提交 → 验证成功”。这种用例看着像模像样,实际上测试工程师拿到手还得从头拆一遍,等于白生成。
问题出在哪?不是模型不行,而是我们把两件不同的事混在一起了。规则引擎擅长的是确定性覆盖:CRUD 增删改查、权限角色区分、边界值(0、负数、超长、空值)、必填字段校验,这些场景有固定模式,10 毫秒就能出 20 多条,而且 100% 不会漏。AI 擅长的是理解业务语义、发现边缘场景、构造复杂数据组合,但它“随机”,标准场景反而可能漏掉。
所以正确的分工是:规则引擎保底,负责快、免费、稳定、结构统一;AI 做锦上添花,负责创意、深入、覆盖边缘。两者串起来,才能把“水用例”压到可接受比例。这篇就按这个思路,把规则模板、Prompt 骨架、temperature 取值、质量评分、容错降级,以及用 TaoToken 统一 Key 接入 API 后的批量生成与人工抽检,一步步拆开讲。
适合谁看?正在做 AI 测试系统、被 AI 生成用例质量折磨、想用规则引擎 + AI 组合提效的测试开发和后端同学。核心检索词就三个:规则引擎、AI 测试用例生成、Prompt 与 temperature 调参。下面从规则引擎怎么写出“不水”的用例开始。
1.1 规则引擎的“水”从哪来:万能模板 vs 实体动作提取
规则引擎生成用例之所以水,根因是用了万能模板。比如“进入功能页面 → 执行正常操作流程 → 提交操作”,这种步骤放到任何模块都能用,也就意味着放到任何模块都没用。要让它不水,核心只有一条:从需求文本里提取实体、字段、动作,再套标准测试模式生成针对性用例。
举个具体例子。需求是“用户可以修改商品名称和价格”。规则引擎先做实体动作提取:
- 实体:商品
- 字段:名称、价格
- 动作:修改
然后套 CRUD 和边界值模式,生成出来的用例就是:
- 修改商品名称为有效值 → 验证名称更新成功
- 修改价格为 0 → 验证系统拒绝
- 修改价格为负数 → 验证系统拒绝
- 修改名称为空字符串 → 验证系统拒绝
- 同时修改名称和价格 → 验证两者都更新成功
对比一下万能模板,差别一眼就能看出来。规则引擎要写得不水,就得把下面这些标准测试模式内置进去:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| CRUD | 增删改查全覆盖 | 所有有数据操作的模块 |
| 权限 | 不同角色的操作权限 | 有角色区分的系统 |
| 边界值 | 数字字段的边界 | 价格、数量、年龄等数值字段 |
| 等价类 | 有效/无效输入分类 | 所有输入框 |
| 异常流 | 网络异常、数据不存在 | 所有接口调用 |
把这些模式写进规则引擎,生成的用例就不再是“万能模板”,而是有针对性的测试场景。规则引擎的定位是保底:快、免费、稳定、覆盖标准场景。它不负责创意,负责的是“一条都不漏”。
1.2 AI 补的是规则引擎够不到的地方
规则引擎再全,也有够不到的地方。复杂业务逻辑组合、边缘场景发现、安全测试场景(注入、越权、数据泄露)、性能测试思路(并发、大数据量),这些需要理解需求语义和测试经验,规则引擎写死模式很难覆盖。这正是 AI 的用武之地。
但 AI 不是丢句话就完事。Prompt 设计得好,生成的用例可以直接用;设计得烂,生成的东西连看都不想多看一眼。经过多轮调优,特别是加了历史参考用例做风格对齐后,生成质量明显提升。下面进入 Prompt 骨架和 temperature 调参的具体配置。
2. TaoToken 统一 Key 前置:一个 Key 打通多模型调用
在讲 Prompt 和 temperature 之前,先把接入层说清楚。做 AI 测试系统,最烦的不是写 Prompt,而是模型换来换去、Key 散落各处、账单对不上。我试过在代码里硬编码不同厂商的 Key,结果换模型要改代码、加环境变量、重启服务,测试环境还经常配错。
TaoToken 解决的就是这个统一入口问题。它提供兼容 OpenAI 风格的 API,一个 Key 可以调用多种模型,Base URL 统一,切换模型只改 Model ID,不用动代码结构。对测试系统这种需要频繁对比不同模型生成质量的场景,特别省事。
前置准备只有三步:
- 注册并登录 TaoToken 控制台,在 API Keys 页面创建一个 Key。
- 记下 Base URL:
https://taotoken.net/api(注意 API 调用不加 UTM 参数)。 - 在环境变量里配置 Key,代码里通过
os.getenv读取,不要硬编码。
控制台地址:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=apikeys
接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc
模型对话入口(用来快速验证模型是否通):https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=chat
如果你后面要做长期编码或 Agent 类任务,可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=codingplan
这里强调一点:TaoToken 是统一 API 接入层,不是替代编辑器,也不是让你绕过任何合规流程。它的价值在于把多模型调用收敛到一个 Key、一个 Base URL,方便测试系统做模型对比和降级。
2.1 环境变量与依赖准备
Python 侧只需要httpx或openaiSDK。我用httpx直接发请求,依赖少、可控。环境变量这样配:
export TAOTOKEN_API_KEY="sk-你的Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"代码里读取:
import os api_key = os.getenv("TAOTOKEN_API_KEY", "") base_url = os.getenv("TAOTOKEN_BASE_URL", "https://taotoken.net/api")没配 Key 时不要报错崩溃,直接走降级到规则引擎,这是后面容错处理的基础。
2.2 为什么统一 Key 对测试系统特别重要
测试系统有个特点:需要对比不同模型、不同 temperature 下的生成质量。如果每个模型一套 Key、一套 SDK,对比成本极高。统一 Key 之后,切换模型只改一个 Model ID 字符串,Prompt 和解析逻辑完全复用。批量生成时,可以先用便宜模型跑全量,再用强模型对低质量用例做二次精修,成本和质量都能兼顾。
3. 可复制配置:Prompt 骨架、temperature 对照表与 settings 片段
这一节是全文最核心的可复制部分。先给 Prompt 骨架,再给 temperature 取值对照表,最后给一份可直接落地的 JSON 配置片段。
3.1 Prompt 骨架:五个要素缺一不可
def _build_prompt(self, requirement: str, context=None) -> str: base_prompt = f""" 你是一个专业的测试工程师。请根据以下需求生成测试用例。 ## 需求描述 {requirement} ## 历史参考用例 {json.dumps(context, ensure_ascii=False, indent=2) if context else "无"} ## 输出格式要求 请按以下 JSON 格式输出: {{ "test_cases": [ {{ "title": "用例标题", "description": "用例描述", "priority": "P0/P1/P2/P3", "type": "functional/api/performance/security", "preconditions": ["前置条件1", "前置条件2"], "steps": [ {{"step": 1, "action": "操作步骤", "expected": "预期结果"}} ], "test_data": "测试数据", "automation": true }} ] }} ## 生成要求 1. 覆盖正常场景和异常场景 2. 包含边界条件测试 3. 优先级合理分配(P0 核心功能,P1 重要功能,P2 一般功能,P3 边缘功能) 4. 步骤清晰可执行 """ return base_prompt五个要素分别是:角色定义(“你是一个专业的测试工程师”,加了和没加,生成质量差很多)、需求描述、历史参考用例(RAG 检索到的历史用例放这里,AI 看到风格后会保持一致水平)、输出格式要求(用 JSON Schema 比自然语言精确)、生成要求(没有这四条,AI 往往只覆盖正常场景,漏掉异常和边界)。
3.2 temperature 取值对照表
temperature 是控制输出随机性的关键参数。实测下来,不同取值效果差别很大:
| temperature | 效果 | 问题 |
|---|---|---|
| 0.3 | 用例很稳定,每次生成几乎一样 | 缺乏多样性,覆盖场景太少 |
| 0.7 | 稳定性和多样性平衡 | 偶尔有低质量用例,需评分过滤 |
| 1.0 | 创意十足,能想到很多边缘场景 | 质量不稳定,有时生成离谱用例 |
最终选 0.7。稳定性够用,多样性也够,偶尔的低质量用例用质量评分过滤掉就行。如果你的场景偏标准功能测试,可以降到 0.5;偏探索性测试,可以升到 0.8,但不建议超过 0.9。
3.3 可复制 JSON 配置片段
把模型、temperature、超时、降级策略都收敛到一份配置里,路径和字段名保持稳定,方便测试系统读取:
{ "llm": { "provider": "taotoken", "base_url": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "model_id": "qwen3.5-plus", "temperature": 0.7, "max_tokens": 2000, "timeout_seconds": 30 }, "quality_gate": { "min_score": 0.7, "weights": { "completeness": 0.3, "clarity": 0.3, "priority": 0.2, "automation": 0.2 } }, "fallback": { "level_1": "llm", "level_2": "rule_engine", "level_3": "mock" } }这份配置里,base_url固定为https://taotoken.net/api,api_key_env指向环境变量,不把 Key 写进文件。quality_gate.min_score是 0.7,低于这个分的用例直接过滤。fallback定义三级降级顺序。
如果你用 Cline MCP 或 Claude Code 这类工具接入,配置三件套要写全:Base URL、Key、Model ID。以 settings 片段为例:
{ "mcpServers": { "taotoken": { "baseUrl": "https://taotoken.net/api", "apiKey": "${TAOTOKEN_API_KEY}", "modelId": "qwen3.5-plus" } } }Base URL、Key、Model ID 三件套缺一不可,少一个就会报连接或鉴权错误。
4. 验证请求与成功结果:批量生成 + 人工抽检
配置写完,得验证它真的能跑通。这一节给一个完整的调用示例,再讲批量生成和人工抽检的动作。
4.1 单次调用验证
import os import json import httpx def call_llm(prompt: str) -> str: api_key = os.getenv("TAOTOKEN_API_KEY", "") base_url = os.getenv("TAOTOKEN_BASE_URL", "https://taotoken.net/api") if not api_key: return "" try: response = httpx.post( f"{base_url}/v1/chat/completions", headers={"Authorization": f"Bearer {api_key}"}, json={ "model": "qwen3.5-plus", "messages": [{"role": "user", "content": prompt}], "temperature": 0.7, "max_tokens": 2000 }, timeout=30.0 ) if response.status_code == 200: return response.json()["choices"][0]["message"]["content"] return "" except Exception: return ""跑通后,返回内容里应该是一段 JSON,包含test_cases数组。如果返回的是自然语言包裹的 JSON,用正则提取:
import re def parse_llm_response(response: str): try: data = json.loads(response) return data.get("test_cases", []) except json.JSONDecodeError: json_match = re.search(r'\{.*\}', response, re.DOTALL) if json_match: try: data = json.loads(json_match.group()) return data.get("test_cases", []) except Exception: pass return []re.DOTALL让.匹配换行符,多行 JSON 也能正确提取。
4.2 质量评分过滤
AI 生成的用例不能直接用,先过质量评分。四个维度:
def calculate_quality_score(test_case: dict) -> float: score = 0.0 steps = test_case.get("steps", []) if len(steps) >= 3: score += 0.3 title = test_case.get("title", "") description = test_case.get("description", "") if len(title) > 5 and len(description) > 10: score += 0.3 priority = test_case.get("priority", "P3") score += {"P0": 0.2, "P1": 0.15, "P2": 0.1, "P3": 0.05}.get(priority, 0.05) if test_case.get("automation", False): score += 0.2 return min(score, 1.0)权重逻辑:步骤不全的用例没法执行(完整性最重要),描述不清楚的难以理解(清晰度次之),优先级和可自动化是加分项。低于 0.7 的直接过滤。
4.3 批量生成与人工抽检
批量生成时,把需求文档拆成功能点,每个功能点走一次规则引擎 + AI。规则引擎先出 15-25 条基础用例,AI 再出 5-10 条深度用例,去重合并后按质量分排序。
人工抽检的动作:从最终结果里随机抽 10%,重点看三类——步骤是否可执行、预期结果是否明确、优先级是否合理。抽检发现的问题反哺到 Prompt 和规则模板里,形成闭环。实测下来,规则引擎 + AI 组合后,低质量用例比例能从 30% 压到 10% 以内。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
接入和调用过程中,报错集中在几个地方。这一节按真实报错逐个排查。
5.1 401 Unauthorized
最常见。原因通常是 Key 没配、配错、或者环境变量没生效。排查顺序:
- 确认
TAOTOKEN_API_KEY环境变量在当前 shell 里能echo出来。 - 确认请求头是
Authorization: Bearer sk-xxx,Bearer 后面有空格。 - 确认 Key 没有多余引号或换行。
- 确认 Base URL 是
https://taotoken.net/api,不要多加/v1之外的路径。
如果 Key 正确还报 401,检查是不是用了别的环境的 Key。
5.2 local proxy failed
这个报错通常出现在本地网络环境有额外代理设置时。排查方向:
- 检查系统环境变量里是否有
HTTP_PROXY、HTTPS_PROXY,如果有,确认它是否指向可用服务。 - 代码里
httpx默认会读取环境变量代理,如果代理不可用就会报 local proxy failed。可以显式关闭:httpx.post(..., trust_env=False)。 - 确认请求地址拼写正确,不要有多余斜杠。
5.3 reading choices 相关报错
典型报错是KeyError: 'choices'或reading 'choices'。原因是返回结构不是预期的 OpenAI 格式,或者返回了错误信息但代码直接取choices。修复方式:
data = response.json() if "choices" not in data: return "" return data["choices"][0]["message"]["content"]先判断choices是否存在,再取值。同时打印完整返回体,确认是模型返回格式问题还是鉴权问题。
5.4 OAuth 相关报错
如果你用 Claude Code 或类似工具接入,可能遇到 OAuth 报错。这类工具默认走 OAuth 流程,接入第三方 API 时需要改成 API Key 模式。检查配置里是否同时存在 OAuth 和 API Key 两套配置,冲突时优先 API Key。三件套 Base URL、Key、Model ID 要写全,缺一个就可能触发 OAuth 回退。
5.5 降级方案:API 挂了不能等死
三级降级:LLM → 规则引擎 → Mock 兜底。
def call_with_fallback(prompt: str, requirement: str = "") -> str: result = call_llm(prompt) if result: return result engine = self.rule_engine if engine and requirement: cases = engine.generate_cases_from_requirement(requirement) if cases: return json.dumps({"test_cases": cases}, ensure_ascii=False) return self._get_mock_response()第一级正常调 LLM;第二级 API 挂了或没配 Key,走规则引擎;第三级极端情况返回硬编码 Mock,保证流程不崩。超时设 30 秒,超时直接降级,用户感知不到。
6. 语义一致 CTA:把统一 Key 接进你的测试系统
规则引擎 + AI 的组合,落地时最容易被忽略的是接入层。模型换来换去、Key 散落各处,会让整个测试系统维护成本飙升。用 TaoToken 统一 Key 之后,Base URL 固定、Model ID 可切换、降级逻辑统一,批量生成和模型对比都省事。
如果你正在排障或接入,先看 API Keys 和接入文档:
- API Keys:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=apikeys
- 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc
想先验证模型是否通,用模型对话入口快速试一条 Prompt:
- 模型对话:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=chat
如果你要做长期编码或 Agent 类任务,比如让 AI 持续参与用例生成和精修,可以看 Coding Plan:
- Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=codingplan
最后留一个实操建议:先把规则引擎的实体动作提取跑通,确保基础用例不水;再接 TaoToken 统一 Key,把 temperature 设成 0.7,加上质量评分过滤;最后用人工抽检 10% 反哺 Prompt。三步走完,你的 AI 测试系统基本就能把“水用例”压到可接受比例。