约 16 分钟阅读

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 是官方解决方案,但不适合我们

  1. 太重:需要独立集群,维护成本高
  2. 太通用:我们的部署流程高度定制化(私有化交付、离线包、特殊网络)
  3. 太贵:Tower 企业版 License 费用不菲
  4. 不够灵活:我们的环境模型(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

设计原则

  1. 环境是核心边界:所有数据(库存、配置、日志)都挂到环境
  2. 高频操作优先:环境选择、配置编辑、执行部署、查看日志
  3. 复用既有组件:文件管理、配置版本沿用已有交互,减少新模型

技术选型

层级技术理由
前端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 不持久化,刷新丢失每次刷新都要重新选环境
5Agent 页会话历史串环境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,复杂操作仍需多步:

  1. 创建环境 → 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)

  1. 多账号系统:告别共用 admin,支持个人账号 + 角色权限
  2. 环境模板:一键创建标准环境(开发/测试/生产)
  3. 部署流水线:支持多阶段部署(dev → test → prod)
  4. 通知集成:飞书/钉钉通知部署结果

中期(2026 Q4)

  1. K8s 深度集成:Helm chart 管理、K8s 资源监控
  2. 成本分析:按环境统计资源使用、成本分摊
  3. 自动化测试:部署后自动运行 smoke test
  4. 回滚策略:支持一键回滚到任意历史版本

长期(2027+)

  1. 多云支持:同时管理 AWS、阿里云、私有云
  2. 智能优化:基于历史数据推荐资源配置
  3. 自愈能力:检测到故障自动修复(如重启服务、扩容)
  4. 开放平台:允许第三方开发技能插件

总结

核心经验

  1. UI 不是 CLI 的包装:需要从产品视角重新设计交互模型
  2. Agent 不是银弹:复杂场景仍需人工确认,安全边界不能丢
  3. 技能系统是关键:封装复杂逻辑,用户只需描述意图
  4. 可观测性优先:每一步都要可追溯,故障排查才不头疼

适用场景

适合

  • 企业内部部署平台
  • 运维自动化工具
  • DevOps 工作台
  • 私有化交付管理

不适合

  • 超大规模集群(> 1000 节点)
  • 需要复杂编排的长期任务
  • 完全无人值守的自动化

开源计划

我们计划将 Ansible UI 的核心模块(技能系统、工具调用循环、会话管理)开源,帮助更多团队构建自己的部署平台。

预计时间:2026 Q3

仓库地址:待定(欢迎提前 star 关注)


相关文章

  • [[轻量级 Agent 开发方案:基于 Skill 插件的工具调用循环]]
  • [[LangGraph 状态机设计模式]]
  • [[Karpathy LLM Wiki 模式:Obsidian 知识库重构指南]]

💬 评论

主题
字体
密度
语言