为 Node.js RAG 接入答案来源校验
开源库 rag-pipeline-utils 提供答案与来源内容的校验接口,可接收其他框架生成的回答,无需重建整条 RAG 流水线。文章给出 Node.js 22+ 的安装与调用示例,面向应用运行和 CI 校验场景。
AI 深度解读
RAG 最麻烦的错误,往往看起来很正常:手册写着年假二十天,聊天机器人回答三十天,接口成功返回,日志也没有异常。检索到了资料,并不保证模型会忠实使用资料。
@devilsdev/rag-pipeline-utils 的作者想补上这道检查:把回答和来源一起送进校验器,让答案是否有依据成为应用和 CI 能检查的值。它值得关注的地方是可以接入现有项目,但「通过校验」距离「回答可靠」还有边界。
已经有 RAG,还需要换一套框架吗
不需要。这个库既能搭建检索增强生成(RAG)流程,也能单独检查其他系统生成的答案。原文明确列出了 LangChain、Mastra、Vercel AI SDK、LlamaIndex,以及自建代码。
安装命令是 npm install @devilsdev/rag-pipeline-utils,运行要求为 Node.js 22+,提供 CommonJS、ESM 和 TypeScript 类型。
下面这段代码解决的是「回答有没有偏离提供给模型的资料」:
import { checkAnswer } from "@devilsdev/rag-pipeline-utils";
const check = await checkAnswer({
answer:
"Full-time employees receive thirty days of paid vacation per year. " +
"Remote work is allowed two days per week.",
sources: [
{
pageContent:
"Full-time employees receive twenty days of paid vacation per year.",
},
{
pageContent:
"Remote work is allowed two days per week with manager approval.",
},
],
});
console.log(check.grounded); // false
console.log(check.groundedness); // 0.5
console.log(check.unsupported); // ["Full-time employees receive thirty days of paid vacation per year."]
重点看 unsupported:示例把年假三十天的句子列为缺乏支持,整体 groundedness 为 0.5。
作者称,检查按句子进行,除了词语,还会检查数字和否定关系。默认在本地运行,不需要 API key,也不调用模型,相同输入会得到相同判断,适合离线测试。
如果正确的改写因措辞不同被误判,可以传入 judge,让 LLM 复核那些仅因措辞检查未通过的句子。这是在确定性检查之外增加语义判断,实际成本和稳定性也需要重新评估。
能跑通检索,和能回答问题是两回事
如果希望由这个库组织流程,createRagPipeline() 可以连接嵌入器、检索器、可选的重排器和 LLM。
原文用 LocalEmbedder 与 MemoryRetriever 演示离线检索:先调用 embedder.train(),再通过 embedder.embed() 生成文档向量,使用 retriever.store() 保存,最后执行 pipeline.run()。其中 LocalEmbedder 使用 TF-IDF,可以理解为依据词频和词语区分度表示文本。
这里有个容易看漏的细节:示例最后检查的是 result.results[0].id 等于 "vacation"。它证明问题找到了对应文档,没有展示 LLM 生成完整回答的过程。
作者列出的可替换模型服务包括 OpenAI、Anthropic、Cohere 和 Ollama,存储包括 pgvector、Qdrant、Pinecone 和 Weaviate,也支持带有 embed() 或 generate() 方法的对象,包括 Vercel AI SDK 模型。不过,文章没有展开各适配器的具体配置。
想从应用起步,可以运行 npm create rag-pipeline@latest,生成面向 Next.js 与 AI SDK、Mastra 或 Cloudflare Workers 的项目。
把答案回归放进 CI,比只看接口成功更有用
修改分块大小、提示词、模型或嵌入器,都可能让答案变差,同时保持程序正常运行。作者因此把测试工具作为这个库的重要部分,提供 Jest 和 Vitest 匹配器。
下面的示例把来源支持、引用和个人身份信息检查写成断言:
import { expect, test } from "vitest"; // 或使用 Jest 的全局 expect
import {
createTestPipeline,
ragMatchers,
} from "@devilsdev/rag-pipeline-utils/testing";
expect.extend(ragMatchers);
test("answers vacation questions from the handbook", async () => {
const { pipeline } = await createTestPipeline();
const result = await pipeline.run({
query: "How many vacation days do I get?",
});
expect(result).toBeGroundedIn(); // 每句话都得到 result.results 的支持
expect(result).toCite("vacation");
expect(result).toContainNoPII();
});
注意 toBeGroundedIn() 的检查对象是检索结果 result.results。如果检索结果本来就错了或过时了,来源支持检查不能自动纠正资料。
整批评估则使用 rag-pipeline eval:对数据集评分,与保存的基线比较,在答案退化时失败。rag-eval-action 可以在每次 pull request 中运行,并把比较结果作为评论发布。
配套能力还包括:通过 groundingMiddleware 接入 Vercel AI SDK,为 Mastra 提供评分器和护栏;在内容进入模型前进行访问控制过滤,并提供提示注入检测与 PII 脱敏。作者称后两者发布了精确率和召回率,但文章没有给出具体数值。
生产能力清单还列出混合检索、重排、token 预算、超时与取消、重试、缓存,以及附带评估分数的 OpenTelemetry 或 Langfuse 追踪。/edge 构建面向 Cloudflare Workers、Vercel Edge 和 Deno;@devilsdev/rag-mcp-server 则让 Claude 搜索文档文件夹并检查答案。关注安装体积时,可以选约 6 MB 的 @devilsdev/rag-eval。
我的判断
让答案具备可执行的断言,比只确认请求成功更接近 RAG 的实际需求。
这个方向成立,尤其适合已经有 Node.js AI 应用、希望补充回归检查的团队。相比完全依赖人工抽查,本地确定性检查更容易重复运行;相比让 LLM 评审全部答案,它减少了默认路径中的模型调用。
但原文提供的是功能演示,没有不同方案的对照数据,也没有足够证据证明它在真实业务中的漏报率和误报率。这些能力还需要用自己的数据验证。
示例本身就留了一个问号:远程办公的来源要求「经理批准」,回答删掉了这个条件,却没有出现在展示的 unsupported 列表里。至少按这段输出,数字冲突被识别了,条件遗漏没有被标出。
因此,我会把它看作答案检查的一层。中文改写、跨句推理、限制条件遗漏能查到什么程度,文章没说清;judge 能否补足,也缺少对照实验。
能拿来做什么
- 已有 Node.js RAG 应用可以先单独接入
checkAnswer,用真实回答和当时提供的来源观察结果,再决定是否据此阻断输出。 - 使用 Jest 或 Vitest 的团队,可以围绕额度、天数、否定句和审批条件整理测试样本,在修改提示词或分块策略后检查回归。
- 使用 Next.js 与 Vercel AI SDK 的项目,可以评估
groundingMiddleware的接入方式,并区分来源支持检查与业务规则校验的职责。 - 引入
rag-pipeline eval前,先建立覆盖真实问题的数据集和基线,把正常改写、数字错误、条件遗漏分别纳入样本,确认评分确实能反映团队关心的退化。