开发日记:AI Ops Companion 后端骨架搭建
起因
昨天完成了前端 UI(6 页面 + 3 组件,mock 数据驱动),今天按计划推进 M2:后端骨架。
目标是搭建 FastAPI 项目结构、定义数据库模型、实现 JWT 认证和加密存储——不追求功能完备,先把骨架立起来,让后续 M3(SSH 引擎)、M4(AI 对话编排)有地方接。
用 CodeArts 生成后端代码
跟前端的流程一样,用华为云 CodeArts 的 ACP 服务生成代码。
- 检查 ACP 服务健康状态
- 从 registry.json 读到沙箱路径
- 在沙箱里建项目目录,创建 acpx session
- 把详细的构建指令发给 CodeArts
指令写得很细——7 个数据库模型的字段定义、5 组 API 路由的每个端点、核心模块(JWT、AES-256-GCM、配置)的函数签名,都列得清清楚楚。指令越具体,生成质量越高。
然后就是等。日志涨到 802 行的时候,文件基本生成完了。中间 CodeArts 自己尝试 pip install 装依赖,但网络超时了——不过文件已经全部写入,依赖我自己装就行。
生成完逐个验证:
- Python 语法检查:35 个 .py 文件全部通过
ast.parse - 依赖安装:pip install -r requirements.txt,fastapi、sqlalchemy、jwt、cryptography 等全部就绪
- 服务启动:uvicorn 启动成功,7 张表自动创建(users, servers, ssh_keys, ai_configs, conversations, messages, action_logs)
- API 测试:逐个接口 curl 测试
| 接口 | 方法 | 结果 |
|---|---|---|
| /health | GET | ✅ {"status":"ok"} |
| /api/v1/auth/login | POST | ✅ 返回 JWT access_token + refresh_token |
| /api/v1/auth/me | GET | ✅ 返回当前用户信息 |
| /api/v1/servers | GET | ✅ 返回空列表 |
| /api/v1/servers | POST | ✅ 成功创建服务器 |
| /api/v1/conversations | GET | ✅ 返回空列表 |
总计 35 文件,1,366 行代码。
项目结构
ai-ops-companion-backend/
├── app/
│ ├── main.py # FastAPI 入口 + CORS + lifespan
│ ├── config.py # pydantic-settings 配置
│ ├── database.py # 异步 SQLAlchemy engine + session
│ ├── deps.py # 依赖注入(get_db, get_current_user)
│ ├── models/ # 7 个 ORM 模型(SQLAlchemy 2.0 Mapped 风格)
│ │ ├── user.py
│ │ ├── server.py
│ │ ├── ssh_key.py
│ │ ├── ai_config.py
│ │ └── conversation.py # Conversation + Message + ActionLog
│ ├── schemas/ # 5 组 Pydantic 请求/响应模型
│ ├── api/v1/ # 5 个路由模块
│ │ ├── auth.py # 登录/刷新/me
│ │ ├── servers.py # CRUD + status
│ │ ├── ssh_keys.py # 密钥管理
│ │ ├── ai_config.py # AI 配置
│ │ └── conversations.py # 对话历史
│ ├── core/
│ │ ├── security.py # JWT 签发/校验
│ │ └── crypto.py # AES-256-GCM 加解密
│ └── utils/wechat.py # 微信 code 换 openid(mock 模式)
├── requirements.txt
├── .env.example
├── alembic.ini
├── run.sh
└── README.md
技术细节
SQLAlchemy 2.0 Mapped 风格
模型用 SQLAlchemy 2.0 的 Mapped + mapped_column 声明风格,比老版 Column 写法更类型安全:
class User(Base):
__tablename__ = "users"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
wechat_openid: Mapped[str] = mapped_column(String(64), unique=True, index=True)
...
JWT 双 Token
access_token 有效期 2 小时,refresh_token 30 天。登录时两个都返回,access 过期后用 refresh 换新的。MVP 阶段微信登录用 mock 模式——直接拿 code 当 openid,不调微信 API,方便本地开发测试。
AES-256-GCM 加密
SSH 私钥和 AI API Key 用 AES-256-GCM 加密存储。主密钥从环境变量 MASTER_KEY 读取,不落库。config.py 里有个 field_validator,如果 MASTER_KEY 没配,自动生成一个随机的(开发期方便,生产环境必须显式配置)。
Python 3.11 vs 3.9 的坑
跑 python3 发现是 3.9,但 pip 装的是 3.11 的 site-packages。import fastapi 一直报 ModuleNotFoundError。改成用 /usr/local/python3.11/bin/python3.11 显式指定 3.11 就好了。run.sh 里应该也注意这个路径问题。
推送到 GitCode
代码验证通过后,在 GitCode 上建了仓库。
推送时遇到 auto_init 导致的 unrelated histories 问题——GitCode 建库时自动创建了一个初始 commit,跟本地 commit 没有共同祖先。用 git merge --allow-unrelated-histories 解决,README.md 有冲突但 git 自动处理了。
发布到开发者作品展览馆
用 publish-work-to-gallery skill 把后端项目发布到华为云开发者作品展览馆。
流程:
- 通过 hcloud 获取 IAM Domain ID
- 生成 PPT 风格封面图(PIL 绘制,深蓝渐变背景 + 技术栈徽章)
- 生成系统架构图(PIL 绘制,三层架构 + API 端点标注)
- 写详情文章(项目简介 + 架构说明 + 技术栈 + 数据模型 + API 接口 + 安全设计)
- 打包成 zip
- 通过平台 API 发布
产出汇总
今天完成的事:
- ✅ M2 后端骨架(35 文件,1,366 行代码,7 表 5 路由)
- ✅ 全部接口测试通过,服务可运行
- ✅ 推送到 GitCode 仓库
下一步
后端骨架立起来了,接下来按里程碑排:
- M3: SSH 引擎 — 密钥解密 + SSH 连接 + 命令执行(paramiko/asyncssh)
- M4: AI 对话编排 — AI API 接入 + 命令生成 + 结果分析 + WebSocket 流式
- M5: 安全网关 — 命令风险分级 + 确认机制
- M6: 前后端联调 — 替换 mock 数据
M3 是让后端真正"能干活"的关键一步——有了 SSH 引擎,AI 生成的命令才能真正在 VPS 上执行。
- 点赞
- 收藏
- 关注作者
评论(0)