第 12 章 · RAG 检索增强
本章目标:掌握 Mastra 的 RAG 管线:文档切片、向量化、入库、检索与重排,把私有知识注入 Agent 上下文。
12.1 RAG 五步管线
模型不知道你的内部文档。RAG(Retrieval-Augmented Generation)的标准流程:
- 加载——把 Markdown/PDF/HTML 转成
MDocument; - 切片——按 token 或语义边界切成 chunk;
- 向量化——用 embedding 模型把 chunk 变成向量并写入向量库;
- 检索——查询时把问题也向量化,取最相似的 top-K;
- 注入——把检索结果拼进提示词让模型回答。
12.2 文档切片与向量化
typescript
// src/rag/ingest.ts
import { MDocument } from '@mastra/rag'
import { embedMany } from 'ai'
import { openai } from '@ai-sdk/openai'
// 从 Markdown 文本创建文档对象(也支持 fromPDF / fromHTML 等)
const doc = MDocument.fromText(`
# 退款政策
下单后 7 天内可无理由退款。
# 发货时效
现货商品 48 小时内发出。
`)
// 按标题结构切片,每块不超过 512 token,块间重叠 50
const chunks = await doc.chunk({
strategy: 'markdown',
size: 512,
overlap: 50,
})
// 批量生成向量(embedding 维度由模型决定)
const { embeddings } = await embedMany({
model: openai.embedding('text-embedding-3-small'),
values: chunks.map((c) => c.text),
})12.3 写入向量库
Mastra 提供多种 Vector 适配器,这里用 LibSQL 的向量扩展:
typescript
// src/rag/store.ts
import { LibSQLVector } from '@mastra/libsql'
const vector = new LibSQLVector({ url: 'file:./vectors.db' })
// 建表:指定维度必须与 embedding 模型输出一致
await vector.createIndex({
indexName: 'kb_docs',
dimension: 1536, // text-embedding-3-small 输出 1536 维
})
// 插入向量与原文元数据
await vector.upsert({
indexName: 'kb_docs',
vectors: embeddings,
metadata: chunks.map((c) => ({ text: c.text })),
})12.4 检索并注入上下文
typescript
// src/rag/query.ts
import { embed } from 'ai'
import { openai } from '@ai-sdk/openai'
export async function retrieve(question: string): Promise<string[]> {
// 问题转向量
const { embedding } = await embed({
model: openai.embedding('text-embedding-3-small'),
value: question,
})
// 余弦相似度取前 3 条
const results = await vector.query({
indexName: 'kb_docs',
queryVector: embedding,
topK: 3,
})
return results.map((r) => r.metadata?.text ?? '')
}
// 用法:把检索结果作为上下文传给 Agent
const context = (await retrieve('退货要多久处理?')).join('\n---\n')
const answer = await agent.generate(
`参考以下资料回答客户问题:\n${context}\n\n问题:退货要多久处理?`,
)12.5 重排与进阶
rerank()可用交叉编码器对初筛结果二次排序,显著提升精度;Metadata Filters支持按类别、时间等字段过滤;
重排示例
向量初筛快但糙,用交叉编码器精排 top-20 再取前 3:
typescript
// src/rag/rerank.ts
import { rerank } from '@mastra/rag'
const candidates = await retrieveAll(question, 20) // 初筛扩大召回
const reranked = await rerank({
query: question,
results: candidates,
topK: 3, // 只保留精排后的前三名注入上下文
})- 元数据过滤(
Metadata Filters)支持按类别、时间等字段收窄检索范围; - 数据量大时可探索 GraphRAG(知识图谱增强检索)。
本章小结
- 数据量大时可探索 GraphRAG(知识图谱增强检索)。
本章小结
- RAG = 切片 → 向量化 → 入库 → 检索 → 注入五步;
MDocument.chunk()支持按 markdown 结构智能切分;- 向量维度必须与 embedding 模型匹配(1536 for text-embedding-3-small);
- 检索质量决定回答上限,必要时加 rerank 与元数据过滤。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. RAG 流程中"切片(chunk)"的主要目的是?
2. 创建向量索引时 dimension 参数必须满足什么条件?
3. vector.query() 中 topK: 3 表示什么?
4. rerank() 在 RAG 管线中的作用是?
🛠️ 动手实践
- 把你的一份真实产品 FAQ 文档做成 RAG 管线,问 5 个问题检验命中率。
- 对比
size: 256与size: 1024两种切片对回答质量的影响。 - 在检索后加入 rerank 步骤,观察 top-3 结果顺序变化。