Agent Capture:用 mitmproxy 给代码智能体做本地流量抓包
调试代码智能体时,最难定位的问题往往不是“模型有没有返回”,而是“请求到底发到了哪里、请求体是什么、响应是否被流式返回、前端或 TUI 为什么没有展示结果”。agent-capture 解决的就是这个问题:它把智能体的 HTTP/HTTPS 流量导入本地代理,用 mitmproxy 抓取请求和响应,再通过一个轻量的 Web 仪表盘展示调用明细。
这个项目的定位很清晰:不侵入被调试的 agent,不要求接 SDK,也不改业务代码。只要让目标进程的网络流量经过本地代理,就可以把请求记录落到本地 JSONL 文件里,并在页面上按 provider、状态、关键词查看。

项目由三部分组成
agent-capture 的核心结构很简单:
capture/capture.py:mitmproxy 插件,负责真正抓包和落盘。server/index.ts:Node/TypeScript API,负责读取 JSONL、汇总统计、提供查询接口。src/main.tsx:React/Vite 仪表盘,负责展示请求列表、详情、统计卡片和 SSE 解析结果。
运行时还有三个默认地址:
mitmproxy 代理:127.0.0.1:8787
Web 仪表盘:http://127.0.0.1:5173
API 服务:http://127.0.0.1:5174
抓到的数据默认写入:
data/captures.jsonl
JSONL 的好处是追加写入成本低、出问题时容易保留历史,也方便后续用脚本二次分析。
抓包原理
整个链路可以理解成这样:
agent 进程 -> HTTP_PROXY/HTTPS_PROXY -> mitmproxy -> 目标模型服务
|
v
data/captures.jsonl
|
v
Node API + React dashboard
当 agent 发起模型请求时,请求先进入本地 mitmproxy。capture.py 在 mitmproxy 的 response 和 error 钩子里拿到完整 flow,然后组装成一条结构化记录,内容包括:
- 请求方法、URL、host、path、HTTP 版本。
- 请求头和响应头。
- 请求体和响应体。
- 状态码、耗时、捕获时间。
- 出错请求的错误信息。
项目会对敏感请求头做脱敏,例如 authorization、cookie、set-cookie、x-api-key、api-key、proxy-authorization。这能降低误把认证信息写入本地文件的风险,但仍然建议把 data/captures.jsonl 当作敏感调试数据处理,不要随意提交或分享。
响应体处理也做了区分:如果是 JSON、文本、XML、表单等文本类型,就直接保存文本;如果是二进制内容,就保存 base64。默认每个请求或响应最多保存 1MB,可以通过环境变量调整。
API 和仪表盘做了什么
Node API 不负责抓包,它只读 JSONL。启动后会提供几个接口:
GET /api/health
GET /api/requests
GET /api/requests/:id
GET /api/stats
POST /api/clear
其中 /api/requests 会把原始记录转换成列表摘要,包括 provider、model、tokens、状态和耗时。provider 的识别是基于 host 的简单规则,例如 OpenAI、Anthropic、Gemini、Azure OpenAI、本地服务等。model 的识别优先从请求体里的 model 字段读取,Gemini 和 Azure OpenAI 会从 path 中提取模型或 deployment 名称。
React 仪表盘每 2.5 秒轮询请求列表和统计数据。页面上可以看到:
- 总请求数、错误数、平均耗时、token 汇总。
- 请求列表:时间、方法、状态、host、path、provider、model、耗时。
- 请求详情:请求体、响应体、请求头、响应头。
- 对 SSE/NDJSON 响应的解析视图,用来直接看流式输出内容。
这对排查“接口 200 但 TUI 没显示”“模型实际返回了什么”“请求是否打到了错误 endpoint”“某次响应是否被截断”等问题很直接。
安装和启动
进入项目目录:
cd /Users/bytedance/code/agent-capture
安装依赖:
npm install
如果本机还没有 mitmproxy,需要单独安装:
brew install mitmproxy
启动 API 和 Web 仪表盘:
npm run dev
另开一个终端启动抓包代理:
npm run capture
然后打开:
http://127.0.0.1:5173
让 agent 流量经过代理
最常见的方式是在启动 agent 时设置代理环境变量:
HTTP_PROXY=http://127.0.0.1:8787 \
HTTPS_PROXY=http://127.0.0.1:8787 \
your-agent-command
如果 agent 是 Node.js 生态的程序,例如 opencode 或 ink,还需要注意 TLS 证书。mitmproxy 会用自己的 CA 证书解密 HTTPS,Node 默认会拒绝这种自签证书。调试时可以加上:
NODE_TLS_REJECT_UNAUTHORIZED=0 \
HTTP_PROXY=http://127.0.0.1:8787 \
HTTPS_PROXY=http://127.0.0.1:8787 \
opencode
更完整的 HTTPS 方案是安装 mitmproxy CA。保持 npm run capture 运行,用走代理的浏览器打开:
http://mitm.it
然后按 macOS 的证书安装说明操作。
抓取 ink 或 opencode 的建议命令
交互式 ink 有一个容易踩坑的点:不要设置 ALL_PROXY。ink 会访问本地 HTTP endpoint 来驱动 TUI 或本地 opencode 服务。如果 ALL_PROXY 把本地请求也转进 mitmproxy,可能出现模型请求已经成功,但交互界面不显示回复的情况。
推荐命令:
env -u ALL_PROXY -u all_proxy \
NODE_TLS_REJECT_UNAUTHORIZED=0 \
HTTP_PROXY=http://127.0.0.1:8787 \
HTTPS_PROXY=http://127.0.0.1:8787 \
NO_PROXY=127.0.0.1,localhost,::1 \
no_proxy=127.0.0.1,localhost,::1 \
ink
非交互式快速验证可以这样跑:
NODE_TLS_REJECT_UNAUTHORIZED=0 \
HTTP_PROXY=http://127.0.0.1:8787 \
HTTPS_PROXY=http://127.0.0.1:8787 \
NO_PROXY=127.0.0.1,localhost,::1 \
no_proxy=127.0.0.1,localhost,::1 \
ink run "只回复 pong"
执行后到仪表盘看是否出现新的模型请求。
常用配置
默认会抓取所有经过 mitmproxy 的请求。如果只想减少落盘内容,可以配置 host 过滤:
AGENT_CAPTURE_HOSTS=api.openai.com,anthropic.com npm run capture
如果只想抓 ink 的模型流量,可以使用:
AGENT_CAPTURE_HOSTS=ink.bytedance.net npm run capture
调整保存的 body 大小:
AGENT_CAPTURE_MAX_BODY_BYTES=2097152 npm run capture
指定落盘文件:
AGENT_CAPTURE_FILE=/tmp/agent-captures.jsonl npm run capture
AGENT_CAPTURE_FILE=/tmp/agent-captures.jsonl npm run dev:server
注意抓包进程和 API 服务要读取同一个 AGENT_CAPTURE_FILE,否则仪表盘会显示为空。
如何排障
如果仪表盘没有请求,先确认代理是否启动在 8787,再确认 agent 启动命令里是否设置了 HTTP_PROXY 和 HTTPS_PROXY。
如果 HTTPS 请求失败,优先检查 mitmproxy CA 是否安装;Node.js agent 调试时可以临时使用 NODE_TLS_REJECT_UNAUTHORIZED=0。
如果模型接口返回 200,但交互式 ink 没显示内容,检查仪表盘里是否抓到了本地请求,例如:
http://127.0.0.1:<port>/command
http://127.0.0.1:<port>/mcp
http://127.0.0.1:<port>/session/.../message
如果这些本地请求也被代理了,说明代理环境变量过宽。去掉 ALL_PROXY,并设置 NO_PROXY=127.0.0.1,localhost,::1。
如果响应体看起来像一堆 data: 分片,可以看仪表盘里的 Parsed SSE Output。它会尝试从 OpenAI-like、Gemini-like 和通用 text 字段里提取流式文本,便于快速判断模型到底返回了什么。
适合什么场景
agent-capture 很适合以下场景:
- 调试代码智能体的模型请求。
- 比较不同 provider 或模型的请求格式。
- 排查流式响应、超时、状态码异常和 token 统计。
- 分析本地 CLI/TUI agent 的网络行为。
- 在不改 agent 源码的情况下保留可复盘的请求记录。
它不适合长期作为生产流量审计系统,也不应该无过滤地抓取包含大量敏感信息的全局系统代理流量。它更像一个本地调试显微镜:临时打开,定位问题,确认结果,然后及时关闭或清理数据。
总结
agent-capture 的价值在于把“黑盒 agent 调用”变成可观察的本地记录。mitmproxy 负责截获真实 HTTP/HTTPS 流量,Python 插件负责结构化落盘,Node API 负责查询聚合,React 仪表盘负责把请求和响应直观展示出来。
对代码智能体调试来说,这种方式足够轻量,也足够直接。遇到“请求没发出去”“接口返回了但界面没反应”“模型输出被流式切片包住”“不知道 token 或耗时在哪里花掉”这类问题时,先把 agent 通过 127.0.0.1:8787 代理跑一遍,通常很快就能看到答案。