02 总体架构:一套应用两副面孔

第二章讲架构。这一章回答三个问题:模块怎么分层、评估监控为什么不碰主链路、一套代码怎么同时伺候「笔记本演示」和「客户内网生产」。
四层结构
自底向上分四层,边界刻意切得很硬:
接入层 API 网关(SpringBoot):鉴权、限流、输入校验、SSE 流式输出
业务层 biz-platform(自研闭源)
├─ RAG 模块:ingestion、语义分块、多路检索、RRF 重排
├─ 业务工具:SQL 沙箱、文件导出、kb_search
├─ 评估模块:Runner、测试集、LLM-as-judge、坏例沉淀
├─ 权限审计:RBAC、多租户、审计日志
└─ 可观测:事件埋点、指标上报
底座层 AgentScope-Java:ReAct 编排、Tool/MCP、事件流、模型适配
设施层 PostgreSQL / Redis / Milvus / OpenSearch
划分原则一句话:底座管「Agent 怎么跑」,业务层管「企业要什么」。所有带业务语义的东西——租户、权限、成本、评估——都落在 biz-platform,上游源码一行不动。这保证了底座升级时我只需要拉版本合并,不用重做冲突仲裁。
关键决策一:评估走旁路
最容易做错的架构点是评估和监控。直觉做法是在 Agent 执行代码里到处插桩,结果就是主链路被埋点淹没,性能和可读性双输。
我的做法:Agent 的所有生命周期事件(思考、工具调用、异常、token 用量)由底座的事件流统一抛出,biz-platform 里做一个事件订阅者旁路消费:
AgentEventPublisher/AgentEventListener:订阅事件,喂给评估与监控模块;MetricCollector:异步聚合 calls、token、p95,不阻塞主链路;AuditLogger:只记录关键动作(agent.chat、tool.kb_search),带租户、用户、耗时。
实测效果:主链路对埋点零感知,GET /api/metrics/summary 拿到的 calls/token/p95 全部来自旁路聚合。这个模式是后面第 11 章的基础。
关键决策二:Profile 双态
企业平台最难伺候的是两个场景的落差:给客户演示要「零依赖秒起」,生产交付要「真组件真持久化」。我的解法是 Spring Profile 双态,一套代码两副面孔:
| 组件 | demo profile | milvus/prod profile |
|---|---|---|
| 数据库 | H2 内存 | PostgreSQL |
| 会话记忆 | InMemoryChatMemory | RedisChatMemory(TTL 1 天) |
| 检索 | InMemoryRetriever(BM25 简化) | MilvusHybridRetriever(向量+BM25+RRF) |
| 向量库 | 无 | Milvus standalone |
以检索器为例,切换只靠一个注解:
@Profile({"prod-milvus", "milvus"})
@Component
public class MilvusHybridRetriever implements Retriever { ... }
两个实现共用 Retriever 接口,上层 RagService 对此完全无感知。demo 态下笔记本上 mvn spring-boot:run 就能跑通全部 API;milvus 态下换成真实向量检索,业务代码零改动。接口先行 + Profile 切换,是这套架构里性价比最高的一个决定。
一次 chat 的完整旅程
把数据流串起来看:
POST /api/agent/chat
→ JWT 认证 + RBAC 鉴权(403/401 在这一层拦)
→ TenantInterceptor 解析租户,塞进 RuntimeContext
→ 构建 Agent,history 从 ChatMemory 拉出拼接
→ ReAct 循环:思考 → 调工具(kb_search / SQL 沙箱)→ 继续推理
→ 事件流旁路:审计落一条 agent.chat(cost=毫秒数),指标聚合
→ 答案返回,本轮 user/assistant 写回会话记忆
实测一轮真实对话:tokenIn=888, tokenOut=89, latency=2768ms,审计行同步落库留痕。这条链路上每一个箭头,后面各章会逐个拆开讲透。
代码地图
biz-platform 的包结构对应上面的分层,找代码按图索骥:
com.agent.biz
├─ agent/ AgentFactory、AgentServiceImpl、BizTools、ChatMemory 体系
├─ gateway/ ChatController(同步+SSE)、SecurityConfig
├─ rag/ RagService、Chunker/SemanticChunker、MilvusHybridRetriever
├─ eval/ EvalRunService、EvalJudge、LlmJudge、BadCaseRepository
├─ auth/ JwtUtil、AuthInterceptor、TenantInterceptor
├─ audit/ AuditLogger
└─ metrics/ MetricsStore、MetricsSubscriber、MetricCollector
下一篇进 RAG:文档从 PDF 到可检索向量,中间的分块与去重是怎么做的。
- 本章对应源码:
com.agent.biz全包 - 配套文档:
docs/02_系统架构.md
