第一章:系统架构设计
企业内部建设 Agent 平台,最容易出现两个问题:一开始就拆出很多服务,系统看起来完整但无法快速上线;或者只实现一个模型调用页面,缺少权限、版本、任务恢复和审计,无法进入真实业务环境。
本章给出一个可以开发、部署和上线的精简方案。它同时支持多租户、单 Agent 和多 Agent,但只保留生产运行需要的模块。
1. 系统定位
这个系统是一个支持多租户隔离,同时支持单 Agent 和多 Agent 协作的企业内部应用。
- 多租户解决数据和权限属于谁:不同租户的用户、Agent、知识、任务、密钥、日志和用量必须隔离。
- 单 Agent用于多数简单任务:一个 Agent 直接调用模型和工具,链路短、成本低、容易排查。
- 多 Agent用于需要分工的复杂任务:主 Agent 拆分任务,成员 Agent 分别执行,最后统一汇总。
多租户和多 Agent 是两个维度。一个租户可以只有一个 Agent,也可以维护多个 Agent 团队。平台不强制所有任务都使用多 Agent。
2. 建设范围
2.1 直接建设的功能
- 统一 Web 控制台和 OpenAPI。
- 租户、成员和角色权限。
- Agent 与 Agent Team 配置、版本发布和回滚。
- 单 Agent 执行,以及主 Agent 调度成员 Agent。
- 在线调试、固定用例回放和版本对比。
- 任务状态、运行轨迹、工具审批、审计和 Token 用量。
2.2 采用简单实现的部分
- 审批只支持单级人工确认。
- 用量按 Token 汇总,暂不建设复杂计费系统。
- 编排只支持顺序、并行和主 Agent 分派。
- 模型适配和工具适配作为 Worker 内部模块。
- 所有 Agent 共用 Worker 池,不为每个 Agent 单独部署服务。
- 复用公司现有网关、SSO、消息队列、密钥和监控系统。
3. 核心概念
| 概念 | 含义 | 关键关系 |
|---|---|---|
| Tenant | 数据与权限的隔离边界 | 拥有用户、Agent、团队、任务和密钥引用 |
| Agent | 包含提示词、模型、知识和工具权限的执行角色 | 发布后生成不可修改的 Agent Version |
| Agent Team | 多个 Agent 的协作定义 | 指定主 Agent、成员、调用关系和运行上限 |
| Task | 用户提交的一次完整请求 | 绑定 Agent Version 或 Team Version |
| Run | 某个 Agent 在任务中的一次运行 | 子 Run 通过 parent_run_id 关联父 Run |
| Step | 一次模型调用、工具调用或任务委派 | 属于 Run,按 step_no 保存输入和输出 |
任务开始后必须固定 Agent 或团队版本。管理员随后修改提示词或工具时,新任务使用新版本,已经开始的任务仍使用原版本。这是任务可复现和版本可回滚的基础。
4. 总体架构
系统只有两个主要部署单元:模块化平台后端和 Agent Worker。中心编排器、Agent Loop、模型适配和工具适配都运行在 Worker 中。
flowchart TB
subgraph ACCESS[接入]
WEB[统一 Web 控制台]
API[OpenAPI]
AUTH[公司 SSO / API Key]
end
subgraph BACKEND[模块化平台后端 · 两个副本]
TENANT[租户与权限]
CONFIG[Agent 与团队配置]
RELEASE[测试、发布与回滚]
TASK[任务、审批与审计]
end
subgraph RUNTIME[Agent Worker 池]
ORCH[中心编排器]
LOOP[Agent Loop]
ADAPTER[模型与工具适配]
ORCH --> LOOP --> ADAPTER
end
subgraph DATA[数据与基础设施]
PG[(PostgreSQL)]
MQ[(公司消息队列)]
REDIS[(Redis)]
STORE[(对象存储 / pgvector)]
end
WEB --> BACKEND
API --> BACKEND
AUTH --> BACKEND
BACKEND --> MQ
MQ --> RUNTIME
BACKEND --> PG
BACKEND --> REDIS
RUNTIME --> PG
RUNTIME --> REDIS
RUNTIME --> STORE
创建任务时,平台后端会把以下信息保存为运行快照:
tenant_id和当前用户;- 已发布的 Agent Version 或 Team Version;
- 当前角色权限和工具白名单;
- 最大步骤数、最大并发数、超时时间和 Token 上限。
运行快照一旦生成就不能被后续配置修改影响。
5. 模块职责
| 模块 | 必须实现的职责 | 部署方式 |
|---|---|---|
| Web 控制台 | Agent/团队配置、在线测试、发布回滚、任务查询和审批 | 一个前端,按角色显示菜单 |
| 平台后端 | 认证、租户权限、配置版本、任务 API、运行查询、审计 | 一个模块化应用,至少两个副本 |
| 中心编排器 | 创建子 Run、分派、并行控制、结果汇总和退出判断 | Worker 内的一种任务处理器 |
| Agent Loop | 上下文组装、模型调用、工具调用、步骤保存和终止 | 所有 Agent 共用同一套执行内核 |
| 模型适配 | 统一请求格式、超时、重试、并发限制和 Token 统计 | Worker 内部模块 |
| 工具适配 | 参数校验、权限、审批、幂等、密钥引用和调用审计 | Worker 内部模块 |
平台后端采用模块化单体,主要原因是租户、版本、任务和审批之间存在明确事务关系。早期拆成多个微服务会增加分布式事务、部署和排障成本。
6. 一次任务怎样执行
sequenceDiagram
participant U as 用户或业务系统
participant B as 平台后端
participant Q as 消息队列
participant W as Agent Worker
participant M as 模型
participant T as 企业工具
U->>B: 提交任务
B->>B: 校验租户、版本和权限
B->>Q: 写入任务消息
Q->>W: Worker 领取任务
W->>W: 加载运行快照并创建 Run
W->>M: 发送上下文
M-->>W: 最终回答或工具调用
alt 需要工具
W->>W: 校验白名单、审批和参数
W->>T: 使用幂等键执行工具
T-->>W: 返回工具结果
W->>M: 带工具结果进入下一轮
end
W->>B: 保存结果、轨迹和 Token 用量
B-->>U: 返回状态和最终结果
具体步骤如下:
- 平台后端校验租户、用户、目标版本和权限,生成
task_id。 - 任务写入消息队列,Worker 使用消息确认和任务租约领取任务。
- 单 Agent 任务直接创建根 Run;团队任务先运行主 Agent。
- 主 Agent 可以直接回答,也可以创建子 Run 委派给成员 Agent。
- Worker 保存每一步模型输入、模型输出、工具调用和 Token 用量。
- 任务最终进入成功、失败或取消状态;需要审批时暂停并释放 Worker。
7. Agent Loop
Agent Loop 重复执行“组装上下文、调用模型、执行工具、保存结果”,直到满足退出条件。
while task.is_running():
check_cancel_timeout_and_budget()
context = build_context(task_snapshot, run_steps)
response = model_adapter.call(context)
if response.is_final_answer():
return succeed(response.answer)
for tool_call in response.tool_calls:
check_tool_permission(tool_call)
result = execute_with_timeout_and_idempotency(tool_call)
save_step(tool_call, result)
if reached_limits() or repeated_same_action():
return fail(reason)
退出条件必须由运行时强制执行,不能只依赖模型自己判断。
| 退出原因 | 判断方式 |
|---|---|
| 正常完成 | 模型返回最终答案,或主 Agent 判断必要子任务已经完成 |
| 达到上限 | 达到 max_steps、max_depth、最大并发、超时或 Token 上限 |
| 用户取消 | Worker 在每次模型或工具调用边界检查取消状态 |
| 失败终止 | 模型连续失败、工具重试耗尽或必要子任务失败 |
| 等待审批 | 保存运行快照,释放 Worker,审批通过后恢复 |
| 循环检测 | 相同 Agent、输入和工具参数连续重复超过阈值 |
建议初始默认值:
{
"max_steps": 12,
"max_depth": 3,
"max_parallel_agents": 3,
"timeout_seconds": 300,
"token_budget": 30000,
"same_action_limit": 3
}
这些限制应该允许租户管理员在平台范围内调整,但不能允许普通用户无限放大。
8. 多 Agent 编排
默认采用主 Agent 负责分派和汇总的方式:
flowchart LR
INPUT[用户任务] --> SUPERVISOR[主 Agent 判断]
SUPERVISOR --> A[成员 Agent A]
SUPERVISOR --> B[成员 Agent B]
SUPERVISOR --> C[成员 Agent C]
A --> JOIN[汇总必要结果]
B --> JOIN
C --> JOIN
JOIN --> FINAL[主 Agent 生成最终结果]
首个版本只需要三种编排节点:
- Agent 节点:运行指定的 Agent Version,返回结构化结果。
- 并行节点:同时派发多个 Agent,并限制最大并发数量。
- 汇总节点:等待必要分支结束,把结果交给主 Agent 整理。
Agent 之间不直接建立私有通信。委派请求、子任务结果和共享事实统一写入 Run 和 Step,由编排器传递。这样才能支持回放、审计和故障恢复。
9. 租户隔离和权限
数据隔离采用一个明确方案:共享 PostgreSQL、共享表、所有租户业务表包含 tenant_id,并启用数据库行级策略。
租户标识的传递过程:
- SSO 用户通过成员关系确定当前租户;API Key 在创建时绑定租户。
- 客户端不能通过请求参数任意切换
tenant_id。 - 平台后端把
tenant_id、user_id、task_id和trace_id写入任务快照和消息。 - 数据访问层自动追加
tenant_id查询条件。 - PostgreSQL 行级策略再次验证租户上下文。
- 缓存键、消息、对象路径、向量索引和日志字段都包含
tenant_id。
工具最终权限按照交集计算:
最终权限 = 租户允许的工具
∩ Agent Version 工具白名单
∩ 当前用户角色权限
高风险工具在权限校验通过后,还需要单级人工确认。密钥保存在公司的密钥系统中,平台数据库只保存密钥引用。
10. 核心数据表
| 表 | 用途 | 关键字段 |
|---|---|---|
tenant | 租户信息和状态 | id, name, status, quota |
tenant_member | 用户在租户中的角色 | tenant_id, user_id, role |
agent_version | 不可修改的 Agent 配置 | tenant_id, agent_id, version, prompt, model, tool_policy |
team_version | 主 Agent、成员和协作图 | tenant_id, team_id, version, supervisor_id, graph |
task | 用户的一次完整请求 | tenant_id, task_id, agent_version_id/team_version_id, status, limits |
agent_run | 一个 Agent 的一次运行 | tenant_id, run_id, parent_run_id, agent_version_id, status |
run_step | 模型、工具或委派步骤 | tenant_id, run_id, step_no, type, input_ref, output_ref, idempotency_key |
approval | 高风险工具审批 | tenant_id, tool_call_id, status, approver, decided_at |
usage_record | Token 和模型调用用量 | tenant_id, task_id, run_id, model, input_tokens, output_tokens |
audit_log | 配置、发布、权限和工具操作 | tenant_id, actor, action, resource, trace_id, created_at |
所有租户业务表的索引和唯一约束都必须包含 tenant_id。大文本、附件、模型原始响应和任务产物放入对象存储,数据库只保存引用。知识向量存入 pgvector,并在索引元数据中保存 tenant_id。
11. 状态与故障恢复
stateDiagram-v2
[*] --> PENDING
PENDING --> RUNNING
RUNNING --> WAITING_APPROVAL: 需要人工审批
WAITING_APPROVAL --> RUNNING: 审批通过
WAITING_APPROVAL --> FAILED: 审批拒绝
RUNNING --> SUCCEEDED: 正常完成
RUNNING --> FAILED: 重试耗尽或超限
PENDING --> CANCELLED: 用户取消
RUNNING --> CANCELLING: 用户取消
CANCELLING --> CANCELLED
SUCCEEDED --> [*]
FAILED --> [*]
CANCELLED --> [*]
| 故障场景 | 处理方式 |
|---|---|
| Worker 进程退出 | 任务租约到期后重新入队,新 Worker 从已保存 Step 恢复 |
| 消息重复投递 | 使用 task_id、run_id 和 step_no 组成幂等键 |
| 工具有副作用 | 工具调用携带 idempotency_key,由连接器记录执行结果 |
| 模型调用超时 | 只对可重试错误进行有限次数重试,并记录每次尝试 |
| 审批等待较长 | 保存运行快照并释放 Worker,通过消息重新唤醒 |
| 用户取消 | 先进入 CANCELLING,Worker 在安全边界停止后变为 CANCELLED |
12. 测试与发布
测试能力放在平台后端中,不单独建设大型评测平台。
- 在线调试:选择草稿版本运行,查看模型输入输出和工具结果。
- 固定用例回放:保存少量代表性输入和检查项,发布前批量执行。
- 版本对比:比较成功率、人工评分、耗时和 Token 用量。
- 发布回滚:发布生成不可修改的新版本;回滚只把线上别名重新指向旧版本。
发布检查至少包含:固定用例全部执行完成、没有越权工具调用、Agent Loop 没有异常循环、Token 和响应时间没有明显失控。
13. 生产部署
flowchart TB
subgraph K8S[公司 Kubernetes 集群 · 单命名空间]
GW[公司网关 / SSO]
APP[平台后端 × 2]
WORKER[Agent Worker × N]
GW --> APP
APP --> WORKER
end
APP --> PG[(PostgreSQL 主备)]
APP --> MQ[(公司消息队列)]
APP --> REDIS[(Redis)]
WORKER --> MQ
WORKER --> PG
WORKER --> REDIS
WORKER --> STORE[(对象存储)]
WORKER --> SECRET[公司密钥系统]
WORKER --> EGRESS[模型与工具固定出口]
APP --> OBS[公司日志、指标与告警]
WORKER --> OBS
生产部署的最低要求:
- 平台后端至少两个副本,保持无状态,配置和任务状态写入 PostgreSQL。
- Agent Worker 至少两个副本,根据队列积压扩缩容。
- PostgreSQL 使用主备部署并每日备份,上线前执行一次恢复验证。
- 消息队列开启确认、有限重试和死信队列。
- Worker 禁止直连业务生产数据库,工具通过受控连接器访问。
- 日志和指标包含
tenant_id、task_id、run_id和agent_version_id。
14. 示例:经营分析任务
用户提交:“分析昨天各区域的销售变化,找出异常原因并生成简报。”
| Agent | 职责 | 允许使用的工具 |
|---|---|---|
| 主 Agent | 理解问题、分派任务、检查结果并生成最终简报 | 任务委派、知识检索 |
| 数据 Agent | 通过受控查询接口获取销售汇总数据 | 经营数据查询 API |
| 分析 Agent | 计算环比、识别异常并整理可能原因 | Python 沙箱、知识检索 |
| 写作 Agent | 把结构化结果整理成固定格式的简报 | 模板读取、文档生成 |
主 Agent 可以同时派发“获取销售数据”和“检索异常背景”,收到结果后再启动分析 Agent,最后交给写作 Agent。任一必要分支失败,主 Agent 返回明确的缺失项,而不是猜测业务数据。
15. 建议开发顺序
- 完成单 Agent 闭环:租户认证、Agent Version、Task/Run/Step、模型调用、任务查询和审计。
- 补齐工具边界:工具白名单、参数校验、密钥引用、超时、幂等和单级审批。
- 增加可靠执行:消息队列、任务租约、重试、取消、审批等待和故障恢复。
- 增加多 Agent:Team Version、父子 Run、主 Agent 分派、并行上限和结果汇总。
- 完成上线能力:固定用例回放、版本回滚、监控告警、数据备份和恢复验证。
先把单 Agent 运行内核做稳定,再增加多 Agent。多 Agent 复用同一套 Task、Run、Step、权限和工具执行机制,不应重新实现一套运行系统。
16. 上线验收清单
- [ ] 两个租户无法读取对方的 Agent、知识、任务和日志。
- [ ] 单 Agent 任务不需要经过团队编排。
- [ ] 任务固定使用已发布版本,历史任务可以复现。
- [ ] 子任务支持并行、超时、重试、取消和失败汇总。
- [ ] Worker 重启后,任务可以重新领取并继续执行。
- [ ] 有副作用的工具不会因消息重复而重复执行。
- [ ] 高风险工具需要审批,全部调用可以追溯。
- [ ] 可以按租户、任务、Agent 和模型查询 Token 用量。
- [ ] 版本可以回滚,数据库备份完成恢复验证。
- [ ] 日志能够通过 tenant_id、task_id 和 run_id 定位。
17. 本章小结
这套架构的关键不是模块数量,而是边界清晰:
- 租户负责数据和权限隔离;
- Agent Version 和 Team Version 负责固定可执行配置;
- Task、Run 和 Step 负责记录完整运行过程;
- Agent Loop 负责模型与工具循环;
- 中心编排器负责多 Agent 分派和汇总;
- 消息队列、任务租约和幂等机制负责故障恢复;
- 测试、审计、监控、备份和回滚保证系统可以上线运行。
在这个基础上继续增加 Agent 类型、工具连接器和业务场景,不需要改变系统的核心执行模型。