LLM 应用的测试难点在于输出的非确定性。同样的 prompt 可能得到措辞不同但语义相近的回答,传统的字符串断言几乎无法使用。这要求我们重新设计测试策略,在保证质量的同时避免测试用例变得过于脆弱。
分层测试金字塔
建议采用三层结构:
单元测试层:测试不涉及 LLM 调用的纯逻辑部分。假设你的 RAG 应用包含向量检索、重排序、上下文拼接等模块,这些都可以用确定性输入验证输出。例如测试「给定 3 个检索结果,重排序函数是否正确按相关度分数排序」,这类测试运行快、结果稳定,应该占测试总量的 60% 以上。
集成测试层:测试 LLM 调用的结构化约束而非具体内容。不要断言「回答必须是『北京是中国的首都』」,而是验证:
- 响应格式符合预期(JSON schema 校验、必填字段存在)
- 输出长度在合理区间(如摘要任务限制在 200 字以内)
- 不包含明显错误模式(如空回复、错误码、拒绝回答的固定句式)
可以用 LLM-as-Judge 模式:让另一个模型评估输出是否满足要求。假设测试客服 Agent 的「退款政策解释」功能,评估 prompt 可以是「判断回答是否包含退款时限、适用条件两个要素,返回 true/false」。这比人工标注答案更灵活,但需注意评估模型本身也有成本和延迟。
回归测试层:针对已修复的 bad case 建立快照。当用户反馈「某个问题 LLM 给出了错误答案」时,修复后将该输入-输出对存入回归集。后续每次发版前重跑,确保:
- 相同输入的新输出与快照语义一致(可用嵌入向量余弦相似度 > 0.9 作为阈值)
- 或人工抽查标记为「仍然正确」
这一层不求覆盖所有场景,而是防止已知问题复现。
关键实践建议
使用确定性参数进行基线测试。多数 LLM API 支持 temperature=0 或种子参数,在这个模式下输出虽不完全相同但重复性更高。可以用它建立「黄金测试集」:10-20 个核心场景的标准输出,每次模型升级或 prompt 改动后对比差异。
分离 prompt 版本管理。将 prompt 模板从代码中抽离到配置文件或数据库,每次修改记录版本号和变更原因。测试时可以针对特定 prompt 版本运行,出问题时能快速回滚到上一个稳定版本。
监控线上真实分布。测试环境再完善也无法穷尽真实用户输入。建议采样 1-5% 的线上请求,记录输入、输出、用户反馈(如果有),定期人工审查异常模式。发现新类型问题时补充到回归测试集。
控制成本与执行时间。集成测试若每个用例都调用旗舰档模型,CI/CD 管道会变得昂贵且缓慢。可以:
- 冒烟测试用轻量档模型(如各家的 mini/Haiku/Flash 系列)
- 完整回归测试仅在发版前或每日定时运行
- 使用模拟(mock)LLM 响应来测试错误处理逻辑
工具链选择
推荐组合:
- 单元测试用语言原生框架(pytest / Jest 等)
- LLM 调用的集成测试可考虑 LangSmith、PromptLayer 等平台的评估功能,或自建轻量评估脚本
- 回归测试的快照对比可用向量数据库(存储历史输出的嵌入)+ 相似度计算
如果你的团队正在搭建 LLM 应用的测试体系,或需要在 AI 项目中引入工程化实践,欢迎与我们交流具体场景下的方案设计。