This commit is contained in:
cancerai committed 2026-08-31 21:53:57 +08:00
commit e8833b172d
2 files changed
+1526

No files matched your search

+476
View File
@@ -0,0 +1,476 @@
# aiagent.sh — 100% POSIX-sh 自然语言运维 Agent
> 一行英文句子 = 一条运维命令。不用背参数,不用记 flag。
`aiagent.sh` 是一个**纯 `/bin/sh` 实现**的轻量级"AI Agent"。它不需要 Python、不需要 node、不需要任何运行时——单文件、零依赖,却能把你输入的**自然英语句子**解析成真实的运维操作。
```sh
$ ./aiagent.sh
aiagent> please show disk usage
[INFO] Disk usage:
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 100G 42G 58G 42% /
aiagent> what is the uptime
[INFO] System uptime:
14:32:11 up 12 days, 3:17, 2 users, load average: 0.12, 0.08, 0.01
aiagent> check port 8080
[INFO] Checking port 8080 ...
[OK] Port 8080 is IN USE
```
---
## ✨ 核心特性
| 特性 | 说明 |
|------|------|
| 🗣️ **自然语言输入** | 接受完整英文句子,不需要任何特殊语法 |
| 🧠 **意图识别** | 自动提取动词、名词、路径、端口、服务名 |
| 🔄 **同义词归一** | `show/display/list` → 统一处理,`kill/stop/terminate` → 统一处理 |
| 🎯 **名词推断动作** | 只说 `uptime` 也能理解成"show uptime" |
| 🔒 **安全确认** | 所有破坏性操作(删除、杀进程、装包)强制 `y/N` 二次确认 |
| 🛡️ **零 eval 注入** | 没有任何字符串拼接执行,包管理器直接调用 |
| ⚙️ **自动适配环境** | 自动检测 `systemctl`/`service`、`ss`/`netstat`、`apt`/`dnf`/`yum`/`apk`/`pacman` |
| 🧩 **可扩展** | 每个 `do_xxx()` 函数独立,新增操作只需加一个 case 分支和一个函数 |
| 📦 **单文件分发** | 约 1050 行,直接 `cp` 到目标机就能跑 |
---
## 🚀 快速上手
### 1. 获取脚本
```bash
# 从git仓库获取
git clone https://github.com/CancerXiaoAi/shell-ai.git
git clone https://git.cancerai.top/cancerai/shell-ai.git
```
### 2. 两种使用方式
```bash
# 方式 A:交互式 REPL(推荐日常使用)
./aiagent.sh
# 方式 B:一行命令模式(适合脚本/CI)
./aiagent.sh "please check port 443"
./aiagent.sh "what is the kernel version"
./aiagent.sh "health check"
```
### 3. 最简示例
```bash
# 系统一句话
./aiagent.sh uptime # 直接说名词就行
./aiagent.sh disk
./aiagent.sh health
# 完整句子也没问题
./aiagent.sh "please help me show memory usage"
./aiagent.sh "could you ping google.com for me"
./aiagent.sh "i want to restart nginx"
```
---
## 📖 完整命令参考
### 💡 语法约定
脚本对输入的容忍度极高。以下写法**全部等价**:
```
please help me check disk usage
help me check disk
check disk
disk
```
规则:
- `please`、`help me`、`to`、`a`、`the`、`can you`、`would you` 等纯语法词**全部自动忽略**
- 只带名词(如 `uptime`)会被自动推断为"show + 该名词"
- 只带动词加短语(如 `check port 80`)直接路由
### 🖥️ 系统信息 — System Info
| 输入示例 | 实际调用 | 说明 |
|---------|---------|------|
| `show disk usage` / `disk` | `df -h` | 磁盘使用情况 |
| `check memory` / `memory` / `ram` | `/proc/meminfo` 或 `free -h` | 内存占用 |
| `check cpu load` / `cpu` / `load` | `/proc/loadavg` | CPU 负载 |
| `what is the uptime` / `uptime` | `uptime` | 系统运行时长 |
| `show kernel version` / `version` | `/etc/os-release` + `uname` | OS 和内核版本 |
| `show listening ports` | `ss -tulnp` 或 `netstat -tulnp` | 监听端口 |
| `who is logged in` / `show users` | `who` | 当前登录用户 |
| `health check` / `check` | 一键跑 uptime + CPU + 内存 + 磁盘 | 健康检查 |
### 📂 文件操作 — Files
| 输入示例 | 实际调用 | 说明 |
|---------|---------|------|
| `list files in /var/log` | `ls -lah /var/log` | 列出目录 |
| `show me content of /etc/hosts` | `ls /etc/hosts` | 查看文件 |
| `find files named *.log in /tmp` | `find /tmp -type f -name "*.log"` | 查找文件 |
| `find process nginx` | `ps aux | grep nginx` | 按名字找进程 |
| `create directory /data` | `mkdir -p /data` | 创建目录 |
| `create file /tmp/hello.txt` | `: > /tmp/hello.txt` | 创建空文件 |
| `copy /etc/hosts /tmp/hosts.bak` | `cp -r/-f` | 自动判断文件/目录复制 |
| `move /tmp/a.log /var/log/` | `mv -f` | 移动/重命名 |
### ⚠️ 破坏性操作 — Destructive(强制 y/N 确认)
| 输入示例 | 实际调用 | 说明 |
|---------|---------|------|
| `please remove /tmp/cache` | `rm -rf`(确认后) | 递归删目录 |
| `delete file /tmp/bad.log` | `rm -f`(确认后) | 删除文件 |
| `clean old log files in /var/log` | `find -delete`(确认后) | 清理日志 |
| `kill process nginx` | `kill` + PID 列表(确认后) | 按名字杀进程 |
| `kill the process on port 8080` | 先 lsof/ss 找 PID(确认后) | 按端口杀进程 |
| `stop nginx` | `systemctl stop`(确认后) | 停服务 |
### 🔌 服务管理 — Services
| 输入示例 | 实际调用 | 说明 |
|---------|---------|------|
| `check status of sshd` | `systemctl status` | 查看服务状态 |
| `start docker service` | `systemctl start` | 启动服务 |
| `restart nginx` | `systemctl restart` | 重启服务 |
| `nginx` | 自动识别服务名 → 查状态 | 裸服务名默认查状态 |
### 🌐 网络 — Network
| 输入示例 | 实际调用 | 说明 |
|---------|---------|------|
| `check port 443` / `port 443` | `ss`/`netstat`/`nc` | 检查端口监听状态 |
| `ping google.com` | `ping -c 3 -W 2` | 连通性测试(3 包) |
| `show listening ports` | `ss -tulnp` | 所有监听端口 |
### 📦 包管理 — Packages
| 输入示例 | 实际调用 | 说明 |
|---------|---------|------|
| `please install package htop` | 自动检测 `apt-get`/`dnf`/`yum`/`apk`/`pacman` 并调用 | 安装系统包(确认后) |
### 📜 日志 — Logs
| 输入示例 | 实际调用 | 说明 |
|---------|---------|------|
| `tail /var/log/syslog` | `tail -30` | 直接路径 |
| `tail nginx log` | 自动匹配 `/var/log/nginx/access.log` | 按服务名猜路径 |
| `follow docker log` | glob `/var/log/*docker*` | 模糊匹配 |
### 🎛️ 其他
| 输入 | 说明 |
|------|------|
| `help` | 打印帮助手册 |
| `quit` / `exit` / `bye` | 退出 REPL |
---
## 🧠 自然语言解析原理
整个解析管线分为 **5 层**,每一层都只使用 POSIX sh 原语实现:
```
用户输入:please help me check port 8080
│
▼
┌─────────────────────────────────┐
│ 第 1 层:strip_fillers() │
│ 丢弃纯语法词:please, help, me │
└─────────────────────────────────┘
│ 得到:check port 8080
▼
┌─────────────────────────────────┐
│ 第 2 层:跳过引导词 │
│ 跳过开头的 help/what/can 等客气词│
└─────────────────────────────────┘
│ 得到:check port 8080
▼
┌─────────────────────────────────┐
│ 第 3 层:canonical_verb() │
│ 动词→同义词归一 │
│ 名词→推断动作(health→check) │
└─────────────────────────────────┘
│ verb=check, phrase="port 8080"
▼
┌─────────────────────────────────┐
│ 第 4 层:dispatch() 一级匹配 │
│ case "$phrase" in *port*) │
│ do_check_port; _matched=1 ;; │
└─────────────────────────────────┘
│
▼
┌─────────────────────────────────┐
│ 第 5 层:do_check_port() │
│ 从短语中提取 "8080" │
│ 依次尝试 ss → netstat → nc │
│ 输出 [OK]/[WARN] 状态 │
└─────────────────────────────────┘
```
### 动词同义词映射(canonical_verb)
```
show ← show, display, list, print, tell, what, reveal, dump
check ← check, monitor, verify, inspect, diagnose
find ← find, locate, search, lookup, track
remove← remove, delete, erase, rm, wipe, cleanup, clean
kill ← kill, stop, terminate, shutdown, halt
start ← start, launch, run, begin, enable
...
```
### 名词 → 推断动作
```
uptime, disk, memory, cpu, version, port, process ... → 自动当作 show
health, status, connection, reachability → 自动当作 check
```
### 三级 fallback 匹配机制
每个规范动词的路由都有三级兜底:
1. **一级关键词匹配**:`*disk*` → do_show_disk,`*port*` → do_check_port
2. **二级兜底**:短语是纯数字 → 当作端口号;短语含已知服务名 → do_service_status
3. **三级兜底**:`check` 空短语 → do_health_check;其他 → 提示用户重述
---
## 🔒 安全设计
### 强制二次确认
以下操作**必须**输入 `y` 或 `yes` 才会继续,其他任何输入都视为取消:
- 删除目录/文件(`remove`, `delete`)
- 杀进程(`kill`)
- 停服务(`stop service`)
- 安装系统包(`install`)
```
[CONFIRM] Recursively remove directory '/tmp/cache' ? (y/N):
```
### 零 eval 注入
整个脚本**没有任何 `eval` 调用**。包管理器的调用采用直接分支方式:
```sh
if command -v apt-get >/dev/null 2>&1; then
apt-get install -y -- "$_pkg" # 直接调用,参数安全引用
elif command -v dnf >/dev/null 2>&1; then
dnf install -y -- "$_pkg"
...
```
### 路径安全
`rm -rf`、`mv`、`cp` 等危险操作都使用了 `--` 分隔符,防止路径以 `-` 开头被解释为选项。
### 信号处理
REPL 模式下按 Ctrl+C 会优雅退出,不会留下终端异常状态:
```sh
trap 'echo; printf "Bye.\n"; exit 130' INT TERM
```
---
## 🏗️ 架构总览
```
aiagent.sh (~1050 lines, 单文件)
├── 辅助函数层
│ ├── info() / warn() / error() / success() # 带颜色的日志输出
│ └── confirm() # y/N 安全确认
│
├── 解析层(第 1–3 层)
│ ├── strip_fillers() # 丢弃纯语法词
│ ├── canonical_verb() # 同义词归一 + 名词推断
│ ├── _extract_path() # 从短语中提取路径
│ ├── _extract_svcname() # 从短语中提取服务名
│ └── _SERVICES_RE # 已知服务名正则
│
├── 路由层(第 4 层)
│ └── dispatch() # 大 case 分支,三级 fallback
│
├── 执行层(第 5 层)
│ ├── do_show_disk / _memory / _cpu / _uptime / _version / ...
│ ├── do_check_port / do_ping_host / do_service_status / do_health_check
│ ├── do_find_process / do_find_file
│ ├── do_remove_dir / _file / _log
│ ├── do_kill_process / do_kill_by_port
│ ├── do_service_start / _restart / _stop
│ ├── do_create_dir / _file
│ ├── do_copy_path / do_move_path
│ ├── do_install_pkg
│ └── do_tail_log
│
├── REPL 层
│ ├── run_one() # 单次命令处理管线
│ └── repl() # 交互式循环
│
└── 入口
└── main() # 分交互式/一行模式
```
### 依赖关系图
```
main() ─→ repl() 或 run_one()
│
▼
dispatch()
│
┌─────────┼─────────────┬──────────┬────────────┐
▼ ▼ ▼ ▼ ▼
show() check() find() remove() install()
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
do_show_* do_check_* do_find_* do_remove_* do_install_pkg
│
▼
confirm() ←── 所有 destructive 函数必经
```
---
## ⚙️ 运行要求
### 最低要求
| 项目 | 要求 |
|------|------|
| Shell 解释器 | `/bin/sh`(POSIX sh,任何实现均可:dash / busybox / bash --posix) |
| 操作系统 | Linux(主要目标);macOS 可读但部分功能受限(无 systemctl/ss) |
| 权限 | 普通用户即可运行,执行破坏性/管理类命令时需要相应权限 |
### 可选依赖(根据操作自动探测)
| 操作 | 依赖(择一) |
|------|-------------|
| 磁盘/内存/CPU | `df`, `/proc/meminfo` 或 `free`, `/proc/loadavg` |
| 服务管理 | `systemctl` 或 `service` |
| 端口检查 | `ss` / `netstat` / `nc` |
| 进程查找 | `ps`, `pgrep`(可选) |
| 进程/端口杀 | `pgrep`, `lsof`, `fuser`(择一) |
| 网络 | `ping` |
| 文件查找 | `find` |
| 包安装 | `apt-get` / `dnf` / `yum` / `apk` / `pacman`(择一) |
### 跨包管理器支持
| 发行版 | 自动使用 |
|--------|---------|
| Debian / Ubuntu | `apt-get` |
| RHEL 8+ / Fedora / CentOS 8+ | `dnf` |
| RHEL 7 / CentOS 7 | `yum` |
| Alpine | `apk` |
| Arch / Manjaro | `pacman` |
---
## ⚡ 性能
解析管线全部使用 POSIX sh 内建实现(`case` / `for` / `if` / `read` / `printf`),**不 fork 任何外部进程**——除了 `grep -qE` 和 `awk` 在少数 fallback 分支里会被调用。整个"strip → canonical → dispatch → route"管线的纯解析开销**可以忽略不计**,实际耗时主要来自底层命令本身(如 `df -h`、`ps aux`、`systemctl` 等)。
---
## 🧪 快速验证
在 Docker 容器里跑一下(无需在本机安装任何东西):
```bash
# Debian
docker run --rm -it -v $(pwd)/aiagent.sh:/aiagent.sh debian:latest \
sh -c 'chmod +x /aiagent.sh && /aiagent.sh "health check"'
# Alpine
docker run --rm -it -v $(pwd)/aiagent.sh:/aiagent.sh alpine:latest \
sh -c 'chmod +x /aiagent.sh && /aiagent.sh "check port 22"'
# CentOS / Rocky / AlmaLinux
docker run --rm -it -v $(pwd)/aiagent.sh:/aiagent.sh rocky:9 \
sh -c 'chmod +x /aiagent.sh && /aiagent.sh "restart sshd"'
```
---
## 🛠️ 扩展指南
想新增一个操作(比如"备份数据库")?三个步骤:
**步骤 1**:加一个规范动词映射(如果是新动词)
```sh
canonical_verb() {
...
backup|dump) echo "backup" ;;
...
}
```
**步骤 2**:在 `dispatch()` 的 case 分支里加路由
```sh
dispatch() {
...
backup)
do_backup_db "$phrase" ;;
...
}
```
**步骤 3**:实现 `do_backup_db()` 函数
```sh
do_backup_db() {
_db=""
for _tok in $1; do
case "$_tok" in mysql|postgres|redis|mongodb) _db="$_tok" ;; esac
done
[ -z "$_db" ] && { error "No DB type. Example: 'backup mysql'"; return 1; }
confirm "Backup $_db ?" || return 1
# 实际备份逻辑
case "$_db" in
mysql) mysqldump ... ;;
postgres) pg_dump ... ;;
...
esac
}
```
完成。现在 `./aiagent.sh "please backup mysql database"` 就能工作了。
---
## 🐛 已知限制
| 限制 | 说明 |
|------|------|
| 只能识别**英文** | 整个关键词库是英语 hardcode 的,不支持中文 |
| 正则只支持 POSIX ERE | 不支持 PCRE(但对运维场景已足够) |
| 交互式 REPL 不支持命令历史 | POSIX sh 的 `read` 没有 readline;可以通过 `rlwrap ./aiagent.sh` 获得历史 |
| 端口号从短语提取用的是 `[0-9]*` | 如果句子里有多个数字,会取最后一个(对"check port 80 on server 192.168.1.1"这种会取 1) |
| macOS 功能受限 | 没有 `systemctl`/`ss`/`/proc/*`,部分操作会降级或报依赖缺失 |
| 包管理器自动检测 | 只是检测命令是否存在,不检查是否真的可用(例如在 chroot 里) |
---
## 📄 License
MIT License. 复制、修改、商用均自由,唯一要求保留版权声明。
---
## 🙏 致谢
- POSIX 标准委员会:没有你们就没有可移植的 shell
- 所有写出漂亮运维命令的前辈:你们的 `df -h`、`ps aux`、`ss -tulnp` 是这个项目的基石