内容
# 1. 项目概述
- 项目名称:`ai-agent-station-study`,来自根模块 [pom.xml](/e:/xfg-code/ai-agent-station-study/pom.xml)。
- 核心目标:把“模型、提示词、MCP 工具、记忆、RAG、执行策略”做成可配置组件,在运行时装配成不同角色的 `ChatClient`,再由不同 Agent 策略执行用户任务。
- 解决的问题:避免把 Agent 能力硬编码在代码里,而是通过数据库配置和启动装配,快速切换模型、Prompt、工具、Advisor、执行流程。
- 面向场景:内容生成与发布、运维监控分析、知识问答、带定时任务的 Agent 执行。测试和部署脚本里直接出现了 CSDN 发布、微信公众号通知、Grafana/Prometheus 分析等场景,[FlowAgentExecuteTest.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/test/java/cn/bugstack/ai/test/domain/FlowAgentExecuteTest.java) 和 [docker-compose-app.yml](/e:/xfg-code/ai-agent-station-study/docs/dev-ops/docker-compose-app.yml#L6) 很明显。
- 一句话概括:这是一个“基于 Spring AI + MCP + RAG + 配置驱动装配”的 Agent 编排平台,不是单个聊天接口,而是一个可组装、可切换策略的 Agent Runtime。
核心代码入口:
[Application.java:9](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/Application.java#L9)
[AiAgentController.java:26](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/http/AiAgentController.java#L26)
[AiAgentAutoConfiguration.java:32](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/AiAgentAutoConfiguration.java#L32)
# 2. 项目整体架构
整体是一个 DDD 风格的多模块单体,模块拆分见 [pom.xml:11](/e:/xfg-code/ai-agent-station-study/pom.xml#L11)。
```text
用户 / 定时任务
-> Trigger 层
-> HTTP Controller / Scheduler Provider
-> Dispatch 层
-> 根据 ai_agent.strategy 选择执行策略
-> Auto Strategy 或 Flow Strategy
-> 读取 ai_agent_flow_config 获取每一步角色配置
-> 调用运行时装配好的 ChatClient
-> Model(OpenAI兼容)
-> MCP Tools
-> Advisor(Memory / RAG)
-> System Prompt
-> SSE 分阶段输出结果
配置数据流
MySQL(ai_agent / ai_client_*)
-> Repository
-> Armory 装配链
-> OpenAiApi Bean
-> McpSyncClient Bean
-> OpenAiChatModel Bean
-> Advisor Bean
-> ChatClient Bean
知识库数据流
文件/文档
-> TikaDocumentReader + TokenTextSplitter
-> PgVector
-> RagAnswerAdvisor 相似检索
```
分层职责:
- `app`:Spring Boot 启动、数据源、向量库、线程池、自动装配配置。[ai-agent-station-study-app/pom.xml](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/pom.xml)
- `trigger`:HTTP 入口和任务触发器。[AiAgentController.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/http/AiAgentController.java) [AgentTaskJob.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/job/AgentTaskJob.java)
- `domain`:真正的 Agent 编排、执行策略、Armory 装配逻辑、领域对象。
- `infrastructure`:Repository、MyBatis DAO、PO。
- `api`:对外接口契约 DTO。
- `types`:通用异常、常量、任务调度基础组件。
模块协作方式:
- `trigger` 不直接拼装模型,只负责接请求和调用 dispatch。
- `domain` 不直接查 SQL,而是走 `IAgentRepository`。
- `infrastructure` 负责把多张配置表拼成 `VO`。
- `app` 在启动时把配置装配成 Spring Bean,执行时直接按 beanName 获取。
# 3. 项目工作流程
这里更适合按“启动期 -> 两条线路与策略期 -> 能力调用期”来理解。这样不只是能讲清楚代码怎么跑,还能讲清楚项目设计思想:`auto` 和 `flow` 是两条执行主线,RAG、MCP、Prometheus、CSDN、微信通知这些不是第三条主线,而是运行时挂载到 `ChatClient` 上、被主线动态调用的能力。
启动期:
1. Spring Boot 从 [Application.java:12](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/Application.java#L12) 启动,并读取 [application.yml:5](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/resources/application.yml#L5) 激活 `dev`。这一层做的事情还只是“把宿主服务跑起来”,还没有进入具体的 Agent 执行。
2. `DataSourceConfig` 先创建 MySQL 和 PGVector 两套数据源,[DataSourceConfig.java:20](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/DataSourceConfig.java#L20) [DataSourceConfig.java:68](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/DataSourceConfig.java#L68)。MySQL 负责保存 Agent、Client、Prompt、MCP、Advisor、TaskSchedule 等配置关系,PGVector 负责后续知识检索。
3. `AiAgentConfig` 创建 `vectorStore`,底层是 `PgVectorStore + OpenAiEmbeddingModel`,[AiAgentConfig.java:14](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/AiAgentConfig.java#L14)。这一步的意义是先把 RAG 基础设施准备好,后续如果某个 client 配了 `RagAnswerAdvisor`,就可以直接查向量库。
4. `ThreadPoolConfig` 创建业务线程池,[ThreadPoolConfig.java:16](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/ThreadPoolConfig.java#L16)。这里不是普通的“顺手加个线程池”,而是整个项目的执行基础设施之一,因为后面的 dispatch 异步执行和装配期的并发配置查询都依赖它。
5. `AiAgentAutoConfiguration` 在 `ApplicationReadyEvent` 后触发自动装配,[AiAgentAutoConfiguration.java:41](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/AiAgentAutoConfiguration.java#L41)。它会读取 [application-dev.yml:55](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/resources/application-dev.yml#L55) 中的 `client-ids`,把这些 client 预装配进 Spring 容器。
client-ids后边的一串数字:
数字:节点编号
一组数字:一条工作流;不同组数字:不同场景下的工作流版本,比如:
3101~3104:通用 Auto
4101~4104:日志/ES 分析版 Auto
5101~5104:Prometheus/Grafana 监控版 Auto
2101~2103:Flow
但要再补一个关键点
数字本身不是“能力名字”,而是“步骤节点编号”。
它背后其实绑着这个节点该怎么干活:
用什么 Prompt
用什么模型
能不能调工具
是分析器还是执行器还是监督器
所以你可以把它想成:
3101 不是单纯一个数字
它其实代表“第一个分析节点,这个节点有自己专属的干活方式”
项目启动完成后,会先把一批 Agent 运行时要用的 ChatClient 提前创建好,放进 Spring 容器里备用。
ChatClient 你可以先把它理解成:
它不是单纯的模型对象
它是“模型 + Prompt + 工具 + Advisor + 调用入口”的组合外壳
你可以把它理解成:
Spring 容器像一个“工具仓库”,AiAgentAutoConfiguration 在应用启动后,先把常用的 AI 客户端做好,放进仓库。后面执行 auto 或 flow 的每一步时,就可以直接按 clientId 去拿,不用临时再拼一遍
那这个项目包含哪些ChatClient呢:
这个项目里的 ChatClient 分成两层:
一层是角色层,比如 TASK_ANALYZER_CLIENT、PLANNING_CLIENT、EXECUTOR_CLIENT;
另一层是实例层,也就是按 clientId 注册到 Spring 容器里的具体 Bean,比如 ai_client_3101、ai_client_5102。角色和实例之间的映射关系由 ai_agent_flow_config 表配置,不是写死在代码里的。
6. 自动装配的第一步,是构造 `ArmoryCommandEntity(commandType=client, commandIdList=...)`,[AiAgentAutoConfiguration.java:76](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/AiAgentAutoConfiguration.java#L76)。这个对象的作用是把“我现在要装配哪一类对象、要装配哪些 ID”明确传给 Armory 总装器。
7. Armory 根节点 [RootNode.java:37](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/RootNode.java#L37) 会根据 `commandType` 找到对应加载策略,具体策略映射由 [ArmoryCommandEntity.java:19](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/model/entity/ArmoryCommandEntity.java#L19) 驱动。当前这里主要走的是 client 装配。
8. `AiClientLoadDataStrategy` 会并发查出 API、Model、Prompt、MCP、Advisor、Client 六类配置,[AiClientLoadDataStrategy.java:32](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/business/data/impl/AiClientLoadDataStrategy.java#L32)。这里是一个关键点:项目不是把模型和 Prompt 写死在代码里,而是先把运行时所需的元数据批量查出来。
9. 装配链会依次注册 `OpenAiApi -> McpSyncClient -> OpenAiChatModel -> Advisor -> ChatClient`,对应 [AiClientApiNode.java:19](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientApiNode.java#L19)、[AiClientToolMcpNode.java:28](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientToolMcpNode.java#L28)、[AiClientModelNode.java:23](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientModelNode.java#L23)、[AiClientAdvisorNode.java:26](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientAdvisorNode.java#L26)、[AiClientNode.java:24](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientNode.java#L24)。
10. 这条装配链最终产出的不是“一个抽象配置对象”,而是可直接调用的 `ChatClient` Bean。也就是说,请求进来以后,策略层不再关心模型怎么建、工具怎么挂、Advisor 怎么拼,它只负责“挑对 client 去执行”。
两条线路与策略期:
1. HTTP 请求从 `/api/v1/agent/auto_agent` 进入,由 [AiAgentController.java:37](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/http/AiAgentController.java#L37) 接收。这里输入的核心不是复杂协议,而是 `aiAgentId + message + sessionId + maxStep` 这几个字段。
2. Controller 会构造 `ExecuteCommandEntity(aiAgentId, message, sessionId, maxStep)`,[AiAgentController.java:52](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/http/AiAgentController.java#L52)。这一步的意义是把 Web 层参数转换成领域层统一命令对象。
3. 接下来进入 `AgentDispatchDispatchService`。它先根据 `aiAgentId` 查询 `ai_agent` 表里的 Agent 元数据,重点拿到 `strategy` 字段,[AgentDispatchDispatchService.java:38](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/dispatch/AgentDispatchDispatchService.java#L38) [ai_agent_mapper.xml:62](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/resources/mybatis/mapper/ai_agent_mapper.xml#L62)。
4. 这里要特别说明:当前项目不是“模型根据用户问题临时决定走 auto 还是 flow”,而是“先根据 `aiAgentId` 找到这个 Agent 预先配置好的策略,再分流”。也就是说,`auto/flow` 的选择是配置驱动,而不是内容驱动。
5. Dispatch 再从 `executeStrategyMap` 中拿到对应策略 bean,并在线程池中异步执行,[AgentDispatchDispatchService.java:28](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/dispatch/AgentDispatchDispatchService.java#L28) [AgentDispatchDispatchService.java:47](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/dispatch/AgentDispatchDispatchService.java#L47)。因此 Controller 负责接入,Dispatch 负责分流,真正的编排逻辑还在策略内部。
6. 无论走哪条线路,策略根节点都会先去 `ai_agent_flow_config` 中加载当前 Agent 的步骤配置和 `step_prompt`,也就是“每一步由哪个角色执行、每一步用什么提示词、顺序是什么”,对应 [auto RootNode.java:33](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/RootNode.java#L33) [flow RootNode.java:32](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/step/RootNode.java#L32) [ai_agent_flow_config_mapper.xml:47](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/resources/mybatis/mapper/ai_agent_flow_config_mapper.xml#L47)。
7. `Auto` 线路进入 [AutoAgentExecuteStrategy.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/AutoAgentExecuteStrategy.java) 后,会在 `DynamicContext` 里初始化 `step`、`maxStep`、`executionHistory`、`currentTask` 等上下文变量,然后开始循环执行。这说明它本质上是一个“多轮闭环”而不是“一次性链路”。
8. `Auto` 的第 1 步是 `Step1AnalyzerNode`,[Step1AnalyzerNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/Step1AnalyzerNode.java)。它的职责不是直接干活,而是先判断用户任务当前是否已经足够明确、是否需要继续拆解、当前完成度怎样。它会把分析结果写回上下文,并通过关键字判断是否已经 `COMPLETED`。
9. `Auto` 的第 2 步是 `Step2PrecisionExecutorNode`,[Step2PrecisionExecutorNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/Step2PrecisionExecutorNode.java)。这一步才是真正执行动作的节点,会根据分析结果、当前任务和历史记录调用对应角色 client 执行,并把结果追加进 `executionHistory`。
10. `Auto` 的第 3 步是 `Step3QualitySupervisorNode`,[Step3QualitySupervisorNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/Step3QualitySupervisorNode.java)。这个 Supervisor 的作用是检查本轮执行结果是否达标,如果不通过,就生成新的 `currentTask`,让下一轮继续;如果通过,就设置完成状态。
11. `Auto` 的第 4 步是 `Step4LogExecutionSummaryNode`,[Step4LogExecutionSummaryNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/Step4LogExecutionSummaryNode.java)。这一层不再追求“继续做事”,而是把多轮执行过程、结论和输出整合成用户可读结果,并最终结束 SSE。
12. 所以 `Auto` 更适合讲成“分析 -> 执行 -> 监督 -> 再执行 -> 总结”的闭环自反思流程。它的优点是适合目标模糊、需要多轮修正的任务,缺点是比较依赖模型输出格式和关键词。
13. `Flow` 线路进入 [FlowAgentExecuteStrategy.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/FlowAgentExecuteStrategy.java) 后,不会像 `Auto` 那样做闭环迭代,而是更像一个典型的 Plan-and-Execute 工作流。
14. `Flow` 的第 1 步是 `Step1McpToolsAnalysisNode`,[Step1McpToolsAnalysisNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/step/Step1McpToolsAnalysisNode.java)。它的职责是先识别当前任务可能需要哪些工具和外部能力,这一步不是做最终执行,而是先做资源感知。
15. `Flow` 的第 2 步是 `Step2PlanningNode`,[Step2PlanningNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/step/Step2PlanningNode.java)。它会根据用户需求和工具分析结果生成一份任务计划,本质上是在做任务拆解。
16. `Flow` 的第 3 步是 `Step3ParseStepsNode`,[Step3ParseStepsNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/step/Step3ParseStepsNode.java)。因为规划结果是文本或 Markdown,所以这里要把文本计划解析成结构化步骤,写入 `stepsMap` 供后续执行。
17. `Flow` 的第 4 步是 `Step4ExecuteStepsNode`,[Step4ExecuteStepsNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/step/Step4ExecuteStepsNode.java)。它会按顺序遍历规划步骤,逐步调用执行角色 client 和外部工具,最后再统一做结果汇总。
18. 所以 `Flow` 更适合讲成“先识别工具 -> 再做计划 -> 再解析步骤 -> 再按步骤执行”的工作流模式。它的优点是结构清晰、适合多工具串行任务,缺点是规划文本解析比较脆弱。
19. 从面试表达上,你可以把这两条线概括为:`Auto` 偏闭环自我反思,`Flow` 偏可拆解的工作流执行。它们共享同一套底层能力,但上层编排方式不同。
能力调用期:
1. 两条主线都不会自己 new 模型、new 工具、new 检索器,而是统一按 `clientId` 去 Spring 容器里取已经装配好的 `ChatClient` Bean。这是整套架构最关键的抽象边界之一。
2. 一个 `ChatClient` 的内部能力组成,大致可以理解成:`system prompt + model + tool callbacks + advisors + default options`。也就是说,策略层看到的是“角色客户端”,而不是底层技术细节。
3. 系统 Prompt 在装配期由 `AiClientNode` 拼成 `defaultSystem`,[AiClientNode.java:39](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientNode.java#L39)。这意味着不同角色可以共享一套执行引擎,但通过不同 Prompt 呈现出不同职责。
4. 如果某个 client 配了 MCP 工具,那么这些工具会以 `defaultToolCallbacks` 的方式挂到 `ChatClient` 上,[AiClientNode.java:76](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientNode.java#L76)。真正把外部工具注册进来的逻辑在 [AiClientToolMcpNode.java:28](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientToolMcpNode.java#L28)。
5. 因此像 Prometheus/Grafana 查询、CSDN 发文、微信通知这些,都应该理解为“工具能力”。它们不是单独主线,而是某一步执行时,当前角色 client 通过 MCP 回调去调用的外部能力。
6. 如果某个 client 配了 Advisor,那么这些 Advisor 会以 `defaultAdvisors` 的方式挂到 `ChatClient` 上,[AiClientNode.java:73](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientNode.java#L73)。这说明 RAG 和 Memory 在架构上不是散落在业务代码里,而是统一纳入 client 能力模型。
7. 如果当前 client 配了 RAG,就会通过 `RagAnswerAdvisor` 在调用模型前先查 `VectorStore`,再把检索结果拼进上下文,[RagAnswerAdvisor.java:46](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/factory/element/RagAnswerAdvisor.java#L46)。所以 RAG 更准确地说是“知识增强能力”,而不是“第三条流程线”。
8. 如果当前 client 配了 Memory,就会通过 `PromptChatMemoryAdvisor` 把历史消息带入当前调用。也就是说,Memory 解决的是“上下文连续性”,RAG 解决的是“外部知识补充”,两者职责不同,但在运行时都通过 Advisor 插件化接入。
9. 在 `Auto` 线路里,能力调用通常会围绕“当前任务 + 历史执行记录 + 监督反馈”展开;在 `Flow` 线路里,能力调用通常围绕“当前步骤 + 规划结果 + 工具输入参数”展开。两条线共享能力层,但上下文组织方式并不一样。
10. 例如一个“生成文章并发布到 CSDN,再发送微信通知”的任务,在 `Flow` 下会先做工具分析,再规划步骤,然后执行步骤 1 生成内容、步骤 2 调 MCP 发 CSDN、步骤 3 调 MCP 发微信。这里 CSDN 和微信都是能力,不是流程本身。
11. 再例如一个“分析 Prometheus/Grafana 的接口 TPS 与响应时间”的任务,如果某个 Agent 配的是 `auto`,那么 Analyzer 先判断分析路径,Executor 实际调 Grafana/Prometheus 工具查询,Supervisor 再检查结果是否完整。这时候 Prometheus/Grafana 仍然只是工具能力,只是被 `auto` 这条主线调用了。
12. 整个执行过程中,每一步结果都会封装成 `AutoAgentExecuteResultEntity(type/subType/content/sessionId)` 并通过 SSE 回传前端,[AutoAgentExecuteResultEntity.java:17](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/model/entity/AutoAgentExecuteResultEntity.java#L17)。因此前端看到的不是单次返回,而是“主线执行过程 + 能力调用结果”的流式展示。
13. 如果从一句话总结这个工作流程,可以概括成:项目启动时先把能力装进 `ChatClient`,请求到来时再按 `aiAgent.strategy` 选择 `auto` 或 `flow` 这条主线,最后由主线在每个 step 中按需调用 Tool、RAG、Memory、Model 等能力完成任务。
# 4. 技术栈分析
- Java 17:基础语言版本,根 POM 指定 [pom.xml:34](/e:/xfg-code/ai-agent-station-study/pom.xml#L34)。适合 Spring Boot 3 / Spring AI;优点是生态稳定,缺点是运行资源开销高于 Go/Python 简单脚本。
- Spring Boot 3.4.3:应用启动、IOC、Web 容器,[pom.xml:59](/e:/xfg-code/ai-agent-station-study/pom.xml#L59)。适合做企业后端和组件装配。
- Spring AI 1.0.0:LLM、Tool Calling、Advisor、VectorStore、MCP 集成主框架,[pom.xml:122](/e:/xfg-code/ai-agent-station-study/pom.xml#L122) [ai-agent-station-study-app/pom.xml](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/pom.xml)。优点是和 Spring 生态贴合,缺点是复杂工作流控制能力不如 LangGraph/Temporal 这类专门编排引擎。
- MyBatis:配置中心数据访问层,[DataSourceConfig.java:48](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/DataSourceConfig.java#L48)。优点是 SQL 可控、适合多张配置表聚合;缺点是映射层样板代码多。
- MySQL:存 Agent/Client/Prompt/MCP/Advisor/TaskSchedule 配置,[ai_agent_mapper.xml](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/resources/mybatis/mapper/ai_agent_mapper.xml) [ai_client_config_mapper.xml](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/resources/mybatis/mapper/ai_client_config_mapper.xml)。
- PostgreSQL + PGVector:知识库存储,[AiAgentConfig.java:30](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/AiAgentConfig.java#L30) [init.sql](/e:/xfg-code/ai-agent-station-study/docs/dev-ops/pgvector/sql/init.sql)。
- MCP Client:支持 SSE/STDIO 两种工具传输,[AiClientToolMcpNode.java:72](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientToolMcpNode.java#L72)。适合把外部工具能力标准化接入。
- Advisor 机制:把记忆和 RAG 挂到 ChatClient 上,[AiClientAdvisorTypeEnumVO.java:26](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/model/valobj/enums/AiClientAdvisorTypeEnumVO.java#L26)。
- SSE:服务端流式返回多阶段结果,[AiAgentController.java:49](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/http/AiAgentController.java#L49)。适合展示过程,但当前实现用 `ResponseBodyEmitter` 手工拼 SSE 数据,不如 `SseEmitter` 语义直接。
- 线程池:业务执行与并发配置加载,[ThreadPoolConfig.java:20](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/ThreadPoolConfig.java#L20)。
- 日志:Logback 异步滚动文件,[logback-spring.xml](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/resources/logback-spring.xml)。优点是落盘完整;缺点是没有链路追踪、结构化埋点还不够。
- 调度:自带轻量任务调度器,不依赖 MQ,[TaskJobAutoConfig.java:28](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-types/src/main/java/cn/bugstack/ai/types/job/config/TaskJobAutoConfig.java#L28)。
- 测试:Junit4 + SpringBootTest + DAO 集成测试较多,但打包时跳过测试,[ai-agent-station-study-app/pom.xml:143](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/pom.xml#L143)。
补充判断:
- 没有前端框架源码;`docs/dev-ops/nginx/html` 更像静态演示页,不是正式前端工程。
- Redis、JWT、Retrofit、Guava Cache 在当前主流程里基本未真正使用,只是依赖或占位配置。
- 没有 Actuator/Micrometer 依赖,说明监控体系更多停留在外围环境脚本,而不是应用内指标。
# 5. 核心模块拆解
## Trigger 入口
- 作用:接收用户请求和定时任务触发。
- 关键位置:[AiAgentController.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/http/AiAgentController.java) [AgentTaskJob.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/job/AgentTaskJob.java)
- 输入:`AutoAgentRequestDTO` 或任务调度记录。
- 输出:`ResponseBodyEmitter` 流式结果或后台异步执行。
- 亮点:HTTP 和定时任务都复用统一 dispatch。
- 问题:Controller 注入了 `autoAgentExecuteStrategy` 和 `threadPoolExecutor` 但未使用,[AiAgentController.java:29](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/http/AiAgentController.java#L29) [AiAgentController.java:32](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/http/AiAgentController.java#L32)。
## Dispatch 调度模块
- 作用:根据 `ai_agent.strategy` 选择执行策略。
- 关键位置:[AgentDispatchDispatchService.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/dispatch/AgentDispatchDispatchService.java)
- 实现思路:先查 `ai_agent` 表,再从 Spring 容器的 `Map<String, IExecuteStrategy>` 中按 beanName 取策略执行。
- 输入:`ExecuteCommandEntity`
- 输出:异步触发策略执行
- 亮点:策略选择和入口解耦。
- 问题:`flow` 和 `auto` 目前实现的不是同一个接口类型,存在真实 bug 风险,下面单列。
## Armory 装配模块
- 作用:把数据库里的配置装配成运行时 `ChatClient`。
- 关键位置:[RootNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/RootNode.java) [AbstractArmorySupport.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AbstractArmorySupport.java)
- 核心链路:API -> MCP -> Model -> Advisor -> Client。
- 输入:`ArmoryCommandEntity(commandType, commandIdList)`
- 输出:多个命名 Bean,如 `ai_client_3101`
- 对外依赖:MySQL 配置表、OpenAI 兼容模型端点、MCP 服务端点、PGVector
- 亮点:真正把模型层能力组件化了。
- 可优化点:当前是“启动期预装配”,不是“按 agent 按需装配”。
## Repository 配置聚合模块
- 作用:把多张配置表拼成领域 VO。
- 关键位置:[AgentRepository.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-infrastructure/src/main/java/cn/bugstack/ai/infrastructure/adapter/repository/AgentRepository.java)
- 实现思路:先查 `ai_client_config` 关系表,再跳表拿 model/api/prompt/advisor/mcp。
- 亮点:数据库模型是“关系配置中心”,不是一张大宽表。
- 问题:读取链路深、校验弱,一旦配置缺失就容易运行时空指针或 bean 缺失。
## Auto Agent 执行策略
- 作用:做“分析 -> 执行 -> 监督 -> 总结”的闭环迭代。
- 关键位置:[AutoAgentExecuteStrategy.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/AutoAgentExecuteStrategy.java) [Step1AnalyzerNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/Step1AnalyzerNode.java) [Step2PrecisionExecutorNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/Step2PrecisionExecutorNode.java) [Step3QualitySupervisorNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/Step3QualitySupervisorNode.java) [Step4LogExecutionSummaryNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/Step4LogExecutionSummaryNode.java)
- 输入:用户原始任务
- 输出:阶段性 SSE + 最终总结
- 设计亮点:有 Supervisor 环节,能形成最简版 self-reflection。
- 风险:状态判断依赖文本关键词,如 `任务状态: COMPLETED`、`是否通过: FAIL`,[Step1AnalyzerNode.java:56](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/Step1AnalyzerNode.java#L56) [Step3QualitySupervisorNode.java:56](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/auto/step/Step3QualitySupervisorNode.java#L56)。
## Flow Agent 执行策略
- 作用:做“工具分析 -> 计划 -> 解析计划 -> 顺序执行”的工作流。
- 关键位置:[FlowAgentExecuteStrategy.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/FlowAgentExecuteStrategy.java) [Step1McpToolsAnalysisNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/step/Step1McpToolsAnalysisNode.java) [Step2PlanningNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/step/Step2PlanningNode.java) [Step3ParseStepsNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/step/Step3ParseStepsNode.java) [Step4ExecuteStepsNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/step/Step4ExecuteStepsNode.java)
- 输入:需要多工具协作的复杂任务
- 输出:规划结果、执行结果、最终总结
- 亮点:明显是 Plan-and-Execute 模式,便于面试讲“工作流 Agent”。
- 风险:规划输出是 Markdown,解析靠正则,[Step3ParseStepsNode.java:84](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/execute/flow/step/Step3ParseStepsNode.java#L84),这会很脆。
## Memory / RAG 模块
- 作用:给 ChatClient 挂记忆和知识检索。
- 关键位置:[AiClientAdvisorTypeEnumVO.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/model/valobj/enums/AiClientAdvisorTypeEnumVO.java) [RagAnswerAdvisor.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/factory/element/RagAnswerAdvisor.java)
- 实现思路:`ChatMemory` 用 `PromptChatMemoryAdvisor`,`RagAnswer` 用自定义 Advisor 包装 `VectorStore.similaritySearch`。
- 亮点:不是把 RAG 写进业务代码,而是作为可插拔 Advisor。
- 问题:知识入库只在测试样例里有,[OpenAiTest.java:117](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/test/java/cn/bugstack/ai/test/spring/ai/OpenAiTest.java#L117),生产链路缺失。
# 6. 项目是怎么实现的
- 请求接收与分发:Controller 只负责接入,真正的策略选择发生在 dispatch 层。
- 任务拆解:`auto` 靠分析 Prompt 先判断状态;`flow` 先做工具分析,再生成计划。
- Agent 决策:`auto` 用文本关键词驱动状态机;`flow` 用规划结果驱动顺序执行。
- Tool 注册:`ai_client_tool_mcp` 表定义传输方式和配置,Repository 解析 JSON,`AiClientToolMcpNode` 转成 `McpSyncClient`。
- Prompt 组织:有两层。
- 系统 Prompt:来自 `ai_client_system_prompt`,在 `AiClientNode` 拼成 `defaultSystem`,[AiClientNode.java:39](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientNode.java#L39)。
- 步骤 Prompt:来自 `ai_agent_flow_config.step_prompt`,按 agent 的每个角色单独配置。
- 上下文维护:
- 会话级:通过 `PromptChatMemoryAdvisor` 和 `chat_memory_conversation_id`。
- 流程级:通过 `DynamicContext` 保存 `currentTask`、`executionHistory`、`stepsMap`、`analysisResult` 等。
- RAG 注入:`RagAnswerAdvisor` 先检索,再把检索结果拼进用户消息下方的 context 区域,[RagAnswerAdvisor.java:46](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/factory/element/RagAnswerAdvisor.java#L46)。
- 数据库存储内容:
- `ai_agent`:Agent 元信息与策略
- `ai_agent_flow_config`:每个 Agent 的步骤角色与 Prompt
- `ai_client*`:模型、API、Prompt、MCP、Advisor 组件配置
- `ai_agent_task_schedule`:定时任务
- `ai_client_rag_order`:知识库标签配置,但当前主流程未真正消费
- 状态管理:没有独立状态机框架,状态全在 `DynamicContext` 和 LLM 输出文本里。
- 容错与重试:主流程基本没有统一重试、熔断、限流、幂等;更多是日志记录或跳过。
- 权限控制:当前主链路没有鉴权、租户隔离、工具授权边界控制。
# 7. Agent 编排专项分析
我的判断:这个项目“有 Agent,但不是严格意义上的多智能体自治协作平台”,更准确地说是“配置驱动的角色化 LLM 编排系统”。
Auto 编排:
- 角色:`TASK_ANALYZER_CLIENT`、`PRECISION_EXECUTOR_CLIENT`、`QUALITY_SUPERVISOR_CLIENT`、`RESPONSE_ASSISTANT`,[AiClientTypeEnumVO.java:17](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/model/valobj/enums/AiClientTypeEnumVO.java#L17)
- 协作方式:串行,Analyzer 先看状态,Executor 做动作,Supervisor 判断是否继续,Summary 负责最后回答。
- 终止条件:`completed=true` 或 `step > maxStep`。
- 优点:结构清晰,容易讲“自我反思闭环”。
- 缺点:强依赖模型输出格式,不够确定性。
Flow 编排:
- 角色:`TOOL_MCP_CLIENT`、`PLANNING_CLIENT`、`EXECUTOR_CLIENT`,[AiClientTypeEnumVO.java:22](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/model/valobj/enums/AiClientTypeEnumVO.java#L22)
- 协作方式:先认工具,再做计划,再把计划解析成步骤,再逐步执行。
- 谁负责拆解:`Step2PlanningNode`
- 谁负责工具调用:`Step4ExecuteStepsNode` 对应的执行客户端
- 谁负责汇总:`Step4ExecuteStepsNode.sendSummaryResult`
- 终止条件:所有步骤执行完即结束
- 优点:适合长任务、多工具任务、面试里也更像 Workflow Agent
- 缺点:计划解析靠正则,稳定性差;步骤上下文和执行状态落库能力没有。
Memory / Tool / RAG 关系:
- Agent 本身不直接碰底层工具或向量库。
- Tool 由 `ChatClient` 的 `defaultToolCallbacks` 挂进去。
- Memory / RAG 由 `defaultAdvisors` 挂进去。
- 所以“Agent 能力”本质上是 `ChatClient(system + tools + advisors + model)` 的组合。
典型一次执行:
1. 用户发起“生成文章并发 CSDN,再发微信通知”
2. Dispatch 根据 `ai_agent.strategy` 选 `flow`
3. `TOOL_MCP_CLIENT` 先判断需要哪些工具
4. `PLANNING_CLIENT` 产出 3 到 5 个步骤
5. `Step3ParseStepsNode` 把 Markdown 计划解析成 `stepsMap`
6. `EXECUTOR_CLIENT` 每步调用 MCP 工具执行
7. SSE 按步骤把分析、执行、总结不断返回前端
# 8. 这个项目的亮点
- 真正把 Agent 做成了“配置中心 + 运行时装配”,不是写死一套 Prompt 和模型。装配链见 [AiClientLoadDataStrategy.java:74](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/business/data/impl/AiClientLoadDataStrategy.java#L74)。
- 同时支持 Memory、RAG、MCP 工具,把 AI 基础能力统一收敛到了 `ChatClient` 这一层。
- 同一套平台支持两类执行模式:自反思闭环 `auto`,以及计划执行流 `flow`。
- 前端体验上不是一次性返回,而是按阶段 SSE 推送,`type/subType` 设计对 UI 很友好,[AutoAgentExecuteResultEntity.java:25](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/model/entity/AutoAgentExecuteResultEntity.java#L25)。
- 工程上不是纯 Demo,已经有双数据源、日志滚动、调度器、Docker 化、DAO 测试和外部 MCP 环境脚本。
# 9. 这个项目的难点
- 难点 1:把“配置表”装配成“运行时 Agent”。
- 难在配置跨很多表,而且依赖顺序严格。
- 代码解决方式是 Armory 链式注册 Bean。
- 未完全解决的问题是装配失败后只有日志,缺少统一校验报告。
- 难点 2:让 LLM 输出可被工作流消费。
- `auto` 用关键词判断状态,`flow` 用 Markdown + regex。
- 这能跑,但鲁棒性差。
- 难点 3:外部 MCP 服务不稳定。
- 代码里对初始化失败是跳过注册,[AiClientToolMcpNode.java:49](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/AiClientToolMcpNode.java#L49)
- 日志也已经出现 SSE/连接类错误和空指针。
- 难点 4:Prompt 和配置的一致性。
- 当前 `step_prompt`、system prompt、client config 一旦不一致,就容易在运行时爆错。
- 难点 5:知识库链路不完整。
- 检索接进来了,但生产入库、标签管理、版本化没有真正成体系。
# 10. 面试时如何介绍这个项目
1 分钟版:
我读透的这个项目本质上是一个配置驱动的 AI Agent 平台。它用 Spring Boot 做宿主,用 Spring AI 统一接模型、RAG、记忆和 MCP 工具,把模型 API、Prompt、工具、Advisor 都存在 MySQL 里,启动时动态装配成不同角色的 `ChatClient`。运行时用户请求进来后,系统先查 `ai_agent` 决定走 `auto` 还是 `flow` 两套策略,再按步骤流式返回结果。`auto` 更像分析、执行、监督、总结的闭环 Agent,`flow` 更像先规划再执行的工作流 Agent。我觉得这个项目最有价值的地方,是它不是简单聊天接口,而是把 Agent Runtime 做成了可配置平台。
3 分钟版:
这个项目是一个 Maven 多模块单体,`app` 负责启动和配置,`trigger` 负责 HTTP 与定时任务入口,`domain` 承担 Agent 编排和装配逻辑,`infrastructure` 负责配置仓储。它的核心设计是 Armory 装配链:启动后读取 `ai_client_*` 和 `ai_agent_flow_config` 这些表,把 API、模型、MCP 工具、Prompt、Advisor 装成 Spring Bean,最后得到像 `ai_client_3101` 这样的 `ChatClient`。请求来了以后,Controller 只做 SSE 接入,Dispatch 根据 `ai_agent.strategy` 选择具体策略。`auto` 这条链是任务分析、精确执行、质量监督、最终总结,适合带反思和多轮改进的任务;`flow` 这条链是工具分析、计划生成、计划解析、步骤执行,适合多工具协同。RAG 和 Memory 都不是散落在业务代码里,而是通过 Advisor 挂进 ChatClient。我面试时会强调两个点:第一,它把 Agent 能力组件化、配置化了;第二,它已经在工程上把工具调用、向量检索、任务调度、日志和部署串起来了。
5 分钟深度版:
如果按架构来讲,我会先说这是一个“Agent 平台化”项目,而不是“一个 Agent”。平台层的核心是配置模型。MySQL 里有 `ai_agent` 定义具体智能体和执行策略,有 `ai_agent_flow_config` 定义每个 Agent 的角色顺序和步骤 Prompt,有 `ai_client_config` 把 client、model、prompt、mcp、advisor 串起来。应用启动后,`AiAgentAutoConfiguration` 会读取配置里的 clientIds,触发 Armory。Armory 先并发查出六类配置,再按 `OpenAiApi -> McpSyncClient -> OpenAiChatModel -> Advisor -> ChatClient` 依次注册 Bean,所以运行期其实拿到的是已经组装好的 Agent 角色客户端。然后请求从 `/api/v1/agent/auto_agent` 进来,Controller 构造命令对象,Dispatch 查数据库决定用 `auto` 还是 `flow`。`auto` 的逻辑比较像轻量多角色协作:分析器判断现在任务完成度,执行器干活,监督器给反馈,如果 fail 或 optimize 就继续下一轮,最后总结器给用户可读结果。`flow` 更像 Workflow:先分析有哪些 MCP 工具可用,再生成计划,再把 Markdown 计划解析成步骤,最后让执行器逐步调用工具。这个项目最打动我的,是它把 Memory、RAG、Tool Calling 全放进了统一的 `ChatClient` 组装模型里,扩展一个新角色或者新工具,更多是加配置和局部节点,而不是重写整条链路。当然它现在也有明显问题,比如 flow 策略接口类型不一致、计划解析太依赖正则、配置校验和热更新不够、知识库入库链路还停留在测试样例。但从“项目深度”和“可面试表达性”来说,这个项目很适合讲平台化 Agent 架构。
# 11. 面试官可能会问的问题
A. 项目背景类
1. 你这个项目到底解决什么问题?
为什么会问:看你是否理解业务价值。
标准回答思路:先说“配置驱动的 Agent 平台”,再说具体场景。
结合当前项目的参考回答:它解决的是把模型、Prompt、RAG、MCP 工具从代码里解耦出来,形成统一装配和执行平台,支持内容发布、监控分析、定时任务等多类 Agent 场景。
如果继续追问:为什么不直接写死一套 Prompt?
更稳的回答:因为这个项目希望复用底层装配能力,让不同 Agent 只通过数据库配置切换角色和能力,不必每次改代码发版。
B. 技术选型类
2. 为什么用 Spring AI,不用 LangChain4j 或 LangGraph?
为什么会问:看你有没有选型意识。
标准回答思路:讲现有项目上下文,而不是空谈框架。
结合当前项目的参考回答:这个项目本身是 Spring Boot 多模块单体,Spring AI 的 `ChatClient`、Advisor、MCP、VectorStore 跟现有 IOC 和配置方式天然贴合,做运行时装配更顺手。
如果继续追问:那缺点呢?
更稳的回答:缺点是工作流控制不够强,复杂 DAG、持久化状态、可恢复执行不如 LangGraph/Temporal。
C. 架构设计类
3. 为什么要做 Armory 动态装配?
为什么会问:这是项目最核心的架构点。
标准回答思路:回答“解耦配置”和“运行时组合能力”。
结合当前项目的参考回答:Armory 解决的是 client/model/prompt/mcp/advisor 五类能力的组合爆炸问题,把它们转成命名 Bean,执行期直接按 `clientId` 取。
如果继续追问:为什么不每次请求动态 new?
更稳的回答:启动期装配能降低请求期开销,也方便统一校验;但当前代码也因此引入了预装配不全的问题,这就是后续要改成按 agent 按需装配的原因。
D. 核心流程类
4. 一次请求从进来到出结果怎么走?
为什么会问:看你是否真的读过调用链。
标准回答思路:入口、dispatch、strategy、step、SSE 五段式回答。
结合当前项目的参考回答:入口是 `AiAgentController`,然后 `AgentDispatchDispatchService` 查 `ai_agent.strategy`,选 `auto` 或 `flow`,加载 `ai_agent_flow_config`,逐步调用装配好的 `ChatClient`,每一步封装成 `AutoAgentExecuteResultEntity` 通过 SSE 返回。
如果继续追问:数据库在这个链路里起什么作用?
更稳的回答:数据库不是存业务数据,而是存 Agent Runtime 配置和执行角色配置。
E. Agent 编排类
5. auto 和 flow 两种策略差别是什么?
为什么会问:看你是否真的理解 Agent 编排。
标准回答思路:一个偏闭环反思,一个偏计划执行。
结合当前项目的参考回答:`auto` 是 Analyzer -> Executor -> Supervisor -> Summary,更像自我迭代;`flow` 是 Tool Analysis -> Planning -> Parse -> Execute,更像工作流。
如果继续追问:那它算不算多 Agent?
更稳的回答:算角色化多 Agent 编排,但不是自治型多 Agent 社会,更接近单请求内的 sequential multi-role orchestration。
F. Prompt / RAG / Memory 类
6. Memory 和 RAG 是怎么挂到 Agent 里的?
为什么会问:看你是否理解 Spring AI Advisor。
标准回答思路:不要说“代码里写死检索”,而是讲 Advisor 插件化。
结合当前项目的参考回答:Memory 用 `PromptChatMemoryAdvisor`,RAG 用自定义 `RagAnswerAdvisor`,都是在 `AiClientAdvisorNode` 装配阶段挂进 `ChatClient`。
如果继续追问:那 RAG 数据怎么入库?
更稳的回答:当前主链路没有生产入库流程,只有 `OpenAiTest.upload` 演示用 Tika + TokenTextSplitter + PgVector 入库。
G. 数据库 / 缓存 / 性能类
7. 为什么 MySQL 和 PGVector 要分开?
为什么会问:看你数据分层是否清楚。
标准回答思路:配置数据和向量检索数据是两种存储模型。
结合当前项目的参考回答:MySQL 存 Agent 配置和关系映射,PGVector 存 embedding 和知识片段,查询方式完全不同,分库更合理。
如果继续追问:Redis 在这里干嘛?
更稳的回答:当前主链路基本没用 Redis,docker compose 有预留,代码只有占位包和 Guava cache 配置。
H. 工程化 / 部署类
8. 这个项目怎么部署?
为什么会问:很多候选人只会讲代码,不会讲落地。
标准回答思路:按“应用 + 配套环境 + MCP 服务”说。
结合当前项目的参考回答:应用本身有 Dockerfile,外部环境通过 compose 起 MySQL、Redis、PGVector、Prometheus、Grafana、MCP 服务,应用启动后自动装配 ChatClient。
如果继续追问:监控是不是完善?
更稳的回答:外围环境有,但应用内没有 Actuator/Micrometer,所以更像半成品。
I. 优化与扩展类
9. 如果继续做大,你会怎么演进?
为什么会问:看你的架构思维上限。
标准回答思路:从稳定性、可观察性、工作流、配置治理四层回答。
结合当前项目的参考回答:我会把 Markdown+Regex 改成 JSON Schema/function calling,把启动预装配改成按 agent 惰性装配,把执行状态持久化,再补工具健康检查、密钥管理和知识库管理后台。
如果继续追问:要不要上状态机或 DAG 引擎?
更稳的回答:如果任务越来越长、可恢复性要求高,我会考虑引入 Temporal 或工作流引擎。
J. 追问 / 压力面类
10. 当前项目最大的坑是什么?
为什么会问:看你是否敢讲真话。
标准回答思路:挑一个最关键、最能体现你读过代码的问题。
结合当前项目的参考回答:最大的坑是运行时强依赖装配完整性和 LLM 输出格式稳定性。前者已经在日志里出现过 `No bean named 'ai_client_3101' available`,后者在 flow 策略里体现为 Markdown+Regex 解析。
如果继续追问:你会先修哪个?
更稳的回答:先修执行策略接口不一致和重复 complete 事件,这两个是会直接影响线上正确性的。
# 12. 高质量面试答案
1. 问:这个项目一句话是什么?
答:这是一个把模型、Prompt、MCP 工具、记忆和 RAG 做成可配置组件,并通过两套策略执行任务的 Spring AI Agent 平台。
2. 问:项目的业务价值是什么?
答:它把 Agent 从“写死一条链路”升级成“平台化可装配能力”,同一套底层可以支持内容发布、监控分析、知识问答和定时执行。
3. 问:为什么说它不是普通聊天接口?
答:因为真正核心不是 `chat()`,而是启动时的装配链和运行时的策略树。请求来了并不是直接调模型,而是先选策略,再选角色客户端,再走工具/RAG/记忆。
4. 问:请求主链路怎么走?
答:`AiAgentController -> AgentDispatchDispatchService -> Auto/FlowExecuteStrategy -> RootNode -> StepNode -> ChatClient -> SSE`。数据库参与的是策略和角色配置,不是业务结果存储。
5. 问:Armory 是什么?
答:Armory 就是运行时装配器。它把数据库中的 API、MCP、Model、Advisor、Prompt、Client 变成 Spring Bean,最终注册出可直接调用的 `ChatClient`。
6. 问:为什么要动态注册 Bean?
答:因为项目要支持大量 Agent 角色组合,如果全部写死在 `@Bean` 里,会非常僵硬;动态注册让“配置变更”变成一等公民。
7. 问:auto 策略怎么工作?
答:先分析任务状态,再执行,再监督,如果监督不通过就进入下一轮,直到完成或达到最大步数,最后再总结给用户。
8. 问:flow 策略怎么工作?
答:先分析有哪些 MCP 工具可用,再做计划,再把计划解析成步骤,最后顺序执行每一步。它更适合工具链长、任务目标明确的场景。
9. 问:项目里有哪些 Agent 角色?
答:Auto 路径有分析器、执行器、监督器、总结器;Flow 路径有工具分析器、规划器、执行器。它们本质上都是不同配置的 `ChatClient`。
10. 问:Prompt 是怎么管理的?
答:系统 Prompt 存在 `ai_client_system_prompt`,步骤 Prompt 存在 `ai_agent_flow_config.step_prompt`。前者面向 client 级别,后者面向 agent-step 级别。
11. 问:Memory 是怎么做的?
答:通过 `PromptChatMemoryAdvisor + MessageWindowChatMemory`,在装配阶段挂到 `ChatClient` 上,请求时再用 `conversation_id` 把会话串起来。
12. 问:RAG 是怎么做的?
答:通过自定义 `RagAnswerAdvisor`,先对 `VectorStore` 做相似检索,再把命中的文档文本注入到当前用户消息上下文里,让模型带着检索结果回答。
13. 问:为什么用 PGVector?
答:因为这个项目已经在 Java/Spring 生态里,PGVector 对 Spring AI 接入成本低,适合轻量知识库场景,不需要额外引入 Milvus 这类单独系统。
14. 问:MCP 工具是怎么接入的?
答:`ai_client_tool_mcp` 表配置工具和传输方式,`AiClientToolMcpNode` 按 `sse/stdio` 建 `McpSyncClient`,再通过 `SyncMcpToolCallbackProvider` 挂到模型或 client。
15. 问:项目里最体现 AI 能力的地方是什么?
答:不是“能调用模型”,而是把 tool calling、memory、rag、planner、executor 统一纳入一个配置驱动的运行时体系。
16. 问:项目里最体现工程能力的地方是什么?
答:动态装配链、双数据源、SSE 流式结果、调度器、日志和 Docker 环境,把一个 Agent Demo 推成了平台化雏形。
17. 问:当前架构最大的技术风险是什么?
答:一是装配完整性依赖很强,二是执行流程依赖 LLM 输出格式。前者会导致 bean 找不到,后者会导致 plan parse 失败或状态判断失真。
18. 问:为什么 flow 用 Markdown 计划再正则解析,不直接 JSON?
答:这是作者当前实现的轻量方案,开发门槛低、提示词容易写,但我会明确指出生产上应改为 JSON Schema 或 function calling。
19. 问:如果新增一个工具怎么做?
答:优先走配置扩展。加 `ai_client_tool_mcp` 和 `ai_client_config` 关系配置即可;如果是新传输协议,再改 `AiClientToolMcpNode`。
20. 问:如果新增一个 Agent 怎么做?
答:先在 `ai_agent` 增一条策略定义,再在 `ai_agent_flow_config` 配每个角色和 Prompt;如果是全新执行模式,再新增一套 strategy/root/step。
21. 问:为什么 MyBatis 比 JPA 更适合这个项目?
答:因为这里不是典型订单/用户领域,而是大量配置关系聚合,SQL 控制比 ORM 自动映射更直观,尤其是跨表组装 VO。
22. 问:为什么要用 SSE?
答:因为这个项目强调“阶段结果可见”,分析、执行、监督、总结都要边跑边回。一次性返回会损失 Agent 过程感和可观测性。
23. 问:定时任务怎么复用主链路?
答:`AgentTaskJob` 从 `ai_agent_task_schedule` 取配置,构造 `ExecuteCommandEntity` 后同样交给 dispatch,所以 HTTP 和 scheduler 复用了同一执行内核。
24. 问:为什么说知识库链路还不完整?
答:因为我只看到 `OpenAiTest.upload` 这种测试型入库,没有正式的文档上传、切片、回写、标签治理服务。
25. 问:如果面试官质疑它“还不够稳定”,怎么答?
答:我会承认,并指出当前版本更像平台雏形。它已经把装配、执行、工具、RAG 串起来了,但生产级稳定性还需要结构化输出、装配校验、热更新和统一重试机制。
# 13. 项目学习路径
第 1 阶段:先看入口
学习目标:知道系统怎么启动、请求怎么进来。
建议顺序:[Application.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/Application.java) -> [AiAgentController.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/http/AiAgentController.java) -> [AgentDispatchDispatchService.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/dispatch/AgentDispatchDispatchService.java)。
重点关注:`aiAgentId`、`strategy`、SSE。
常见误区:一上来就钻 Prompt 内容,反而看不见主链路。
第 2 阶段:再看装配
学习目标:理解 `ai_client_xxxx` 是怎么来的。
建议顺序:[AiAgentAutoConfiguration.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/AiAgentAutoConfiguration.java) -> [RootNode.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/RootNode.java) -> [AiClientLoadDataStrategy.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/business/data/impl/AiClientLoadDataStrategy.java) -> `AiClient*Node` 系列。
重点关注:Bean 注册顺序、配置表关系、命名规则。
常见误区:只看 `AiClientNode`,不看前面的 API/MCP/Model/Advisor 节点。
第 3 阶段:重点啃执行策略
学习目标:吃透 Auto 和 Flow 的差异。
建议顺序:先 Auto 四步,再 Flow 四步。
重点关注:`DynamicContext` 里放了什么,下一步由谁决定,终止条件是什么。
常见误区:把它想成真正多智能体平台;它其实更像“多角色串行编排”。
第 4 阶段:补 RAG、Memory、数据库
学习目标:理解 AI 能力是怎么接进来的。
建议顺序:[AiClientAdvisorTypeEnumVO.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/model/valobj/enums/AiClientAdvisorTypeEnumVO.java) -> [RagAnswerAdvisor.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/armory/factory/element/RagAnswerAdvisor.java) -> [OpenAiTest.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/test/java/cn/bugstack/ai/test/spring/ai/OpenAiTest.java) -> MyBatis mapper。
重点关注:检索注入点、知识库标签、配置表。
常见误区:把 `ai_client_rag_order` 当成主流程核心;当前它更多是预留。
第 5 阶段:用日志做反证
学习目标:知道系统真实会在哪些地方翻车。
建议顺序:看 `data/log` 里的 `NoSuchBeanDefinitionException`、`ResponseBodyEmitter has already completed`、模板错误和 MCP 初始化失败。
重点关注:装配完整性、SSE 生命周期、工具连接稳定性。
常见误区:只看代码“设计得很美”,不看它实际跑出来的问题。
# 14. 最终总结
- 一句话总结项目本质:这是一个配置驱动、角色化编排、可接工具和知识库的 Spring AI Agent 平台。
- 一句话总结技术核心:核心不是调用模型,而是“数据库配置 -> Armory 装配 -> Strategy 执行 -> SSE 输出”这条运行时链路。
- 一句话总结面试卖点:你可以把它讲成“Agent 平台化设计”,而不是“我接了个大模型接口”。
- 一句话总结最容易被问住的点:`auto` 和 `flow` 的差异、Armory 为什么存在、RAG/Memory 怎么挂进 ChatClient。
- 一句话总结你接下来最该补的部分:把配置表关系、两套执行策略、RAG/Memory/Tool 接入机制三件事讲到闭环。
# 15. 额外问题直答
1. 这个项目最核心的入口文件是哪几个?
最核心是 [Application.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/Application.java)、[AiAgentAutoConfiguration.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-app/src/main/java/cn/bugstack/ai/config/AiAgentAutoConfiguration.java)、[AiAgentController.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-trigger/src/main/java/cn/bugstack/ai/trigger/http/AiAgentController.java)、[AgentDispatchDispatchService.java](/e:/xfg-code/ai-agent-station-study/ai-agent-station-study-domain/src/main/java/cn/bugstack/ai/domain/agent/service/dispatch/AgentDispatchDispatchService.java),以及两套执行策略根节点。
2. 最重要的 3 到 5 条调用链是什么?
`启动 -> AutoConfig -> Armory -> 注册 ChatClient`;`HTTP -> Controller -> Dispatch -> Auto Strategy -> SSE`;`HTTP -> Controller -> Dispatch -> Flow Strategy -> Tool Calling`;`TaskJob -> AgentTaskJob -> Dispatch`;`RAG 文件 -> Tika/切片 -> PgVector -> RagAnswerAdvisor`。
3. 如果我要给别人讲懂这个项目,最少必须讲明白哪几件事?
一定要讲明白 4 件事:它的配置中心模型、Armory 装配链、Auto/Flow 两套执行策略、Memory/RAG/MCP 怎么挂进 ChatClient。
4. 如果面试官让我现场画架构图,我应该怎么画?
画 6 个框:`Client/Task -> Trigger -> Dispatch -> Strategy(auto/flow) -> ChatClient Runtime -> External LLM/MCP/RAG`。旁边再画 `MySQL Config Center` 和 `PGVector Knowledge Base` 两个数据源。
5. 如果面试官问“为什么这么设计,不这么设计行不行”,我应该怎么答?
可以答:行,但这个项目优先追求“配置可切换、Spring 内集成简单、轻量可落地”,所以选了 in-process orchestration;如果做更复杂的长流程和可恢复执行,再上状态机或工作流引擎。
6. 如果让我做二次开发,最适合从哪里下手?
最容易从 3 个点下手:新增一个 MCP 工具;新增一个 Agent 角色配置;把现有 flow 的 Markdown+Regex 改成 JSON 结构化输出。
7. 这个项目里最体现工程能力的地方是什么?
是运行时装配。很多人会写 Prompt,但很少有人把 Prompt、模型、工具、记忆、RAG、任务调度和流式返回放进一个统一运行时里。
8. 这个项目里最体现 AI / Agent 能力的地方是什么?
是“角色化编排 + Tool Calling + Memory + RAG”的统一组合,而不是单个模型接口。尤其 `auto` 的 Analyzer/Executor/Supervisor 闭环很适合拿来讲 Agent 思维。
9. 这个项目当前架构最可能的瓶颈在哪里?
最大瓶颈不是 CPU,而是稳定性:装配完整性、外部 MCP 可用性、Prompt 结构契约、以及 flow 计划解析的脆弱性。
10. 如果把项目继续做大,未来应该如何演进?
我会按 4 步演进:统一执行接口和配置校验;计划输出结构化;按 agent 惰性装配并支持热更新;把执行状态、工具调用、检索结果做成可观测可追溯的持久化工作流。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器