第 15 章:实现本地知识库问答
本章目标
这一章把前面的模块串起来:文档切分、向量检索、Prompt 组装、模型回答。
本章效果
这一章完成本地知识库问答主链路:用户提问后,系统返回答案和引用来源。

问答链路
本章要完成:
用户问题
-> 生成问题 embedding
-> 向量库检索 topK chunks
-> 组装知识库上下文
-> 调用模型
-> 返回答案和引用来源
检索函数
export async function retrieveRelevantChunks(question: string) {
const embeddings = createEmbeddings();
const queryEmbedding = await embeddings.embedQuery(question);
return searchRecords(queryEmbedding, 5);
}
组装上下文
export function buildRagContext(
results: Array<{ record: VectorRecord; score: number }>
) {
return results
.map((item, index) => {
return [
`片段 ${index + 1}`,
`来源:${item.record.metadata.source}`,
`相似度:${item.score.toFixed(4)}`,
item.record.content
].join("\n");
})
.join("\n\n");
}
RAG API
import { createChatModel } from "@/lib/ai/model";
import { KB_ASSISTANT_SYSTEM_PROMPT } from "@/lib/ai/prompts";
export async function POST(request: Request) {
const { question } = await request.json();
const results = await retrieveRelevantChunks(question);
const context = buildRagContext(results);
const model = await createChatModel();
const answer = await model.invoke([
{ role: "system", content: KB_ASSISTANT_SYSTEM_PROMPT },
{
role: "user",
content: `
请基于以下知识库片段回答问题。
知识库片段:
${context}
用户问题:
${question}
`
}
]);
return Response.json({
answer: answer.text,
sources: results.map((item) => ({
title: item.record.metadata.title,
source: item.record.metadata.source,
score: item.score
}))
});
}
前端展示引用来源
function SourceList({ sources }: { sources: Array<{ title: string; score: number }> }) {
return (
<ul>
{sources.map((source, index) => (
<li key={index}>
{source.title} · {source.score.toFixed(3)}
</li>
))}
</ul>
);
}
引用来源可以折叠显示,避免干扰主要答案。
拒答策略
如果检索结果分数过低,可以拒答:
const bestScore = results[0]?.score ?? 0;
if (bestScore < 0.2) {
return Response.json({
answer: "知识库中没有找到足够相关的资料,暂时无法回答。",
sources: []
});
}
阈值要通过真实数据调试,不要拍脑袋定死。
实战任务
完成:
/api/kb/ask- 检索 topK chunk
- 组装 Prompt
- 返回 answer + sources
- 前端展示答案和引用来源
常见坑
不要把相似度分数直接当成“准确率”。它只是检索相似度。
不要把低质量 chunk 塞给模型。错误上下文会诱导模型给出错误答案。
不要只返回答案。知识库问答必须返回 sources。
本章小结
我们完成了本地知识库问答的主链路。下一章会优化 RAG 效果,包括召回、重排和引用。