如何看到 AI 编码代理在你的服务器上执行了什么

代理正在一台生产服务器上干活,终端里只显示它在调用一个工具。它到底执行了哪条命令,机器又返回了什么?会话转录事后会告诉你。本文讲我们如何让这一切在发生时就可见,最初试过什么,以及不用我们的应用也能做到同样效果的方法。

你问一个 DevOps 代理,生产环境的 API 为什么慢。它开始干活。终端里出现一行,说它在调用一个工具,然后又一行,又一行。六次调用之后,它告诉你磁盘已经用了 97 %,提议清理日志目录。

它在那台机器上到底执行了什么?哪条 du,哪条 find,是不是已经删了什么?答案是有的,但它在会话转录里,以 JSON 写成,你只能事后读。在笔记本上这没问题。在生产服务器上,事后再说“等等,不是那个文件夹”就太晚了。

我们在做 AgentsRoom,一款运行编码代理的桌面应用,并给代理提供连接你的服务器、数据库和集群的工具。这篇文章讲的是我们怎样让这些调用在发生时就可见:没成功的那一版,成功那一版背后的数字,以及不用我们的应用怎样做到同样的事。

简短的回答

  • CLI 让你看到的是工具运行过,而不是另一端的会话。 完整的命令和输出都进了你磁盘上的转录。
  • 要实时看到,必须有东西在每次调用开始时就记录,而不是等会话结束。
  • 每个连接一份日志行得通。每条命令一个终端标签页行不通。 我们在单个会话里测到了 166 条远程命令。
  • 把这份日志留在你自己的机器上。 生产主机上的一行命令里有密钥,也有客户数据。
  • 不用我们的应用: 一个把每条 shell 命令追加到文件里的 Claude Code hook 能解决大部分问题,剩下的交给转录。

为什么在服务器上只有转录不够

Claude Code、Codex 和其他 CLI 确实什么都记。Claude Code 在 ~/.claude/projects/ 下为每个会话写一个 JSONL 文件,Codex 在 ~/.codex/sessions/ 下写一个。每次工具调用连同输入和结果都在里面。

问题不在完整性,而在时机和形式。转录是写给 CLI 的,好让它能恢复会话。你要等代理停下来才能读,还得在一行行 JSON 里翻找。三个代理同时干活,你就得读三个文件。而代理的终端,也就是你真正盯着的地方,每次调用只显示一段折叠起来的摘要。

对于笔记本上的代码,事后再读是正常的审查流程:提交之前看一眼 diff。服务器没有 diff。一条 systemctl restart 或一条 DELETE,执行的那一刻就生效了。

我们最初的尝试,以及那 166 条命令

我们给代理的第一个远程工具,会在一个终端标签页里打开连接。看起来没问题:用户能看到会话。结果它以一种我们没料到的方式失败了。

这个工具没有给代理任何办法去读取它刚打开的标签页里发生了什么。于是在一位用户的项目里,代理干脆不用它了。那个会话的统计:我们的连接工具被调用了 16 次,而代理通过自己的 shell 工具执行了 166 条 sshpass 命令,代理向用户要密码,用户把密码粘贴进聊天。生产环境的凭据就这样以明文留在了转录里,每条命令运行时留在 ps aux 里,还留在 /tmp 下的一个文件里。

教训不是“代理太鲁莽”。代理只是做了唯一行得通的事。一个安全但不让代理完成工作的工具会被绕过,而绕过的结果比没有工具还糟。

于是我们写了 ssh_exec:代理发送一条命令,AgentsRoom 用保存好的连接执行它,密码留在应用里,然后返回输出和退出码。代理从头到尾看不到凭据,也就没有理由去拼一条 sshpass 命令。

安全问题解决了,可见性问题又来了。如果每次 ssh_exec 都开一个标签页,那个会话就会产生 166 个标签页。所以 ssh_exec 一个都不开,两个月里,能看到这些命令的地方又只剩代理的对话。

每个连接一份日志

我们在 2026 年 10 月 29 日发布的版本(AgentsRoom 1.242.0)守住一条规则:不按命令开标签页。取而代之,每次调用都进入一份日志,每个连接一份。

  • 右侧面板的活动标签页,在文件、更改和测试旁边,用卡片列出代理碰过的连接(最后一条命令、代理、时间、状态),并在时间线上显示最近 40 次调用。可以按代理筛选,也能搜索命令、连接名和输出。
  • 一个连接的日志读起来像终端:代理 · 时间,然后 $ 命令,然后是输出,然后是 已完成 · 退出码 0 · 1.2 s。SSH 输出实时滚动,只要你不往上翻,视图就一直跟着底部。一个按钮就能把整份日志复制成文本。
  • 代理标题栏里的胶囊,代理碰过的每台服务器、每个数据库或集群各一个,调用进行中带一个绿点。点一下就打开对应的日志。
  • 代理工作中徽章,出现在服务器、数据库和 Kubernetes 窗口里该连接所在的行上,只在调用运行时显示。

日志是只读的。想自己在机器上敲命令,入口仍然是服务器窗口里的 SSH 标签页。完整的功能页面是 AI 代理的 SSH 连接,数据库那一侧见 数据库连接。

哪些会被记录,哪些不会

调用进入日志原因
ssh_exec(SSH、AWS SSM、WinRM)是主要场景:远程机器上的一条命令,没有自己的标签页
ssh_transfer是往服务器复制或从服务器复制文件,是对那台服务器的操作
db_query、db_schema是代理写的原样 SQL,以及结果的前几行
kube_kubectl是显示为带参数的 kubectl 命令行
commands_run、ssh_connect否它们本来就会打开一个可以盯着看的终端标签页
代理自己的 shell 工具(直接敲的 ssh、psql、kubectl)否不经过 AgentsRoom:在代理的终端和转录里

最后一行是老实交代的局限。日志只看得到经过我们工具的东西。如果你希望每个远程操作都出现在那里,工具就必须是代理更省事的那条路,这正是那 166 条命令给的教训。

还有一个细节:只有 SSH 会在命令运行时流式输出,因为它走的是你机器上一个真正的终端。WinRM、SQL 和 kubectl 的结果在调用结束时才出现。

保留这份日志的代价

我们的用户会同时跑很多代理:一台机器上 18 个项目里有 45 个代理,另一台上有 48 个控制台。任何按代理或按输出块计算的东西都会被这个数字放大,所以日志有硬性上限:

  • 每个项目 120 次调用,最旧的先丢。
  • 每次调用 32,000 个字符的输出,保留末尾,因为错误和退出码都在那里。
  • 每次调用 2,000 个字符的命令或 SQL。
  • 实时输出每次调用每 120 ms 一条更新消息,绝不是每个终端输出块一条。
  • 空闲时没有定时器。 只要没有代理调用远程工具,日志就零开销。

记录只发生在一个点:所有 CLI 的工具调用都要经过的那座桥。所以无论是 Claude Code、Codex、Antigravity CLI,还是应用运行的其他任何 CLI,它都一样工作,不需要按提供商写代码。

我们选择的界限:什么都不离开这台机器

日志保存在桌面应用的内存里,退出应用就消失。它不会同步到我们的服务器,这在我们这里并不常见:AgentsRoom 里几乎所有其他东西都会跟着你的账户在不同电脑间同步。

这个偏偏不同步,是有意为之。在服务器上执行 env 的输出里有密钥。对客户表的一条 SELECT 里有客户数据。一个为了让这些东西可见而做的工具,不应该再顺手把它们复制到别的地方。

手机可以在代理的资料页里跟着看同一份日志(移动应用 2.47 及以上)。数据流通过端到端加密的链路从你的电脑传到你的手机,密钥在发出之前就被遮盖(API 密钥、KEY=value 键值对、URL 里的密码、令牌),服务器上什么都不保存。同一次调用也照旧能在代理的对话里读到。

Claude Code 审计日志是另一回事

如果你搜过“Claude Code 审计日志”,大概会找到 Anthropic 面向 Claude Enterprise 的 Compliance API:活动流、审计日志事件,以及登录了 Enterprise 账户的本地会话的会话转录。它是为管理员和合规团队做的,覆盖整个组织,而且是事后查阅。

它回答的是“公司里谁用 Claude 做了什么”。它不回答“我的代理此刻在数据库服务器上执行哪条命令”。两者可以共存,如果你所在的公司有合规要求,不管第二件事用什么,第一件事你大概都需要。

如果你不用 AgentsRoom

用 CLI 已经提供的东西,你就能拿到其中很大一部分。

在每条 shell 命令开始时就记录下来。 Claude Code hook 可以在每次工具调用之前运行一条命令。hook 指南里给出了这种写法:在 Bash 工具上挂一个 PreToolUse hook,把 jq -r .tool_input.command 的结果写进日志文件。在第二个终端里对这个文件执行 tail -f,代理每发出一条命令你都能立刻看到,ssh 命令行也包括在内。

需要输出时就读转录。 hook 给你的是命令,不是服务器回答了什么。这部分在 ~/.claude/projects/ 下的会话文件里(Codex 则是 ~/.codex/sessions/),每次调用的完整结果都在。

在服务器上给代理开一个专用账户。 用专用用户,每个连接在服务器的认证日志里都能追溯到人。如果你的服务器跑着 auditd,给这个用户的 execve 加一条规则,就能在服务器一侧记录它启动的每个进程,代理绕不过去。

让凭据远离代理。 如果唯一的连接方式是一个代理必须向你要的密码,你就会在聊天里看到 sshpass 命令行。用一个代理永远读不到的密钥,或者用一个替它保管秘密的工具。我们另写了一篇指南,讲如何把密钥交给代理而不写进提示词。

这套做法给不了你的,是把三者串起来:哪个代理、在哪个连接上、产生了什么实时输出,都在一个地方。这正是我们做的那部分。

大家真正会问的问题

Claude Code 在远程服务器上干活时,我能实时看到它在做什么吗?

终端里你能看到工具调用,以及调用结束后的一段简短结果。完整的命令和输出会写进你磁盘上的会话转录,你只能事后去读。要在发生时就看到,需要有东西在每次调用开始时就把它记下来:一个把每条 Bash 命令写进日志文件的 Claude Code hook,或者一个替代理执行远程调用并实时展示的应用,AgentsRoom 的活动标签页做的就是这件事。

Claude Code 把它执行过的命令记录在哪里?

记录在会话转录里,也就是 ~/.claude/projects/ 下的 JSONL 文件,每个项目一个文件夹,每个会话一个文件。每次工具调用占一行,包含输入和结果。Codex 在 ~/.codex/sessions/ 下也为每个会话保存类似的文件。两者都是完整的,但两者都是写给 CLI 用来恢复会话的,不是给人浏览的。

这和 Claude Code 审计日志是一回事吗?

不是。人们用这个名字搜索的审计日志,是 Anthropic 在 Enterprise 方案中通过 Compliance API 提供的组织级记录:活动流、审计事件,以及已登录会话的转录,由管理员事后查阅。它回答的是组织里谁做了什么。实时查看一台服务器上的命令,是另一种工具,服务的是另一类人。

为什么不为代理执行的每条命令开一个终端标签页?

我们走过这条路,也做了测量:一个处理生产故障的代理在一个会话里发出了 166 条远程命令。每条命令一个标签页,十分钟后标签栏就没法用了。行得通的做法是每个连接一份日志,每次调用是一条记录,包含命令、实时输出、退出码和耗时。

AgentsRoom 会把命令和输出发送到服务器吗?

不会。日志保存在桌面应用的内存里,每个项目最多 120 次调用,退出应用就消失。手机可以在代理的资料页里跟着看(移动应用 2.47 及以上):数据流通过端到端加密的链路从你的电脑传到你的手机,密钥会被遮盖,服务器上什么都不保存。

活动标签页不显示代理的哪些命令?

只记录经过 AgentsRoom 工具的调用:ssh_exec、ssh_transfer、db_query、db_schema 和 kube_kubectl。代理用自己的 shell 工具执行的命令,比如直接敲的 ssh 或 psql 命令行,会出现在它的终端和转录里,但不在日志里。commands_run 和 ssh_connect 是有意排除的,因为它们本来就会打开一个你可以盯着看的终端标签页。

一句话总结

在服务器上干活的代理需要你给它两样东西:一种不经过你密码就能工作的方式,以及一种让你在它干活时就能看到它在做什么的方式。只有前者没有后者,你只能事后读 JSON。只有后者没有前者,代理会绕过去,往聊天里贴 sshpass 命令行。

我们最后做成的是每个连接一份日志,有上限,留在你自己的机器上。想试试的话,AgentsRoom 可以免费下载,SSH 连接页面一步步展示了设置方法。如果你更想只用 CLI,就从 PreToolUse hook 加一个 tail -f 开始:五分钟就能搞定,你再也不用纳闷最后那六次工具调用到底干了什么。

下载 AgentsRoom

在一个窗口中运行你所有项目的所有 AI 代理。

免费下载 AgentsRoom

配套应用:随时随地监控你的 Agent

使用 Claude、Codex、Antigravity CLI 或其他 AI 提供商。

获取扩展程序
Chrome Web Store

把 Bug 和需求直接发送到您的公开待办清单。

多项目管理
多供应商
多代理运行
实时状态
文件差异与提交
移动应用
实时预览
代理团队
浏览器自动化
Backlog 驱动开发
提示词库
技能库
查看所有功能

继续阅读