Ansible UI 部署工作台设计复盘:从 CLI 到 Agent 技能系统
为什么我们放弃 CLI 转向 UI?一个企业内部部署平台的 6 阶段演进:从脚本到产品化,从手动到 Agent 智能
Ansible UI 部署工作台设计复盘:从 CLI 到 Agent 技能系统
引言:为什么需要 UI?
公司内部现状
2024 年初,我们团队面临一个典型困境:
- 10+ 个环境:开发、测试、预发布、生产,每个环境 3-5 台服务器
- 5+ 个服务:AskBI、LangChain 应用、Milvus 向量库、MinIO 对象存储、前端服务
- 3 个运维同事:每人维护 2-3 个环境,频繁切换
- 零文档:部署流程靠口口相传,新人入职 1 周学不会
核心痛点:
“每次部署都要查笔记、翻 Slack 记录、问老同事。同一个操作,三个人有三种写法。“
CLI 的局限性
Ansible 本身是优秀的自动化工具,但CLI 不是产品:
| 问题 | 表现 | 影响 |
|---|---|---|
| 学习门槛高 | 新人需要懂 YAML、SSH、网络、容器 | 入职培训 2 周+ |
| 无状态 | 每次执行都是独立的,无法追溯历史 | 故障排查困难 |
| 无协作 | 多人同时部署容易冲突 | 生产事故风险 |
| 无可视化 | 日志是纯文本,无法快速定位问题 | 排查效率低 |
| 无权限 | 要么全权,要么无权 | 安全边界模糊 |
为什么没有官方工具?
Ansible Tower / AWX 是官方解决方案,但不适合我们:
- 太重:需要独立集群,维护成本高
- 太通用:我们的部署流程高度定制化(私有化交付、离线包、特殊网络)
- 太贵:Tower 企业版 License 费用不菲
- 不够灵活:我们的环境模型(env + config + job)与 Tower 的 inventory + playbook 不匹配
结论:我们需要一个轻量级、定制化、产品化的部署工作台。
Phase 1-2:从脚本到工作台(2024 Q2)
初始设计
目标:把散落在脚本、笔记、Slack 中的部署流程,整合成一个可重复使用的工作台。
核心模型:
环境 (Environment)
├── 库存 (Inventory):服务器列表、SSH 配置
├── 配置 (Config):main.yml、hosts.yml、.env
├── 作业 (Job):部署历史、日志、产物
└── 动作 (Action):check、deploy、clean、rollback
设计原则:
- 环境是核心边界:所有数据(库存、配置、日志)都挂到环境
- 高频操作优先:环境选择、配置编辑、执行部署、查看日志
- 复用既有组件:文件管理、配置版本沿用已有交互,减少新模型
技术选型
| 层级 | 技术 | 理由 |
|---|---|---|
| 前端 | React + TypeScript + Ant Design | 团队熟悉,组件丰富 |
| 后端 | FastAPI + Python | 与 Ansible 生态无缝集成 |
| 执行器 | Ansible shell 通道 | 复用既有 SSH 能力,无需引 paramiko |
| 存储 | 文件系统 + JSONL | 轻量,无需数据库 |
| 部署 | Docker Compose | 与目标环境一致 |
关键决策
Q:为什么不直接用 Ansible API?
A:Ansible 的 Python API 太重,且绑定特定版本。我们用shell 通道(ansible <env> -m shell -a "<cmd>")作为执行层,好处:
- 版本无关:任何 Ansible 版本都能用
- 权限复用:直接用
~/.ssh/config的 ProxyJump、别名 - 日志透明:stdout/stderr 直接返回,无需额外解析
Q:为什么不引入数据库?
A:初期数据量小(< 100 个环境,< 1000 个作业),文件系统 + JSONL 足够:
- 开发快:无需 ORM、迁移
- 调试易:直接
cat文件就能看数据 - 部署简:Docker volume 挂载即可持久化
Phase 3-4:用户体验与协作(2024 Q3-Q4)
用户反馈
上线 3 个月后,收集到 5 个核心问题:
| # | 问题 | 根因 | 影响 |
|---|---|---|---|
| 1 | 任务列表不跟随选中环境 | Jobs 页用独立 state,与全局环境无联动 | 用户频繁切环境,容易误操作 |
| 2 | 多人共用 admin 账号 | 无审计、无并发控制 | 无法追溯谁做了什么 |
| 3 | 登录态不稳定(常显示 guest) | 异步加载期间按 guest 渲染 | 用户以为没权限,放弃操作 |
| 4 | 环境选择在 tab 间不一致 | selectedEnv 不持久化,刷新丢失 | 每次刷新都要重新选环境 |
| 5 | Agent 页会话历史串环境 | Agent 的 env 是局部 state | 切环境后看到别人的会话 |
解决方案
统一状态管理:
// 之前:每个页面独立 state
const [selectedEnv, setSelectedEnv] = useState("");
const [jobFilters, setJobFilters] = useState({ env: "" });
// 之后:全局 Provider + URL 参数
const { env, setEnv } = useGlobalEnv(); // 持久化到 localStorage + URL ?env=xxx
操作者标识:
# 每条任务记录客户端 IP + User-Agent
task = {
"env": env_name,
"action": "deploy",
"operator": f"{request.client.host} ({request.headers.get('User-Agent', 'Unknown')})",
"timestamp": datetime.now(),
"status": "running"
}
登录态三态:
type AuthState = "unknown" | "admin" | "guest";
// 加载中显示 loading,不按 guest 渲染
const [auth, setAuth] = useState<AuthState>("unknown");
效果
- ✅ 环境一致性:所有 tab 统一消费全局环境,刷新不丢失
- ✅ 操作可追溯:每条任务记录 IP + UA,至少知道是谁的机器
- ✅ 登录稳定:三态管理,加载中不降级为 guest
Phase 5:Agent 技能系统(2026 Q1)
为什么引入 Agent?
问题:即使有 UI,复杂操作仍需多步:
- 创建环境 → 2. 编辑配置 → 3. 上传私钥 → 4. 信任主机 → 5. 执行部署
用户反馈:
“我知道要做什么,但不知道每一步点哪里。有时候漏了一步,部署失败还要重来。”
目标:让 Agent 理解意图,自动规划,执行全流程。
技能系统设计
核心思想:Skill = 带 SKILL.md 的目录
skills/
├── create-env/
│ └── SKILL.md # 技能说明
│ └── tools.py # 工具定义
├── ssh-ops/
│ └── SKILL.md
└── diagnosis/
└── SKILL.md
渐进式披露:
- 系统提示只给技能目录(
name + description) - 模型判断相关后,调用
load_skill工具拉取正文 - 节省 Token,按需加载
工具调用循环:
用户:创建一个新的测试环境
模型:需要调用 create_environment 工具
→ 执行工具 → 返回结果
模型:需要调用 add_authorized_key 工具
→ 执行工具 → 返回结果
模型:需要调用 run_deploy_action 工具
→ 执行工具 → 返回结果
模型:部署完成,总结步骤
技能示例:create-env
SKILL.md:
---
name: create-env
title: 环境创建与部署
description: 创建新环境、复制环境、修改配置、执行部署
---
# 环境创建与部署技能
## 能力范围
- 创建新环境(指定服务器、SSH 配置)
- 复制现有环境(保留配置,生成独立 vault 密码)
- 修改环境配置(走 inventory,留版本历史)
- 执行部署动作(check、deploy、clean、rollback)
## 工具调用
- `create_environment(env, host, user, port, deploy_root)`
- `copy_environment(source_env, target_env)`
- `update_env_config(env, config_updates)`
- `run_deploy_action(env, action, force=false)`
## 使用原则
- 少问:只问必要信息(env、host、SSH 凭据),其余默认
- 确认:部署前让用户确认配置
- 留痕:改配置走 inventory,可 diff/回滚
效果:
- ✅ 意图理解:用户说”创建一个测试环境”,Agent 自动规划步骤
- ✅ 少问多干:只问必要信息,其余用默认值
- ✅ 可追溯:每一步都有工具调用记录,可审计
Phase 6:全流程运维助手(2026 Q2)
会话与交互增强
会话历史:
- 服务端持久化(JSONL),按环境过滤
- 50 会话上限,200 条/会话,30 天 TTL
- 刷新/切换可恢复,包含 reasoning 和工具轨迹
附件上传:
- 支持上传私钥、配置文件
- 工具按 file id 读取原始内容,不经模型转述
- 避免大段 base64 被改坏,也不进模型上下文
可终止任务:
- 运行中”发送”按钮变”停止”
- AbortSignal 终止当前工具调用
- AbortError 不当报错,友好提示
环境全流程工具
多意图技能:
# create-env 技能重写为多意图
def handle_create_env_intent(message):
if "创建" in message or "新建" in message:
return "create"
elif "复制" in message:
return "copy"
elif "修改" in message or "改配置" in message:
return "update"
elif "删除" in message:
return "delete"
elif "部署" in message:
return "deploy"
工具集:
| 工具 | 作用 | 调用次数 |
|---|---|---|
create_environment | 创建新环境 | 1 |
copy_environment | 复制环境 | 1 |
update_env_config | 修改配置 | 1 |
delete_environment | 删除环境 | 1 |
run_deploy_action | 执行部署动作 | 1-3 |
add_authorized_key | 添加 SSH 公钥 | 1 |
replace_container_file | 替换容器内文件 | 1 |
trust_ssh_host | 信任 SSH 主机 | 1 |
get_deployer_public_key | 获取部署机公钥 | 1 |
max_steps = 128:一条龙部署需 7-8+ 次工具调用,留足余量。
排查/修复引导原则
写入系统提示:
排查/修复原则:
1. 改配置优先走 inventory(留版本历史可 diff/回滚)
2. 服务日志以 docker-compose 挂载路径为准(docker inspect Mounts)
3. 不假装轮询:Agent 无法自我定时唤醒,长任务引导用户看任务看板
4. 定位最早失败点:从部署日志找到第一个 ERROR,不盲目重试
效果:
- ✅ 改配置留痕:优先
update_env_config,不直接改文件 - ✅ 日志路径准确:按 compose mount 路径,不猜服务名
- ✅ 不假装轮询:引导用户看任务看板,不循环调用
read_job_log
设计取舍与经验
1. 为什么不做成”低代码平台”?
问题:很多内部工具想做成”拖拽式编排”,但我们刻意避免。
原因:
- 学习成本:拖拽式看似简单,但用户仍需理解流程、变量、条件
- 灵活性差:拖拽式难以表达复杂逻辑(如”如果 A 失败则重试 3 次”)
- 维护困难:每个自定义流程都要单独测试、文档化
我们的选择:
- Agent 驱动:用户说”我要做什么”,Agent 自动规划
- 技能封装:复杂逻辑封装在技能中,用户无需理解细节
- 可审计:每一步都有工具调用记录,可追溯
2. 为什么不用工作流引擎(如 Temporal、Argo Workflows)?
问题:工作流引擎适合长期运行、复杂编排的任务,但我们的场景是短任务、多步骤。
对比:
| 维度 | 工作流引擎 | Agent 技能系统 |
|---|---|---|
| 适用场景 | 长期运行(小时/天)、复杂依赖 | 短任务(分钟级)、线性流程 |
| 学习成本 | 需理解 DAG、状态机 | 自然语言描述意图 |
| 灵活性 | 需预先定义流程 | 动态规划,可调整 |
| 可观测性 | 内置可视化 | 工具调用轨迹 |
我们的选择:Agent 技能系统,因为:
- 部署任务通常是线性流程(创建 → 配置 → 部署)
- 用户更习惯自然语言描述意图
- 工具调用轨迹已足够可观测
3. 为什么不做成”完全自动化”?
问题:理论上 Agent 可以全自动完成所有操作,但我们刻意保留确认环节。
原因:
- 安全:生产环境部署需要人工确认
- 学习:用户需要知道 Agent 做了什么,才能信任
- 审计:关键操作需要人工审批
我们的设计:
Agent:检测到需要部署生产环境
→ 暂停,请求用户确认
用户:确认
→ 继续执行
效果:
- ✅ 安全:关键操作有人工把关
- ✅ 透明:用户知道每一步在做什么
- ✅ 可审计:确认记录可追溯
未来规划
短期(2026 Q3)
- 多账号系统:告别共用 admin,支持个人账号 + 角色权限
- 环境模板:一键创建标准环境(开发/测试/生产)
- 部署流水线:支持多阶段部署(dev → test → prod)
- 通知集成:飞书/钉钉通知部署结果
中期(2026 Q4)
- K8s 深度集成:Helm chart 管理、K8s 资源监控
- 成本分析:按环境统计资源使用、成本分摊
- 自动化测试:部署后自动运行 smoke test
- 回滚策略:支持一键回滚到任意历史版本
长期(2027+)
- 多云支持:同时管理 AWS、阿里云、私有云
- 智能优化:基于历史数据推荐资源配置
- 自愈能力:检测到故障自动修复(如重启服务、扩容)
- 开放平台:允许第三方开发技能插件
总结
核心经验
- UI 不是 CLI 的包装:需要从产品视角重新设计交互模型
- Agent 不是银弹:复杂场景仍需人工确认,安全边界不能丢
- 技能系统是关键:封装复杂逻辑,用户只需描述意图
- 可观测性优先:每一步都要可追溯,故障排查才不头疼
适用场景
适合:
- 企业内部部署平台
- 运维自动化工具
- DevOps 工作台
- 私有化交付管理
不适合:
- 超大规模集群(> 1000 节点)
- 需要复杂编排的长期任务
- 完全无人值守的自动化
开源计划
我们计划将 Ansible UI 的核心模块(技能系统、工具调用循环、会话管理)开源,帮助更多团队构建自己的部署平台。
预计时间:2026 Q3
仓库地址:待定(欢迎提前 star 关注)
相关文章:
- [[轻量级 Agent 开发方案:基于 Skill 插件的工具调用循环]]
- [[LangGraph 状态机设计模式]]
- [[Karpathy LLM Wiki 模式:Obsidian 知识库重构指南]]