位置:首页 > 进阶教程 > AgentScope Java新手村16 从RAG到多路检索

AgentScope Java新手村16 从RAG到多路检索

时间:2026-07-25  |  作者:318050  |  阅读:0

很多朋友可能已经注意到了,AgentScope 2.0 在某些核心设计上来了个大转弯。尤其是在知识检索这块,曾经大家熟悉的 SimpleRAGKnowledgeBgeRAGKnowledge 这些 1.x 的 API,在最新的 RC2 版本中已经被正式标记为“过去式”了。

为什么要把看似成熟、好用的“文档分块-嵌入-检索”黑盒管道拿掉?简单来说,框架的思路变了。1.x 把这件事做成了一个固定的、你只管配置参数的“体质”。而 2.0 的思路更激进:把检索的决策权,真正交还给大模型(LLM)本身

新方案把“检索”拆解成“subagent + 文件检索 + Skill 仓库”。

你的文档不再需要切片、向量化,直接放在 ./docs 目录里就行。Subagent 可以像人一样,用 grep_files 搜关键词找文件,再用 read_file 读原文。搜什么词、读哪段,都由 LLM 自己权衡,这比硬编码一个检索管道要灵活得多。

为了更好地承接与迁移,本章我们先回顾一下 1.x 的旧 API 作为参考(主要是为了维护老项目的同学),然后详细展开 2.0 推荐的新做法。

16.1 1.x RAG 旧 API 回顾

先看一个 1.x 的典型用法,算是留个念想:

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(...) 方法上已经被标记了 @Deprecated(forRemoval = true),编译会告警。所以,新项目就不要再走回头路了。

16.2 2.0 推荐的"subagent + 文件检索"

为什么不用 1.x 的 RAG 了?

我们掰开揉碎来看看 1.x 那条固定管道到底哪里别扭:

文档 → 切片 → 嵌入(向量化) → 存向量库
    ↓
用户提问 → 同样嵌入 → 余弦相似度搜索 → 取 top-k 切片 → 拼进 prompt → LLM 回答

这条路走下来,至少有三大痛点:

第一,黑盒检索,查无对症。 向量相似度高,不代表语义就相关。搜出来的片段可能“长得像”,但跟你的问题可能驴唇不对马嘴。最要命的是,你根本没地方去 debug 为什么它找到了这段,而不是那段。

第二,管道路径固定,模型是“局外人”。 怎么切片、怎么嵌入、怎么搜,都被管道定死了。LLM 在整个检索过程中就是个旁观者,完全没有参与决策。它只能被动接受喂到 prompt 里的东西。

第三,依赖的“外援”太多。 需要 Embedding 模型(比如 DashScope / Qwen Embedding),还得搭一个向量数据库(如 Milvus、Pinecone),凭空多了两个微服务需要维护,复杂度一下就上去了。

2.0 怎么做?

核心思路就是把“选择权”交还给 LLM。Agent 自带 grep_files(关键词搜索)和 read_file(读文件)两个利器,让 LLM 自己决定该搜什么关键词、该读哪个文件、该读多少内容。

整个工作流就变成了:

用户提问 → LLM 判断应该用什么关键词去 grep → 打开读相关文件 → 综合信息给出答案

对比之下,差距就非常明显了:

  • 检索决策者:1.x RAG — 管道(程序);2.0 subagent 文件检索 — LLM(agent)
  • 检索方式:1.x RAG — 向量相似度;2.0 subagent 文件检索 — grep_files 关键词搜索 + read_file 精读
  • 外部依赖:1.x RAG — Embedding 模型 + 向量库;2.0 subagent 文件检索 — 无,全依赖 agent 内置工具
  • 可调试性:1.x RAG — 差(不知道管道为什么找了那段);2.0 subagent 文件检索 — 好(agent 日志会显示 grep 了什么词、读了哪个文件)
  • 灵活性:1.x RAG — 固定管道,一成不变;2.0 subagent 文件检索 — LLM 可以自主分步:先 grep 找文件名 → 再 read 读内容 → 线索不够再 grep 扩大范围

这个思想的本质就是:与其让程序去猜“哪段文本和用户问题长得最像”,不如让 LLM 自己去想“我应该搜什么词、读哪个文件”。

在代码实现上,HarnessAgent 已经自带了 read_filegrep_filesglob_files 三个内置工具。Subagent 可以直接使用它们:

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 看到用户问题里带有“文档”字眼,就会主动 spawn 刚刚注册的 doc_reader subagent,后者再用 grep 和 read 工具自己决定怎么查。

16.3 进阶:用 Skill 仓库做"结构化 RAG"

如果你的文档量很大,并且希望按照主题进行“切分和管理”,直接把每份文档做成一个 Skill 是更明智的做法(具体可参考第 18 章)。你的目录结构会是这样的:

workspace/
└── skills/
    ├── product-faq/
    │   └── SKILL.md
    ├── engineering-handbook/
    │   └── SKILL.md
    └── legal-policies/
        └── SKILL.md

每个 SKILL.md 就像一份说明书,描述“这个 skill 是干什么的”:

# 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 框架推荐的做法是:自己手写一个 @Tool

@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);
}

写好这个普通 Java 工具,然后注册到你的 Agent 或 Subagent 里就行。这才是 2.0 框架推崇的核心理念:该用什么工具,就用什么工具,不必再拘泥于一个叫 RAGKnowledge 的抽象层。

16.5 最小迁移清单(1.x RAG → 2.0)

最后,如果你正在从 1.x 迁移过来,下面这张对照表应该能帮你快速找到“新路”:

  • 1.x:调 RAGKnowledge.retrieve(...) 自动检索 → 2.0:Subagent 用内置 grep_files + read_file 检索
  • 1.x:用 SimpleRAGKnowledge 等内置分块、嵌入 → 2.0:框架已去掉内置管道。如需嵌入,自己写 @Tool 调向量库
  • 1.x:配置分块策略、嵌入模型 → 2.0:在自定义 @Tool 里自由实现,框架不再限制
  • 1.x:agent.knowledge(knowledge) → 2.0:.subagent(retriever).toolkit(toolkit)
  • 1.x:agent.call(..., retriever=knowledge) → 2.0:拆成 subagent + 工具,LLM 自主决定何时检索

总结一下所有变化的根本:1.x 的 RAG 是框架内置的固定管道,你只需要配参数;而 2.0 框架不再内置具体实现,但给了你极大的自由。你可以用 @Tool 实现任意你想要的检索逻辑。检索的决策权,也从管道转移到了 LLM 手上。

16.6 完整可运行示例

为了让你有个更直观的感受,我们来看一个完整的例子。这个例子要展示什么?

一个 QA agent 配备了两种检索方式,LLM 会像“专家系统”一样,根据问题的类型自己决定用哪一种:

  • doc_reader subagent:使用内置的 grep_filesread_file,在 ./docs 目录下做文件级关键词检索。适合“退货政策是什么?”“怎么开发片?”这类事实性、精准的问答,零外部依赖。
  • vector_search 工具:调用后端的 Milvus/ES 服务,做语义级的向量检索。适合用户输入“心情不好”要找“沮丧相关文档”这类模糊、需要联想的问题。

这并非功能冗余,而是互补。Subagent 查文件快但只能精确匹配,向量检索慢但能理解语义。LLM 就像一个聪明的调度员,看到事实性问题就 spawn subagent,看到模糊问题就调 vector_search 工具。两者可以和谐地共存于同一个 agent 中。

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.x 的 RAGKnowledge 在 2.0 中已被标记为弃用,并将在未来版本中被移除。
  • 2.0 推荐的做法是 “subagent + 文件检索” 或是 “业务方手写向量检索 @Tool
  • 对于大量结构化的文档,可以设计成 Skill 仓库,利用其 description 来做智能路由,管理更方便。
  • 当真正需要用到嵌入和向量数据库时,完全可以通过 @Tool 自由实现,框架不再限制你的手脚。
AgentScope Java新手村16 从RAG到多路检索_wishdown.com

来源:整理自互联网
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多