
1. 从“点点点”到“跑链路”AI测试工程到底在解决什么问题如果你做过三年以上测试大概率经历过这样的场景需求评审完手工用例写了两百条回归一轮三天上线前夜还在补边界值。AI测试工程要解决的不是“让AI替你点按钮”而是把用例生成、断言校验、回归对比这三件最耗人的事变成可复用、可度量、可追溯的流水线。我先把概念对齐一下。AI测试工程指的是用大模型能力嵌入测试工作流让机器承担“理解需求、生成用例、判断差异、归纳缺陷”的部分人负责定义验收标准和最终放行。它适合谁适合已经有基础自动化、但维护成本高、用例覆盖率上不去的团队也适合刚起步想直接跳到“大模型驱动”的个人开发者。核心检索词就三个AI测试、Prompt工程、RAG。这三个词不是并列关系而是递进关系。Prompt工程决定单次生成的质量上限RAG决定模型能不能用上你私有的用例库和缺陷库而AI测试工程是把这两者串成一条能跑起来的链路。为什么必须“统一Key”因为真实项目里你不会只用一个模型。生成用例可能用推理强的断言校验可能用速度快的RAG的embedding又是另一个接口。如果每个环节都单独配一套Key和Base URL环境变量会爆炸CI里改一处漏一处。用TaoToken做统一通道本质是把“模型接入”这件事从每个脚本里抽出来收敛成一份配置。这一节先建立认知AI测试不是银弹它有三个硬边界。第一模型不知道你系统的最新业务规则必须靠RAG或上下文注入第二模型会生成“读起来很顺但逻辑错”的用例必须人工复核关键路径第三一旦模型能操作测试环境写权限必须分级管控。记住这三条后面所有配置才有意义。2. 前置准备用TaoToken统一Key收敛模型接入层在写任何Prompt或RAG脚本之前先把接入层做干净。我试过在五个脚本里各写一套requests调用结果换模型时改了半小时。正确做法是所有模型调用都走同一个Base URLKey从环境变量读模型ID作为参数传入。TaoToken的API地址是https://taotoken.net/api兼容OpenAI风格的接口路径。你需要在控制台创建一个API Key然后把它写进环境变量而不是硬编码在代码里。这一步看起来简单但它是后面所有链路能复用的前提。先配置环境变量。Linux/macOS下编辑~/.bashrc或~/.zshrcWindows下用系统环境变量或.env文件配合python-dotenv。推荐后者因为CI里更好管理。# .env 文件放在项目根目录记得加进 .gitignore TAOTOKEN_API_KEYsk-你的实际Key TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_MODEL_GENclaude-sonnet-4-20250514 TAOTOKEN_MODEL_JUDGEgpt-4o-mini TAOTOKEN_EMBED_MODELtext-embedding-3-small这里我分了三个模型变量GEN用于用例生成JUDGE用于断言校验和回归对比EMBED用于RAG的向量化。为什么要分开因为生成用例需要强推理成本高但调用次数少断言校验调用频繁用便宜快的模型更划算。统一Key不等于统一模型而是统一通道、分模型调度。如果你用Claude Code做测试脚本的辅助开发可以在项目根目录建.claude/settings.json把Base URL和Key配进去。注意Claude Code的配置格式和通用OpenAI SDK略有不同它读的是Anthropic风格的字段。{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的实际Key, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }如果你用Cline或Continue这类编辑器插件配置项通常在插件的settings里字段名是baseURL或apiBase填https://taotoken.net/apiKey填同一个Model ID填你选的模型。三件套永远是Base URL Key Model ID缺一个都连不上。Python侧我建议装openai SDK因为它兼容性最好而且TaoToken的接口路径和它一致。安装命令pip install openai python-dotenv numpy然后写一个统一的客户端封装后面所有脚本都import它不要重复写调用逻辑。# llm_client.py import os from dotenv import load_dotenv from openai import OpenAI load_dotenv() client OpenAI( api_keyos.getenv(TAOTOKEN_API_KEY), base_urlos.getenv(TAOTOKEN_BASE_URL) ) def chat(prompt, modelNone, temperature0.2): model model or os.getenv(TAOTOKEN_MODEL_GEN) resp client.chat.completions.create( modelmodel, messages[{role: user, content: prompt}], temperaturetemperature ) return resp.choices[0].message.content def embed(texts, modelNone): model model or os.getenv(TAOTOKEN_EMBED_MODEL) resp client.embeddings.create(modelmodel, inputtexts) return [d.embedding for d in resp.data]这段代码是整个链路的地基。temperature0.2是测试场景的推荐值太低会死板太高会编造。封装好之后换模型只需要改环境变量不用动业务代码。3. 可复制配置Prompt模板与RAG评测脚本落地这一节给可直接复制的东西。先给Prompt模板再给RAG检索命中率验证脚本最后给回归对比的配置片段。Prompt工程的核心不是“咒语”而是把角色、任务、约束、输出格式讲清楚。下面这个模板用于用例生成我把它存成prompts/gen_cases.txt脚本读取后拼接需求文本。你是资深测试工程师擅长从需求文档中提取测试点并生成结构化用例。 任务基于下方需求生成测试用例。 约束 1. 覆盖功能、边界、异常、权限四个维度。 2. 每条用例必须包含用例编号、场景分类、前置条件、测试步骤、预期结果。 3. 对“依据文档推导”和“基于经验猜测”的部分分别标注 [DOC] 和 [GUESS]。 4. 输出Markdown表格不要输出多余解释。 需求文档 {requirement}调用时用Python做字符串替换注意{requirement}用.replace()而不是f-string避免需求里的花括号冲突。# gen_cases.py from llm_client import chat with open(prompts/gen_cases.txt, encodingutf-8) as f: template f.read() requirement open(docs/login_prd.md, encodingutf-8).read() prompt template.replace({requirement}, requirement) result chat(prompt) print(result)接下来是RAG检索命中率验证脚本。RAG的效果不取决于模型多强而取决于检索出来的片段对不对。所以你必须有一个命中率验证环节否则你不知道是检索错了还是生成错了。思路准备一组“问题-期望命中的文档ID”对跑检索看Top-K里有没有期望ID。下面用numpy做余弦相似度不依赖向量数据库方便你本地验证。# rag_eval.py import numpy as np from llm_client import embed # 模拟知识库真实场景从用例库/缺陷库加载 docs [ {id: case_001, text: 登录功能密码错误5次锁定账号30分钟}, {id: case_002, text: 支付功能网络超时后重复支付需幂等校验}, {id: case_003, text: 积分功能订单取消后积分原路退回有效期不变}, {id: case_004, text: 权限功能普通用户不可访问管理后台接口}, ] # 评测集问题 期望命中的文档ID eval_set [ {q: 密码输错多次会怎样, expect: case_001}, {q: 重复支付怎么测, expect: case_002}, {q: 取消订单积分怎么处理, expect: case_003}, ] doc_vecs np.array(embed([d[text] for d in docs])) def retrieve(query, top_k2): q_vec np.array(embed([query])[0]) sims doc_vecs q_vec / (np.linalg.norm(doc_vecs, axis1) * np.linalg.norm(q_vec)) idx np.argsort(sims)[::-1][:top_k] return [(docs[i][id], float(sims[i])) for i in idx] hit 0 for item in eval_set: results retrieve(item[q]) ids [r[0] for r in results] ok item[expect] in ids hit ok print(fQ: {item[q]} | 期望: {item[expect]} | 命中: {ids} | {PASS if ok else FAIL}) print(f\n命中率: {hit}/{len(eval_set)} {hit/len(eval_set):.0%})跑出来如果命中率低于80%先别怪模型去检查切片粒度。常见问题是把一条完整业务流的用例切成了两半导致语义断裂。解决办法是按“功能模块-接口”层级切而不是按固定字数切。最后给回归对比的配置片段。回归对比的本质是同一组用例在两个版本上跑让模型判断差异是否属于预期变更。配置存成config/regression.toml[regression] baseline results/v1.2.0.json current results/v1.3.0.json judge_model gpt-4o-mini output reports/regression_diff.md [thresholds] max_diff_ratio 0.05 ignore_fields [timestamp, request_id, duration_ms]ignore_fields很关键时间戳和请求ID每次都变不忽略的话全是噪音。max_diff_ratio是允许的差异比例超过就告警。4. 验证请求跑通一次完整的生成与校验链路配置写完必须验证否则你不知道是Key错了、模型ID错了还是网络问题。按下面顺序逐步执行每一步都有明确的成功标志。第一步验证基础连通性。写一个最小脚本只发一句“回复OK”。# verify_conn.py from llm_client import chat print(chat(只回复两个字OK))成功标志终端输出OK。如果报401说明Key错了或没读到环境变量如果报Connection error检查Base URL是不是写成了https://taotoken.net/api注意结尾没有斜杠SDK会自动补/v1。第二步验证embedding接口。RAG依赖它单独测一次。# verify_embed.py from llm_client import embed vecs embed([测试文本一, 测试文本二]) print(f维度: {len(vecs[0])}, 数量: {len(vecs)})成功标志输出类似维度: 1536, 数量: 2。维度取决于你选的embedding模型只要不是0就说明通了。第三步跑完整的用例生成。用第3节的gen_cases.py准备一份真实的需求文档片段。成功标志输出一个Markdown表格每行有用例编号和预期结果且[DOC]和[GUESS]标注清晰。如果模型输出了一堆解释性文字而不是表格说明Prompt里的“不要输出多余解释”没生效把temperature再降到0.1。第四步跑RAG命中率验证。执行rag_eval.py成功标志命中率打印出来且你能看到每个问题的Top-2结果。如果命中率是0%先检查embed返回的向量是不是全零再检查余弦相似度计算有没有除零。第五步跑回归对比。准备两份结果JSON执行对比脚本成功标志生成regression_diff.md里面列出了差异项和判定结果。如果差异项全是时间戳说明ignore_fields没生效。这五步跑完你的链路就通了。整个过程的核心是每步单独验证不要一次性跑全流程然后对着一个报错猜半天。5. 常见报错排查401、local proxy failed、reading choices、OAuth这一节对照真实报错给排查路径。这些错我都踩过按顺序查基本能定位。401 Unauthorized。最常见三个原因Key没读到、Key失效、Base URL拼错。先确认环境变量echo $TAOTOKEN_API_KEY如果为空说明.env没加载检查load_dotenv()是不是在import之前执行。如果Key有值去控制台确认Key没过期、没被删。最后检查Base URL必须是https://taotoken.net/api不要手动加/v1SDK会自己拼。local proxy failed / connection refused。这个报错通常出现在你本地配了代理但代理没启动或端口不对。排查检查环境变量HTTP_PROXY和HTTPS_PROXY如果设了但代理没开清掉这两个变量再试。另一个可能是防火墙拦了出站请求换网络环境验证。reading choices of undefined。这是SDK层面的报错意思是返回体里没有choices字段。原因通常是模型ID写错了服务端返回了错误信息而不是正常响应或者Base URL指向了一个不兼容OpenAI格式的端点。排查打印完整响应体看resp里到底是什么。把model参数换成确认存在的模型ID再试。OAuth / authentication failed。如果你用Claude Code或某些CLI工具它们可能走OAuth流程而不是API Key。排查确认工具读的是ANTHROPIC_API_KEY还是OAuth token。如果是Claude Code检查.claude/settings.json里的env字段有没有正确写入。三件套再确认一遍Base URL、Key、Model ID缺一个都会报认证失败。模型返回空内容。不是报错但更隐蔽。原因Prompt太长超了上下文窗口或者temperature设成了0导致模型“不敢说话”。排查缩短Prompt把temperature调到0.2再试。RAG检索结果全是同一个文档。说明embedding没区分度可能是文本太短或模型选错了。排查换一个embedding模型或者把文档切片加长到100字以上。排查的核心原则先验证连通性再验证业务逻辑。连通性用最小脚本测业务逻辑用单步脚本测。不要在一个大脚本里混着调报错时你分不清是哪层的问题。6. 把链路接进CI长期编码与Agent化的下一步链路跑通之后下一步是把它接进CI让它自动跑。但这里有个分叉你是只想在本地辅助写用例还是想让Agent在CI里自动执行回归如果只是本地辅助那前面的配置够了每次改需求时手动跑一次生成脚本人工复核后入库。这种模式成本低、风险小适合大多数团队起步。如果想做长期编码和Agent化建议用Coding Plan把模型调用额度管起来避免CI里跑飞了账单失控。Agent化的关键是权限分级查询类操作只读生成类操作写草稿执行类操作必须人工确认。前面Harness那节讲的约束在CI里就是一道道门禁。具体落地时把gen_cases.py和rag_eval.py包成CI job每次需求文档变更时触发。生成结果先落到drafts/目录人工review后再合并到正式用例库。回归对比脚本挂在 nightly build 上差异超过阈值就发通知。最后给一个实用技巧把Prompt模板和评测集都纳入版本管理。Prompt改了要能追溯评测集加了要能回归。这样你的AI测试工程才不是一次性的玩具而是能持续迭代的资产。如果你要接着往下做接入文档里有完整的接口说明和参数列表API Keys页面可以管理你的Key和额度。模型对话适合快速验证Prompt效果Coding Plan适合把调用量管起来做长期工程。链路是自己的工具是辅助的先把最小闭环跑通再谈规模化。