Răsfoiți Sursa

docs: add platform roadmap and database design

Jax Docker 2 luni în urmă
comite
df6a9bbe67

+ 1441 - 0
docs/agent-platform-database-design.md

@@ -0,0 +1,1441 @@
+# Python 智能体开发平台数据库设计(多服务 / 可横向扩展版)
+
+## 1. 设计目标
+
+本设计面向一套基于 Python 的智能体开发平台,要求支持:
+
+- 多应用、多租户、多环境
+- 多智能体、团队协作、复杂工作流
+- 会话、运行态、上下文、记忆、技能、工具、插件
+- 多服务部署与水平扩展
+- 高并发写入、长链路执行、可观测与审计
+
+数据库设计的目标不是只满足 `V0.1`,而是保证从早期共库部署到后期多服务独立演进都能平滑过渡。
+
+## 2. 总体原则
+
+### 2.1 核心原则
+
+- 配置数据和运行数据分离
+- 热路径数据和冷路径数据分离
+- 强事务数据优先放 PostgreSQL
+- 短期状态与幂等控制优先放 Redis
+- 语义记忆与知识检索使用 `pgvector`
+- 文件和产物不落数据库,统一进入对象存储
+
+### 2.2 分库分域原则
+
+初期可以由一个 PostgreSQL 集群承载多个 schema,后期再按热点服务拆分成独立数据库。建议逻辑分域如下:
+
+- `auth_db`
+- `app_db`
+- `session_db`
+- `runtime_db`
+- `memory_db`
+- `tool_db`
+- `retrieval_db`
+- `trace_db`
+
+### 2.3 横向扩展原则
+
+- 所有运行态表必须支持按 `tenant_id`、`app_id`、`run_id` 定位
+- 长链路表优先使用追加写,减少热点更新
+- 高并发表尽量避免大事务和跨域 join
+- 跨服务关联尽量靠业务 ID,不依赖数据库外键
+- 表设计默认支持归档和分区
+
+## 3. ID 与通用字段规范
+
+### 3.1 主键策略
+
+建议统一使用 `UUID` 或 `ULID` 作为主键。
+
+推荐:
+
+- 配置类对象:`UUID`
+- 高写入运行表:`ULID` 或时序友好的 UUID v7
+
+好处:
+
+- 支持多服务独立生成 ID
+- 避免数据库序列成为全局瓶颈
+- 便于未来跨库迁移
+
+### 3.2 通用字段
+
+核心业务表建议统一带上以下字段:
+
+- `id`
+- `tenant_id`
+- `org_id`
+- `created_by`
+- `updated_by`
+- `created_time`
+- `updated_time`
+- `deleted_time`
+- `version`
+
+说明:
+
+- `tenant_id`:多租户隔离关键字段
+- `org_id`:组织维度隔离,可选
+- `deleted_time`:软删除标记
+- `version`:乐观锁或对象版本控制
+
+时间字段规范:
+
+- 所有时间字段统一使用 `_time` 后缀
+- 所有时间字段统一使用 `datetime` 类型
+- 禁止混用 `_at`、`date`、`timestamp` 等命名风格
+
+### 3.3 枚举字段建议
+
+不要使用数据库原生 enum 绑定太死,建议使用 `varchar + check` 或应用层常量控制,方便演进。
+
+## 4. 分域数据库设计
+
+## 4.1 Auth / Tenant 域
+
+职责:
+
+- 用户、组织、租户、角色、权限
+
+### 表:`tenant`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| code | varchar(64) | 租户编码,唯一 |
+| name | varchar(128) | 租户名称 |
+| status | varchar(32) | `active` / `suspended` |
+| plan_code | varchar(64) | 套餐 |
+| settings_json | jsonb | 租户级配置 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+索引:
+
+- `uk_tenant_code(code)`
+- `idx_tenant_status(status)`
+
+### 表:`organization`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| parent_id | uuid | 上级组织 |
+| name | varchar(128) | 组织名 |
+| status | varchar(32) | 状态 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+索引:
+
+- `idx_org_tenant(tenant_id)`
+- `idx_org_parent(parent_id)`
+
+### 表:`user_account`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| org_id | uuid | 组织 ID |
+| username | varchar(64) | 用户名 |
+| email | varchar(128) | 邮箱 |
+| phone | varchar(32) | 手机号 |
+| display_name | varchar(128) | 显示名 |
+| status | varchar(32) | 状态 |
+| profile_json | jsonb | 扩展资料 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+索引:
+
+- `uk_user_tenant_username(tenant_id, username)`
+- `uk_user_tenant_email(tenant_id, email)`
+- `idx_user_org(org_id)`
+
+### 表:`role`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| code | varchar(64) | 角色编码 |
+| name | varchar(128) | 角色名 |
+| role_type | varchar(32) | 系统角色 / 自定义角色 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+### 表:`permission`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| code | varchar(128) | 权限编码 |
+| name | varchar(128) | 权限名称 |
+| resource_type | varchar(64) | 资源类型 |
+| action | varchar(32) | 动作 |
+
+### 表:`user_role`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| user_id | uuid | 用户 ID |
+| role_id | uuid | 角色 ID |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_user_role(tenant_id, user_id, role_id)`
+
+### 表:`role_permission`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| role_id | uuid | 角色 ID |
+| permission_id | uuid | 权限 ID |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_role_permission(role_id, permission_id)`
+
+## 4.2 App / Workflow 配置域
+
+职责:
+
+- 应用定义
+- 工作流定义
+- 版本与环境配置
+- Agent、Team、Skill 绑定
+
+### 表:`app_definition`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| code | varchar(64) | 应用编码 |
+| name | varchar(128) | 应用名称 |
+| description | text | 描述 |
+| app_type | varchar(32) | chat / workflow / hybrid |
+| status | varchar(32) | draft / active / archived |
+| owner_user_id | uuid | 负责人 |
+| settings_json | jsonb | UI、默认模型等配置 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+索引:
+
+- `uk_app_tenant_code(tenant_id, code)`
+- `idx_app_owner(owner_user_id)`
+- `idx_app_status(tenant_id, status)`
+
+### 表:`app_environment`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| env_name | varchar(32) | dev / test / prod |
+| model_policy_json | jsonb | 环境模型策略 |
+| secret_ref_json | jsonb | 环境密钥引用 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+唯一索引:
+
+- `uk_app_env(app_id, env_name)`
+
+### 表:`app_version`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| version_no | integer | 版本号 |
+| status | varchar(32) | draft / published / rollback |
+| workflow_version_id | uuid | 当前工作流版本 |
+| published_time | datetime | 发布时间 |
+| published_by | uuid | 发布人 |
+| changelog | text | 发布说明 |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_app_version(app_id, version_no)`
+
+### 表:`workflow_definition`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| code | varchar(64) | 流程编码 |
+| name | varchar(128) | 流程名称 |
+| workflow_type | varchar(32) | main / subflow / template |
+| latest_version_no | integer | 最新版本号 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+唯一索引:
+
+- `uk_workflow_code(app_id, code)`
+
+### 表:`workflow_version`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| workflow_id | uuid | 流程定义 ID |
+| version_no | integer | 版本号 |
+| dsl_json | jsonb | 内部 DSL |
+| compiled_plan_json | jsonb | 编译后的执行计划 |
+| schema_version | varchar(32) | DSL 版本 |
+| checksum | varchar(128) | 内容摘要 |
+| status | varchar(32) | draft / validated / published |
+| created_by | uuid | 创建人 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `uk_workflow_version(workflow_id, version_no)`
+- `idx_workflow_version_status(workflow_id, status)`
+
+### 表:`workflow_import_record`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| source_type | varchar(32) | dify / custom_yaml / json |
+| source_uri | varchar(512) | 原始来源 |
+| raw_content_ref | varchar(512) | 原始文件对象存储地址 |
+| converted_workflow_version_id | uuid | 转换后的流程版本 |
+| import_status | varchar(32) | success / failed |
+| error_message | text | 错误原因 |
+| created_by | uuid | 导入人 |
+| created_time | datetime | 创建时间 |
+
+### 表:`agent_definition`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| code | varchar(64) | Agent 编码 |
+| name | varchar(128) | Agent 名称 |
+| role_type | varchar(32) | planner / worker / judge / custom |
+| description | text | 描述 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+唯一索引:
+
+- `uk_agent_code(app_id, code)`
+
+### 表:`agent_version`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| agent_id | uuid | Agent 定义 ID |
+| version_no | integer | 版本号 |
+| system_prompt | text | 系统提示词 |
+| model_policy_json | jsonb | 模型策略 |
+| tool_policy_json | jsonb | 工具策略 |
+| output_schema_json | jsonb | 输出结构约束 |
+| created_by | uuid | 创建人 |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_agent_version(agent_id, version_no)`
+
+### 表:`team_definition`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| code | varchar(64) | Team 编码 |
+| name | varchar(128) | Team 名称 |
+| team_mode | varchar(32) | leader_worker / debate / pipeline |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+### 表:`team_version`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| team_id | uuid | Team 定义 ID |
+| version_no | integer | 版本号 |
+| config_json | jsonb | 团队策略 |
+| created_by | uuid | 创建人 |
+| created_time | datetime | 创建时间 |
+
+### 表:`team_member_binding`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| team_version_id | uuid | Team 版本 ID |
+| agent_version_id | uuid | Agent 版本 ID |
+| member_role | varchar(32) | planner / reviewer / researcher |
+| sort_order | integer | 顺序 |
+| config_json | jsonb | 角色级配置 |
+
+索引:
+
+- `idx_team_member_team(team_version_id)`
+
+### 表:`skill_definition`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| code | varchar(64) | 技能编码 |
+| name | varchar(128) | 技能名称 |
+| skill_type | varchar(32) | prompt / workflow / decision / retrieval |
+| owner_scope | varchar(32) | system / tenant / app |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+### 表:`skill_version`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| skill_id | uuid | 技能定义 ID |
+| version_no | integer | 版本号 |
+| content_json | jsonb | 技能定义内容 |
+| created_by | uuid | 创建人 |
+| created_time | datetime | 创建时间 |
+
+### 表:`app_binding`
+
+统一保存应用对 Agent / Team / Skill / Tool / Plugin 的绑定关系。
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| bind_type | varchar(32) | agent / team / skill / tool / plugin |
+| target_id | uuid | 绑定对象 ID |
+| target_version_id | uuid | 绑定版本 ID |
+| binding_scope | varchar(32) | app / env / workflow / node |
+| config_json | jsonb | 绑定配置 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `idx_app_binding_app(app_id, bind_type)`
+
+## 4.3 Session 域
+
+职责:
+
+- 用户会话
+- 对话消息
+- 请求入口
+- 应答记录
+
+### 表:`session`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| user_id | uuid | 用户 ID |
+| channel_type | varchar(32) | web / api / webhook / sdk |
+| session_status | varchar(32) | active / closed |
+| title | varchar(256) | 会话标题 |
+| started_time | datetime | 开始时间 |
+| last_active_time | datetime | 最后活跃时间 |
+| closed_time | datetime | 结束时间 |
+
+索引:
+
+- `idx_session_user(user_id, last_active_time desc)`
+- `idx_session_app(app_id, last_active_time desc)`
+
+### 表:`conversation_turn`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| session_id | uuid | 会话 ID |
+| turn_no | integer | 轮次 |
+| input_message_id | uuid | 用户消息 ID |
+| output_message_id | uuid | 最终回答消息 ID |
+| run_id | uuid | 对应运行 ID |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_turn_session_no(session_id, turn_no)`
+
+### 表:`message`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| session_id | uuid | 会话 ID |
+| turn_id | uuid | 对话轮次 ID |
+| role | varchar(32) | user / assistant / system / tool |
+| content_type | varchar(32) | text / json / file / stream |
+| content_text | text | 文本内容 |
+| content_json | jsonb | 结构化消息 |
+| token_count | integer | token 数 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `idx_message_session(session_id, created_time)`
+- `idx_message_turn(turn_id)`
+
+### 表:`run_request`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| session_id | uuid | 会话 ID |
+| app_version_id | uuid | 应用版本 ID |
+| workflow_version_id | uuid | 流程版本 ID |
+| trigger_type | varchar(32) | chat / api / schedule / webhook |
+| request_payload_json | jsonb | 原始请求 |
+| request_status | varchar(32) | accepted / rejected / started |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `idx_run_request_session(session_id, created_time desc)`
+
+## 4.4 Runtime 域
+
+职责:
+
+- 流程运行
+- 节点执行
+- 状态迁移
+- 快照与恢复
+- 异步事件
+
+这是平台最高频的核心域之一。
+
+### 表:`workflow_run`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| app_version_id | uuid | 应用版本 ID |
+| workflow_id | uuid | 流程定义 ID |
+| workflow_version_id | uuid | 流程版本 ID |
+| session_id | uuid | 会话 ID,可空 |
+| parent_run_id | uuid | 父运行 ID,子流程时使用 |
+| root_run_id | uuid | 根运行 ID |
+| run_type | varchar(32) | main / subflow / scheduled / batch |
+| status | varchar(32) | pending / running / completed / failed / cancelled / paused |
+| trigger_type | varchar(32) | user / api / event / timer |
+| priority | integer | 优先级 |
+| current_node_count | integer | 已执行节点数 |
+| started_time | datetime | 开始时间 |
+| finished_time | datetime | 结束时间 |
+| error_code | varchar(64) | 错误码 |
+| error_message | text | 错误信息 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `idx_run_root(root_run_id)`
+- `idx_run_session(session_id, created_time desc)`
+- `idx_run_status(status, created_time desc)`
+- `idx_run_app(app_id, created_time desc)`
+
+### 表:`node_run`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| run_id | uuid | 运行 ID |
+| parent_node_run_id | uuid | 父节点运行 ID |
+| node_id | varchar(128) | DSL 节点 ID |
+| node_type | varchar(32) | llm / tool / code / team 等 |
+| attempt_no | integer | 第几次尝试 |
+| status | varchar(32) | pending / queued / running / completed / failed / skipped |
+| worker_key | varchar(128) | 执行 worker 标识 |
+| lease_expire_time | datetime | 执行 lease 到期时间 |
+| queued_time | datetime | 入队时间 |
+| started_time | datetime | 开始时间 |
+| finished_time | datetime | 结束时间 |
+| error_code | varchar(64) | 错误码 |
+| error_message | text | 错误信息 |
+| created_time | datetime | 创建时间 |
+
+唯一索引建议:
+
+- `uk_node_run_attempt(run_id, node_id, attempt_no)`
+
+普通索引:
+
+- `idx_node_run_status(status, queued_time)`
+- `idx_node_run_run(run_id, started_time)`
+- `idx_node_run_worker(worker_key, status)`
+
+### 表:`node_io_snapshot`
+
+用于存储节点输入输出快照,便于回放和问题定位。
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| node_run_id | uuid | 节点运行 ID |
+| snapshot_type | varchar(32) | input / output / intermediate |
+| payload_json | jsonb | 快照内容 |
+| payload_ref | varchar(512) | 大对象外置引用 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `idx_node_snapshot_node(node_run_id, snapshot_type)`
+
+### 表:`run_state_snapshot`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| run_id | uuid | 运行 ID |
+| snapshot_no | integer | 快照号 |
+| state_json | jsonb | 当前运行态 |
+| context_hash | varchar(128) | 状态摘要 |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_run_snapshot(run_id, snapshot_no)`
+
+### 表:`run_event`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | bigint | 主键 |
+| tenant_id | uuid | 租户 ID |
+| run_id | uuid | 运行 ID |
+| node_run_id | uuid | 节点运行 ID,可空 |
+| event_type | varchar(64) | 事件类型 |
+| event_time | datetime | 事件时间 |
+| payload_json | jsonb | 事件内容 |
+
+索引:
+
+- `idx_run_event_run(run_id, id)`
+- `idx_run_event_type(event_type, event_time desc)`
+
+建议:
+
+- `run_event` 可按月分区
+
+### 表:`run_queue_task`
+
+适合在没有独立 MQ 可视化追踪时保留调度状态。
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| run_id | uuid | 运行 ID |
+| node_run_id | uuid | 节点运行 ID |
+| task_type | varchar(32) | schedule / retry / timeout / resume |
+| execute_after_time | datetime | 可执行时间 |
+| task_status | varchar(32) | pending / taken / done / dead_letter |
+| retry_count | integer | 重试次数 |
+| payload_json | jsonb | 任务内容 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+索引:
+
+- `idx_queue_ready(task_status, execute_after_time)`
+
+## 4.5 Memory / Context 域
+
+职责:
+
+- 会话上下文
+- 任务上下文
+- 长期记忆
+- 领域隔离记忆
+- 召回记录
+
+### 表:`context_namespace`
+
+表示不同作用域下的上下文命名空间。
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| namespace_type | varchar(32) | session / run / user / domain / team |
+| namespace_key | varchar(256) | 如 `session:{id}` 或 `domain:policy` |
+| owner_ref | varchar(256) | 归属对象 |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_context_namespace(tenant_id, namespace_type, namespace_key)`
+
+### 表:`context_kv`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| namespace_id | uuid | 命名空间 ID |
+| key | varchar(128) | 键 |
+| value_type | varchar(32) | string / number / bool / json |
+| value_json | jsonb | 值 |
+| revision | integer | 修订号 |
+| updated_time | datetime | 更新时间 |
+| updated_by_run_id | uuid | 最后修改运行 |
+
+唯一索引:
+
+- `uk_context_kv(namespace_id, key)`
+
+### 表:`context_change_log`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | bigint | 主键 |
+| tenant_id | uuid | 租户 ID |
+| namespace_id | uuid | 命名空间 ID |
+| key | varchar(128) | 键 |
+| before_json | jsonb | 修改前 |
+| after_json | jsonb | 修改后 |
+| change_source | varchar(32) | node / tool / system |
+| run_id | uuid | 来源运行 |
+| node_run_id | uuid | 来源节点 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `idx_context_change_namespace(namespace_id, id desc)`
+
+### 表:`memory_record`
+
+统一长期记忆记录。
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| user_id | uuid | 用户 ID,可空 |
+| session_id | uuid | 会话 ID,可空 |
+| run_id | uuid | 运行 ID,可空 |
+| namespace | varchar(128) | `user` / `app` / `domain:order` |
+| memory_type | varchar(32) | fact / preference / summary / episode |
+| importance_score | numeric(5,2) | 重要性 |
+| freshness_score | numeric(5,2) | 新鲜度 |
+| content_text | text | 内容 |
+| content_json | jsonb | 结构化内容 |
+| source_type | varchar(32) | conversation / tool / import / rule |
+| status | varchar(32) | active / archived / deleted |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+索引:
+
+- `idx_memory_namespace(namespace, created_time desc)`
+- `idx_memory_user(user_id, created_time desc)`
+- `idx_memory_app(app_id, created_time desc)`
+- `idx_memory_type(memory_type, status)`
+
+### 表:`memory_embedding`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| memory_id | uuid | 记忆记录 ID |
+| embedding_model | varchar(64) | Embedding 模型 |
+| embedding | vector | 向量 |
+| token_count | integer | token 数 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- 向量索引:`ivfflat` 或 `hnsw(embedding)`
+- `idx_memory_embedding_memory(memory_id)`
+
+### 表:`memory_recall_log`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | bigint | 主键 |
+| tenant_id | uuid | 租户 ID |
+| run_id | uuid | 运行 ID |
+| node_run_id | uuid | 节点运行 ID |
+| query_text | text | 召回查询 |
+| namespace | varchar(128) | 召回命名空间 |
+| top_k | integer | 返回条数 |
+| result_ids_json | jsonb | 命中记录 ID 列表 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `idx_memory_recall_run(run_id, created_time desc)`
+
+## 4.6 Tool / Plugin 域
+
+职责:
+
+- 工具、插件、凭据、调用记录
+
+### 表:`plugin_definition`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID,可空表示系统插件 |
+| code | varchar(64) | 插件编码 |
+| name | varchar(128) | 插件名称 |
+| provider | varchar(128) | 提供方 |
+| source_type | varchar(32) | marketplace / local / git |
+| manifest_json | jsonb | 插件清单 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+### 表:`plugin_version`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| plugin_id | uuid | 插件 ID |
+| version | varchar(64) | 版本号 |
+| package_ref | varchar(512) | 包引用 |
+| checksum | varchar(128) | 校验值 |
+| status | varchar(32) | active / disabled |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_plugin_version(plugin_id, version)`
+
+### 表:`tool_definition`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID,可空表示系统工具 |
+| plugin_id | uuid | 所属插件 |
+| code | varchar(64) | 工具编码 |
+| name | varchar(128) | 工具名称 |
+| tool_type | varchar(32) | function / http / mcp / db |
+| description | text | 描述 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+唯一索引:
+
+- `uk_tool_code(tenant_id, code)`
+
+### 表:`tool_version`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tool_id | uuid | 工具定义 ID |
+| version_no | integer | 版本号 |
+| input_schema_json | jsonb | 输入 schema |
+| output_schema_json | jsonb | 输出 schema |
+| invoke_config_json | jsonb | 调用配置 |
+| timeout_ms | integer | 超时 |
+| retry_policy_json | jsonb | 重试策略 |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_tool_version(tool_id, version_no)`
+
+### 表:`tool_credential`
+
+不要直接存明文密钥,建议只存密文或外部 Secret 引用。
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| credential_name | varchar(128) | 名称 |
+| secret_type | varchar(32) | api_key / oauth / service_account |
+| secret_ref | varchar(512) | Secret Manager 引用 |
+| encrypted_payload | bytea | 可选密文 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+### 表:`tool_binding`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| tool_version_id | uuid | 工具版本 ID |
+| credential_id | uuid | 凭据 ID |
+| binding_scope | varchar(32) | app / env / workflow / node |
+| enabled | boolean | 是否启用 |
+| config_json | jsonb | 绑定配置 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `idx_tool_binding_app(app_id, binding_scope)`
+
+### 表:`tool_invocation_log`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| run_id | uuid | 运行 ID |
+| node_run_id | uuid | 节点运行 ID |
+| tool_id | uuid | 工具 ID |
+| tool_version_id | uuid | 工具版本 ID |
+| request_json | jsonb | 请求参数 |
+| response_json | jsonb | 响应结果 |
+| response_ref | varchar(512) | 大对象引用 |
+| status | varchar(32) | success / failed / timeout |
+| latency_ms | integer | 调用耗时 |
+| error_message | text | 错误信息 |
+| invoked_time | datetime | 调用时间 |
+
+索引:
+
+- `idx_tool_invocation_run(run_id, invoked_time desc)`
+- `idx_tool_invocation_tool(tool_id, invoked_time desc)`
+- `idx_tool_invocation_status(status, invoked_time desc)`
+
+## 4.7 Retrieval / Knowledge 域
+
+职责:
+
+- 知识库
+- 文档与分片
+- 向量索引
+- 检索审计
+
+### 表:`knowledge_base`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| code | varchar(64) | 知识库编码 |
+| name | varchar(128) | 名称 |
+| retrieval_strategy | varchar(32) | vector / hybrid / keyword |
+| status | varchar(32) | active / disabled |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+### 表:`document`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| kb_id | uuid | 知识库 ID |
+| source_type | varchar(32) | file / url / api / manual |
+| source_uri | varchar(512) | 来源 |
+| title | varchar(256) | 标题 |
+| mime_type | varchar(128) | 文件类型 |
+| object_ref | varchar(512) | 文件存储引用 |
+| parse_status | varchar(32) | pending / parsed / failed |
+| metadata_json | jsonb | 元数据 |
+| created_time | datetime | 创建时间 |
+| updated_time | datetime | 更新时间 |
+
+索引:
+
+- `idx_document_kb(kb_id, created_time desc)`
+
+### 表:`document_chunk`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| document_id | uuid | 文档 ID |
+| chunk_no | integer | 分片序号 |
+| content_text | text | 分片内容 |
+| metadata_json | jsonb | 分片元数据 |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_document_chunk(document_id, chunk_no)`
+
+### 表:`chunk_embedding`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| chunk_id | uuid | 分片 ID |
+| embedding_model | varchar(64) | Embedding 模型 |
+| embedding | vector | 向量 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- 向量索引:`ivfflat` 或 `hnsw(embedding)`
+- `idx_chunk_embedding_chunk(chunk_id)`
+
+### 表:`retrieval_log`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | bigint | 主键 |
+| tenant_id | uuid | 租户 ID |
+| run_id | uuid | 运行 ID |
+| node_run_id | uuid | 节点运行 ID |
+| kb_id | uuid | 知识库 ID |
+| query_text | text | 查询语句 |
+| strategy | varchar(32) | vector / hybrid |
+| top_k | integer | 命中数 |
+| result_json | jsonb | 命中详情 |
+| latency_ms | integer | 耗时 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `idx_retrieval_run(run_id, created_time desc)`
+- `idx_retrieval_kb(kb_id, created_time desc)`
+
+## 4.8 Model / LLM 域
+
+如果 `model-gateway` 需要单独统计模型调用和成本,建议独立表。
+
+### 表:`model_provider`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| code | varchar(64) | openai / azure_openai / anthropic |
+| name | varchar(128) | 名称 |
+| provider_type | varchar(32) | hosted / self_hosted |
+| config_json | jsonb | 默认配置 |
+| created_time | datetime | 创建时间 |
+
+### 表:`model_definition`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| provider_id | uuid | Provider ID |
+| model_code | varchar(128) | 模型编码 |
+| model_kind | varchar(32) | chat / embedding / rerank |
+| capability_json | jsonb | 能力描述 |
+| pricing_json | jsonb | 价格配置 |
+| status | varchar(32) | active / deprecated |
+| created_time | datetime | 创建时间 |
+
+唯一索引:
+
+- `uk_model_provider_code(provider_id, model_code)`
+
+### 表:`model_invocation_log`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| run_id | uuid | 运行 ID |
+| node_run_id | uuid | 节点运行 ID |
+| provider_id | uuid | Provider ID |
+| model_id | uuid | 模型 ID |
+| request_json | jsonb | 请求摘要 |
+| response_json | jsonb | 响应摘要 |
+| prompt_tokens | integer | 输入 token |
+| completion_tokens | integer | 输出 token |
+| total_tokens | integer | 总 token |
+| estimated_cost | numeric(18,6) | 预估成本 |
+| latency_ms | integer | 耗时 |
+| status | varchar(32) | success / failed / timeout |
+| invoked_time | datetime | 调用时间 |
+
+索引:
+
+- `idx_model_invocation_run(run_id, invoked_time desc)`
+- `idx_model_invocation_model(model_id, invoked_time desc)`
+
+## 4.9 Trace / Eval 域
+
+职责:
+
+- 链路追踪
+- 回放
+- 评测与基线
+
+### 表:`trace_span`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| trace_id | uuid | Trace ID |
+| parent_span_id | uuid | 父 Span |
+| span_type | varchar(32) | run / node / tool / model / memory |
+| ref_id | varchar(128) | 关联业务 ID |
+| name | varchar(128) | Span 名称 |
+| status | varchar(32) | ok / error |
+| started_time | datetime | 开始时间 |
+| finished_time | datetime | 结束时间 |
+| attributes_json | jsonb | 属性 |
+
+索引:
+
+- `idx_trace_trace(trace_id, started_time)`
+- `idx_trace_ref(span_type, ref_id)`
+
+### 表:`trace_event`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | bigint | 主键 |
+| tenant_id | uuid | 租户 ID |
+| trace_id | uuid | Trace ID |
+| span_id | uuid | Span ID |
+| event_name | varchar(128) | 事件名 |
+| payload_json | jsonb | 事件内容 |
+| event_time | datetime | 事件时间 |
+
+索引:
+
+- `idx_trace_event_trace(trace_id, id)`
+
+### 表:`eval_suite`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| app_id | uuid | 应用 ID |
+| name | varchar(128) | 评测集名称 |
+| description | text | 描述 |
+| created_by | uuid | 创建人 |
+| created_time | datetime | 创建时间 |
+
+### 表:`eval_case`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| suite_id | uuid | 评测集 ID |
+| input_json | jsonb | 输入 |
+| expected_json | jsonb | 预期输出 |
+| tags_json | jsonb | 标签 |
+| created_time | datetime | 创建时间 |
+
+### 表:`eval_run`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| tenant_id | uuid | 租户 ID |
+| suite_id | uuid | 评测集 ID |
+| app_version_id | uuid | 评测应用版本 |
+| status | varchar(32) | pending / running / completed |
+| started_time | datetime | 开始时间 |
+| finished_time | datetime | 结束时间 |
+| created_time | datetime | 创建时间 |
+
+### 表:`eval_result`
+
+| 字段 | 类型 | 说明 |
+| --- | --- | --- |
+| id | uuid | 主键 |
+| eval_run_id | uuid | 评测运行 ID |
+| eval_case_id | uuid | 评测用例 ID |
+| run_id | uuid | 实际运行 ID |
+| score | numeric(5,2) | 得分 |
+| verdict | varchar(32) | pass / fail |
+| detail_json | jsonb | 评测详情 |
+| created_time | datetime | 创建时间 |
+
+索引:
+
+- `idx_eval_result_run(eval_run_id)`
+
+## 5. 关键关系说明
+
+核心关系可以理解为:
+
+- 一个 `tenant` 下有多个 `app_definition`
+- 一个 `app_definition` 下有多个 `app_version`
+- 一个 `app_definition` 下有多个 `workflow_definition`
+- 一个 `workflow_definition` 下有多个 `workflow_version`
+- 一个 `app` 可以绑定多个 `agent`、`team`、`skill`、`tool`
+- 一个 `session` 会产生多轮 `conversation_turn`
+- 一次输入通常对应一个 `run_request` 和一个 `workflow_run`
+- 一个 `workflow_run` 下会有多个 `node_run`
+- 一个 `node_run` 会产生快照、工具调用、模型调用、trace 和 memory recall
+- `memory_record` 与 `context_namespace` 共同组成“长期记忆 + 运行状态”的双层体系
+
+## 6. 索引与分区建议
+
+### 6.1 必须优先建索引的表
+
+- `workflow_run`
+- `node_run`
+- `run_event`
+- `message`
+- `memory_record`
+- `tool_invocation_log`
+- `model_invocation_log`
+- `retrieval_log`
+- `trace_event`
+
+### 6.2 建议分区的表
+
+当数据量上来后,以下表建议按时间分区:
+
+- `run_event`
+- `tool_invocation_log`
+- `model_invocation_log`
+- `retrieval_log`
+- `trace_event`
+- `context_change_log`
+
+优先方案:
+
+- PostgreSQL 按月 range partition
+
+### 6.3 JSONB 使用建议
+
+适合放 `jsonb` 的字段:
+
+- DSL 内容
+- 节点快照
+- 模型能力描述
+- 工具输入输出 schema
+- 配置策略
+
+不要把核心检索条件全部塞进 `jsonb`,例如状态、版本、归属、时间等必须单独成列。
+
+## 7. Redis 设计建议
+
+Redis 不替代主数据库,主要承载以下内容:
+
+- `session:{id}:recent_messages`
+- `run:{id}:state_cache`
+- `run:{id}:node_lock:{node_id}`
+- `idempotency:{key}`
+- `queue:ready`
+- `model_rate_limit:{provider}:{model}`
+
+建议:
+
+- 所有 Redis Key 带租户前缀
+- 运行态缓存必须可从数据库重建
+- 分布式锁必须带 TTL
+
+## 8. 对象存储设计建议
+
+对象存储主要保存:
+
+- 原始导入 YAML/JSON
+- 大体积节点快照
+- 工具大响应结果
+- 文件上传
+- 回放原始材料
+- 检索文档原文
+
+建议存储路径规范:
+
+- `tenant/{tenant_id}/app/{app_id}/imports/...`
+- `tenant/{tenant_id}/run/{run_id}/snapshots/...`
+- `tenant/{tenant_id}/trace/{trace_id}/...`
+- `tenant/{tenant_id}/kb/{kb_id}/documents/...`
+
+## 9. 分阶段建表建议
+
+### V0.1 必需表
+
+- `tenant`
+- `user_account`
+- `app_definition`
+- `app_version`
+- `workflow_definition`
+- `workflow_version`
+- `session`
+- `message`
+- `run_request`
+- `workflow_run`
+- `node_run`
+- `node_io_snapshot`
+- `tool_definition`
+- `tool_version`
+- `tool_binding`
+- `tool_invocation_log`
+- `model_provider`
+- `model_definition`
+- `model_invocation_log`
+
+目标:
+
+- 跑通“应用配置 + 工作流执行 + 工具调用 + 基础日志”
+
+### V0.2 新增表
+
+- `agent_definition`
+- `agent_version`
+- `skill_definition`
+- `skill_version`
+- `app_binding`
+- `context_namespace`
+- `context_kv`
+- `memory_record`
+- `memory_embedding`
+- `memory_recall_log`
+
+目标:
+
+- 跑通“Agent + 技能 + 记忆”
+
+### V0.3 新增表
+
+- `team_definition`
+- `team_version`
+- `team_member_binding`
+- `run_state_snapshot`
+- `run_queue_task`
+- `context_change_log`
+- `knowledge_base`
+- `document`
+- `document_chunk`
+- `chunk_embedding`
+- `retrieval_log`
+
+目标:
+
+- 跑通“多智能体 + 子流程 + 检索 + 恢复”
+
+### V0.4 新增表
+
+- `organization`
+- `role`
+- `permission`
+- `user_role`
+- `role_permission`
+- `plugin_definition`
+- `plugin_version`
+- `trace_span`
+- `trace_event`
+- `eval_suite`
+- `eval_case`
+- `eval_run`
+- `eval_result`
+
+目标:
+
+- 跑通“治理、可观测、评测、插件化”
+
+## 10. 跨服务数据边界建议
+
+为避免后续服务拆分时数据库耦合过深,建议遵循以下约束:
+
+- `auth-service` 只直接管理 `auth_db`
+- `workflow-service` 只直接写 `app_db`
+- `runtime-service` 只直接写 `runtime_db`
+- `memory-service` 只直接写 `memory_db`
+- `tool-service` 只直接写 `tool_db`
+- `retrieval-service` 只直接写 `retrieval_db`
+- `trace-service` 只直接写 `trace_db`
+
+其他服务如果需要这些数据:
+
+- 通过 API 读
+- 或通过事件异步复制只读视图
+
+不要在应用层做跨库强事务。
+
+## 11. 迁移与演进建议
+
+### 11.1 迁移工具
+
+- `Alembic` 统一管理迁移
+- 每个服务单独 migration 目录
+- 共用库只提供模型定义,不直接统一迁移所有库
+
+### 11.2 演进策略
+
+- 先 schema 兼容,再代码切换
+- 大字段新增优先 nullable
+- 热表结构变更优先分阶段 rollout
+- 分区表和归档表尽量提前规划
+
+### 11.3 审计策略
+
+以下操作建议强制审计:
+
+- 应用发布
+- 工作流导入
+- 工具绑定变更
+- 记忆写入策略变更
+- 权限变更
+- 人工审批结果
+
+## 12. 推荐下一步
+
+如果进入工程实施,最顺的下一步是:
+
+1. 先把 `V0.1` 的 SQLAlchemy 模型定义出来
+2. 建 Monorepo 下的多服务目录和共享 `libs`
+3. 先跑通 `app_db + session_db + runtime_db + tool_db`
+4. 后续再补 `memory_db` 和 `trace_db`
+
+## 13. 结论
+
+这套数据库设计的核心思想是:
+
+- 用 PostgreSQL 承载配置、运行、治理主数据
+- 用 Redis 承载高频短期状态和幂等控制
+- 用 pgvector 承载语义记忆与知识检索
+- 用对象存储承载大对象和原始产物
+- 用分域设计保证未来多服务拆分和水平扩展不需要推翻重来
+
+如果你下一步继续让我执行,我建议直接进入:
+
+1. `V0.1 SQLAlchemy 模型骨架`
+2. `Alembic 初始建表脚本`

+ 803 - 0
docs/agent-platform-multi-service-roadmap.md

@@ -0,0 +1,803 @@
+# Python 智能体开发平台规划(多服务 / 可横向扩展版)
+
+## 1. 项目定位
+
+本项目目标不是做一个单体的聊天机器人系统,而是建设一套基于 Python 的智能体开发平台,支持:
+
+- 多应用承载:客服、销售、运营、知识问答、流程自动化、研发助手等
+- 多智能体协作:单 Agent、团队 Agent、角色分工、任务拆解、结果汇总
+- 复杂流程编排:LLM、条件分支、代码节点、工具节点、检索节点、子流程、人工审批
+- 记忆系统:短期记忆、长期记忆、用户记忆、任务记忆、领域隔离记忆
+- 技能与工具扩展:技能复用、工具注册、插件接入、外部系统集成
+- 平台化运营:版本管理、调试回放、权限治理、监控审计、灰度发布
+
+一句话定位:
+
+**一套支持多应用、多智能体、多流程、多服务部署的智能体编排与运行平台。**
+
+## 2. 建设原则
+
+### 2.1 架构原则
+
+- 先做运行内核,再做可视化 Studio
+- 先定义内部 DSL,再做第三方流程导入
+- 以图执行引擎为中心,而不是以单个 Agent 为中心
+- 状态和记忆是平台一等公民,不能只靠 prompt 拼接
+- 所有执行链路必须可追踪、可回放、可审计
+- 单服务可独立部署,服务间通过事件和 API 解耦
+
+### 2.2 工程原则
+
+- 代码按领域边界拆分,避免“伪微服务”
+- 核心协议统一,服务内部可独立演进
+- 同步调用只用于短链路,长链路一律事件化
+- 服务设计默认支持无状态横向扩容
+- 数据库按域拆分,读写边界明确
+
+## 3. 总体架构
+
+平台建议采用“网关 + 核心运行时 + 支撑服务”的多服务架构。
+
+### 3.1 逻辑分层
+
+1. 接入层
+- API Gateway
+- Web Studio
+- SDK / Webhook
+
+2. 编排与运行层
+- Session Service
+- Workflow Service
+- Agent Runtime Service
+- Team Runtime Service
+- Scheduler Service
+
+3. 能力层
+- Tool Service
+- Skill Service
+- Memory Service
+- Retrieval Service
+- Plugin Service
+- Model Gateway
+
+4. 支撑层
+- Auth / Tenant Service
+- Trace / Eval Service
+- Notification Service
+- File / Artifact Service
+
+5. 基础设施层
+- PostgreSQL
+- Redis
+- pgvector
+- MinIO
+- Kafka / RabbitMQ
+- Prometheus / Grafana / OpenTelemetry
+
+### 3.2 推荐部署形态
+
+- `api-gateway`:统一接入入口
+- `studio-web`:管理后台
+- `session-service`:会话与运行入口
+- `workflow-service`:流程定义、版本、执行图解析
+- `runtime-service`:节点执行调度
+- `agent-service`:单智能体执行
+- `team-service`:多智能体协作
+- `memory-service`:记忆与上下文读写
+- `tool-service`:工具注册、鉴权、调用
+- `retrieval-service`:知识库和语义检索
+- `model-gateway`:统一模型接入
+- `trace-service`:追踪、回放、评测
+- `scheduler-service`:异步任务、延迟任务、重试
+- `auth-service`:用户、组织、租户、权限
+- `artifact-service`:文件、产物、日志附件
+
+## 4. 为什么要做多服务
+
+如果平台未来要支持复杂工作流、多租户、多团队并发开发,以及长链路任务执行,单体架构会很快遇到以下问题:
+
+- 模型调用、工具调用、检索调用耦合在一起,扩容粗糙
+- 长任务阻塞普通会话接口
+- 记忆、工具、检索、工作流版本难以独立演进
+- 某类流量暴涨时无法按服务维度单独扩容
+- 复杂流程出问题时定位困难
+
+因此建议从一开始就按照“模块化单体 -> 受控多服务”的方式设计代码和边界,即使初期只部署成少量服务,也要保证未来拆分成本可控。
+
+## 5. 服务拆分方案
+
+### 5.1 API Gateway
+
+职责:
+
+- 统一 HTTP / WebSocket / SSE 入口
+- 用户认证与请求转发
+- 限流、熔断、审计入口
+- 聚合常用接口
+
+扩展方式:
+
+- 完全无状态
+- 可直接多副本水平扩容
+
+### 5.2 Session Service
+
+职责:
+
+- 会话生命周期管理
+- 用户请求接收
+- 会话变量初始化
+- 运行实例创建
+- 对接 Runtime Service 发起执行
+
+数据边界:
+
+- `session`
+- `conversation`
+- `message`
+- `run_request`
+
+扩展方式:
+
+- 无状态服务 + Redis 会话缓存
+- 通过消息队列把长任务移出请求线程
+
+### 5.3 Workflow Service
+
+职责:
+
+- 应用定义管理
+- 工作流 DSL 存储和版本化
+- 节点/边校验
+- 工作流编译和执行计划生成
+- 第三方 YAML 导入适配
+
+数据边界:
+
+- `app_definition`
+- `app_version`
+- `workflow_definition`
+- `workflow_version`
+- `workflow_template`
+
+扩展方式:
+
+- 读多写少,适合多副本部署
+- 编译结果可缓存到 Redis
+
+### 5.4 Runtime Service
+
+职责:
+
+- 工作流运行调度
+- 节点状态流转
+- 并发控制
+- 重试 / 超时 / 取消 / 恢复
+- 事件发布
+
+这是平台核心服务。
+
+数据边界:
+
+- `workflow_run`
+- `node_run`
+- `run_event`
+- `run_snapshot`
+
+扩展方式:
+
+- Worker 模式水平扩展
+- 消费消息队列任务
+- 通过分片键避免同一 run 被多个 worker 冲突处理
+
+### 5.5 Agent Service
+
+职责:
+
+- 单智能体执行
+- Prompt 拼装
+- 结构化输出
+- 工具调用策略
+- 记忆召回拼装
+
+数据边界:
+
+- `agent_definition`
+- `agent_version`
+- `agent_policy`
+
+扩展方式:
+
+- 无状态执行服务
+- 可按模型类型、业务类型拆分不同池子
+
+### 5.6 Team Service
+
+职责:
+
+- 多智能体团队定义
+- 任务拆解
+- 角色分配
+- 共享上下文管理
+- 结果汇总和冲突裁决
+
+数据边界:
+
+- `team_definition`
+- `team_version`
+- `team_member`
+- `team_run`
+- `team_task`
+
+扩展方式:
+
+- 和 Agent Service 一样无状态
+- 高并发时可独立扩容,避免影响普通单 Agent 任务
+
+### 5.7 Memory Service
+
+职责:
+
+- 短期记忆读写
+- 长期记忆写入与召回
+- 领域记忆 namespace 隔离
+- 会话状态与上下文存取
+- 记忆压缩和清洗
+
+数据边界:
+
+- `memory_record`
+- `memory_fact`
+- `memory_episode`
+- `context_namespace`
+- `context_kv`
+
+扩展方式:
+
+- API 层无状态
+- 底层依赖 PostgreSQL + pgvector + Redis
+
+### 5.8 Tool Service
+
+职责:
+
+- 工具定义、注册、版本管理
+- 工具鉴权
+- 参数校验
+- 调用转发
+- 调用审计
+
+数据边界:
+
+- `tool_definition`
+- `tool_version`
+- `tool_binding`
+- `tool_credential`
+- `tool_invocation_log`
+
+扩展方式:
+
+- 工具元数据无状态服务
+- 真正执行可下沉到 executor worker
+
+### 5.9 Retrieval Service
+
+职责:
+
+- 文档导入
+- 分片、Embedding
+- 向量检索
+- 混合检索
+- 知识库权限隔离
+
+数据边界:
+
+- `knowledge_base`
+- `document`
+- `document_chunk`
+- `embedding_index`
+- `retrieval_log`
+
+### 5.10 Model Gateway
+
+职责:
+
+- 统一管理 OpenAI / Azure / Anthropic / Gemini / 本地模型
+- 模型路由
+- 限流与熔断
+- token 统计与成本统计
+- 模型级缓存
+
+扩展方式:
+
+- 纯无状态
+- 可单独横向扩容
+
+### 5.11 Trace Service
+
+职责:
+
+- 采集 run trace、node trace、tool trace、memory trace
+- 执行链路回放
+- 错误定位
+- 离线评测
+- 成本与性能分析
+
+数据边界:
+
+- `trace_span`
+- `trace_event`
+- `eval_case`
+- `eval_result`
+
+## 6. 服务通信模型
+
+### 6.1 同步调用
+
+适合:
+
+- 用户实时请求
+- 配置查询
+- 权限校验
+- 轻量级元数据读取
+
+建议使用:
+
+- REST API
+- 内部 gRPC 可作为后续优化选项
+
+### 6.2 异步调用
+
+适合:
+
+- 工作流执行
+- 节点执行调度
+- 记忆写入
+- 索引构建
+- 批量评测
+- 失败重试
+
+建议使用:
+
+- Kafka 或 RabbitMQ
+- Celery / Dramatiq 作为任务分发层
+
+### 6.3 推荐事件
+
+- `run.created`
+- `run.started`
+- `node.scheduled`
+- `node.completed`
+- `node.failed`
+- `memory.updated`
+- `tool.invoked`
+- `team.task.created`
+- `trace.emitted`
+
+## 7. 数据存储与边界
+
+### 7.1 核心原则
+
+- 配置类数据和运行类数据分离
+- 热数据和冷数据分离
+- 向量数据独立索引
+- 文件产物独立存储
+
+### 7.2 推荐存储
+
+- PostgreSQL:应用、流程、Agent、Team、工具、运行记录
+- Redis:缓存、幂等键、分布式锁、短期上下文、任务状态
+- pgvector:语义记忆和知识检索
+- MinIO:文件、附件、产物、回放原始数据
+- Kafka / RabbitMQ:异步事件流
+
+### 7.3 数据拆分建议
+
+初期可共用一个 PostgreSQL 集群,但按 schema 或 database 区分域:
+
+- `app_db`
+- `runtime_db`
+- `memory_db`
+- `tool_db`
+- `trace_db`
+- `auth_db`
+
+后续热点域可独立迁移。
+
+## 8. 横向扩展策略
+
+### 8.1 无状态服务优先
+
+以下服务默认设计为无状态:
+
+- `api-gateway`
+- `workflow-service`
+- `agent-service`
+- `team-service`
+- `tool-service`
+- `model-gateway`
+
+这样可以直接通过容器副本水平扩容。
+
+### 8.2 状态服务去中心化
+
+有状态能力不要依赖本地内存:
+
+- 会话状态放 Redis / DB
+- 运行状态放 Runtime DB
+- 记忆放 Memory DB
+- 文件产物放对象存储
+
+### 8.3 长任务与短请求隔离
+
+- 用户入口只负责接收请求和返回 run_id
+- 长链路任务由 Runtime Worker 处理
+- WebSocket / SSE 通过 trace/event 推流
+
+### 8.4 分布式控制
+
+需要引入:
+
+- 分布式锁
+- 幂等键
+- 节点执行 lease
+- 重试次数与死信队列
+- 取消和超时标记
+
+### 8.5 扩容维度
+
+不同服务按不同指标扩容:
+
+- Gateway:QPS
+- Model Gateway:模型请求 TPS 和延迟
+- Runtime Worker:待处理 run / node 队列长度
+- Retrieval:检索吞吐和索引吞吐
+- Team Service:复杂任务并发数
+- Trace Service:事件写入速率
+
+## 9. 统一内部 DSL
+
+不要直接使用第三方工作流协议作为内核运行格式,建议定义内部 DSL:
+
+- `workflow`
+- `nodes`
+- `edges`
+- `inputs`
+- `outputs`
+- `policies`
+- `runtime_options`
+
+节点类型至少支持:
+
+- `llm`
+- `condition`
+- `code`
+- `tool`
+- `retrieval`
+- `template`
+- `answer`
+- `agent`
+- `team`
+- `human_approval`
+- `sub_workflow`
+
+第三方 YAML 通过 Importer 转换为内部 DSL。
+
+## 10. 代码仓结构建议
+
+建议采用 Monorepo,多服务共享基础库。
+
+```text
+auto-platform/
+  services/
+    api-gateway/
+    session-service/
+    workflow-service/
+    runtime-service/
+    agent-service/
+    team-service/
+    memory-service/
+    tool-service/
+    retrieval-service/
+    model-gateway/
+    trace-service/
+    auth-service/
+    artifact-service/
+    scheduler-service/
+  libs/
+    core-domain/
+    core-dsl/
+    core-events/
+    core-auth/
+    core-trace/
+    sdk-models/
+    sdk-tools/
+    sdk-memory/
+  deployments/
+    docker/
+    k8s/
+    helm/
+  docs/
+  scripts/
+  tests/
+```
+
+### 10.1 公共库职责
+
+- `core-domain`:领域模型、枚举、基础对象
+- `core-dsl`:工作流 DSL、节点协议、校验器
+- `core-events`:事件定义、消息契约
+- `core-auth`:认证鉴权模型
+- `core-trace`:统一 trace schema
+- `sdk-models`:模型调用封装
+- `sdk-tools`:工具协议和客户端
+- `sdk-memory`:记忆访问协议
+
+## 11. Python 服务代码结构建议
+
+每个服务内部尽量保持一致结构:
+
+```text
+service-name/
+  app/
+    api/
+    application/
+    domain/
+    infrastructure/
+    tasks/
+    schemas/
+    bootstrap/
+  tests/
+  pyproject.toml
+```
+
+### 11.1 分层说明
+
+- `api`:HTTP / WebSocket / gRPC 接口
+- `application`:用例编排、服务层
+- `domain`:领域实体、仓储接口、规则
+- `infrastructure`:DB、Redis、MQ、第三方适配器
+- `tasks`:异步任务消费
+- `schemas`:请求响应模型
+- `bootstrap`:依赖注入和启动
+
+## 12. 核心运行模型
+
+### 12.1 一次请求的链路
+
+1. 用户请求进入 `api-gateway`
+2. `session-service` 创建会话和 run
+3. `workflow-service` 返回对应 workflow version 和执行计划
+4. `runtime-service` 创建 root run 并投递节点任务
+5. 各 executor 调用 `agent-service`、`tool-service`、`retrieval-service`
+6. `memory-service` 负责读写上下文和记忆
+7. `trace-service` 持续收集执行事件
+8. 用户通过 SSE/WebSocket 获取进度和结果
+
+### 12.2 节点执行模型
+
+每类节点统一接口:
+
+- `prepare(context)`
+- `execute(input)`
+- `handle_result(output)`
+- `emit_events()`
+- `schedule_next_nodes()`
+
+这样方便以后继续扩展节点类型。
+
+## 13. 版本落地路线
+
+### V0.1 基础内核版
+
+目标:
+
+- 跑通最小闭环
+
+交付:
+
+- Monorepo 工程
+- `api-gateway`
+- `session-service`
+- `workflow-service`
+- `runtime-service`
+- `model-gateway`
+- `tool-service`
+- 基础 DSL
+- 基础节点:`llm`、`condition`、`tool`、`code`、`answer`
+
+验收标准:
+
+- 可以创建一个应用并执行一条流程
+- 支持基础工具调用
+- 支持 run 级日志追踪
+
+周期:
+
+- 4~6 周
+
+### V0.2 智能体版
+
+目标:
+
+- 把流程平台升级为智能体平台
+
+交付:
+
+- `agent-service`
+- `memory-service`
+- 技能系统
+- Agent 节点
+- 短期记忆
+- 长期记忆基础版
+
+验收标准:
+
+- 单 Agent 能结合工具与记忆完成任务
+- 记忆支持按用户、应用、会话隔离
+
+周期:
+
+- 4~5 周
+
+### V0.3 多智能体与复杂流程版
+
+目标:
+
+- 支撑复杂业务场景
+
+交付:
+
+- `team-service`
+- Team 节点
+- `retrieval-service`
+- 子流程节点
+- 并行节点
+- 人工审批节点
+- 异步挂起与恢复
+- 领域记忆 namespace
+
+验收标准:
+
+- 支持复杂路由、长链路、多角色协作
+- 支持失败恢复、流程中断、人工接管
+
+周期:
+
+- 5~6 周
+
+### V0.4 平台治理版
+
+目标:
+
+- 支撑多人协作与生产发布
+
+交付:
+
+- `auth-service`
+- `trace-service`
+- 环境管理
+- 版本发布
+- 灰度策略
+- 审计日志
+- 成本与性能监控
+
+验收标准:
+
+- 多团队可在同平台开发多个应用
+- 平台具备基础治理能力
+
+周期:
+
+- 4~6 周
+
+### V0.5 Studio 可视化版
+
+目标:
+
+- 提升交付效率
+
+交付:
+
+- 可视化流程设计器
+- Agent / Team 配置台
+- 技能和工具配置台
+- 回放与调试页面
+- 评测面板
+
+验收标准:
+
+- 大部分应用可通过平台配置完成搭建
+
+周期:
+
+- 4~6 周
+
+### V1.0 企业生产版
+
+目标:
+
+- 进入生产化稳定运营
+
+交付:
+
+- 多租户
+- 配额与计费
+- 高可用部署
+- 沙箱执行
+- 插件市场
+- 第三方工作流导入适配器
+- 大规模性能优化
+
+验收标准:
+
+- 可稳定支撑多个生产应用和复杂工作流
+
+周期:
+
+- 6~8 周
+
+## 14. MVP 与最终形态的关系
+
+初期不建议一开始就拆十几个独立服务上线。更稳妥的方式是:
+
+### 阶段 A
+
+- 先按多服务边界写代码
+- 但物理上只部署为 3~4 个服务
+
+建议初期合并:
+
+- `session-service + workflow-service`
+- `agent-service + team-service + model-gateway`
+- `tool-service + retrieval-service + memory-service`
+
+### 阶段 B
+
+- 当并发量和复杂度上来后再独立拆出热点服务
+
+这样既保留横向扩展能力,也避免前期微服务治理成本过高。
+
+## 15. 技术选型建议
+
+- Python:`3.11+`
+- Web 框架:`FastAPI`
+- 数据校验:`Pydantic v2`
+- ORM:`SQLAlchemy 2.x`
+- 迁移:`Alembic`
+- 任务队列:`Celery` 或 `Dramatiq`
+- 消息队列:`Kafka` 或 `RabbitMQ`
+- 缓存:`Redis`
+- 主数据库:`PostgreSQL`
+- 向量检索:`pgvector`
+- 对象存储:`MinIO`
+- 容器化:`Docker + Kubernetes`
+- 可观测:`OpenTelemetry + Prometheus + Grafana`
+
+## 16. 风险与治理建议
+
+### 16.1 主要风险
+
+- 过早微服务化导致研发效率低
+- 多智能体成本和延迟快速上升
+- 记忆污染导致答复不稳定
+- 工具权限控制不到位带来安全问题
+- 流程 DSL 演进失控导致兼容性问题
+
+### 16.2 治理建议
+
+- 所有协议强制版本化
+- 所有节点执行结果强制 trace
+- 所有工具调用强制审计
+- 所有记忆写入建立策略控制
+- 长链路任务默认异步执行
+- 先支持 80% 场景,再做高级自治能力
+
+## 17. 结论
+
+这套平台的正确建设路径,不是从“聊天机器人”出发,而是从“可横向扩展的流程运行内核”出发。只有先把工作流执行、状态管理、记忆隔离、服务边界和异步通信做好,后面的多智能体、复杂业务编排、Studio 可视化和企业级治理才能稳稳落下去。
+
+如果下一步进入实施,建议优先产出两份工程文档:
+
+1. 数据库表结构设计
+2. Monorepo 代码骨架与各服务启动模板