一、模型供应商表 model_providers
python
# 文件: app/db/models.py, 行 40-52
class ModelProvider(Base):
__tablename__ = "model_providers"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(100), unique=True) # 供应商名称
provider_type: Mapped[ProviderType] = mapped_column(String(32)) # openai/anthropic/qwen/minimax/deepseek
model_name: Mapped[str] = mapped_column(String(120)) # 模型名(如 gpt-4o)
api_key_enc: Mapped[str | None] = mapped_column(Text) # 🔐 加密的 API Key
base_url: Mapped[str | None] = mapped_column(String(300)) # 自定义 API 地址
temperature: Mapped[float] = mapped_column(default=0.0) # 温度参数
is_default: Mapped[bool] = mapped_column(Boolean, default=False) # 是否默认模型
extra: Mapped[dict] = mapped_column(JSON, default=dict) # 额外配置
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)二、SSH 密钥库表 ssh_keys
python
# 文件: app/db/models.py, 行 58-67
class SSHKey(Base):
__tablename__ = "ssh_keys"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(100), unique=True) # 密钥名称(如 prod-deploy)
private_key_enc: Mapped[str] = mapped_column(Text) # 🔐 加密的私钥
passphrase_enc: Mapped[str | None] = mapped_column(Text) # 🔐 加密的密码短语
description: Mapped[str | None] = mapped_column(Text) # 描述说明
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)三、服务器表 servers
python
# 文件: app/db/models.py, 行 70-86
class Server(Base):
__tablename__ = "servers"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(100), unique=True) # 服务器名称
host: Mapped[str] = mapped_column(String(255)) # 主机地址
port: Mapped[int] = mapped_column(Integer, default=22) # SSH 端口
username: Mapped[str] = mapped_column(String(100)) # 用户名
auth_type: Mapped[str] = mapped_column(String(20), default="password") # 认证方式
password_enc: Mapped[str | None] = mapped_column(Text) # 🔐 加密的密码
private_key_enc: Mapped[str | None] = mapped_column(Text) # 🔐 加密的私钥
passphrase_enc: Mapped[str | None] = mapped_column(Text) # 🔐 加密的密码短语
ssh_key_id: Mapped[int | None] = mapped_column(ForeignKey("ssh_keys.id")) # 关联密钥库
tags: Mapped[list] = mapped_column(JSON, default=list) # 标签(如 ["prod", "web"])
description: Mapped[str | None] = mapped_column(Text) # 描述说明
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)四、云账号表 cloud_accounts
python
# 文件: app/db/models.py, 行 93-111
class CloudAccount(Base):
__tablename__ = "cloud_accounts"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(100), unique=True) # 云账号名称(如 aliyun-prod)
cloud_type: Mapped[CloudType] = mapped_column(String(32)) # aliyun / cloudflare
transport: Mapped[str] = mapped_column(String(20), default="stdio") # stdio / streamable_http
# stdio 方式
command: Mapped[str | None] = mapped_column(String(300)) # MCP 命令
args: Mapped[list] = mapped_column(JSON, default=list) # 命令参数
# http 方式
url: Mapped[str | None] = mapped_column(String(400)) # HTTP 端点
secrets_enc: Mapped[dict] = mapped_column(JSON, default=dict) # 🔐 加密的密钥字典
enabled: Mapped[bool] = mapped_column(Boolean, default=True) # 是否启用
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)五、会话表 conversations
python
# 文件: app/db/models.py, 行 117-126
class Conversation(Base):
__tablename__ = "conversations"
id: Mapped[int] = mapped_column(primary_key=True)
thread_id: Mapped[str] = mapped_column(String(64), unique=True, index=True) # LangGraph thread ID
title: Mapped[str | None] = mapped_column(String(255)) # 会话标题
status: Mapped[str] = mapped_column(String(32), default="active") # active / waiting_approval / done
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
audits: Mapped[list["AuditLog"]] = relationship(back_populates="conversation") # 关联审计日志六、消息表 messages
python
# 文件: app/db/models.py, 行 129-138
class Message(Base):
__tablename__ = "messages"
id: Mapped[int] = mapped_column(primary_key=True)
conversation_id: Mapped[int | None] = mapped_column(ForeignKey("conversations.id")) # 关联会话
role: Mapped[str] = mapped_column(String(20)) # user / assistant / tool
content: Mapped[str] = mapped_column(Text, default="") # 消息内容
tool_name: Mapped[str | None] = mapped_column(String(120)) # 工具名称(tool 类型时)
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)七、自动审批白名单表 auto_approve_rules
python
# 文件: app/db/models.py, 行 141-147
class AutoApproveRule(Base):
__tablename__ = "auto_approve_rules"
id: Mapped[int] = mapped_column(primary_key=True)
command: Mapped[str] = mapped_column(Text) # 精确命令文本
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)八、审计日志表 audit_logs
python
# 文件: app/db/models.py, 行 150-166
class AuditLog(Base):
__tablename__ = "audit_logs"
id: Mapped[int] = mapped_column(primary_key=True)
conversation_id: Mapped[int | None] = mapped_column(ForeignKey("conversations.id")) # 关联会话
tool_name: Mapped[str] = mapped_column(String(120)) # 工具名称
target: Mapped[str | None] = mapped_column(String(255)) # 目标(服务器名/云账号名)
command: Mapped[str | None] = mapped_column(Text) # 执行的命令
level: Mapped[CommandLevel] = mapped_column(String(20), default=CommandLevel.readonly) # readonly/mutating/dangerous
approved: Mapped[bool | None] = mapped_column(Boolean) # 是否审批通过(None=无需审批)
approved_by: Mapped[str | None] = mapped_column(String(100)) # 审批人
success: Mapped[bool] = mapped_column(Boolean, default=True) # 是否执行成功
output: Mapped[str | None] = mapped_column(Text) # 执行输出(限制 5000 字符)
created_at: Mapped[dt.datetime] = mapped_column(DateTime(timezone=True), default=_now)
conversation: Mapped["Conversation | None"] = relationship(back_populates="audits")📋 表结构汇总
| 表名 | 主键 | 用途 | 关联关系 |
|---|---|---|---|
model_providers | id | LLM 供应商配置 | - |
ssh_keys | id | SSH 私钥库 | 1 ↔ N → servers |
servers | id | 服务器 SSH 配置 | N → 1 ssh_keys |
cloud_accounts | id | 云账号 MCP 配置 | - |
conversations | id | 会话记录 | 1 ↔ N → audit_logs |
messages | id | 消息历史 | N → 1 conversations |
auto_approve_rules | id | 自动审批白名单 | - |
audit_logs | id | 审计日志 | N → 1 conversations |
🔗 表关系图
┌─────────────────┐ ┌─────────────────┐
│ ssh_keys │ │ model_providers │
│ ───────────── │ │ ───────────── │
│ • id (PK) │ │ • id (PK) │
│ • name │ │ • name │
│ • private_key │ │ • provider_type│
│ • passphrase │ │ • model_name │
└────────┬────────┘ │ • api_key_enc │
│ └─────────────────┘
│ 1:N
▼
┌─────────────────┐ ┌─────────────────┐
│ servers │ │ cloud_accounts │
│ ───────────── │ │ ───────────── │
│ • id (PK) │ │ • id (PK) │
│ • name │ │ • name │
│ • host/port │ │ • cloud_type │
│ • ssh_key_id(FK)│ │ • secrets_enc │
└────────┬────────┘ └─────────────────┘
│
│ N:1
▼
┌─────────────────────────────────────────────────┐
│ conversations │
│ ───────────────────────────────────────────── │
│ • id (PK) │
│ • thread_id (unique index) │
│ • title │
│ • status │
└────────┬────────────────────────┬───────────────┘
│ 1:N │ 1:N
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ messages │ │ audit_logs │
│ ───────────── │ │ ───────────── │
│ • id (PK) │ │ • id (PK) │
│ • conversation │ │ • conversation │
│ • role │ │ • tool_name │
│ • content │ │ • command │
│ • tool_name │ │ • level │
└─────────────────┘ │ • approved │
│ • success │
│ • output │
└─────────────────┘
┌─────────────────┐
│auto_approve_rules│
│ ───────────── │
│ • id (PK) │
│ • command │
└─────────────────┘🔐 加密字段标记
所有带 _enc 后缀的字段都使用 Fernet 对称加密 存储:
| 表名 | 加密字段 |
|---|---|
model_providers | api_key_enc |
ssh_keys | private_key_enc, passphrase_enc |
servers | password_enc, private_key_enc, passphrase_enc |
cloud_accounts | secrets_enc |