项目目录
整体链路:用户提交调研需求 → 规划 Agent 拆分任务 → 协同多智能体分工执行 → 联网 / 查知识库 → 资料汇总 → 生成报告 → 自动落库 + 向量化存入向量库 → 后续提问自动 RAG 召回历史资料
一、1. 用户接入 & 接口模块(Controller 层,对外能力)
- 课题调研提交接口:POST 传入调研主题、可选参数(报告篇幅:精简 / 详细、启用历史知识库参考开关、指定模型 DeepSeek / 通义千问)
- 历史记录查询接口:按关键词 / 时间查看过往全部调研任务、完整报告
- 知识库文档上传接口:上传 PDF/TXT 文档,自动切片、向量化入库,纳入全局 RAG 知识库
- 相似问题检索接口:单独测试 RAG,输入问题,返回数据库中相似度 Top5 历史文档 / 报告
- 统一 JSON 返回体、全局异常捕获、参数校验(工程化加分)
二、2. 五大智能体协同核心功能(项目最大亮点:Multi-Agent 分工,SAA Graph 驱动)
①规划 Agent(总调度大脑)
- 解析用户调研需求,拆解成多个子任务:需要联网搜索?需要调取历史 RAG 知识库?需要多轮信息补充?
- 动态调度其余 4 个 Agent,控制任务执行顺序、终止条件(避免无限循环调用工具)
- 任务异常兜底:资料不足时主动标记,提示补充搜索
②搜索 Agent(外部信息采集)
- 根据规划指令生成精准搜索关键词,调用联网工具全网检索行业资料
- 自动抓取目标网页正文,清洗广告、无效内容,格式化留存有效信息
- 多轮补充搜索:信息残缺时自主扩词二次搜索
③RAG 检索 Agent(项目记忆中心)
- 接收用户问题 / 子任务,调用 Embedding 生成向量,去 pgvector 做余弦相似度检索
- 混合检索:向量相似度 + 数据库关键词联合检索(区别普通 Demo,面试高频亮点)
- 筛选、精简召回内容,过滤冗余文本,把参考资料拼接进 LLM 上下文
④内容分析 Agent(数据整理)
- 合并网页搜索内容 + RAG 召回历史资料,去重、分类、剔除冲突信息
- 提炼关键结论,梳理逻辑框架,为最终报告提供结构化素材
⑤报告生成 Agent(结果输出)
- 依托整理好的素材,输出 Markdown 标准调研报告(分级标题、参考文献来源标注)
- 报告生成完毕后,自动拆分报告片段生成 Embedding 向量,存入 PostgreSQL 向量表
三、3.RAG 知识库全链路功能(核心技术考点)
- 文档入库流水线:PDF/TXT 上传 → 文本提取 → 分段切片 → Embedding 向量化 → 结构化 + 向量双落 PG
- 运行时动态 RAG 增强:每次新课题调研优先检索自有知识库,优先复用历史沉淀内容,减少重复联网
- 知识库增量更新:每次生成的新报告自动入库扩充知识库,形成自迭代知识库
- 向量索引优化:pgvector 创建向量索引,提升百万级数据相似度检索效率
四、4. 自定义工具集 Tool 能力(@Tool 注解,Agent 自主按需调用)
- 全网搜索引擎工具、网页内容解析工具
- 数据库查询工具:Agent 可自主查表读取历史报告、任务数据
- 数值计算工具:调研涉及数据统计、公式运算时自主调用
核心特性:Agent 自主判断何时调用哪个工具,无需人工编码干预(原生 ReAct 工具调用)
五、5. 数据持久化 & 存储能力(三层数据表:业务表 + 文档向量表)
结构化数据(普通 PG 字段)
- 调研任务表:存储任务状态、提问内容、创建时间
- 调研报告表:存储完整正文、所属任务 ID、生成时间
向量数据(pgvector 向量字段)
- 全局知识库表:存储切片文本 + 对应 Embedding 向量(RAG 数据源)
- 历史报告片段向量表:拆分过往报告做向量存储,用于后续召回
六、6. 附加加分扩展功能
- 多模型动态切换:接口传参切换 DeepSeek-R1 / 通义千问,底层依托 SpringAI ChatModel 抽象无缝替换
- 任务异步化改造:长耗时调研任务改用异步线程处理,接口快速返回任务 ID,后续轮询查结果(进阶后端考点)
- 对话短期记忆:同会话多轮提问,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 容易出现重复执行、死循环、任务跳步、互相冲突
- 复杂课题无法正确拆分子任务
解决方案
- 采用 SAA Graph 状态机工作流,固定智能体执行顺序
- 设计 PlanningAgent 作为中央调度,统一控制流程
- 给每个 Agent 设定严格的系统提示词边界
- 设置 最大执行轮次,防止无限调用工具
- 任务状态落库,异常可中断、可重试、可回溯
这句话面试直接说
多智能体最大的问题是协同混乱,我通过中央规划 Agent + 状态机工作流 + 执行轮次熔断,让整个链路可控、可观测、可回溯。
2. RAG 检索精度低(所有 RAG 项目共同痛点,高频考点)
难点
- 向量检索召回不相关内容
- 长文本切片后语义断裂
- 简单向量检索无法满足复杂科研问题
解决方案
-
query扩写
-
使用 混合检索:向量检索 + BM25 关键词检索 + 重排(Rerank)
-
采用 语义分段,而不是固定长度切片
-
加入 上下文窗口扩展,关联前后文
-
对检索结果做过滤、去重、截断,减少噪声
面试金句
我没有只依赖单一向量检索,而是通过多路召回 + 重排机制,让 RAG 准确率提升 30% 以上。
3. Agent 工具调用不稳定(Tool Calling 难点)
难点
- LLM 偶尔不调用工具
- 偶尔参数格式错误
- 工具返回结果太长,撑爆上下文
解决方案
- 优化 Tool 描述提示词
- 工具返回结果做内容裁剪、摘要
- 加入 重试机制 + 异常捕获
- 强制规划 Agent 判断 "是否必须调用工具"
4. 长上下文管理 & 历史记忆(高级工程难点)
难点
- 调研资料太多 → 上下文溢出
- 多轮对话 → 历史丢失、LLM 失忆
- 报告太长 → token 爆炸
解决方案
- 动态上下文压缩:只保留核心摘要
- 结构化记忆存储:关键信息存入 PG
- 向量记忆:长期记忆走 RAG 检索
- 短期记忆:保留最近 N 轮对话
5. 向量数据库性能优化(pgvector 真实难点)
难点
- 数据量变大后 检索变慢
- 向量维度高、占用空间大
- 没有索引导致全表扫描
解决方案
- 创建 ivfflat 索引
- 使用 余弦相似度 检索
- 向量预先归一化
- 分段入库,避免单条文本过长
面试金句
我通过向量索引 + 分段存储 + 归一化,让系统在万级数据下检索响应 < 200ms。
6. 报告生成质量不稳定(LLM 生成类项目难点)
难点
- 有时逻辑乱
- 有时格式错误
- 有时编造信息(幻觉)
解决方案
- 严格 System Prompt 约束
- 提供 参考资料强制引用
- 加入 事实校验环节
- 输出格式固定为 Markdown,强制结构
8. 分布式 / 异步任务处理(高阶加分难点)
难点
- 深度调研耗时 20~50 秒
- HTTP 同步请求超时
- 无法中断、无法查看进度
解决方案
- 异步化执行
- 任务进度存入数据库
- 提供进度查询接口
- 支持任务取消、重试
9.检索不到会怎样? 模型会不会瞎编? 异常场景怎么兜底?
RAGAgent 检索为空,log.warn 告警;SearchAgent 有try-catch,返回"搜索失败",问题可观测;
编写严谨的prompt约束模型禁止编造;
搜不到就告警,分析不出就直说,报告写不了就拒绝------每一层都堵死 LLM 瞎编的入口
1.@PostConstruct一般用于初始化,要求方法无参数、返回值void、不能是static
- 只用在字符串上
@NotNull:仅禁止 null,空字符串 / 空格能通过校验@NotEmpty:禁止 null + 空字符串"",纯空格" "会放行@NotBlank:最严格,null / "" / 全空格 全部拦截
想要 @NotBlank 生效,Controller 入参前必须加 @Valid,例如:
java
@PostMapping("/research")
public Result startTask(@Valid @RequestBody ResearchTaskDTO dto) {
}
注解作用:
- 统一参数校验,无需每个接口写大量的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模糊索引