本章主要介绍在非服务化场景下使用 RAG 功能,包括索引文件、检索知识、集成到智能体等。
现有实现
AgentScope 为每个模块提供了开箱即用的默认实现,全部基于基类继承,方便用户替换:解析器
切块器
嵌入模型
请见嵌入模型章节。向量数据库
RAG 使用
AgentScope 推荐通过知识库句柄KnowledgeBase 作为入口使用 RAG。它把嵌入模型、向量库、collection(以及可选的 metadata_filter 多租户隔离配置)绑定在一起,对外只暴露四个动作:
索引文件
索引文件需要经过 文件解析 → 切块 → 嵌入入库 三步,对应上述三个模块。下面展示端到端的索引流程。1
解析文件
使用解析器的
parse 方法把原始文件读取成 Section 数组,每个 Section 对应文件的一个自然边界(PDF 页 / PPT 幻灯片 / 图片 …)。parse(file, filename) 的 file 参数同时支持 bytes 与 str:bytes直接作为原始文件内容;str在二进制解析器(PDFParser/PPTParser/WordParser/ExcelParser/ImageParser)中表示文件路径,解析器自动读盘;str在TextParser中按运行时判断——若该字符串指向一个存在的文件就当作路径读盘并按encoding解码,否则当作已解码的文本内容直接使用。
2
切分 Chunk
使用切块器的
chunk 方法把 Section 数组切成最终入库的 Chunk 数组。约定:不跨 Section 合并;多模态 DataBlock 整块透传;chunk_index 从 0 连续编号,total_chunks 在每个 chunk 上都是同一值。3
写入知识库
构造一个 如果希望使用其他后端,安装对应的可选依赖后,只需要替换向量库的构造方式:
KnowledgeBase 句柄,把 chunk 数组写入即可——嵌入与写库由句柄一并完成。同一文档的所有 chunk 共享一个 document_id,便于后续按文档级别整体删除。KnowledgeBase 不会自己创建 / 关闭向量库连接,使用前需要先把 VectorStoreBase 实例置于 async with 上下文中。向量检索
通过KnowledgeBase.search 直接传入查询字符串/TextBlock/DataBlock 即可,无需手动嵌入:
search 内部做了以下几件事:
- 过滤不可用查询:若绑定的嵌入模型
supports_multimodal == False,会静默丢弃DataBlock类型的查询; - 批量嵌入:所有查询一次性批量嵌入,再并发地对 collection 检索;
- 去重:按
(document_id, chunk_index)去重,保留每条记录的最高分; - 截断:按分数降序排序后截断为
top_k。
VectorSearchResult 数组,每条记录包含 score、document_id 与命中 chunk。
文档管理
KnowledgeBase 暴露了文档级别的两个辅助方法:
DocumentSummary 包含 document_id、原始文件名 source、chunk_count,以及由解析器/上传方写入第一条 chunk 的 metadata。
多租户隔离:metadata_filter
如果多个逻辑知识库需要共用同一个物理 collection,可以在构造 KnowledgeBase 时传入 metadata_filter(典型场景:每条记录都带一个 {"tenant_id": "..."} payload):
metadata_filter 是深度防御机制:
search与list_documents严格按这些key == value过滤记录——永远跨不出当前作用域;insert_document会强制覆盖每个 chunk 的同名 metadata 字段,从而即使解析器/调用方误写也不会让记录跨域泄漏。
None(默认值)表示禁用过滤,对应”每个知识库独占自己的 collection”的部署形态。
多模态支持
AgentScope 的 RAG 原生支持多模态数据的入库与检索,关键在于解析器与嵌入模型能力的匹配——前者要能把多模态文件解析成DataBlock,后者要能直接对 DataBlock 做嵌入:
-
查看 Parser 支持的文件类型:每个
ParserBase子类通过类属性supported_media_types(IANA 媒体类型列表)声明能力,可直接读取或在 IDE 中自动补全。 -
查看嵌入模型支持的模态:通过实例属性
embedding_model.supports_multimodal判断模型是否能直接处理DataBlock(图片 / 视频 / 音频)。
Chunk、且 embedding_model.supports_multimodal == True 时,入库与检索链路无需额外配置即可工作。文本模型遇到 DataBlock 查询时会在 KnowledgeBase.search 内部被静默丢弃,不会报错。
集成到智能体
通过RAGMiddleware 把检索接入智能体类 Agent 的推理-行动循环。中间件不拥有嵌入模型或向量库——它消费的是一组已经构造好的 KnowledgeBase 句柄,可以混合多个使用不同嵌入模型的知识库。
RAGMiddleware 支持两种工作模式(RAGMiddleware.Parameters.mode),可以单独使用,也可以叠加使用(同时挂两个不同 mode 的实例):
参数全部封装在嵌套的
RAGMiddleware.Parameters 模型中:
此外,
RAGMiddleware.list_tools() 在 agentic 模式下会返回一个 search_knowledge 工具——需要手动把它注册到智能体的 Toolkit 里,模型才能调用。该工具的描述里会自动列出已挂载的所有知识库的 name / description,模型也可以通过 knowledge_bases=[...] 参数把搜索限定到指定子集。
通过如下代码给智能体实例配置 RAG 功能:
自定义拓展
RAG 的所有模块都采用基类继承的方式,用户可以自定义 Parser、Chunker、Embedding Model、Vector Store——只要继承对应基类、实现核心方法,就能被无缝接入上面的流水线。自定义解析器
继承ParserBase,在类属性 supported_media_types 中声明能处理的 IANA 媒体类型,并实现 async def parse(file, filename) 把字节流拆成若干 Section:
supported_extensions()(默认由 supported_media_types 反查得到;如果你的解析器希望前端文件选择器只展示某几个扩展名,建议显式覆盖)。
自定义切块器
继承ChunkerBase,实现 async def chunk(sections) 把若干 Section 切成入库的 Chunk。约定:不跨 Section 合并;多模态 DataBlock 整块透传;chunk_index 在结果内从 0 连续编号;total_chunks 在每个 chunk 上一致:
自定义向量数据库
继承VectorStoreBase,实现 create_collection / delete_collection / has_collection / insert / delete / search / list_documents,并通过 __aenter__ / __aexit__ 管理底层连接的生命周期:
delete按document_id删除该文档的所有记录,调用方按文档为单位增删。search/list_documents必须把metadata_filter翻译成对应后端的 payload filter,以支持多租户隔离。insert时需要把VectorRecord.document_id与chunk都持久化下来——否则delete与list_documents都无法工作。
延伸阅读
RAG 服务
多租户、分布式的 RAG 服务,支持 HTTP API、文件托管、向量数据库托管。
中间件
了解
RAGMiddleware 是如何嵌入 reply / reasoning 钩子的。嵌入模型
可用的嵌入模型及其参数。