10 KiB
10 KiB
reviewStatus, reviewedAt, replacedBy
| reviewStatus | reviewedAt | replacedBy |
|---|---|---|
| pending | null | null |
第一阶段工程基线数据库设计
1. 设计边界
本文档定义第一阶段用户资料和 Agent 运行审计数据的逻辑结构、约束、索引、迁移与回滚策略。开发和自动化测试使用 SQLite,集成与生产使用 PostgreSQL。
项目尚未确认 PostgreSQL 精确版本,因此本文档不采用版本专属字段、索引方法、表达式索引或方言 SQL。实现以 Django 6.0.8 ORM 和迁移能力表达;版本专属优化须在 PostgreSQL 版本确认后另行评审。
关联设计:
2. 设计原则
- 用户私有数据必须具有明确的用户归属。
- 状态转换由服务层执行,数据库约束负责守住唯一性和基础合法性。
- 运行事件采用追加模式,保留审计轨迹。
- JSON 字段只保存经过脱敏和大小限制的摘要。
- 时间统一存储为支持时区的 Django 时间值,显示时转换到用户时区。
- 金额、token 和耗时使用确定类型,避免浮点误差。
- 表名、约束名和索引名在迁移中显式稳定,避免不同数据库自动命名差异影响排查。
3. 实体关系
erDiagram
AUTH_USER ||--o| USER_PROFILE : has
AUTH_USER ||--o{ AGENT_RUN : owns
AGENT_RUN ||--o{ AGENT_RUN_EVENT : contains
AGENT_RUN ||--o{ TOOL_CALL : contains
AGENT_RUN ||--o{ HUMAN_APPROVAL : requests
AUTH_USER ||--o{ HUMAN_APPROVAL : resolves
4. 表结构草案
4.1 accounts_user_profile
| 字段 | Django 类型建议 | 空值 | 约束与说明 |
|---|---|---|---|
id |
BigAutoField |
否 | 主键 |
user_id |
OneToOneField |
否 | 唯一,关联 Django 用户 |
display_name |
CharField |
是 | 空字符串表示未设置,长度上限实现时确认 |
timezone |
CharField |
否 | 默认 Asia/Shanghai,必须来自受控候选 |
created_at |
DateTimeField |
否 | 创建时写入 |
updated_at |
DateTimeField |
否 | 修改时更新 |
删除策略:用户尚无审计数据时资料可随用户删除;用户存在 Agent Run 时由运行记录的保护关系阻止用户物理删除。
4.2 agent_runtime_agent_run
| 字段组 | 字段 | 类型建议 | 说明 |
|---|---|---|---|
| 标识 | id |
UUIDField |
主键,避免在页面暴露连续编号 |
| 归属 | owner_id |
ForeignKey(PROTECT) |
用户私有归属 |
| 展示 | title |
CharField |
简短标题 |
| 状态 | status |
CharField |
使用代码枚举和数据库检查约束 |
| 并发 | lock_version |
PositiveBigIntegerField |
每次状态写入递增 |
| 摘要 | input_summary |
JSONField |
脱敏、限长输入摘要 |
| 摘要 | output_summary |
JSONField |
可空,脱敏输出摘要 |
| 版本 | agent_name |
CharField |
Agent 稳定标识 |
| 版本 | agent_version |
CharField |
可空 |
| 版本 | instruction_version |
CharField |
可空 |
| 版本 | toolset_version |
CharField |
可空 |
| 模型 | model_name |
CharField |
第一阶段允许为空 |
| 追踪 | trace_id |
CharField |
可空,非秘密标识 |
| 时间 | started_at |
DateTimeField |
可空 |
| 时间 | finished_at |
DateTimeField |
可空 |
| 耗时 | duration_ms |
PositiveBigIntegerField |
可空 |
| 用量 | input_tokens |
PositiveBigIntegerField |
可空 |
| 用量 | output_tokens |
PositiveBigIntegerField |
可空 |
| 费用 | estimated_cost |
DecimalField |
可空,精度实现前确认 |
| 失败 | error_code |
CharField |
可空、稳定机器码 |
| 失败 | error_summary |
TextField |
可空、脱敏且限长 |
| 审计 | created_at |
DateTimeField |
否 |
| 审计 | updated_at |
DateTimeField |
否 |
检查约束至少保证:
status属于已定义枚举。lock_version >= 0。- token、耗时和费用非负。
跨字段状态不变量仍由服务层验证,因为 SQLite 与 PostgreSQL 对复杂检查约束和时间语义的行为需要保持一致。
4.3 agent_runtime_agent_run_event
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
BigAutoField |
主键 |
run_id |
ForeignKey(PROTECT) |
关联 Run,审计事件不可级联丢失 |
sequence |
PositiveBigIntegerField |
Run 内递增序号 |
event_type |
CharField |
事件枚举 |
summary |
CharField |
短摘要 |
payload_summary |
JSONField |
脱敏事件数据 |
occurred_at |
DateTimeField |
业务发生时间 |
created_at |
DateTimeField |
数据库记录时间 |
唯一约束:(run_id, sequence)。
索引:(run_id, sequence) 唯一索引已覆盖详情页时间线读取,无需重复创建同前缀普通索引。
4.4 agent_runtime_tool_call
| 字段组 | 字段 | 类型建议 | 说明 |
|---|---|---|---|
| 标识 | id |
BigAutoField |
主键 |
| 归属 | run_id |
ForeignKey(PROTECT) |
关联 Run |
| 调用 | call_id |
CharField |
Run 内调用标识 |
| 工具 | tool_name |
CharField |
工具稳定名称 |
| 工具 | tool_version |
CharField |
可空 |
| 幂等 | idempotency_key |
CharField |
可空,作用域见约束 |
| 状态 | status |
CharField |
started/succeeded/failed |
| 摘要 | arguments_summary |
JSONField |
脱敏、限长 |
| 摘要 | result_summary |
JSONField |
可空、脱敏、限长 |
| 失败 | error_code |
CharField |
可空 |
| 失败 | error_summary |
TextField |
可空、限长 |
| 时间 | started_at |
DateTimeField |
否 |
| 时间 | finished_at |
DateTimeField |
可空 |
| 耗时 | duration_ms |
PositiveBigIntegerField |
可空 |
| 审计 | created_at、updated_at |
DateTimeField |
否 |
唯一约束:
(run_id, call_id)唯一。- 非空幂等键的作用域在真实工具模型确定前采用
(run_id, idempotency_key),后续如需跨 Run 幂等必须重新设计业务作用域。
4.5 agent_runtime_human_approval
| 字段 | 类型建议 | 说明 |
|---|---|---|
id |
UUIDField |
主键 |
run_id |
ForeignKey(PROTECT) |
关联 Run |
request_key |
CharField |
Run 内稳定请求键 |
approval_type |
CharField |
确认类型枚举 |
status |
CharField |
确认状态枚举 |
request_summary |
JSONField |
脱敏请求摘要 |
decision_summary |
JSONField |
可空、脱敏处理摘要 |
requested_at |
DateTimeField |
请求时间 |
resolved_at |
DateTimeField |
可空 |
resolved_by_id |
ForeignKey(PROTECT) |
可空,处理人 |
created_at、updated_at |
DateTimeField |
审计时间 |
唯一约束:(run_id, request_key)。
索引:(status, requested_at),支持 Admin 查询待处理确认。
5. 主要访问模式与索引
| 访问模式 | 过滤与排序 | 索引建议 |
|---|---|---|
| 当前用户 Run 列表 | owner_id,created_at DESC |
(owner_id, created_at) |
| 当前用户按状态查询 | owner_id、status、created_at DESC |
第一阶段无筛选需求,暂不新增 |
| Run 事件时间线 | run_id、sequence ASC |
唯一索引 (run_id, sequence) |
| Run 工具调用列表 | run_id、started_at ASC |
(run_id, started_at) |
| 待处理人工确认 | status、requested_at ASC |
(status, requested_at) |
| trace 定位运行 | trace_id |
有真实查询需求后再决定唯一性和索引 |
索引以第一阶段真实页面和 Admin 查询为依据,不为未来假设查询提前增加索引。
6. 事务与并发
- Run 状态变更、状态事件和关联确认记录在同一事务内完成。
- 更新 Run 前锁定目标记录,并校验
lock_version。 - 事件序号在锁定 Run 后读取最大值并递增。
- 唯一约束捕获遗漏的并发冲突,并转换为领域冲突错误。
- 工具外部调用不持有数据库事务;开始和结束分别使用短事务。
- SQLite 不提供等价的行锁验证,PostgreSQL 集成测试必须覆盖双并发更新。
7. 数据生命周期
- 用户资料可修改,保留最新值即可。
- Agent Run、事件、工具调用和人工确认属于审计数据,第一阶段不提供删除入口。
- 用户存在运行记录时不得物理删除,改为停用账户。
- 第一阶段不自动清理日志或审计记录。
- 后续建立保留周期时必须区分运行摘要、完整原始证据和应用日志,不能使用同一删除策略。
8. 迁移顺序
- 创建
common基础抽象代码,不生成抽象表。 - 创建
accounts与UserProfile迁移。 - 创建
agent_runtime核心表和基础约束。 - 单独迁移补充经验证的组合索引和检查约束。
- 在空 SQLite 数据库执行完整迁移。
- 确认 PostgreSQL 精确版本和隔离环境。
- 在空 PostgreSQL 数据库执行完整迁移和核心约束测试。
迁移发布后不得直接修改历史迁移;修正通过新迁移完成。
9. 回滚策略
- 第一阶段没有存量业务数据转换,回滚以撤销未发布迁移为主。
- 已发布环境回滚前必须确认表内是否已产生审计数据。
- 存在数据时禁止直接反向删除表,应先停止写入、导出验证数据并制定显式迁移。
- 应用代码回滚必须与数据库迁移兼容,不能先删除旧代码仍会读取的字段。
10. 验证清单
- Django 迁移无遗漏。
- 空 SQLite 数据库全量迁移和反向迁移测试。
- 空 PostgreSQL 数据库全量迁移。
- 用户一对一资料唯一约束。
- Run 状态、非负数值和用户保护约束。
- 事件序号唯一约束。
- 工具调用编号和幂等键冲突。
- 人工确认请求键唯一约束。
- 两个并发状态更新只有一个成功。
- 主要列表查询使用预期索引;数据量不足时不声称完成性能验收。
11. 待确认项
- PostgreSQL 精确版本、部署方式和连接池策略。
- 摘要字段的最大序列化字节数。
- 字符字段长度、费用精度和稳定约束名称。
- trace 标识是否需要全局唯一。
- PostgreSQL 版本确认后是否需要部分索引或其他专属优化。