【AgentScope Java新手村系列】(16)从RAG到多路检索

简介: 从 RAG 到多路检索:废弃内置 RAG 管道,改用 subagent grep/read 查文件 + 自定义 @Tool 调向量库,两条路线互补,LLM 自主选路。

第十六章 从 RAG 到多路检索:subagent 查文件,向量工具查语义

1.x 的 SimpleRAGKnowledgeBgeRAGKnowledgeEmbeddingRAGKnowledge 等 RAG 实现类在 RC2 中已被移除(它们是 1.x 特有的 API,2.0 中不存在)。

原因:传统 RAG 抽象把"文档分块 + 嵌入 + 检索"做成黑盒。2.0 改为"subagent + 文件检索 + Skill 仓库":业务方把文档放 ./docs 目录里,subagent 用 grep_files 按关键词搜文件、用 read_file 读原文内容,不切片、不嵌入。LLM 自己决定搜什么词、读哪段,比硬编码检索管道灵活得多。

本章先给出 1.x 旧 API 的最小示例(仅供维护老项目参考),再讲 2.0 推荐的新做法。

16.1 1.x RAG 旧 API 回顾

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 是一条固定管道

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

这条管道有三个问题:

问题 影响
黑盒检索 向量相似度 ≠ 语义相关。搜出来的切片可能"看起来像但内容不相关",你没地方 debug
管道路径固定 先切片、再嵌入、再搜索。LLM 全程不参与检索决策,搜什么、怎么搜全由管道定
依赖外部组件 需要 embedding 模型(DashScope/Qwen Embedding)+ 向量库(Milvus/Pinecone),多两个微服务

2.0 怎么做?

把检索权交给 LLM。agent 自带 grep_files(关键词搜索)和 read_file(读文件),LLM 自己决定搜什么关键词、读哪个文件、读多少内容。不切片、不嵌入、不向量库。

2.0 工作流:
用户提问 → LLM 自己决定用什么关键词 grep → 自己读相关文件 → 自己综合答案

对比一下:

1.x RAG 2.0 subagent + 文件检索
检索决策者 管道(程序) LLM(agent)
检索方式 向量相似度 grep_files 关键词 + read_file 精读
外部依赖 embedding 模型 + 向量库 无,全是 agent 内置工具
可调试性 差(你不知道为啥搜到这个切片) 好(agent 日志里能看到 grep 了什么、读了什么)
灵活性 固定管道 LLM 可以分步检索:先 grep 找文件名 → 再 read 读内容 → 不够再 grep 扩大范围

核心思想:与其让程序猜"哪段和用户问题最像",不如让 LLM 自己想"我应该搜什么词、读哪个文件"。HarnessAgent 自带 read_file / grep_files / glob_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,后者用 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);
}

把工具注册到 agent / subagent 即可。这就是 2.0 推荐的"该用什么工具就用什么工具",不必拘泥于 RAGKnowledge 抽象。

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

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

核心变化:1.x 的 RAG 是框架内置管道(你只管配参数)。2.0 框架不再内置分块/嵌入/向量搜索,但你可以用 @Tool 自由实现任意检索逻辑。检索决策从管道转移到 LLM。

16.6 完整可运行示例

这个例子在演示什么?

一个 QA agent 配了两种检索方式,LLM 根据问题类型自己决定用哪个:

  • doc_reader subagent:用内置 grep_files + read_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 自由实现即可。
目录
相关文章
|
3月前
|
前端开发 安全 中间件
【AgentScope Java新手村系列】(14)人机交互
人机交互 — Permission 系统五种模式配合 ALLOW/DENY/ASK 规则,运行时 HITL 自动拦截与决策收集。
559 6
【AgentScope Java新手村系列】(14)人机交互
|
3月前
|
Java 中间件 API
【AgentScope Java新手村系列】(10)实战-多Agent天气助手
实战-多Agent天气助手 — 文件驱动 subagent 实战,主 agent 自主编排天气查询、航班搜索、景点推荐三个子任务并行调研。
726 1
|
前端开发 Java 中间件
【AgentScope Java新手村系列】(3)工具系统
工具系统 — @Tool/@ToolParam 注解将 Java 方法注册为 Agent 能力,自主决定调用时机,支持同步/异步返回。
601 0
|
3月前
|
SQL JSON Java
【AgentScope Java新手村系列】(15)MCP协议工具
MCP协议工具 — tools.json 一行声明一个 MCP server,支持 stdio/sse/ws 协议,McpMeta 传递调用元数据。
558 1
|
3月前
|
自然语言处理 Java API
【AgentScope Java新手村系列】(7)子Agent编排
子Agent编排 — SubagentDeclaration 描述子 agent,主 agent 通过 agent_spawn 工具同步/异步委派子任务。
801 0
|
2月前
|
Java 关系型数据库 MySQL
【AgentScope Java新手村系列】(18)Skills技能系统
用 SKILL.md 文件定义可复用技能,HarnessAgent 自动扫描匹配,智能体按需调用。
500 0
|
3月前
|
JSON Java 中间件
【AgentScope Java新手村系列】(13)工具分组
工具分组 — Toolkit 注册全量工具,ToolsConfig 按 allow/deny 精确匹配过滤,同一套工具两个角色两个视野。
427 2
|
2月前
|
中间件 Java API
【AgentScope Java新手村系列】(17)长期记忆系统
长期记忆 — 废弃 LongTermMemory,改用 MEMORY.md + Compaction 压缩 + MemoryFlush 冲刷 + @Tool 主动写。三层机制互补,框架自动维护,业务方按需定制。
525 0
|
前端开发 NoSQL Java
【AgentScope Java新手村系列】(2)第一个Agent-基础对话
第一个Agent-基础对话 — 演示 HarnessAgent 的 Builder 模式创建、ReAct 推理循环、流式事件与思考模式三个核心能力。
984 2
|
JSON 自然语言处理 Java
【AgentScope Java新手村系列】(4)结构化输出
结构化输出 — JSON Schema 约束 LLM 输出格式,直接反序列化为 Java POJO,打通文本到对象的转换。
599 0

热门文章

最新文章