架构总览¶
如果只用一句话概括 Dubbo Admin AI 的架构,它是一个“组件化运行时驱动的流式 Agent 服务”:Server 负责对外 API 和 SSE,Agent 负责多阶段编排,Models / Tools / Memory / RAG 提供能力支撑,runtime 负责把这些组件装配起来。
1. 为什么项目被拆成这些层¶
这种拆法解决的是三个实际问题:
- 对外协议和内部能力要解耦,避免每次换模型或工具都改 HTTP 层。
- 推理流程要可编排,不能把所有逻辑都塞进一个 prompt。
- 能力要可替换,模型、工具、检索和记忆都应该能独立演进。
2. 系统全貌¶
flowchart TB
Client["Client / Frontend"] --> Server["Server<br/>Gin + SSE"]
Server --> Agent["Agent<br/>ReAct Orchestrator"]
Agent --> Memory["Memory<br/>History Window"]
Agent --> Tools["Tools<br/>Internal / Mock / MCP"]
Agent --> Models["Models<br/>Genkit Registry"]
Tools --> RAG["RAG<br/>Loader / Splitter / Indexer / Retriever / Reranker"]
Models --> Provider["LLM / Embedding Providers"]
RAG --> VectorDB["Vector Backend / Index"]
3. 一次请求怎么走¶
最关键的主链路是 POST /api/v1/ai/chat/stream。
sequenceDiagram
participant C as Client
participant S as Server
participant A as Agent
participant H as Memory
participant T as Tools/RAG
participant M as Model
C->>S: chat/stream(message, sessionID)
S->>S: 校验 session
S->>A: Interact(...)
A->>H: 追加用户输入到历史
A->>M: Think
A->>T: 按需调用工具 / 检索
A->>M: Observe 并流式输出
A-->>S: StreamFeedback
S-->>C: SSE events
A->>H: NextTurn(sessionID)
这条链路的设计重点在于:HTTP 层并不直接理解“思考”和“工具调用”,它只消费 Agent 产出的流式反馈。
4. 运行时如何装配系统¶
运行时入口是 runtime.Bootstrap(configPath, registerFactorys)。它做四件事:
- 注册组件工厂。
- 读取
config.yaml和各组件 YAML。 - 按工厂顺序创建组件并执行
Validate -> Init。 - 把组件存入注册表,再统一执行
Start()。
默认工厂注册顺序定义在 main.go:
loggermemorymodelsragtoolsserveragent
这里要注意一个事实:文档上的“依赖关系”和运行时的“实际启动顺序”不完全等价。比如 server 在注册顺序里早于 agent,但 server.Start() 会从 runtime 取 agent,而 Start() 的遍历顺序来自 sync.Map.Range,严格说并不保证顺序稳定。
5. 组件分工¶
Server¶
- 提供 HTTP API
- 维护 Session
- 把 Agent 输出转成 SSE
Agent¶
- 驱动
think -> act -> observe阶段循环 - 决定是否调用工具
- 管理中间输出和最终答案
Models¶
- 初始化 Genkit Registry
- 注册各 Provider 的模型和 Embedding
- 提供统一模型调用入口
Tools¶
- 聚合 internal、mock、MCP 三类工具
- 暴露
ToolRef给 Agent
Memory¶
- 保存进程内短期对话历史
- 按 session 输出窗口上下文
RAG¶
- 负责文档加载、切分、索引、检索和可选重排
6. 为什么说这是“组件化运行时”¶
因为项目真正的装配单位不是包、不是接口文件,而是满足 runtime.Component 生命周期的组件:
Name()Validate()Init(*Runtime)Start()Stop()
这个模型的好处是清楚,坏处是也带来一些现实限制,比如当前绝大多数组件 Name() 返回固定值,导致天然更偏向单实例。
7. 设计上的强项¶
- 配置加载链路严格,降低“配置看起来写对了,运行却默默错了”的风险。
- 组件边界清楚,文档和代码比较容易对齐。
- 流式输出是第一等能力,不是事后补出来的。
- RAG、Tools、Models 都可以相对独立演进。
8. 当前最重要的架构约束¶
- Session 和 Memory 是进程内状态,不支持天然共享。
genkit.Init()当前只适合初始化一次,Provider 扩展方式仍偏集中式。- Runtime 注册表按组件名存储,限制多实例能力。
- 部分配置字段已经进入 schema,但尚未完整贯穿执行逻辑。