# zai **Repository Path**: educloudtest/zai ## Basic Information - **Project Name**: zai - **Description**: 会动手的 Linux 运维 Agent:一句话,自己登录、自己排查、自己给结论;黑名单 + 风险分级 + 人工审批三层闸门,敢连生产,全程可审计。 - **Primary Language**: Python - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 3 - **Created**: 2026-11-09 - **Last Updated**: 2026-11-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # zai zai 是一个用自然语言驱动的运维 Agent。你描述问题,它拆解步骤、登录主机、执行命令、观察真实输出、失败自动重规划,最后给你一份带证据链的报告。 它不是"把日志贴进对话框,等你复制命令"的聊天机器人——它自己上去看。 它也不是"放飞自我"的自动化脚本——黑名单硬拦截、动态风险分级、逐条人工审批,让它有资格碰生产环境。 根据自然语言要求,自主规划并在 **本机或 SSH 远程主机** 上执行 Linux 命令、**连接 MySQL 完成查询与运维管理**、**连接 Docker 引擎在指定容器内执行 Linux 运维操作**、**连接 Kubernetes 集群进行巡检、资源查询、日志/事件分析与受控写操作**,完成运维任务的 Agent 工程。支持通过 `skills/` 目录放置知识文档扩展自定义技能。 ![ssh](doc/images/ssh.png) ## 演示视频 > 若浏览器不支持内嵌播放,可直接打开或下载视频:[doc/video/test.mp4](doc/video/test.mp4) ## 工作原理 两层循环的 Plan-and-Execute 架构: 1. **规划**:Planner 把用户任务拆解为 1-3 个执行步骤(JSON 计划); 2. **执行**:Executor 对每一步运行 ReAct 循环(默认最多 8 次迭代), LLM 通过 function calling 调用工具,观察结果后继续推理,直到输出步骤总结; 执行阶段默认流式输出自然语言,上下文超预算时自动摘要压缩; 3. **纠错**:步骤失败(或输出 `FAILED:`)触发重规划(最多 3 次), 基于已完成结果生成新计划; 4. **汇总**:所有步骤结束后输出最终报告(含 Token 消耗统计)。 strict 档下规划完成后会先暂停,可审阅/编辑计划再执行(见“计划审阅”)。 ## 目录结构 ``` linux_agent/ ├── agent_core/ # 通用 Agent 框架(与领域解耦) │ ├── agent.py # 主流程:规划 -> 执行 -> 重规划 -> 汇总 │ ├── planner.py # 任务规划器(JSON 计划容错解析) │ ├── executor.py # ReAct 步骤执行器(动态风险审批 + 审计) │ ├── audit.py # JSON Lines 审计日志 │ ├── config.py # .env 配置加载 │ ├── skills.py # 自定义技能加载(frontmatter 解析 / 索引 / 热重载) │ ├── events.py # 运行事件观察者 │ ├── llm/ # OpenAI 兼容 LLM 客户端 │ ├── memory/ # 短期记忆(消息裁剪 + Token 感知上下文压缩) │ └── tools/ # 工具基类(风险分级/classify 钩子)与注册中心 ├── agent_tools/ # Linux 运维 + MySQL + Docker 容器执行 + Kubernetes + 技能工具集 │ ├── linux_tools.py # run_command / read_file / grep / glob / list_directory / system_info / write_file / edit_file │ ├── backends.py # 本机 subprocess / SSH(paramiko)/ 容器 exec 统一执行后端 + 会话目标管理 │ ├── mysql_tools.py # mysql_query / mysql_execute / mysql_overview │ ├── mysql_backend.py # MySQL 会话连接管理(内存态不落盘)+ SQL 执行 │ ├── mysql_policy.py # SQL 黑名单硬拦截 + 动态风险分级 │ ├── docker_backend.py # Docker 会话连接管理(http.client,可选 TLS)、API 请求与容器 exec 通道 │ ├── docker_policy.py # 容器 exec 逃逸黑名单硬拦截(docker.sock / nsenter / /proc/1) │ ├── k8s_tools.py # k8s_overview / get / describe / logs / events / top / apply / delete / scale / rollout │ ├── k8s_backend.py # Kubernetes 会话连接(kubeconfig / API Server)+ REST 请求与资源解析 │ ├── k8s_policy.py # Kubernetes 删除黑名单 + 写操作动态风险分级 │ ├── session_connections.py # 通用会话连接中心(MySQL / Docker / Kubernetes 复用) │ ├── skill_tools.py # load_skill:按需读取自定义技能正文(SAFE 免审批) │ └── command_policy.py # 命令黑名单硬拦截 + 动态风险分级 ├── skills/ # 自定义技能目录(放置 <名称>/SKILL.md 即生效,见下文) ├── examples/ │ └── smoke_test.py # 离线冒烟测试(FakeLLM,无需网络与 key) ├── main.py # CLI 入口(含启动执行目标选择交互) ├── .env.example # 配置模板 └── hosts.json.example # SSH 主机清单模板 ``` ## 安装 ```bash cd linux_agent # 重要:用与运行 Agent 相同的解释器安装依赖(系统存在多个 Python 时, # pip 与 python 可能不对应,如 python3.12 -m pip install -r requirements.txt) python3 -m pip install -r requirements.txt # openai + paramiko + pymysql + pyyaml cp .env.example .env # 填入 LLM API key(DeepSeek / 通义 / Ollama 等) ``` > Kubernetes 接入不依赖 kubectl 与 kubernetes Python 客户端,直接调用 API Server; > `kubeconfig` 与 YAML 清单解析依赖 `PyYAML`(JSON 清单无需)。 ## 远程主机配置(可选) 复制 `hosts.json.example` 为 `hosts.json` 并填写: ```json { "web1": {"host": "192.168.1.10", "port": 22, "user": "root", "key_file": "~/.ssh/id_rsa"}, "db1": {"host": "192.168.1.11", "port": 22, "user": "root", "password": "xxx"} } ``` `key_file` 与 `password` 二选一。该文件含敏感信息,建议 `chmod 600 hosts.json` 且不要提交版本库。 不配置远程主机时,所有工具仍可在本机使用(host 参数留空或填 `local`)。 ## 使用 ```bash python main.py "查看本机磁盘占用最高的 5 个目录" python main.py "在 web1 上检查 nginx 服务状态并汇总" python main.py "查询 MySQL 中 app 库最近 1 小时新增的订单数" python main.py # 交互式 REPL(选择执行目标、连接与操作限制级别) python main.py tools # 列出工具及参数(无需 LLM key) python main.py hosts # 列出已配置的远程主机 python main.py skills # 列出技能目录已加载的自定义技能(无需 LLM key) python main.py --yes "统计 /var/log 下各日志文件大小" # 自动批准(等同 --level auto) python main.py --level readonly "查看各服务运行状态" # 只读档:非只读操作自动拒绝 python main.py --level strict "重启 nginx 并验证" # 严格档(默认):逐条人工确认 python main.py --plan-review "..." # 执行前审阅并可编辑计划(默认仅 strict 档开启) python main.py --no-plan-review "..." # 跳过计划审阅直接执行 python main.py --verbose "..." # 打印 LLM 交互摘要 python main.py "@example-disk-check 检查本机磁盘使用情况" # 技能钉住:技能正文直接注入本次任务 ``` ### 交互式启动(REPL) 启动时先显示欢迎信息(名称与版本号;版本号取自 `agent_core.__version__`,当前 0.1.0)。 进入 REPL 时会先选择执行方式(五种模式相互独立,各自注册对应工具): ``` ──────────────────────────────────────────────────────────────── [启动] 请选择任务的执行目标 ──────────────────────────────────────────────────────────────── [1] 本机(当前运行 linux_agent 的服务器) [2] SSH 远程服务器(输入 IP / 用户名 / 密码登录) [3] MySQL 数据库(输入主机 / 端口 / 用户名 / 密码连接) [4] Docker 容器(连接 Docker 引擎,选择一个容器作为执行目标) [5] Kubernetes 集群(kubeconfig 或 API Server + 凭据接入) ──────────────────────────────────────────────────────────────── ``` - 选 `[1]` 本机:与单次任务模式相同,host 参数留空即本机执行; - 选 `[2]` SSH:依次输入 **服务器 IP/主机名、端口(默认 22)、用户名(默认 root)、 密码**,Agent 会立即发起 SSH 登录验证(执行 `hostname; whoami`); - 登录成功后,该主机注册为**会话默认目标**:后续任务中工具 host 参数留空时 默认在远程主机上执行(可填 `local` 强制回到本机,或填其它别名切主机); - 登录失败会显示原因,可原地重试,或直接用回车改用本机执行; - 选 `[3]` MySQL:依次输入 **MySQL 主机、端口(默认 3306)、用户名(默认 root)、密码**(及可选默认 数据库),Agent 立即发起连接验证(执行 `SELECT VERSION()`); - 连接成功后该连接成为**会话默认 MySQL 连接**:`mysql_*` 工具 connection 参数留空即使用它;可继续添加多个连接(以 `主机:端口` 为别名区分); - 连接失败显示原因,可原地重试或跳过; - 选 `[4]` Docker 容器:依次输入 **引擎地址(IP 或主机名,可带 `http://` / `https://` / `tcp://` 前缀)、端口(默认 2375;`https://` 前缀或 2376 端口启用 TLS)**; TLS 时可选填证书目录(含 `ca.pem` 校验 CA,含 `cert.pem`+`key.pem` 双向认证, 留空回落到 `DOCKER_TLS_CERT_DIR`),Agent 立即发起连接验证(`/_ping` + `/version`); - 连接成功后**列出该引擎上运行中的容器**,按序号(回车默认 1)或名称/ID 前缀选择; 选定的容器注册为**会话执行目标**:Linux 工具整体切换到容器内执行,host 参数 留空即在容器内(审批面板显示“容器 xxx(会话默认)”),填 `local` 强制回本机; - 选择后会做一次 `/bin/sh` 轻量探测:distroless 等无 shell 镜像会给出警告(不阻断); - 连接失败显示原因与常见排查方向(daemon 未开 TCP 监听、端口不通、TLS 端口用了 http 或反之),可原地重试或返回菜单; - 选 `[5]` Kubernetes:选择接入方式: - **kubeconfig**(默认):输入文件路径(回车取 `KUBECONFIG` 或 `K8S_KUBECONFIG`, 支持 `~` 展开),列出全部 context(标注当前 context 与命名空间),按序号或名称选择; - **手工接入**:输入 API Server 地址(如 `https://10.0.0.1:6443`),选择 Token 或 用户名 + 密码认证,可选 CA 证书路径、跳过 TLS 校验与默认命名空间; - 接入后立即调用 `GET /version` 验证,成功后该连接成为**会话默认 Kubernetes 连接**: `k8s_*` 工具 connection 参数留空即使用它;失败会显示原因(地址不通、证书不受信、 Token 过期/权限不足)并返回菜单; - 支持静态凭据(Token / tokenFile / 客户端证书 / Basic Auth);`exec` 与 `auth-provider` 等需要外部插件的认证方式不支持(会明确提示改用 Token 或证书); - 五种模式**相互独立**:选 `[1]`/`[2]` 后不会再询问 MySQL/Docker/Kubernetes;选 `[3]`/`[4]`/`[5]` 连接失败跳过时会返回菜单重新选择; - 每个模式**只向 AI 注册必要的工具**:`[1]`/`[2]`/`[4]` 均注册 Linux 工具 (`[4]` 在选定的容器内执行),`[3]` 仅注册 MySQL 工具,`[5]` 仅注册 Kubernetes 工具(`k8s_*`),避免跨类型误调用; - Docker 模式可用 REPL 命令 `/container` 查看运行中的容器(标注当前目标)或 `/container <名称|ID前缀>` 随时切换目标容器(提示符同步更新); - 选定模式后还需选择**操作限制级别**(`--level` 直接指定;`--yes` 时跳过询问按自动档处理): - `[1]` 只读 —— 非只读操作自动拒绝(AI 只能查看/查询); - `[2]` 严格(默认)—— 写操作与危险操作逐条人工确认(回车默认同意); - `[3]` 自动 —— 全部自动放行(灾难语句黑名单始终硬拦截); - REPL 提示符按模式区分:本机 `local>`、SSH `ssh[主机别名]>`、MySQL `mysql[默认连接]>`、Docker `docker[容器名]>`、Kubernetes `k8s[连接别名]>`;启动横幅显示模式、目标、工具集、会话记忆与限制级别; - **会话级记忆**:会话内自动记录每个已完成任务的结果摘要,并注入后续任务的规划与执行提示(如“刚才检查过的那台服务器再查一下”);输入 `memory` 查看、`memory clear` 清空,详见下文。 - **自定义技能**:`skills/` 目录放置的知识文档会以索引形式注入提示词;REPL 中输入 `skills` 查看、`skills reload` 重载、`skills show <名称>` 查看正文,详见下文。 - **技能钉住**:`@技能名 任务` 把技能钉到本次任务(`/技能名 任务` 同义):技能正文直接注入规划与执行提示,AI 按其中步骤执行,不依赖自主 `load_skill`;只输入 `@技能名` 可先选定,下一条任务生效(单任务语义,完成后自动解除)。技能名支持 **Tab 补全**:输入 `@` 或 `/` 后按 Tab 模糊匹配(前缀 > 子串 > 子序列,如 `@dc` 可命中 `example-disk-check`),多候选时列出带说明的菜单;技能名输入接近某个技能时会提示“相近技能”,技能多时可用 `skills search <关键字>` 按名称/描述模糊搜索。 - **直连执行模式**:`/shell`(本机 / SSH)与 `/sql`(MySQL)进入粘性直连模式(提示符 `sh[目标]>`、`sql[连接]>`),输入即执行;或用 `/shell <命令>`、`/sql <语句>` 单条执行后停留 AI 模式。直连沿用与 AI 完全相同的安全链路(黑名单硬拦截、按当前限制级别审批),审计日志以 `_origin: direct` 区分人工直连;`exit/quit` 或 `Ctrl+C` 返回 AI 模式(`EOF` 退出程序)。 - `/help` 按当前模式列出全部 REPL 命令。 > 交互登录的主机、MySQL、Docker 连接、容器目标及 Kubernetes 连接/凭据仅保存在当前会话内存中(不写入任何文件),密码与 Token 不会落盘。 > REPL 命令速览:`@技能名 任务` 钉住技能;`/shell`、`/sql` 直连执行;`/container` 切换容器; > `/help` 查看命令;`memory` 会话记忆;`skills` 技能管理;`exit/quit` 退出。 离线自检(无需网络与 API key): ```bash python examples/smoke_test.py ``` ### 内置 Linux 工具 | 工具 | 风险 | 说明 | |---|---|---| | `run_command` | 按命令动态 | 执行 shell 命令(管道/连接符拆分子命令取最高等级) | | `read_file` | safe | 读取文本文件(默认前 200 行;`offset` 分页续读并提示下一步) | | `grep` | safe | 正则递归搜索(`glob` 过滤文件名、`ignore_case`、`max_results` 截断提示) | | `glob` | safe | 按 `find -name` 语义查找文件(如 `*.conf`) | | `list_directory` | safe | 列出目录(含权限、大小、修改时间) | | `system_info` | safe | 主机名/内核/负载/内存/磁盘概览 | | `write_file` | confirm(敏感路径 dangerous) | base64 写入,适合新建或整体重写 | | `edit_file` | confirm(敏感路径 dangerous) | 精确字符串替换(要求唯一匹配或 `replace_all=true`),审批面板展示 diff 预览 | ## 安全机制(三层) 1. **黑名单硬拦截**(任何情况下不可执行,审批也无法放行): `rm -rf /` 及系统关键目录、`mkfs`、`dd`/重定向写块设备、fork 炸弹、 `wipefs`、对根目录 `chmod -R 777` 等; 2. **动态风险分级**(按命令内容判定,管道/连接符拆分子命令取最高等级): - `safe`:只读命令(ls/cat/df/ps/systemctl status/journalctl 等)直接执行; - `confirm`:有副作用命令(rm/mv/chmod/包管理/服务起停/docker 等)终端人工审批; - `dangerous`:高危命令(reboot/shutdown/userdel/分区与 LVM/清空防火墙/ `curl | sh` 等)醒目提示后审批; - 未识别命令保守定为 `confirm`; 3. **人工审批**:SAFE 直接执行;其余按操作限制级别处理(启动交互选择,或 `--level` 指定)——严格档在终端逐条确认(显示风险等级与完整命令,回车默认同意),只读档自动拒绝, 自动档(`--level auto` / `--yes`)自动放行;黑名单硬拦截不受级别影响。 ### MySQL 三层防护 对 SQL 的管控与命令一致(mysql_execute / mysql_query 共用): 1. **黑名单硬拦截**:`DROP DATABASE/SCHEMA`、`SHUTDOWN`、对系统库 (mysql / sys / performance_schema / information_schema)的写操作; 2. **动态风险分级**(按语句内容判定): - `safe`:只读查询(SELECT/SHOW/EXPLAIN/DESCRIBE/USE/HELP)直接执行; - `confirm`:常规写操作(INSERT/UPDATE/DELETE 带 WHERE/CREATE/ALTER 等) 终端人工审批; - `dangerous`:DROP/TRUNCATE/无 WHERE 的 UPDATE/DELETE/GRANT/KILL/ SET GLOBAL/SELECT INTO OUTFILE 等醒目提示后审批; - 一次仅允许一条语句(分号拆分检测,字符串/注释内的分号不误判); 3. **人工审批**:审批面板显示 MySQL 连接、判定原因与完整 SQL; 放行/拒绝由操作限制级别决定(严格逐条确认 / 只读自动拒绝 / 自动直接放行)。 ### MySQL 工具 | 工具 | 风险判定 | 说明 | |---|---|---| | `mysql_query` | safe(加锁查询升级为 confirm) | 只读查询,结果以对齐表格返回(默认最多 200 行,最大 2000) | | `mysql_execute` | 按 SQL 内容动态 | 执行单条写语句,返回受影响行数 | | `mysql_overview` | safe | 版本/运行状态/数据库列表(含数据量)/当前进程(前 15 条) | ### Docker 容器模式 选 `[4]` 连接 Docker 引擎并选定一个**运行中的容器**后,Agent 会把 Linux 工具 (run_command / read_file / list_directory / system_info / write_file)整体切换到 该容器内执行(等价于在容器里跑 shell),并在此基础上自主规划排障与运维步骤: - **执行通道**:Docker Engine API 的 exec 三步流程(创建 exec → start 读取多路复用 输出帧 → 查询退出码),命令统一经 `/bin/sh -c` 执行,因此容器需具备 shell (distroless 镜像在选择时会给出探测警告); - **文件读写**:`read_file` / `write_file` / `edit_file` / `list_directory` / `grep` / `glob` 复用容器内 `head` / `sed` / `base64` / `ls` / `grep` / `find` 实现,无需额外挂载; - **安全防护**: 1. **黑名单硬拦截**(任何情况下不可执行,审批也无法放行):命令含 `docker.sock` (可绕过审批直接控制宿主 Docker)、`nsenter`、`/proc/1/root`、`/proc/1/ns`、 `/proc/1/cwd`(宿主机逃逸类特征)时直接拒绝; 2. **动态风险分级**:容器内执行的每条命令与“命令三层防护”一致(黑名单 + safe/confirm/dangerous 分级 + 人工审批); 3. **人工审批**:审批面板显示目标容器、判定原因与完整命令; - **默认目标**:选中的容器成为**会话默认执行目标**(审批面板标注“容器 xxx(会话默认)”) 工具 `host` 参数留空即在容器内执行,填 `local` 强制回本机; - **容器切换**:REPL 内 `/container` 列出当前引擎运行中的容器(标注当前目标), `/container <名称|ID前缀>` 随时切换(切换即时生效,提示符同步更新); - **能力边界**:不提供镜像/网络/数据卷/删除等 Docker 管理工具;需要时可在宿主机 用 `host=local` 执行 `docker ...` 命令(同样走命令三级审批);exec 无交互终端 (非 TTY),交互式命令请在宿主机终端用 `docker exec -it` 操作。 ### Kubernetes 集群模式 选 `[5]` 接入 Kubernetes 集群后,Agent 仅注册 `k8s_*` 工具,用自然语言完成集群巡检、 资源查询、故障定位与受控变更。全部操作直连 API Server(`http.client` + TLS), **不依赖 kubectl 与 kubernetes Python 客户端**。 - **接入方式**: - `kubeconfig`(默认):读取 `KUBECONFIG`(多路径取第一个)或 `K8S_KUBECONFIG`, 也可输入任意路径;列出全部 context(标注当前 context 与命名空间)供选择; 支持 Token / tokenFile / 客户端证书 / CA / Basic Auth / `insecure-skip-tls-verify`; - 手工接入:API Server 地址 + Token 或用户名密码,可选 CA 证书、跳过 TLS 校验 与默认命名空间; - 接入后立即 `GET /version` 验证;成功即成为**会话默认连接**(工具 `connection` 参数留空即使用它),提示符显示为 `k8s[连接别名]>`(别名重名时自动追加序号); - `exec` / `auth-provider` 等需要外部插件的认证方式不支持,请改用 Token 或证书。 - **资源解析**:内置常用资源表(pod / deployment / statefulset / daemonset / replicaset / job / cronjob / service / ingress / configmap / secret / pvc / pv / node / namespace / event 等),支持短名(`po` / `deploy` / `svc`)与 CRD 复数名 (通过 Discovery API 自动发现,按连接缓存)。 **分析与巡检场景**(均为只读,免审批): - 日常巡检:`k8s_overview` 一次拉取版本、节点 Ready/容量、Pod 阶段分布与重启 Top、非运行 Pod、工作负载就绪情况、最近 Warning 事件与 metrics 用量; - 异常定位:`k8s_get` 定位对象 → `k8s_describe` 查看状态/条件/关联事件 → `k8s_events` 梳理时间线 → `k8s_logs` 拉取容器日志(`previous` 读崩溃实例、 `since_seconds` 限定时间窗); - 发布与容量:`k8s_rollout action=status` 查看期望/已更新/就绪/可用副本与 generation;`k8s_top` 查看节点或 Pod 的 CPU/内存(需部署 metrics-server)。 | 工具 | 风险 | 说明 | |---|---|---| | `k8s_overview` | safe | 集群健康概览(巡检入口:版本/节点/Pod/工作负载/告警事件/用量) | | `k8s_get` | safe | 查询资源列表或单个对象(命名空间、标签/字段选择器、`output=json`) | | `k8s_describe` | safe | 资源详情 + 关联事件(Pod/Deployment/Node/Service/PVC/PV 等) | | `k8s_logs` | safe | Pod 容器日志(容器、行数、`previous`、`since_seconds`、时间戳) | | `k8s_events` | safe | 事件查询(默认全命名空间 Warning,可按对象名过滤) | | `k8s_top` | safe | 节点/Pod 实时 CPU 与内存(依赖 metrics-server) | | `k8s_apply` | confirm / dangerous | 服务端 apply 单个 YAML/JSON 清单(集群级对象、特权模板升级为 dangerous) | | `k8s_delete` | confirm / dangerous | 删除单个资源(工作负载/服务/配置类为 dangerous;黑名单硬拦截) | | `k8s_scale` | confirm / dangerous | 调整 Deployment/StatefulSet/ReplicaSet 副本(缩到 0 或 >100 为 dangerous) | | `k8s_rollout` | status=safe / restart=confirm | 查看发布状态或触发滚动重启 | **Kubernetes 三层防护**: 1. **黑名单硬拦截**(审批也无法放行):删除 Namespace / Node / PV / CRD / APIService / Mutating/ValidatingWebhookConfiguration、删除 `cluster-admin` 绑定;DaemonSet 副本由节点数决定,`k8s_scale` 直接拒绝; 2. **动态风险分级**: - `safe`:overview / get / describe / logs / events / top / rollout status; - `confirm`:apply 普通对象、删除单个 Pod、常规副本调整、rollout restart; - `dangerous`:apply 集群级对象(CRD / ClusterRole / ClusterRoleBinding / StorageClass / PV / Namespace / APIService / Webhook)、Pod 模板使用特权 容器 / hostPath / hostNetwork / hostPID / hostIPC、kube-system 内写操作; 删除工作负载 / 服务 / 配置类资源;缩容到 0 或一次扩到 100 副本以上; 3. **人工审批**:审批面板显示 K8s 连接、目标对象(类型/名称 + 命名空间)、 apply 的 Kind/name 与清单预览、scale 的旧 → 新副本及判定原因;放行/拒绝由 操作限制级别决定(只读档拒绝非只读、严格档逐条确认、自动档放行)。 接入后在 REPL 中直接用自然语言下达任务,例如: ```text 查看集群整体健康状况,列出 NotReady 节点和异常 Pod 并分析原因 payment 命名空间接口 5xx 升高,定位异常 Pod 并分析最近 30 分钟日志 检查 web 命名空间 frontend Deployment 的滚动发布状态 统计 prod 命名空间 CPU 占用最高的 5 个 Pod 把 frontend 副本从 2 扩到 4,并确认全部就绪 ``` - **能力边界**:不提供 Helm release 管理、port-forward、`kubectl exec` 交互终端、 `kubectl cp` 与按标签批量删除;一次 `apply` 仅支持单个资源清单(多文档 YAML 请拆分);日志为一次性拉取,不支持 `-f` 持续跟随;单次任务模式 (`python main.py "..."`)不注册 `k8s_*` 工具,Kubernetes 连接仅在交互式启动 `[5]` 中建立。 ## 计划审阅 / 流式输出 / 上下文压缩 三个执行体验开关(均可用环境变量控制): - **计划审阅**:strict 档默认在规划完成后暂停,可选 `[1] 执行(默认) [2] 编辑步骤 [3] 取消`:编辑模式逐行输入新步骤 (空行结束),确认后按新计划执行;取消后任务标记为“已取消”。 仅初始计划审阅,失败重规划不重复打断。`--plan-review` / `--no-plan-review` 可覆盖默认值;非交互(stdin 关闭)时自动按执行 处理,不会阻塞管道与 CI。 - **流式输出**:执行阶段 LLM 的自然语言输出实时打印(逐字增量), 规划/重规划仍为非流式(JSON 不适合流式展示)。`AGENT_STREAM=off` 关闭。 - **上下文压缩**:单步骤执行上下文超过 `AGENT_CONTEXT_MAX_TOKENS` (启发式估算:CJK 按 1 token、ASCII 按 3.5 字符/token)时,把中段 历史交给 LLM 摘要为一条 system 消息,保留首条系统提示与最近 `AGENT_CONTEXT_KEEP_MESSAGES` 条消息;压缩不会拆开工具调用与其结果, 摘要失败时降级为“早期上下文已省略”标记。`AGENT_CONTEXT_MAX_TOKENS=0` 关闭压缩。 ## 审计日志 所有工具调用(时间、工具、参数、风险等级、是否审批、成败、耗时)以 JSON Lines 追加写入 `logs/audit.log`(可用 `AGENT_AUDIT_LOG` 修改路径或设为 `off` 关闭): ```bash tail -f logs/audit.log ``` ## Token 统计 每个任务完成后,最终报告附带 Token 消耗统计(数据来自 LLM 端点返回的 usage): - `本次任务 Tokens`:该任务全部 LLM 调用(规划 + 步骤执行 + 重规划)的输入/输出/合计与调用次数; - `会话累计 Tokens`:当前进程内所有任务的累计消耗(REPL 模式下跨任务累加)。 ``` 共 3 个步骤,成功 3 个,失败 0 个。 本次任务 Tokens:输入 3210 / 输出 480 / 合计 3690(LLM 调用 8 次) 会话累计 Tokens:输入 7690 / 输出 1210 / 合计 8900(LLM 调用 19 次) ``` ## 会话级记忆(REPL) REPL 会话内自动记录每个已完成任务的结果摘要(任务、成败、各步骤总结),并在后续任务 的规划与执行提示中注入“本会话此前任务的结果”,使 Agent 能延续上下文: - 仅存内存、退出即清空(与交互登录的连接信息一致,不落盘); - 默认保留最近 5 个任务,单条任务/摘要自动截断(`AGENT_SESSION_MEMORY_MAX_TASKS` 调整); - `AGENT_SESSION_MEMORY=off` 可整体关闭(关闭后行为与之前版本一致); - REPL 中输入 `memory` 查看当前记忆,`memory clear` 清空。 ## 自定义技能(Skills) 在 `skills/` 目录放置 Markdown 知识文档,即可在**不改任何代码**的情况下为 Agent 增强技能(如“nginx 故障排查”“磁盘清理规范”)。技能是**知识**而非**权限**:仅作为 提示词增强供 AI 参考,不注册执行能力,命令审批与黑名单链路完全不变。 - 目录布局:`skills/<名称>/SKILL.md`(推荐,可附带辅助文件)或 `skills/<名称>.md`; `README*`/`index*` 与 `_` 前缀文件不会被加载;技能名缺省取目录名/文件名; - 文件格式(frontmatter 三个字段均可选,无 frontmatter 时 `description` 取正文首个标题): ``` --- name: nginx-troubleshoot description: 排查 nginx 服务异常:端口监听、配置语法、错误日志 targets: linux,ssh --- # 正文:详细步骤 / 命令模板 / 检查清单 ``` `targets` 取 `linux`/`ssh`/`mysql`/`docker`/`k8s`(逗号分隔),缺省表示全部模式适用; - 渐进式披露:技能**索引**(名称 + 一行说明)随任务注入规划与执行提示,正文由 AI 在任务相关时通过 `load_skill` 工具按需读取(单次上限 `AGENT_SKILL_MAX_CHARS`), 控制 Token 开销; - 技能由 AI 自主选择(按索引说明判断相关性),也可由用户**钉住**(REPL 输入 `@技能名 任务`,技能正文直接注入本次任务);为便于确认实际使用情况: 终端实时显示 `load_skill: 技能「xxx」` 调用行,任务结束报告标注 `本次使用技能:xxx` (钉住技能置前显示),审计日志亦有完整记录(`grep load_skill logs/audit.log`); - REPL 中输入 `skills` 查看已加载技能,`skills reload` 重新扫描目录(新增/修改的 技能文件立即生效、无需重启),`skills show <名称>` 查看技能正文, `skills search <关键字>` 按名称/描述模糊搜索; - 命令行 `python main.py skills` 离线查看(无需 LLM key); - 技能目录可用 `AGENT_SKILLS_DIR` 覆盖(多个目录用 `:` 分隔;相对路径以项目根为基准),`AGENT_SKILLS=off` 整体关闭; - 打包运行(PyInstaller):项目根 = **可执行文件所在目录**,`.env` / `skills/` / `hosts.json` / `logs/` 与 exe 同级放置即可被加载;也可用 `AGENT_SKILLS_DIR` 指定绝对路径(如 `/opt/linux_agent/skills`)。 示例:仓库自带 `skills/example-disk-check/SKILL.md`(磁盘检查与清理建议),可复制其目录结构新建自己的技能。 ## 配置项(.env) | 变量 | 默认值 | 说明 | |---|---|---| | `LLM_API_KEY` / `LLM_BASE_URL` / `LLM_MODEL` | - | OpenAI 兼容端点配置 | | `SHELL_COMMAND_TIMEOUT` / `SHELL_COMMAND_TIMEOUT_MAX` | 60 / 600 | 命令默认超时与上限(秒) | | `SHELL_COMMAND_WORKDIR` | 空 | 本机命令默认工作目录 | | `SSH_HOSTS_FILE` | hosts.json | 主机清单路径,留空禁用远程 | | `SSH_CONNECT_TIMEOUT` | 10 | SSH 连接超时(秒) | | `MYSQL_CONNECT_TIMEOUT` | 10 | MySQL 连接超时(秒) | | `MYSQL_QUERY_TIMEOUT` | 30 | MySQL 单条语句读/写超时(秒) | | `DOCKER_CONNECT_TIMEOUT` | 10 | Docker API 连接超时(秒) | | `DOCKER_API_TIMEOUT` | 30 | Docker API 请求读超时(秒) | | `DOCKER_TLS_INSECURE` | off | TLS 跳过证书校验(自签证书场景),`on` 启用 | | `DOCKER_TLS_CERT_DIR` | 空 | TLS 证书目录(含 `ca.pem` 校验 CA;含 `cert.pem`+`key.pem` 做双向认证) | | `K8S_KUBECONFIG` | 空 | 默认 kubeconfig 路径(`KUBECONFIG` 存在时优先取它) | | `K8S_CONNECT_TIMEOUT` | 10 | Kubernetes API 连接超时(秒) | | `K8S_API_TIMEOUT` | 30 | Kubernetes API 单次请求读超时(秒) | | `AGENT_MAX_STEPS` / `AGENT_MAX_ITERATIONS` / `AGENT_MAX_REPLANS` | 3 / 8 / 3 | 防失控三闸 | | `AGENT_MAX_OUTPUT_CHARS` | 4000 | 反馈给 LLM 的观察文本上限 | | `AGENT_SESSION_MEMORY` | on | 会话级记忆开关(REPL 跨任务注入历史摘要),`off` 关闭 | | `AGENT_SESSION_MEMORY_MAX_TASKS` | 5 | 会话记忆保留的任务条数上限 | | `AGENT_SKILLS` | on | 自定义技能开关(从技能目录加载 SKILL.md),`off` 关闭 | | `AGENT_SKILLS_DIR` | 空 | 技能目录(默认项目内 `skills/`;多个用 `:` 分隔) | | `AGENT_SKILLS_MAX` | 20 | 最多加载的技能数(注入索引上限) | | `AGENT_SKILL_MAX_CHARS` | 8000 | 单次 `load_skill` 返回正文的字数上限 | | `AGENT_STREAM` | on | 执行阶段流式输出(自然语言增量实时打印),`off` 关闭 | | `AGENT_CONTEXT_MAX_TOKENS` | 12000 | 执行上下文 Token 预算(启发式估算),超限用 LLM 摘要压缩;`0` 关闭 | | `AGENT_CONTEXT_KEEP_MESSAGES` | 10 | 上下文压缩时保留的最近消息条数 | | `AGENT_AUDIT_LOG` | logs/audit.log | 审计日志路径,`off` 关闭 | | `AGENT_MD_RENDER` | on | 最终报告 Markdown 终端渲染(标题/表格/列表/代码块美化),`off` 关闭;非 TTY 或 `NO_COLOR` 时自动原样输出 | ## 注意事项 - SSH 首次连接使用 AutoAddPolicy 自动记录主机指纹,生产环境请评估中间人风险; - 请避免让 Agent 执行交互式命令(vi/nano/top 等),必要时使用 `-y`/`--batch` 参数; - 真实 `hosts.json` 与 `.env` 均含敏感信息,切勿提交到公开仓库; - 若登录远程主机时提示“导入 paramiko 失败”,说明安装依赖的 pip 与运行 Agent 的 Python 解释器不是同一个;按报错信息中的解释器路径重新安装(如 `python3.12 -m pip install paramiko`)后重试即可(pymysql 同理); - MySQL 连接信息在启动交互中输入,仅存内存不落盘;工具调用与审批结果照常写入审计日志; - MySQL 工具只允许单条语句执行;批量脚本请拆分为多次调用或使用命令行客户端。 - Docker 集成基于 Docker Engine API:目标 daemon 需开启 TCP 监听(如 `dockerd -H tcp://0.0.0.0:2375`,或在 `/etc/docker/daemon.json` 配置 `"hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]`); 注意开启 TCP 后,任何能访问该端口的人都能以 root 权限控制 Docker,请仅在受信内网开启; - 2375 端口为**明文无认证**协议,仅限内网/受信网络;跨网段请启用 TLS(地址加 `https://` 前缀或使用 2376 端口,自签证书可用 `DOCKER_TLS_INSECURE=on`, 双向认证配置 `DOCKER_TLS_CERT_DIR`); - Docker 连接信息与容器目标同样仅存内存不落盘;容器内命令无交互终端(非 TTY), 且被硬拦截的逃逸类命令(docker.sock / nsenter / /proc/1/*)经审批也无法放行。 - Kubernetes 接入直接调用 API Server(不依赖 kubectl),kubeconfig 与清单解析依赖 PyYAML;`exec` / `auth-provider` 等认证插件不支持,请改用 Token 或客户端证书; 连接信息与凭据同样仅存内存,不写入任何文件。 - Kubernetes 删除 Namespace / Node / PV / CRD / APIService / 准入 Webhook 与 cluster-admin 绑定被安全策略硬拦截,审批无法放行;建议为 Agent 使用最小权限 RBAC(按命名空间授予 get/list/watch/logs 与必要的写权限),不要直接使用 cluster-admin。写操作(apply / delete / scale / rollout restart)均需审批并写入审计日志。 - 终端中文输入依赖 UTF-8:程序启动时会自动切换 UTF-8 编码并启用行编辑 (按字符删除中文、上翻历史);若仍出现删除异常或乱码,请检查终端客户端的 编码设置(应使用 UTF-8,而非 GBK);输入中混入的非法字节会被自动替换为 `?` 并给出提醒,不会导致任务崩溃。 ## 作者与交流 - Gitee 开源地址: - 问题反馈:欢迎在 [Gitee Issues](https://gitee.com/mfznanceyin/zai/issues) 提交问题或建议 - 微信公众号:(扫码关注,获取项目更新与运维实践) ![微信公众号](doc/images/wechat.jpg)