【免费下载链接】ai-builders-curriculum
Open, vendor-neutral curriculum and hackathon starter kits for learning to build full-stack AI applications end-to-end. MIT-licensed. A project of the AI Builders Foundation (501c3).
学习构建 RAG(检索增强生成)应用时,最容易被忽视的环节就是单元测试。开源项目ai-builders-curriculum(AI Builders Foundation 推出的 AI 全栈应用课程)在两个实战套件中内置了可直接运行的 RAG 管道测试:纯函数、零网络依赖、无需 API Key,一条npm test命令即可验证分块(chunking)、**余弦相似度(cosine similarity)和决策校验(decisions)**三大核心环节。本文带你拆解这些测试为什么值得写、以及怎么写。
为什么 RAG 管道特别适合写单元测试?
RAG 管道 = 摄入文档 → 分块 → 向量化 → 检索 → 生成答案。其中真正"脏活"的部分(调用 LLM、读写数据库)难以测试,但管道里藏着三个纯函数环节:
- 📦分块:把长文本切成带重叠的片段,只依赖输入字符串
- 📐余弦相似度:比较两个向量的数学计算,只依赖数字数组
- 🛡️决策校验:把用户提交的任意 JSON 解析成一份合法的配置对象
这三个环节的共同点是:不碰网络、不碰数据库、不需要 API Key,运行瞬间完成。项目测试文件的注释把这点说得直白——"纯函数,无网络无数据库,这正是它值得被直接测试的原因"(见 chunk.test.ts 文件头部说明)。
测试环境如何搭建:零框架依赖的快速启动
这两个套件没有引入 Jest 或 Vitest,而是直接使用 Node.js 内置的node:test运行器 +node:assert/strict断言库,配合tsx直接执行 TypeScript。测试脚本定义在 package.json 中:
"test": "tsx --test test/*.test.ts"也就是说,安装依赖后运行npm test即可,无需任何测试框架依赖。每个测试文件只需两行导入:
import { test } from "node:test"; import assert from "node:assert/strict";这种"标准库优先"的做法对小项目非常友好:没有配置、没有快照目录、没有 mock 工具链,测试代码和被测代码一样轻量。
实战一:如何测试分块函数(chunkText)
分块是 RAG 的第一道关卡。被测函数 chunkText 按词数把文本切成重叠片段——chunkSize控制窗口大小,overlap让每个片段的末尾词在下一片段开头重复,避免句子恰好被切在边界上。
对应的 chunk.test.ts 共 6 个测试,覆盖了分块逻辑的全部关键行为:
| 测试场景 | 验证点 | 参考位置 |
|---|---|---|
| 空文本 / 纯空白 | 返回空数组[] | L12-L15 |
| 短于 chunkSize 的文本 | 整体成为单个 chunk | L17-L20 |
| 长文本滑动窗口 | 8 个词、窗口 4、重叠 1 → 精确的 3 个 chunk | L22-L27 |
| 无重叠模式 | chunk 之间连续且不重叠 | L29-L34 |
| 多余空白折叠 | 任意空白串被规范为单空格 | L36-L39 |
| 非法参数 | chunkSize <= 0或overlap >= chunkSize必须抛错 | L41-L46 |
最值得学习的是用可计算的精确输入锁定输出:构造w0 w1 w2 w3 w4 w5 w6 w7这样的 8 词输入,配合chunkSize: 4, overlap: 1,断言结果精确等于["w0 w1 w2 w3", "w3 w4 w5 w6", "w6 w7"]。不用模糊的"长度大于 N",而是钉死每一个词——滑动窗口哪怕前进一格,测试立刻变红。
实战二:如何测试余弦相似度(cosineSimilarity)
检索环节的"比较两个向量"步骤由 cosineSimilarity 实现:计算两个向量夹角的余弦值,范围从 -1(方向相反)到 1(方向相同)。similarity.test.ts 用 8 个测试把这组数学性质的边界全部钉住:
- 方向性质:相同向量为 1、相反向量为 -1、正交向量为 0(L12-L22)
- 尺度无关性:
[1, 1]与[2, 2]相似度应为 1——向量长度不重要,只看方向,这正是 RAG 需要的特性(L24-L27) - 零向量防御:零向量没有方向,约定返回 0 而不是除零崩溃(L29-L32)
- 维度不匹配:必须抛错(L34-L36)
对topKBySimilarity这个"检索"函数,测试验证了两个契约:结果按分数从高到低排序且最相似的排第一(L38-L53),以及请求 k=10 但只有 2 个候选时,绝不多返回(L55-L62)——这类"上界约束"是新人写测试时最容易漏掉的。
实战三:如何测试决策校验(resolveDecisions)
glassbox 套件更进一步:它把 RAG 答案背后的 8 个隐藏参数(引用数量、temperature、语气、引用样式、不确定时的策略、目标读者、立场等)全部暴露为可调项,而 resolveDecisions 是唯一的校验闸门——客户端传来的任何 JSON 都必须经它净化后才能进入管道。
decisions.test.ts 的测试策略很有参考价值,按"信任边界"层层加码:
- 无输入 = 精确的默认值:
null、undefined、{}全部解析为 DEFAULT_DECISIONS(L15-L20) - 部分覆盖只动被动的字段:改 2 个值,其余 6 个必须逐一对回默认值(L22-L33)
- 数字越界要夹紧(clamp)而非报错:
sourceCount: 9999→ 10,temperature: 5→ 1(L58-L66) - 脏数据回落默认值:
NaN、字符串"four"、Infinity都安全降级(L68-L73) - 未知枚举值回落而非崩溃:
tone: "pirate"→"neutral"(L75-L90) - 未知键被静默丢弃:结果对象必须恰好只有 8 个已知键(L109-L127)
压轴的是"垃圾输入大乱斗"测试:把所有字段同时塞上越界数字、字符串、布尔值、未知键(L129-L151),断言输出是一份完整的合法配置。这个测试的价值在于端到端证明"任何输入都能得到全合法输出"这一契约,而不是只测单个字段的防御逻辑。
可复用的测试清单:给 RAG 管道写测试的 5 条经验
从这两个套件可以提炼出一套通用的 RAG 单元测试方法:
- 优先测纯函数环节——分块、相似度、参数解析,不碰网络和数据库,跑起来最快、最稳
- 用可计算的精确输入锁定精确输出,避免"长度合理"之类的模糊断言
- 边界场景与正常场景同等重要:空输入、零向量、越界值、维度不匹配,每个都要有专属用例
- 校验类函数要做"垃圾输入"测试,证明契约是"永远输出合法结果",而不是"遇到脏数据报错"
- 零依赖起步——
node:test+node:assert/strict足够支撑纯函数测试,先跑起来,再考虑引入框架
下一步:动手运行这些测试
课程仓库(可运行git clone https://gitcode.com/gh_mirrors/ai/ai-builders-curriculum获取)中,三个测试文件分别位于 rag-starter/test/ 与 glassbox/test/,配套的被测源码在 rag-starter/server/ 和 glassbox/server/。建议的动手路径:
- 在任一套件目录执行
npm install && npm test,观察node:test的输出格式 - 故意改坏 chunk.ts 中的滑动步长
step,看测试如何立刻变红 - 为 resolveDecisions 补一个新字段的测试,体会"先写断言、再改实现"的节奏
更完整的课程脉络可阅读 curriculum/04-ai-and-agents.md 与 starter-kits/glassbox/BUILD-ALONG.md,前者覆盖 AI 应用的整体设计,后者按步骤带你从零搭出 glassbox 应用。
【免费下载链接】ai-builders-curriculum
Open, vendor-neutral curriculum and hackathon starter kits for learning to build full-stack AI applications end-to-end. MIT-licensed. A project of the AI Builders Foundation (501c3).
相关推荐
Intercooler-js测试策略:如何编写可靠的单元测试
Intercooler js测试策略:如何编写可靠的单元测试 Intercooler js是一个轻量级的AJAX库,它通过HTML属性简化了前端开发。要确保这个
前端Vuelidate测试策略:如何编写可靠的验证单元测试和集成测试
Vuelidate测试策略:如何编写可靠的验证单元测试和集成测试 Vuelidate作为Vue.js生态中简单轻量的模型验证库,为前端表单验证提供了优雅的解决方
前端Passport.js测试策略:如何编写可靠的认证单元测试
Passport.js测试策略:如何编写可靠的认证单元测试 Passport.js作为Node.js生态中最流行的认证中间件,其测试策略为开发者提供了编写可靠认
后端认证鉴权
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考