核心架构设计

用户在输入框里敲了一句话,点了发送。看起来很简单,但在 Super Agent 内部,这条消息要经过一条远比你想象中复杂的链路,才能变成一个靠谱的回答。

先看整体流程,后面再逐块拆解每个环节的设计细节:

Fi0Q_mSxh3zRCAh_5orNt-Rbx0Dr-110dacf9

核心思路是:不是让 Agent 自己决定所有事情,而是先用确定性的编排逻辑做好决策,再把执行交给最合适的引擎。 知识问答走稳定的证据驱动生成,开放式问题才走 Agent 自由探索。

"确定性编排 + 场景化执行"是 Super Agent 区别于市面上其他 Agent 项目的根本设计哲学。大多数项目把所有问题都扔给一个 Agent 去处理,结果是不可控、不可解释。Super Agent 的做法是:能确定的事情先确定好,只把真正需要自主探索的部分交给 Agent

完整请求链路概述

一条用户消息从进入系统到返回回答,要经过以下核心阶段:

  • 会话记忆加载:从 MySQL 中加载历史对话记忆,按配置的策略(无记忆 / 滑动窗口 / 摘要压缩)组装上下文
  • 前置编排决策:LLM 分析用户意图,执行问题改写、路由判定、歧义检测、子问题拆分、知识域收缩五步决策
  • 执行器分发:根据编排结果选择最合适的执行器——歧义追问、RAG 知识问答或 ReAct Agent
  • 回答生成:执行器执行检索或推理,生成最终回答
  • SSE 流式输出:正文分片推送、引用来源补发、推荐追问问题生成
  • 会话记忆更新:将本轮对话持久化,触发摘要压缩(如需要)

整个链路中,每一步的输入输出、耗时、决策结果都有完整的 Trace 记录,出了问题可以精确定位到具体环节。

下面这张截图是对话观测中的会话链路面板,可以看到本次会话中每一轮问答的完整信息——执行模式(知识问答还是 Agent)、各阶段耗时、Token 消耗和费用,一目了然:

FsL1L_6oIy8WwKP877IvcN6At4p_-93a72246

Agent 这块是怎么设计的

面试中聊 Agent,面试官不想听你说"我用了 ReactAgent",他想听的是你对这些问题的思考:

  • 用户提了一个问题,系统是怎么决定用哪种方式来回答的? 不是让模型自己选,而是先经过路由判定、问题改写、歧义检测这一整轮编排,最后才决定走哪个执行器。判断顺序是:歧义澄清 > 知识问答 > 开放式 Agent
  • 为什么不是所有问题都走 Agent? 知识问答追求"稳"和"可解释",让 Agent 自己探索反而容易不可控。只有真正需要联网搜索、多步推理的开放式问题,才适合走 Agent
  • Agent 死循环了怎么办? 用 ModelCallLimitHook 限制单次运行最多调用模型 8 次,用 ToolCallLimitHook 限制 Tavily 搜索最多调 6 次。单个会话线程累计也有上限,分别是 40 次和 30 次
  • 联网搜索调用失败了怎么处理? ToolRetryInterceptor 做指数退避重试,最多重试 2 次,初始延迟 200ms,最大延迟 1200ms,带随机抖动。如果最终还是失败,ToolErrorInterceptor 做兜底,不让异常直接抛给用户
  • 对话状态怎么持久化? 用 Spring AI Alibaba 的 MysqlSaver 把 ReactAgent 的 Checkpoint 存到 MySQL,应用重启后能继续之前的对话
  • 并行工具执行怎么做? ReactAgent 配置了 parallelToolExecution,最多 4 个工具并行执行

这些设计在代码里都能找到对应实现,不是概念上的东西。

FkPkR-g8m2dD7DQxD6TC47896MLF-d909a90e

三层执行器:不是所有问题都该交给 Agent

知识问答追求"稳"和"可解释"——用户问"退款规则是什么",你需要的是从文档中精准检索证据,然后让模型基于证据生成回答。这种场景让 Agent 自己探索反而容易不可控,可能跑去联网搜索一堆无关内容。

而"今天北京天气怎么样"这种问题,知识库里根本没有答案,必须让 Agent 调用搜索工具去获取实时信息。

所以 Super Agent 设计了三层执行器,按场景精准分流:

执行器 触发条件 处理方式
歧义追问执行器 用户问题信息量不足,无法确定意图 生成澄清问题,引导用户补充信息
RAG 知识问答执行器 问题可以在知识库中找到答案 证据驱动生成,引用来源可追溯
ReAct Agent 执行器 需要联网搜索、多步推理的开放式问题 自主决策 + 工具调用 + 多轮推理循环

判断顺序是:歧义澄清 > 知识问答 > 开放式 Agent。优先用最稳定的方式回答,只有确实需要自由探索时才启动 Agent。

歧义优先是因为在信息不足时,任何回答都可能是错的,不如先问清楚。知识问答优先于 Agent 是因为知识库的回答可控、可解释、可追溯来源,而 Agent 的自由探索虽然能力更强,但不可预测性也更高。在企业级系统中,可控比聪明更重要。

Agent 安全机制详解

在生产环境中,Agent 的自主决策能力是一把双刃剑。如果不加控制,Agent 可能会陷入无限推理循环、过度消耗搜索资源,甚至因为工具调用异常导致整个会话崩溃。Super Agent 在这方面做了多层防护:

安全机制 配置参数 作用
单次模型调用上限 ModelCallLimitHook = 8 次 防止 Agent 单次请求陷入死循环
单次工具调用上限 ToolCallLimitHook = 6 次 防止搜索工具被过度调用
会话模型调用累计上限 40 次 / 线程 防止长对话累积消耗过多资源
会话工具调用累计上限 30 次 / 线程 控制整体工具使用成本
工具重试机制 最多 2 次,指数退避 200-1200ms 容忍短暂网络抖动
异常兜底 ToolErrorInterceptor 工具彻底失败时优雅降级,不影响主流程

在观测面板的轮次详情中,可以直观看到每一轮对话的模型使用情况:输入 Token、输出 Token、总 Token、费用估算,以及当前模型调用次数和工具调用次数相对于上限的使用进度。这些数据让资源消耗完全透明可控:

image-fd0273fb

前置编排器到底做了什么

前面说了系统不会把所有问题直接扔给模型,而是先做一轮完整的编排。它在每次对话中做的事情远比你想象的多:

路由判定

用户发进来的消息,首先要判断它属于哪种类型。是一个可以在知识库里找到答案的问题?还是需要联网搜索的开放式问题?还是信息不全需要先追问?这个判定不是靠关键词匹配,而是通过模型分析上下文后给出路由方向。

路由判定的本质是一次带结构化输出的 LLM 调用。系统会把用户的当前问题、最近几轮对话历史、以及知识库的元信息一起传给模型,让模型判断这个问题最适合走哪个执行器。这种方式比基于规则的路由更灵活,能处理各种模糊边界的情况。

问题改写

用户的问题往往不适合直接检索。比如"那它怎么配置?"——"它"指的是什么?得结合前几轮对话才知道。问题改写就是把这些省略的信息补回来,让检索能找到东西。

下面是观测面板中问题改写的实际效果。可以看到系统把用户的原始问题、结合对话历史改写后的完整问题、以及参考的历史上下文都记录了下来,改写前后的对比一目了然:

Fnt4UeGkIHnhs4a1p3KansJbIyrl-3cf77ce9

问题改写的典型场景:

原始问题 改写后 改写原因
那它怎么配置? MinIO 对象存储怎么配置? 指代消解,补全主语
还有其他方案吗? 除了向量检索,还有其他检索方案吗? 补全省略的上下文
怎么用? Spring AI 的 ChatClient 怎么使用? 结合前文话题补全完整问题

子问题拆分

"退款规则是什么?审批流程怎么走?"这种复合问题,如果直接拿去检索,两个意图互相干扰,效果很差。系统会拆成独立子问题,每个单独走检索链路,最后合并结果。单轮最多拆 4 个子问题,避免过度切碎。

意图解析与知识域收缩

拆完子问题后,还要分析每个子问题属于哪个知识域,把检索范围从"全库"缩小到"相关领域"。这一步直接影响检索的精准度和速度。

假设知识库里有"产品手册""开发文档""HR 制度"三个领域的文档。用户问"年假怎么申请",如果在全库范围内检索,可能会因为产品手册里也提到了"申请"这个词而引入噪声。知识域收缩会先判断这是 HR 相关问题,只在"HR 制度"领域内检索,大幅提升精准度。

歧义检测

如果用户的问题信息量不够,比如只说"查一下那个",系统不会硬着头皮去检索,而是先生成澄清问题让用户补充信息。这比返回一个不相关的答案体验好得多。

所有这些步骤完成后,编排器会产出一个 执行计划,里面包含执行多种执行编排模式、改写后的问题、拆分后的子问题列表、知识域范围等,交给对应的执行器去执行。

Fhlgtu1zQWc3WjPpTjHWxVcozK4S-e0922214

编排器的产出物:ConversationExecutionPlan

前置编排的最终产物是一个结构化的执行计划,包含以下关键信息:

字段 说明 示例
executionMode 执行模式 CLARIFY / RAG_CHAT / REACT_AGENT
rewrittenQuestion 改写后的完整问题 "MinIO 对象存储怎么配置连接参数?"
subQuestions 拆分后的子问题列表 ["退款规则是什么", "审批流程怎么走"]
knowledgeDomains 知识域范围 ["产品手册", "运维文档"]
clarifyQuestion 澄清问题(仅 CLARIFY 模式) "请问你想了解的是哪个产品的配置?"

这个执行计划是编排层和执行层之间的标准契约,执行器只需要根据计划执行,不需要关心编排过程的细节。这种解耦设计使得编排逻辑和执行逻辑可以独立演进。

检索链路到底有多细

很多人以为检索过程就是"查个向量库 + 让模型回答",但实际上中间的环节比想象中多得多。下面列的这些问题,在项目中都有对应的设计:

问题进来之后怎么处理?

  • 用户问"那它怎么配置?"这种省略了主语的追问,直接拿去检索什么都找不到。所以要先做问题改写,结合最近几轮历史把指代补全
  • 一个问题里问了两件事,比如"退款规则是什么?审批流程怎么走?",不能一股脑去检索。要拆成独立子问题,每个子问题单独走检索链路
  • 单轮最多拆 4 个子问题,避免过度切碎

检索是怎么做的?

  • 不是只用向量检索。用户问一个订单号、一个配置项名,向量检索很可能找不到。所以用了双通道并行:向量检索走 + 关键词检索
  • 两路结果分数量纲完全不同,不能直接比大小。用 RRF(Reciprocal Rank Fusion) 按排名倒数法融合
  • 向量通道设了最低相似度,关键词通道用相对阈值,低于阈值的弱命中直接过滤掉
  • 融合后可以接外部 Rerank 精排(支持 SiliconFlow 兼容协议),在较干净的候选集上继续优化排序
  • 检索粒度用 Child 小块保证命中率,回答阶段通过 Parent-Child 聚合提升到 Parent 大块,保证上下文完整性

证据够不够怎么判断?

  • 如果最终没有任何有效证据,直接短路返回,告诉用户"当前文档中没有检索到足够证据"。不让模型凭空编造,这是防止幻觉最直接的手段
  • 如果证据太多,有预算控制:单个子问题字符、全部证据总预算,单个父块最大字符。防止把模型上下文窗口吃满

最终怎么组装回答?

  • 按子问题边界分别组织证据,注入到 Prompt 里,模型按编号逐一回答
  • 要求模型在引用证据时标注来源编号 [1][2]
  • 答案通过 SSE 实时流式推送,结束时补发引用来源和推荐追问问题
Fs6IzbN7UwyMlHbl6EeLrs_PMnTL-6a1c2cfc

双通道并行检索

用户问一个订单号、一个配置项名,向量检索很可能找不到——语义相似度对精确匹配天然弱势。所以 Super Agent 用了双通道并行:向量检索 + 关键词检索,两路同时出发,互不阻塞。

两路结果的分数量纲完全不同,不能直接比大小。系统用 RRF(Reciprocal Rank Fusion) 按排名倒数法融合,向量通道设了最低相似度阈值,关键词通道用相对阈值,低于阈值的弱命中直接过滤。融合后还可以接外部 Rerank 精排,在较干净的候选集上继续优化排序。

RRF 的核心公式是:score = Σ 1/(k + rank_i),其中 k 是常数(通常为 60),rank_i 是文档在第 i 路检索结果中的排名。这个公式的巧妙之处在于:它不依赖原始分数的绝对值,只依赖排名,因此可以直接融合不同量纲的检索结果。一个文档如果在两路检索中排名都靠前,融合后的分数就会很高。

父子块聚合

这是整个检索链路中最精巧的设计之一。检索粒度用 Child 小块保证命中率——小块语义集中,更容易被向量检索命中。但回答阶段如果只用小块,上下文往往不完整。所以系统在命中 Child 块后,自动聚合提升到 Parent 大块,保证回答时有足够的上下文信息。

检索用小块保精度,回答用大块保完整性。 这个设计在业界也属于比较前沿的实践。

证据预算控制参数

参数 默认值 说明
单子问题证据上限 2,200 字符 防止单个子问题的证据过多
全部证据总预算 5,200 字符 控制注入 Prompt 的总证据量
单父块最大字符 2,200 字符 防止单个父块占用过多预算
向量检索最低相似度 0.45 过滤低质量向量匹配
关键词检索相对阈值 0.35 过滤弱命中的关键词结果

文档从上传到可检索经历了什么

很多项目的文档处理就是"切成固定长度 → 向量化 → 完事"。但实际上不同文档差异很大,一刀切的效果很难好。Super Agent 的文档处理是一条完整的异步流水线,每一步都有独立的状态追踪和任务日志:

Fn9VJM7B9KZZ2x4a1TqKKrZBrqxe-1a958111

第一步:上传和存储

文件上传到 MinIO 对象存储后,通过 Kafka 异步触发解析任务。Apache Tika 负责处理 PDF、Word、PPT 等多种格式,把五花八门的文档统一转成干净的文本。PDF 里的表格、扫描件、双栏排版——每一个都是坑,Tika 帮你踩过了。

并且可以配置 知识域编码知识域名称业务分类文档标签 等元信息,后续检索和分析都能用得上。

image-9d811ecc

第二步:异步解析和策略推荐

解析完成后,系统不是让用户盲选切块算法,而是根据文档类型和内容特征自动推荐最优的切块策略组合。用户可以查看推荐结果,也可以手动调整——比如文档质量不太好,可以额外开启 LLM 智能切块。

Fiu_x5T7ZoUfnnoLxCcveJ_7pKFv-dd31da61

第三步:组合式切块引擎

四种切块策略不是四选一,而是各司其职的组合流水线:

策略 角色 什么时候用
基于文档结构切块 主干 按标题/章节/段落切成语义完整的块
递归分块 兜底 结构块太大时继续往下裁剪,控制块大小
语义分块 优化 在结构切块基础上做边界精修
LLM 智能切块 增强 处理低质量文档和复杂文档,默认关闭

一句话:结构负责保留文档天然边界,递归负责控制块大小,语义负责优化块边界,大模型负责处理疑难场景。

一份包含标题层级的产品手册,系统会推荐:结构切块(主干)+ 递归分块(兜底)。如果这份文档的段落非常长且话题跳跃频繁,系统还会自动开启语义分块来优化边界。而对于一份扫描后 OCR 识别的低质量文档,可以手动开启 LLM 智能切块来增强效果。

Ful5rW11KmCFWv0Dwce6Tx9dHSWA-b6c4be14

第四步:向量化与双引擎索引

确认策略后,系统通过 Kafka 异步执行向量化和索引构建。向量写入向量数据库,关键词写入倒排索引数据库,构建双通道检索的基础。每一步都有独立的任务日志,出了问题能精确定位到哪一步失败。

FgOQcRirFAHOnRiToTuhjEBdleLL-5b081145

会话记忆:Token 成本和上下文完整性的博弈

20 轮对话全塞给模型?Token 成本扛不住。只带最近几轮?可能丢掉关键上下文。这是生产环境下绕不开的问题。

FqG_eDQ5RoZvAAbKhlUkmnBc6MfU-05f1eca2

项目中设计了三种策略:

  • 无记忆:每轮独立,不携带历史。适合一次性查询
  • 滑动窗口:保留最近 N 轮完整对话。适合短期连续追问
  • 摘要压缩:长期摘要 + 最近原文窗口。这是生产环境最推荐的方案

FulDFy2EFTJS_ynHuDXDmM7ilIAp-37c4f68c

摘要压缩的具体设计:

  • 最近 4 轮原文始终保留,不做压缩
  • 更早的历史增量摘要,单次最多推进 6 轮,避免一次处理超长历史
  • 最近原文窗口最大 2200 字符,长期摘要最大 1400 字符
  • 所有记忆数据持久化到 MySQL,应用重启不丢失

如果每次都对全部历史做摘要,随着对话越来越长,摘要的输入会越来越大,成本和延迟都会线性增长。增量摘要的做法是:每次只处理新增的几轮对话,把它们融合到已有的摘要中。这样不管对话多长,每次摘要的成本都是固定的。

三种策略的适用场景对比

策略 Token 成本 上下文完整性 适用场景
无记忆 最低 一次性查询、FAQ 问答
滑动窗口 中等 最近 N 轮完整 短期连续追问、调试场景
摘要压缩 可控 长期摘要 + 近期原文 生产环境长对话

MCP 工具协议与 Skills 能力扩展

Agent 的价值不只是能聊天,更在于能调用外部工具完成实际任务。Super Agent 在工具集成这块做了两层设计:

MCP 工具协议

MCP(Model Context Protocol)是 Anthropic 提出的开放协议标准,定义了模型与外部工具之间的通信规范。Super Agent 基于 MCP 协议实现了完整的工具调用链路:

  • 动态工具发现:Agent 启动时自动扫描并注册可用的 MCP 工具,不需要硬编码工具列表
  • 标准化通信:工具的输入输出遵循 MCP 协议规范,支持 Stdio 和 SSE 两种传输模式,兼容主流 MCP Server 生态
  • 参数自动提取:模型根据用户意图自动识别需要调用的工具并提取参数,无需用户手动指定
  • 多工具编排:单次对话中可以串联调用多个 MCP 工具,前一个工具的输出可以作为后一个工具的输入
  • 安全沙箱:工具调用在受控环境中执行,有超时限制和异常隔离,防止恶意工具影响主流程

相比传统的 Function Call 硬编码方式,MCP 协议的优势在于标准化和可扩展性——新增一个工具不需要改任何业务代码,只需要部署一个符合 MCP 协议的 Server 即可。

Skills 能力扩展

Skills 是比 MCP 更上层的能力抽象,解决的是"Agent 怎么获得特定领域的专业能力"这个问题:

  • 声明式定义:每个 Skill 通过 SKILL.md 配置文件描述能力边界、触发条件、执行逻辑,结构清晰易维护
  • 目录化管理:Skills 按领域组织成目录结构,支持嵌套分类,方便大规模能力管理
  • 自动加载机制:系统启动时自动扫描 Skills 目录,新增 Skill 只需要放入对应目录,零配置生效
  • 引用脚本与参考资料:Skill 可以关联外部脚本(Python、Shell 等)和参考文档,执行时自动加载上下文
  • 能力组合:多个 Skills 可以组合使用,Agent 根据任务需求自动选择最合适的 Skill 组合

Skills 体系让 Agent 的能力边界不再是固定的,而是可以持续扩展的。今天加一个"数据分析"Skill,明天加一个"代码审查"Skill,Agent 的能力就跟着增长,核心代码一行不用改。

info MCP 与 Skills 的关系 MCP 解决的是"工具怎么调"的问题——标准化工具的通信协议。Skills 解决的是"能力怎么扩"的问题——如何让 Agent 获得特定领域的专业知识和决策能力。两者互补:MCP 提供工具执行能力,Skills 提供领域知识和决策框架。一个 Skill 可以调用多个 MCP 工具来完成复杂任务。

全链路可观测:出了问题不用猜

前面讲了这么多环节,如果某一步出了问题怎么排查?Super Agent 基于 AOP 做了全链路追踪,每一轮对话的完整执行过程都能在观测面板中看到。

下面这张截图是轮次详情中的执行阶段时间线。可以看到一次对话请求经过了哪些阶段(会话记忆加载 → 问题改写 → 路由判定 → 结构图查询 → 推荐问题生成 → 收尾归档),每个阶段花了多长时间,关键决策结果是什么——整个链路一目了然:

image-dc988764

企业级项目导航:⬅️ 00-SuperAgent总览 | 01-核心架构设计 | ➡️ 02-工程化技术概括