16.1 1.x RAG 旧 API 回顾java代码解读复制代码import io.agentscope.core.rag.SimpleRAGKnowledge; import io.agentscope.core.rag.Knowledge; import io.agentscope.core.rag.loader.LocalFileLoader; import io.agentscope.core.ReActAgent; import io.agentscope.core.model.DashScopeChatModel; public class Chapter16_LegacyRag { public static void main(String[] args) { // 1. 准备知识库 Knowledge knowledge new SimpleRAGKnowledge( new LocalFileLoader(./docs), new DashScopeEmbeddingModel()); // 2. agent 装上 knowledge ReActAgent agent ReActAgent.builder() .name(doc_qa) .sysPrompt(你是文档问答助手。) .model(DashScopeChatModel.builder() .apiKey(System.getenv(DASHSCOPE_API_KEY)) .modelName(qwen-plus) .build()) .knowledge(knowledge) // 1.x .build(); // 3. 调用时 agent 内部会先 retrieve 再回答 } }2.0 仍可编译ReActAgent.knowledge(...)在 RC2 中标记为Deprecated(forRemoval true)编译通过但会告警。新项目请不要使用。16.2 2.0 推荐的subagent 文件检索为什么不用 1.x 的 RAG 了1.x 的 RAG 是一条固定管道css代码解读复制代码文档 → 切片 → 嵌入向量化 → 存向量库 ↓ 用户提问 → 同样嵌入 → 余弦相似度搜索 → 取 top-k 切片 → 拼进 prompt → LLM 回答这条管道有三个问题问题影响黑盒检索向量相似度 ≠ 语义相关。搜出来的切片可能看起来像但内容不相关你没地方 debug管道路径固定先切片、再嵌入、再搜索。LLM 全程不参与检索决策搜什么、怎么搜全由管道定依赖外部组件需要 embedding 模型DashScope/Qwen Embedding 向量库Milvus/Pinecone多两个微服务2.0 怎么做把检索权交给 LLM。agent 自带grep_files关键词搜索和read_file读文件LLM 自己决定搜什么关键词、读哪个文件、读多少内容。不切片、不嵌入、不向量库。perl代码解读复制代码2.0 工作流 用户提问 → LLM 自己决定用什么关键词 grep → 自己读相关文件 → 自己综合答案对比一下1.x RAG2.0 subagent 文件检索检索决策者管道程序LLMagent检索方式向量相似度grep_files关键词 read_file精读外部依赖embedding 模型 向量库无全是 agent 内置工具可调试性差你不知道为啥搜到这个切片好agent 日志里能看到 grep 了什么、读了什么灵活性固定管道LLM 可以分步检索先 grep 找文件名 → 再 read 读内容 → 不够再 grep 扩大范围核心思想与其让程序猜哪段和用户问题最像不如让 LLM 自己想我应该搜什么词、读哪个文件。HarnessAgent自带read_file/grep_files/glob_files三个内置工具subagent 可以直接用它们typescript代码解读复制代码import io.agentscope.harness.agent.subagent.SubagentDeclaration; import io.agentscope.harness.HarnessAgent; public class Chapter16_NewRag { public static void main(String[] args) { // 文档检索 subagent用 grep_files read_file 代替传统向量检索 SubagentDeclaration docReader SubagentDeclaration.builder() .name(doc_reader) .description( 文档检索 subagent。 拿到问题后 1. 先用 grep_files 在 ./docs 找关键词 2. 用 read_file 读最相关的 1-2 个文件 3. 综合内容回答 ) // LLM 根据 description 决定何时 spawn 它 .inlineAgentsBody(你是一个文档检索员 只用 read_file / grep_files 找答案。) // subagent 自己的系统提示词 .build(); HarnessAgent host HarnessAgent.builder() .name(qa) .sysPrompt(你是问答助理需要查文档时 spawn doc_reader。) .model(model()) .workspace(Path.of(./workspace)) .subagent(docReader) // 注册 subagent .build(); } }跑host.call(...)时LLM 看到用户的问题含文档会主动 spawndoc_reader后者用 grep read 自己决定查什么。16.3 进阶用 Skill 仓库做结构化 RAG如果文档量很大、希望按主题切分可以直接把每份文档做成一个Skill详见第 18 章objectivec代码解读复制代码workspace/ └── skills/ ├── product-faq/ │ └── SKILL.md ├── engineering-handbook/ │ └── SKILL.md └── legal-policies/ └── SKILL.md每份SKILL.md描述这个 skill 解决什么问题makefile代码解读复制代码# product-faq/SKILL.md name: product-faq description: | 产品 FAQ当用户问如何退款 / 如何开发票 / 如何修改地址时优先用。 allowed-tools: [read_file, grep_files]主 agent 在 prompt 里被告知先看 SKILL.md 决定用哪个 skill。LLM 按 description 路由到对应 skill再读 SKILL.md 里手动维护的文档链接。这种方式优势路由可读产品经理也能改SKILL.md调整路由token 省一次只载入相关 skill 的元信息不一次性塞进 prompt可管理文档更新时只改对应 skill 的内容16.4 何时仍用真正的嵌入 向量检索如果你的检索需求满足下面任一条件仍可保留传统 RAG文档量 10 万条subagent 用 grep_files 检索太慢检索要求语义相似用户写心情不好要找到沮丧段需要 hybrid search同时跑 BM25 和向量搜索把两边的结果按权重凑成一份最终排名此时推荐在 2.0 中手写一个Toolless代码解读复制代码Tool(name vector_search, description 向量检索) public String vectorSearch( ToolParam(name query) String query, ToolParam(name topK, required false) Integer topK) { // 调你自己的向量库Milvus / Elasticsearch / PGVector return vectorStore.search(query, topK null ? 5 : topK); }把工具注册到 agent / subagent 即可。这就是 2.0 推荐的该用什么工具就用什么工具不必拘泥于RAGKnowledge抽象。16.5 最小迁移清单1.x RAG → 2.01.x 你做了什么2.0 怎么做调RAGKnowledge.retrieve(...)自动检索subagent 用内置grep_filesread_file检索用SimpleRAGKnowledge等内置分块嵌入框架已去掉内置管道。如需嵌入自己写Tool调向量库配置分块策略、嵌入模型在自定义Tool里自由实现框架不再限制agent.knowledge(knowledge).subagent(retriever)或.toolkit(toolkit)agent.call(..., retrieverknowledge)拆成 subagent 工具LLM 自主决定何时检索核心变化1.x 的 RAG 是框架内置管道你只管配参数。2.0 框架不再内置分块/嵌入/向量搜索但你可以用Tool自由实现任意检索逻辑。检索决策从管道转移到 LLM。16.6 完整可运行示例这个例子在演示什么一个 QA agent 配了两种检索方式LLM 根据问题类型自己决定用哪个doc_readersubagent用内置grep_filesread_file在./docs目录做文件级关键词检索。适合退货政策是什么怎么开发票这类事实性问题零外部依赖。vector_search工具调 Milvus/ES 做语义级向量检索。适合用户写心情不好要找沮丧相关文档这类模糊匹配。这不是冗余是互补subagent 查文件快但只能精确匹配向量检索慢但能理解语义。LLM 看到问题类型后自己选路事实问题 spawn subagent模糊问题调 vector_search。两个可以共存于同一个 agent。typescript代码解读复制代码public class Chapter16_Full { public static void main(String[] args) { // 文件检索 subagent用内置工具不额外写 Java 代码 SubagentDeclaration docReader SubagentDeclaration.builder() .name(doc_reader) .description(文档检索输入问题输出从 ./docs 找出的相关段落) .inlineAgentsBody( 你是一个文档检索员。 1. 用 grep_files 在 ./docs 下找关键词 2. 用 read_file 读最相关 2 份文件 3. 把内容整理成 200 字以内回答 ) .build(); // 语义检索工具业务方自己接向量库可选 Toolkit toolkit new Toolkit(); toolkit.registerTool(new VectorSearchTool(http://localhost:19530)); HarnessAgent host HarnessAgent.builder() .name(qa) .sysPrompt( 你是问答助理。 优先 spawn doc_reader 查本地文档如果用户问模糊的语义类问题调 vector_search 工具。 ) .model(model()) .workspace(Path.of(./workspace)) .subagent(docReader) // 文件检索关键词 .toolkit(toolkit) // 向量检索语义 .build(); // 事实性问题 → LLM 会 spawn doc_reader host.call( List.of(new UserMessage(user, 退款政策是什么)), RuntimeContext.empty()) .block(); // 模糊问题 → LLM 会调 vector_search host.call( List.of(new UserMessage(user, 有哪些和用户不满意相关的政策)), RuntimeContext.empty()) .block(); } }16.7 本章小结1.xRAGKnowledge在 2.0 中被标记为弃用未来会移除。2.0 推荐subagent 文件检索或业务方手写向量检索Tool。大量结构化文档可以做成 Skill 仓库用 description 做路由。真正需要嵌入 向量库时业务方用Tool自由实现即可。