Skip to content

在 AI 超级智能体项目中,你为什么要使用动态 RAG Advisor 工厂? ​

  • 标签:后端、编程导航

🏛 业务架构师 ​

我用动态 RAG Advisor 工厂的核心动机:不同业务域的知识库,检索策略参数天然不同,一套配置打天下必然次优。

真实场景:我的项目里同时有"公司制度库"(结构化强、术语精确、关键词过滤价值大)和"行业资讯库"(时效敏感、语义多样、多查询扩展收益高)——固定 Advisor 链在 A 库好用的参数(如激进的重写、强元数据过滤)到 B 库就是灾难(漏召回)。知识特征差异 → 检索策略差异,这是业务规律。

实现方式:工厂按"知识库标识/场景码"运行时组装 Advisor 链——每个知识库有自己的策略配置(是否多查询扩展、重写模板、topK、相似度阈值、元数据过滤规则、重排开关),配置驱动、热更新。

业务架构的三个收益:

  1. 新知识库接入成本降到"写配置":运营配置策略参数即可上线,不写代码不发包——AI 能力的运营化;
  2. 策略可独立调优:每个库用自己的评测集验证参数调整——不然 A 库调优把 B 库调坏,互相污染;
  3. 灰度与回滚:策略配置化后可按用户百分比灰度、出问题秒回滚——AI 检索策略也是生产变更,要有变更纪律。

一句话总结:动态工厂体现的架构思想是——把"策略"从代码里剥离成配置资产。RAG 的效果一半靠语料,一半靠策略运营;策略不能运营(写死在代码里)的 RAG 系统,上线之日就是效果冻结之时。

🏗 系统架构师 ​

动态 RAG Advisor 工厂解决的问题是:不同知识库/不同会话需要不同的检索策略,而调用链不能写死。

遇到的具体痛点:我有多套知识库(产品文档库、内部规章库、各租户私有库),策略各不相同——向量库不同(租户隔离)、TopK 与阈值不同、是否开启多查询/重写不同、元数据过滤条件不同(租户/密级)。如果 RAG 增强 Advisor 硬编码单例配置,每加一个库就要改代码发版。

我的实现(工厂 + 运行时装配):

java
public class RagAdvisorFactory {
    public Advisor create(RagConfig cfg) {
        var builder = QuestionAnswerAdvisor.builder(cfg.getVectorStore())
            .searchRequest(cfg.toSearchRequest())   // TopK/阈值/过滤表达式
            .promptTemplate(cfg.getPromptTemplate());
        if (cfg.isMultiQuery())  builder.advisors(multiQueryAdvisor);
        if (cfg.isRewrite())     builder.advisors(rewriteAdvisor);
        if (cfg.getContextEnhance()) builder.advisors(contextAdvisor);
        return builder.build();
    }
}

配置存数据库/配置中心(按知识库/租户维度),会话初始化时工厂按配置动态装配 Advisor 链(带本地缓存避免重复构建)。

架构价值:

  • 策略与配置分离:检索策略调优(K 值、开关)不用发版,运营可调;
  • 租户隔离:每个租户的 VectorStore 指向与过滤条件随配置注入,数据边界由工厂保证;
  • 开闭原则落地:新检索优化(重排序、混合检索)做成 Advisor 注册进工厂即可组合。

一句话:把 RAG 从"写死的增强"变成"可配置组合的能力链",这是智能体层多租户化的基础设计。

💻 全栈开发专家 ​

背景:项目里有多个知识库(产品手册、制度文档、技术 wiki),不同用户/场景能用的知识库、检索参数(topK、相似度阈值)、advisor 组合都不一样。最初写死一个 RAG Advisor,每加一种场景就改代码发版——所以做成工厂 + 配置驱动。

实现:运行时按配置组装 Advisor 链:

java
@Component
public class RagAdvisorFactory {
    private final Map<String, VectorStore> stores;        // 多个知识库

    public QuestionAnswerAdvisor create(RagConfig cfg) {
        SearchRequest search = SearchRequest.builder()
            .topK(cfg.getTopK())                          // 场景化参数
            .similarityThreshold(cfg.getThreshold())      // 相似度阈值
            .filterExpression(cfg.getFilter())            // 元数据过滤(权限/分类)
            .build();
        return new QuestionAnswerAdvisor(
            stores.get(cfg.getVectorStore()), search, promptTemplate);
    }
}

// 业务侧:按请求动态构建(配置来自 DB/配置中心,可热更)
ChatClient client = baseClient.mutate()
    .defaultAdvisors(memoryAdvisor, ragFactory.create(cfg))
    .build();

收益(它解决了什么):

  1. 新增知识库零代码:运营在后台配 vectorStore/filter/参数即可上线;
  2. A/B 与调参不重启:topK、阈值在线调整,配合评估集快速迭代;
  3. 权限隔离:filter 按用户部门动态生成,知识库级别的越权访问被结构性挡住;
  4. 职责收敛:RAG 相关的所有变化点收口在一个工厂,排查链路清晰。

踩坑:Advisor 实例非线程安全的部分要每次新建(工厂每次 create 而不是缓存单例);配置变更要刷新缓存并留痕(谁改的、改了什么)。