最近在琢磨 eBPF Agent 观测这个方向的时候,我反复遇到一个名字——AgentSight。
不是那种零星出现的提到,而是论文(ACM SIGOPS 2025)、arXiv、GitHub、开发者社区的讨论里,几乎同时指向它。深入一看才发现,这不止是一个工具,它背后有一种叫做「边界追踪」(boundary tracing)的观测范式,而且已经在一篇正式的学术论文里做了完整的系统性论证。
这篇文章是我对 AgentSight 的技术拆解——从它的设计理念到代码结构,从 eBPF 探针到 Web 前端,我希望尽量客观地讲清楚这个项目在做什么、怎么做、以及为什么值得关注。
项目背景
AgentSight 来自 eunomia-bpf 社区的核心成员 Yusheng Zheng(UC Santa Cruz)和 Yanpeng Hu(上海科技大学),合作方包括 eunomia-bpf 社区的 Tong Yu 和 UCSC 的 Andi Quinn。
它的论文发表在 ACM SIGOPS 2025(DOI: 10.1145/3766882.3767169),arXiv 编号 2508.02736。项目本身以 MIT 许可证开源在 GitHub 上,仓库地址是 github.com/eunomia-bpf/agentsight。
截至我查看时,项目用 Rust(约 6000 行核心代码)加 TypeScript Web 前端(约 3000 行)构建,核心 eBPF 探针用 C 编写。依赖栈覆盖了 cilium/ebpf(通过 libbpf)、tokio 异步运行时、rusqlite、ratatui TUI 等。前端是一个 Next.js 应用,内嵌了 WebSocket 实时通信层。
关键的数据:
| 维度 | 数据 |
|---|---|
| 核心语言 | Rust / C (eBPF) / TypeScript |
| 许可证 | MIT |
| 论文 | ACM SIGOPS 2025, arXiv:2508.02736 |
| 技术栈 | libbpf, tokio, rusqlite, ratatui, Next.js |
| 性能开销 | < 3%(论文实测) |
| 支持的 Agent | Claude Code, Codex, Gemini CLI, OpenCode, OpenClaw 等 |
产品定位:不是又一个 APM 工具
AgentSight 的自我介绍很克制:「A local-first top/strace-like observability tool for AI agents。It connects prompts, model calls, and tool decisions to their real effects on your machine。」
我的理解是:它不是 LangFuse/Arize Phoenix 那样的应用层追踪工具,也不是 Falco/Tracee 那样的纯系统级监控。它做的是横跨这两层的事——把 Agent 的意图(LLM 对话)和效果(系统调用、文件操作、进程创建)关联起来。
这是本质区别。传统的 Agent 可观测性工具(LangSmith、LangFuse、Phoenix)都是在应用内插桩——你代码里有 LangChain 回调,它们就能追踪到 tool call 的语义。但 Agent 一旦 spawn 了一个 subprocess(比如 Claude Code 跑 bash script.sh),这些工具的追踪链就断了——那个 bash 进程做的事情它们看不见。反过来,系统级工具(如 Falco)能看到一切系统调用,但它不知道这些调用是「修复认证模块的 bug」还是「植入后门」——它没有语义上下文。
AgentSight 做的,就是同时看到两边,然后把它们关联起来。
核心概念:边界追踪
论文里提出的核心理念叫「边界追踪」(boundary tracing)。它的洞察其实很简洁:Agent 的代码和框架可能会变,但它和世界交互的接口是稳定的——内核(系统调用)和网络(LLM API 调用)。只要在这两个边界上放探针,就能在不侵入 Agent 内部的前提下,拿到全部观测数据。
这里有个关键判断:稳定接口 vs 不稳定接口。Agent 框架(LangChain、AutoGen、Vercel AI SDK)的 API 可能在几个月内大变,但 SSL_read、execve、openat2 这些系统接口可以稳定工作十年。对观测工具来说,选稳定接口做探针,意味着框架升级时不需要改动代码。
这也是 AgentSight 敢宣称「无需 SDK、无需代理、无需厂商集成」的底气所在——它不依赖 Agent 配合,直接在内核层做观测。
技术架构拆解
AgentSight 的架构可以纵向切分为四层:
┌─────────────────────────────────────┐
│ Next.js Web UI / TUI (ratatui) │ ← 呈现层
├─────────────────────────────────────┤
│ Rust Daemon (collector) │
│ ┌─ Correlation Engine │ ← 关联引擎
│ │ ├─ 实时关联 (因果链) │
│ │ └─ LLM 语义分析 (二级模型) │
│ ├─ Analyzers Pipeline │ ← 分析管线
│ │ ├─ SSL Filter / HTTP Filter │
│ │ ├─ Protocol Events │
│ │ └─ Materializing / SSE Proc │
│ └─ Sinks (SQLite DB / Snapshot) │ ← 持久化
├─────────────────────────────────────┤
│ agentsight-capture (Rust) │
│ ┌─ Runners (eBPF / JSONL / local) │ ← 运行时
│ └─ Event Model │
├─────────────────────────────────────┤
│ eBPF Probes (C) │
│ ┌─ sslsniff.bpf.c │ ← TLS 流量捕获
│ ├─ process.bpf.c │ ← 进程/系统调用追踪
│ ├─ stdiocap.bpf.c │ ← 标准输入输出捕获
│ └─ browsertrace.bpf.c │ ← 浏览器追踪
└─────────────────────────────────────┘
第一层:eBPF 探针
这是 AgentSight 的数据源头,也是它最硬核的部分。四个 BPF 程序各有分工:
sslsniff.bpf.c(约 16KB)—— 通过 uprobe 挂载到 OpenSSL 的 SSL_read/SSL_write 函数上,拦截解密后的 LLM 请求和响应数据。支持 OpenSSL 1.1+、BoringSSL 和 Rustls 的变体(通过不同的偏移量配置)。数据通过 BPF ring buffer 传递给用户态。这里还有一个值得注意的细节:它对 SSE 协议的流式数据做了分片重组,不是简单的一包一报。
process.bpf.c(约 8KB)—— 用 sched_process_exec tracepoint 追踪进程创建,建立完整的进程血缘树(parent→child 关系)。同时通过 kprobe 监控 openat2、connect、execve 等关键系统调用。它最实用的设计是内核级动态过滤——通过追踪 fork/exec 事件动态建立 Agent 的进程树后,只在内核层放行属于该 Agent 家族的进程事件,其他系统进程的噪音直接过滤掉。这是达到 < 3% 开销的关键原因。
stdiocap.bpf.c(约 4KB)—— 捕获 Agent 子进程的标准输出/标准错误流。这对调试 Agent 在无头模式下运行的输出特别有用。
browsertrace.bpf.c(约 6KB)—— 用于追踪浏览器中的 Agent 活动。这个探针更多用于 Web-based Agent(如基于浏览器的自动化工具)。
第二层:Capture Runtime(agentsight-capture)
这是一个独立的 Rust crate(agentsight-capture),提供了三个核心抽象:
- Runner——数据源抽象。eBPF Runner 处理来自内核的事件流,JSONL Runner 处理离线日志文件,native Runner 读取 Agent 本地会话文件(Claude Code/Codex/Gemini 的本地记录)。这三种 Runner 输出统一格式的
Event结构体。 - Event——统一的事件模型。每个事件带时间戳、进程 PID、命令名和数据负载。不区分来源(eBPF、本地文件、JSONL),下游无需关心数据从哪来。
- EventStream——异步事件流,通过
tokio::sync::mpsc通道在 Runner 和 Analyzer 之间传递。
这种设计的好处很明显:你把 sudo agentsight record -- claude 录下来的 SQLite DB 文件,可以事后在任何机器上(甚至没有 eBPF 支持的 macOS/Windows)用 agentsight report 回放分析。
第三层:Correlation Engine + Analyzers
这是 AgentSight 最核心的智力所在。它分两阶段工作:
第一阶段——实时关联引擎:
- 从 SSL 探针拿到 LLM 的
prompt → response对(意图流) - 从进程探针拿到
fork → execve → open → write事件链(动作流) - 用三种信号建立因果关系:进程血缘(子进程归到父 Agent)、时间临近(LLM 响应后 100-500ms 内的动作)、参数匹配(LLM 响应里的文件名/URL/命令和系统调用参数匹配)
这个引擎在用户态 Rust daemon 中运行,用 tokio 异步流处理。Analyzers 是一个可插拔的处理管线——目前实现了 HTTP 解析器、SSL 过滤器、SSE 处理器、协议事件提取器、时间戳规范化器等。
第二阶段——二级 LLM 语义分析: 关联引擎把原始事件组织成结构化 trace 后,用一个独立的 LLM(作为「安全分析师」)来分析这个 trace。LLM 被要求:
- 判断事件序列是否异常
- 推断可能的安全风险(prompt injection、数据泄露、资源滥用)
- 给出置信度评分
这个设计很有意思——用 AI 来观察 AI。论文的评估显示这种混合方式在检测 indirect prompt injection 攻击时,比纯规则引擎的误报率低很多。
第四层:呈现层
AgentSight 提供三种界面:
agentsight top——TUI 模式,类似htop但针对 Agent 会话。实时显示激活中的 Agent 会话,按 CPU/RSS/Token/执行次数/文件/网络活动排序。这是最常用的工作模式。agentsight vis——可视化回放。在 Git 仓库中运行,它会扫描 Claude/Codex/Gemini 的本地会话记录,生成一个「Agent Nebula」动画 GIF/HTML,展示 Agent 在仓库上的文件操作(读、写、创建、删除、重命名)的历史回放。- Web UI——内嵌的 Next.js 网页应用,通过 WebSocket 连接 daemon 做实时展示。也支持离线加载 SQLite DB 做事后分析。
部署方式
AgentSight 的安装选项比较多:
- cargo install agentsight——最简单的方式,直接通过 Cargo 安装
- Homebrew——
brew tap eunomia-bpf/tap && brew install agentsight(支持 Linux x86-64) - Release Binary——GitHub Releases 页面下载预编译二进制
- Docker——需要 privileged 权限运行(因为有 eBPF 探针)
- 源码构建——需要 Rust 工具链 + LLVM/Clang(用于编译 BPF 程序)
使用的基本模式:
# 实时监控(类似 top)
sudo agentsight top
# 录制一个 Agent 会话
sudo agentsight record -- claude
# 事后分析
agentsight report
agentsight report prompts --json # 看 LLM 对话全文
agentsight report token # 看 Token 使用统计
agentsight report audit --json # 看审计事件
平台兼容性:top、vis、report 命令在 macOS 和 Windows 上也可以工作(读取已有的 session DB 文件),但 record 命令需要 Linux 4.1+ 内核和 eBPF 支持(推荐 5.0+)。
我观察到的几个点
1. 「边界追踪」是一种设计哲学,不止是一个技术方案
AgentSight 最值得关注的其实不是它用了 eBPF,而是它选择在哪个层面做观测。当前大多数 Agent 可观测性工具(包括我自己之前深入看过的 LangFuse、Phoenix)都选择在应用内插桩——你的 Agent 框架要集成它们的 SDK。AgentSight 选择了相反的方向:不在应用内,不在框架层,而是在操作系统边界。这个选择让它在面对闭源 Agent(如 Claude Code CLI)时仍然有效,而且框架升级不影响观测能力。
2. 内核级动态过滤是性能的基石
Agent 在跑的时候,系统里还有大量其他进程在活动——sshd、cron、浏览器、IDE。如果不做过滤,eBPF probe 产生的数据量会淹没用户态处理程序。AgentSight 的做法是先通过 sched_process_exec tracepoint 建立 Agent 的进程树,然后只允许这个树上的事件通过。这个过滤逻辑跑在内核层(BPF 程序内),不需要用户态介入。论文实测 < 3% 的开销,这个设计是主要原因。
3. 混合关联策略是实用主义的选择
纯时间窗口关联(「如果进程启动在 LLM 响应后 500ms 内,就认为两者相关」)对简单场景够用,但在流式推理和并行 tool call 的场景下会有误关联。AgentSight 叠加了进程血缘和参数匹配两种信号来降低误报。从 Rust 源码里看 analyzers/ 目录,materializing.rs 里实现的关联逻辑确实在维护状态化的进程树和文件描述符映射——这不是简单的 if-then 规则。
4. 二级 LLM 分析是把双刃剑
用 LLM 分析 Agent trace 来判断「这是正常行为还是攻击」——这个想法很符合直觉,但在工程上引入了两个问题:延迟(LLM 调用需要数十到数百毫秒)和成本(每次 trace 分析消耗 tokens)。AgentSight 通过异步处理来解耦实时关联(毫秒级)和语义分析(秒级),但异步意味着安全事件不是实时告警的。论文的消融实验显示二级 LLM 分析确实能检测到规则引擎会漏掉的 prompt injection,但它在生产环境的延迟和成本仍需在实际部署中验证。
5. Rust 技术栈的选择
从 Cargo.toml 看,项目选择了 tokio + rusqlite + ratatui + libbpf 的组合,2024 edition + 1.87 minimum rust version。对一个以 eBPF 探针为核心的工具来说,Rust 是合理的选择——它既有 C 级别的系统编程能力,又在内存安全上优于 C(特别是用户态 daemon 中处理大量异步事件流时)。项目拆分得比较清晰:agentsight-capture 作为独立 crate 可被其他 Rust 项目复用,collector 是 CLI/TUI 壳层,frontend 是 Next.js 前端。
写在最后
AgentSight 给我的感觉是,它在用一种「观测系统」而非「观测应用」的视角来做 Agent 可观测性。它不在 Agent 的代码里插桩,而是在 Agent 运行环境的稳定边界上架设探针——这是一种做基础设施的人会更认同的思路。
在 eBPF Agent 观测这个赛道上,如果你已经在运行 Agent 工作流,想看看 Agent 到底在系统上做了什么,AgentSight 是目前少有的、无需集成、即装即用的系统级观测方案。
《ClawGuard 源码级解析:eBPF Agent TLS 明文捕获》 —— 另一篇关于 eBPF Agent 观测的技术拆解,聚焦 TLS 明文捕获的实现路径。