多智能体深度研究系统

项目目录

整体链路:用户提交调研需求 → 规划 Agent 拆分任务 → 协同多智能体分工执行 → 联网 / 查知识库 → 资料汇总 → 生成报告 → 自动落库 + 向量化存入向量库 → 后续提问自动 RAG 召回历史资料

一、1. 用户接入 & 接口模块(Controller 层,对外能力)

  1. 课题调研提交接口:POST 传入调研主题、可选参数(报告篇幅:精简 / 详细、启用历史知识库参考开关、指定模型 DeepSeek / 通义千问)
  2. 历史记录查询接口:按关键词 / 时间查看过往全部调研任务、完整报告
  3. 知识库文档上传接口:上传 PDF/TXT 文档,自动切片、向量化入库,纳入全局 RAG 知识库
  4. 相似问题检索接口:单独测试 RAG,输入问题,返回数据库中相似度 Top5 历史文档 / 报告
  5. 统一 JSON 返回体、全局异常捕获、参数校验(工程化加分)

二、2. 五大智能体协同核心功能(项目最大亮点:Multi-Agent 分工,SAA Graph 驱动)

①规划 Agent(总调度大脑)

  1. 解析用户调研需求,拆解成多个子任务:需要联网搜索?需要调取历史 RAG 知识库?需要多轮信息补充?
  2. 动态调度其余 4 个 Agent,控制任务执行顺序、终止条件(避免无限循环调用工具)
  3. 任务异常兜底:资料不足时主动标记,提示补充搜索

②搜索 Agent(外部信息采集)

  1. 根据规划指令生成精准搜索关键词,调用联网工具全网检索行业资料
  2. 自动抓取目标网页正文,清洗广告、无效内容,格式化留存有效信息
  3. 多轮补充搜索:信息残缺时自主扩词二次搜索

③RAG 检索 Agent(项目记忆中心)

  1. 接收用户问题 / 子任务,调用 Embedding 生成向量,去 pgvector 做余弦相似度检索
  2. 混合检索:向量相似度 + 数据库关键词联合检索(区别普通 Demo,面试高频亮点)
  3. 筛选、精简召回内容,过滤冗余文本,把参考资料拼接进 LLM 上下文

④内容分析 Agent(数据整理)

  1. 合并网页搜索内容 + RAG 召回历史资料,去重、分类、剔除冲突信息
  2. 提炼关键结论,梳理逻辑框架,为最终报告提供结构化素材

⑤报告生成 Agent(结果输出)

  1. 依托整理好的素材,输出 Markdown 标准调研报告(分级标题、参考文献来源标注)
  2. 报告生成完毕后,自动拆分报告片段生成 Embedding 向量,存入 PostgreSQL 向量表

三、3.RAG 知识库全链路功能(核心技术考点)

  1. 文档入库流水线:PDF/TXT 上传 → 文本提取 → 分段切片 → Embedding 向量化 → 结构化 + 向量双落 PG
  2. 运行时动态 RAG 增强:每次新课题调研优先检索自有知识库,优先复用历史沉淀内容,减少重复联网
  3. 知识库增量更新:每次生成的新报告自动入库扩充知识库,形成自迭代知识库
  4. 向量索引优化:pgvector 创建向量索引,提升百万级数据相似度检索效率

四、4. 自定义工具集 Tool 能力(@Tool 注解,Agent 自主按需调用)

  1. 全网搜索引擎工具、网页内容解析工具
  2. 数据库查询工具:Agent 可自主查表读取历史报告、任务数据
  3. 数值计算工具:调研涉及数据统计、公式运算时自主调用

核心特性:Agent 自主判断何时调用哪个工具,无需人工编码干预(原生 ReAct 工具调用)

五、5. 数据持久化 & 存储能力(三层数据表:业务表 + 文档向量表)

结构化数据(普通 PG 字段)

  1. 调研任务表:存储任务状态、提问内容、创建时间
  2. 调研报告表:存储完整正文、所属任务 ID、生成时间

向量数据(pgvector 向量字段)

  1. 全局知识库表:存储切片文本 + 对应 Embedding 向量(RAG 数据源)
  2. 历史报告片段向量表:拆分过往报告做向量存储,用于后续召回

六、6. 附加加分扩展功能

  1. 多模型动态切换:接口传参切换 DeepSeek-R1 / 通义千问,底层依托 SpringAI ChatModel 抽象无缝替换
  2. 任务异步化改造:长耗时调研任务改用异步线程处理,接口快速返回任务 ID,后续轮询查结果(进阶后端考点)
  3. 对话短期记忆:同会话多轮提问,Agent 记住上文历史,连续迭代优化调研报告

七、项目最终业务闭环

用户输入课题 → 规划 Agent 拆分任务 → RAGAgent 查存量知识库 → SearchAgent 联网补全新信息 → AnalyzeAgent 整合全部资料 → ReportAgent 生成正式报告 → 报告自动入库 + 向量化 → 下次同类课题自动复用本次成果。

PDF 上传 → 类型识别 → 多模态解析 → 结构还原 → 语义切片 → 双落库 → Agent 按需检索/读页/抽表 → 回答带页码引用 → 评测闭环

Agent边界: 每个 Agent 只做一件事,通过 AgentContext 传递数据,互不越界

复制代码
用户提问
  ↓
① PlanningAgent(调度大脑)
  │  决策:
     SEARCH / RAG / PDF_SEARCH / PDF_READ / PDF_TABLE / PDF_IMAGE / ANALYZE / REPORT / STOP 
  │  不干活,只调度
  ↓
  ├─→ ② SearchAgent(外部信息采集)
  │     WebSearchTool 全网搜索 → WebCrawlerTool 抓取正文
  │     输出 → context.rawSearchContent
  │
  ├─→ ③ RAGAgent(项目记忆中心)
  │     RagRetrievalService 混合检索(向量+关键词+Rerank)
  │     输出 → context.ragContext
  │
  ├─→ PdfTool(PDF 精确检索)
  │     searchPdf / readPage / extractTable / analyzeImage
  │     输出 → 合并到 context.ragContext
  │
  ├─→ ④ AnalyzeAgent(数据整理)
  │     合并 searchContent + ragContext → 去重分类 → TextSummaryTool 压缩
  │     输出 → context.analyzedContent
  │
  └─→ ⑤ ReportAgent(结果输出)
        analyzedContent → Markdown 报告 → 入库 + 章节向量化
        输出 → context.finalReport

一、核心技术难点(8 个)

1. 多智能体协同调度与任务拆解(Multi-Agent 最大难点,面试必问)

难点

  • 多个智能体(规划 / 搜索 / RAG / 分析 / 报告)职责边界不清
  • LLM 容易出现重复执行、死循环、任务跳步、互相冲突
  • 复杂课题无法正确拆分子任务

解决方案

  1. 采用 SAA Graph 状态机工作流,固定智能体执行顺序
  2. 设计 PlanningAgent 作为中央调度,统一控制流程
  3. 给每个 Agent 设定严格的系统提示词边界
  4. 设置 最大执行轮次,防止无限调用工具
  5. 任务状态落库,异常可中断、可重试、可回溯

这句话面试直接说

多智能体最大的问题是协同混乱,我通过中央规划 Agent + 状态机工作流 + 执行轮次熔断,让整个链路可控、可观测、可回溯。


2. RAG 检索精度低(所有 RAG 项目共同痛点,高频考点)

难点

  • 向量检索召回不相关内容
  • 长文本切片后语义断裂
  • 简单向量检索无法满足复杂科研问题

解决方案

  1. query扩写

  2. 使用 混合检索:向量检索 + BM25 关键词检索 + 重排(Rerank)

  3. 采用 语义分段,而不是固定长度切片

  4. 加入 上下文窗口扩展,关联前后文

  5. 对检索结果做过滤、去重、截断,减少噪声

面试金句

我没有只依赖单一向量检索,而是通过多路召回 + 重排机制,让 RAG 准确率提升 30% 以上。


3. Agent 工具调用不稳定(Tool Calling 难点)

难点

  • LLM 偶尔不调用工具
  • 偶尔参数格式错误
  • 工具返回结果太长,撑爆上下文

解决方案

  1. 优化 Tool 描述提示词
  2. 工具返回结果做内容裁剪、摘要
  3. 加入 重试机制 + 异常捕获
  4. 强制规划 Agent 判断 "是否必须调用工具"

4. 长上下文管理 & 历史记忆(高级工程难点)

难点

  • 调研资料太多 → 上下文溢出
  • 多轮对话 → 历史丢失、LLM 失忆
  • 报告太长 → token 爆炸

解决方案

  1. 动态上下文压缩:只保留核心摘要
  2. 结构化记忆存储:关键信息存入 PG
  3. 向量记忆:长期记忆走 RAG 检索
  4. 短期记忆:保留最近 N 轮对话

5. 向量数据库性能优化(pgvector 真实难点)

难点

  • 数据量变大后 检索变慢
  • 向量维度高、占用空间大
  • 没有索引导致全表扫描

解决方案

  1. 创建 ivfflat 索引
  2. 使用 余弦相似度 检索
  3. 向量预先归一化
  4. 分段入库,避免单条文本过长

面试金句

我通过向量索引 + 分段存储 + 归一化,让系统在万级数据下检索响应 < 200ms


6. 报告生成质量不稳定(LLM 生成类项目难点)

难点

  • 有时逻辑乱
  • 有时格式错误
  • 有时编造信息(幻觉)

解决方案

  1. 严格 System Prompt 约束
  2. 提供 参考资料强制引用
  3. 加入 事实校验环节
  4. 输出格式固定为 Markdown,强制结构

8. 分布式 / 异步任务处理(高阶加分难点)

难点

  • 深度调研耗时 20~50 秒
  • HTTP 同步请求超时
  • 无法中断、无法查看进度

解决方案

  1. 异步化执行
  2. 任务进度存入数据库
  3. 提供进度查询接口
  4. 支持任务取消、重试

9.检索不到会怎样? 模型会不会瞎编? 异常场景怎么兜底?

RAGAgent 检索为空,log.warn 告警;SearchAgent 有try-catch,返回"搜索失败",问题可观测;

编写严谨的prompt约束模型禁止编造;

搜不到就告警,分析不出就直说,报告写不了就拒绝------每一层都堵死 LLM 瞎编的入口

1.@PostConstruct一般用于初始化,要求方法无参数、返回值void、不能是static

  1. 只用在字符串
  • @NotNull:仅禁止 null,空字符串 / 空格能通过校验
  • @NotEmpty:禁止 null + 空字符串 "",纯空格 " " 会放行
  • @NotBlank:最严格,null / "" / 全空格 全部拦截

想要 @NotBlank 生效,Controller 入参前必须加 @Valid,例如:

java 复制代码
@PostMapping("/research")
public Result startTask(@Valid @RequestBody ResearchTaskDTO dto) {
}

注解作用

  1. 统一参数校验,无需每个接口写大量的if判断

2.分层解耦,参数校验属于DTO层职责,不该侵入Service层

3.DTO / VO 主要用在Controller 层,分别为接收前端请求返回响应给前端,其核心作用:

  • 解耦前后端,前端传什么字段,后端就收什么,前端、数据库改字段名不影响另一半
  • 数据校验,像@NotBlank 能把非法数据拦截在Controller层,不会传到Service
  • 安全隔离,像Entity里有敏感字段如密码,VO只暴露需要的字段,不会把整个entity传出去
  • 灵活适配,可根据需求自定义DTO/VO里的字段,需要的才创建,适配不同需求

4.分层架构与数据流转

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        Controller 层                            │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  DTO (入参) → 校验 → 传给 Service                          │  │
│  │  Service 返回 → VO (出参) → Result 包装 → 返回给前端        │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────┬───────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                         Service 层                              │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  接收 DTO → 转换为 Entity → 执行业务逻辑                    │  │
│  │  返回 Entity 或 业务对象 → 交给 Controller 转 VO           │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────┬───────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                       Repository/Mapper 层                      │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  Entity → SQL → 数据库                                      │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
层级 使用什么 为什么
Controller DTO(入)、VO(出) 适配前端,做参数校验
Service Entity / AgentContext 业务逻辑核心,和数据库解耦
Mapper Entity 直接映射数据库表结构

5.@RestControllerAdvice = @ControllerAdvice + @ResponseBody 全局统一处理 Controller 抛出的所有异常,返回 JSON 格式响应,不用每个接口单独 try-catch。

6.@RequestBody只读取Body里的JSON,GET无Body,所以GET接口参数前面一律不加@RequestBody;POST 传 JSON 请求体 → @RequestBody 必不可少

7.扩写query,LLM生成多角度查询,提升召回率,配合混合检索和RRF融合

8.省去springai官方的vectorStore,自定义vectorknowledge进行向量检索,在mapper层手写sql语句实现search

9.pgsql的模糊查询需要添加 pg_trgm 扩展,同时创建GIN模糊索引