大模型应用上线后,最容易被忽视的回归项往往是提示词本身。模型版本更新、接口参数调整、甚至同一模型在不同时段的输出波动,都可能让原本稳定的提示词突然失效。依靠人工在对话框里反复试,既无法覆盖大量用例,也难以沉淀成可追溯的质量标准。把提示词测试脚本化,是解决这个问题的直接路径。

自动化测试脚本并不只是把提示词丢给模型再打印结果。它需要像传统软件测试一样,明确输入、预期行为和失败条件。对于大模型输出,断言对象可以是文本中的关键词、固定结构、JSON字段、代码语法,也可以是语义层面的相似度。脚本的价值在于把这些检查固化成可重复执行、可对比版本的流程,让提示词调整有据可依。
一、Prompt自动化测试要解决哪些问题
提示词不同于普通函数输入,它的输出具有随机性和多样性。即使设置了较低的temperature,同一提示词在不同请求中也可能出现措辞变化。测试脚本首先要解决的是稳定性问题:怎样判断一次输出是合理的波动,还是提示词失效导致的错误。其次要解决回归问题:当提示词从版本A改到版本B时,哪些用例的表现发生了退化。
另一个容易被忽略的问题是测试数据的组织。手工维护一堆聊天记录既不规范,也不利于团队协作。好的脚本会把测试用例拆成独立文件,每条用例包含输入变量、预期关键词、禁止出现的内容、允许的格式等信息。这样新增或修改用例时,不需要改动主逻辑。
同时,模型接口本身也会引入干扰。网络超时、限流、返回结构变化都可能让脚本误报。测试框架需要把这些外部因素与真正的提示词问题区分开,避免因为一次网络抖动就判定全部失败。
二、设计测试脚本的基本结构
一个可用的Prompt自动化测试脚本通常包含四层:用例加载层、模型调用层、断言判断层和报告输出层。用例加载层负责读取JSON或YAML文件,将每条测试数据转换成统一结构。模型调用层封装接口请求,统一处理鉴权、超时和重试。断言判断层根据用例配置执行规则,并返回通过或失败。报告输出层生成终端摘要和文件记录。
下面以一个最小可运行的Python脚本为例。先定义测试数据,再逐条调用模型并检查关键词是否命中。
import os
import json
import requests
def call_llm(prompt):
api_key = os.getenv("LLM_API_KEY")
url = "https://api.ipipp.com/v1/chat/completions"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
payload = {
"model": "gpt-4o-mini",
"messages": [
{"role": "system", "content": "你是一个严谨的测试助手"},
{"role": "user", "content": prompt}
],
"temperature": 0.1
}
response = requests.post(url, headers=headers, json=payload, timeout=30)
data = response.json()
return data["choices"][0]["message"]["content"]
test_cases = [
{
"name": "提取城市名",
"prompt": "请从以下句子中提取城市名:我下周要去杭州出差。",
"must_contain": ["杭州"],
"must_not_contain": ["北京"]
},
{
"name": "生成JSON格式",
"prompt": "用JSON输出两个字段:姓名和年龄,姓名为张三。",
"must_contain": ["姓名", "年龄"]
}
]
for case in test_cases:
output = call_llm(case["prompt"])
print(f"用例:{case['name']}")
print(f"输出:{output}")
passed = True
for keyword in case["must_contain"]:
if keyword not in output:
passed = False
print(f"缺少关键词:{keyword}")
for keyword in case.get("must_not_contain", []):
if keyword in output:
passed = False
print(f"出现禁止词:{keyword}")
status = "通过" if passed else "失败"
print(f"结果:{status}\n")
这段代码解决了最基本的自动化验证,但还缺少对输出结构和语义的判断。实际项目中,提示词会要求模型返回JSON、Markdown表格或代码片段,单纯检查关键词容易造成误判。比如模型返回了包含关键词但完全不可解析的JSON,关键词断言会错误地给出通过。
因此,脚本需要把断言设计成可插拔的规则集合。每条用例可以声明多个断言类型,包括关键词命中、正则匹配、JSON Schema校验、代码编译检查和语义相似度阈值。断言失败时给出清晰的差异信息,而不是只输出一个布尔值。
三、处理输出不稳定:断言策略和评价指标
大模型输出不稳定是自动化测试中最棘手的问题。如果用例期望模型返回“杭州”,而模型返回“浙江省杭州市”,精确字符串匹配会失败,但语义上并无错误。此时需要引入多级断言策略。第一级做结构检查:输出是否可以解析为目标格式。第二级做关键信息检查:核心实体或字段是否存在。第三级才考虑语义相似度,用来识别表述不同但含义相同的回答。
语义相似度可以通过调用嵌入模型计算两个文本的向量余弦值来实现。测试脚本中预置一组标准答案或参考输出,将模型本次输出与参考答案做相似度计算。阈值通常设置在0.8到0.95之间,具体根据业务容忍度调整。对于事实性要求高的场景,还可以引入更细的规则,比如数字范围、日期格式、单位一致性等。
import numpy as np
def cosine_similarity(vec_a, vec_b):
a = np.array(vec_a)
b = np.array(vec_b)
if a.shape[0] == 0 or b.shape[0] == 0:
return 0.0
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
def embed_text(text):
# 调用嵌入模型接口,返回向量列表
# 这里用伪向量代替,实际项目替换为真实嵌入结果
return [0.1, 0.2, 0.3, 0.4]
reference = "杭州"
actual = "浙江省杭州市"
ref_vec = embed_text(reference)
actual_vec = embed_text(actual)
score = cosine_similarity(ref_vec, actual_vec)
if score < 0.8:
print(f"语义相似度过低:{score}")
else:
print(f"语义相似度达标:{score}")
需要注意的是,嵌入模型本身也有成本。如果测试用例数量很大,可以先用低成本的关键词和正则过滤掉大部分明显失败的情况,只对少数模糊用例计算语义相似度。这样能在保证覆盖率的同时控制接口调用开销。
除了相似度,结构校验也值得单独封装。例如模型被要求输出JSON时,先尝试json.loads解析,再根据预期字段做逐项比较。解析失败直接判定为结构错误,不需要进入后续断言。这样能快速区分是格式问题还是内容问题。
四、脚本落地与持续集成
自动化测试脚本只有接入持续集成流程,才能真正发挥回归价值。可以将脚本放在项目的tests目录下,通过配置文件读取不同环境的模型地址和密钥。每次提交代码或修改提示词时,CI系统自动运行全部用例,并生成HTML或文本报告。报告里包含每个用例的输出摘要、失败原因、耗时和模型版本。
提示词本身也应该纳入版本管理。建议将提示词模板存放在独立文件中,测试用例引用模板名称而不是直接写死提示词内容。这样当提示词更新时,可以对比同一套测试用例在不同提示词版本下的通过率变化。测试报告可以额外输出每个用例在旧版本和新版本下的输出差异,帮助定位退化原因。
# test_config.yaml
environment:
llm_api_url: "https://api.ipipp.com/v1/chat/completions"
api_key_env: "LLM_API_KEY"
model: "gpt-4o-mini"
temperature: 0.1
prompts:
city_extract:
template: "请从以下句子中提取城市名:{sentence}"
test_cases:
- name: "提取城市名"
prompt_key: "city_extract"
variables:
sentence: "我下周要去杭州出差。"
assertions:
- type: "keyword"
value: "杭州"
- type: "not_keyword"
value: "北京"
YAML配置中的花括号变量在加载时会被替换成具体值,这样同一个提示词模板可以驱动多条测试用例。如果提示词模板发生变化,只需要修改一处,所有引用该模板的用例都会自动使用新版本。这种设计也方便在CI中对比不同分支的提示词变化。
最后,测试报告不要只记录通过或失败。建议保留完整的输入和输出内容,以及每项断言的耗时。对于性能敏感的场景,可以统计首字延迟和总响应时间。把这些数据沉淀下来,后续能做趋势分析,也能在模型供应商切换时快速评估兼容性。
大模型Prompt测试自动化测试脚本提示词工程修改时间:2026-10-04 00:48:01