别只给 Agent 配一个 API 网关:aitori 如何在设备出口处观察、路由并约束 AI 流量
当团队开始给 Claude Code、桌面客户端和浏览器里的 AI 服务接入网关时,最容易忽略的一段链路是:请求究竟能不能稳定地抵达网关。
传统做法通常依赖客户端支持自定义 Base URL、代理或企业策略。但浏览器里的 Claude/ChatGPT、不同版本的桌面客户端、以及各自携带网络配置的命令行工具,并不一定提供统一入口。结果是同一台机器上,一部分模型调用被记录、计费和执行策略,另一部分请求却直接离开设备;排查时只看到网关日志“缺了一段”,却不知道漏在何处。
aitori 选择把边界前移到设备出口:它是一个用 Go 编写的本地 HTTP(S) 代理,针对明确列出的主机进行选择性 TLS 解密,识别模型或 MCP 调用后再转发至 AI 网关;其他主机流量不解密,目标主机中不属于模型/MCP 的请求也可直接透传。这个思路并不是再造一个模型代理,而是补上“客户端无法改配置时,怎样在本机建立可观察、可治理入口”的空白。
先理解:它治理的是请求路径,而不是替你保管模型密钥
aitori 的处理可以拆成四步:
- 客户端仍请求原始站点,例如模型提供商 API 或浏览器中的 AI 服务;
- 本机代理仅对
intercept_hosts允许的主机终止 TLS,未列出的主机只是字节级转发; - 对已解密请求,按主机、路径、方法、规则和 JSON 体判断为
llm、mcp或other; - 只有命中的模型/MCP 请求才被重定向到网关,其余请求按策略透传或返回 HTTP 403。
因此,应用看到的仍是原始主机,自己的 Authorization、x-api-key、Cookie、请求体和路径仍由应用构造。aitori 会向网关额外加入三个 x-tfy-* 头:网关身份令牌、完整原始 URL,以及包含 app、pid、类别、主机和系统信息的归因 JSON。网关验证令牌、记录调用后,必须去掉这些内部头,再把原始凭证随请求转给真正上游。
这个区分很重要:网关令牌用于识别设备到网关的治理链路,不能替代用户原本的提供商凭证;网关也不能把内部头继续发送到上游。若自行实现兼容网关,应保持响应状态、头、流式分块和 SSE 节奏原样返回,并避免自动重试非幂等请求。
用最小配置先做“看得见”,再决定“要不要拦”
项目内置了 Claude Code、Claude Desktop、Claude 网页、ChatGPT 网页以及 Anthropic/OpenAI API 的一些配置档案。首次验证时,不应立刻把所有请求变成强制阻断,而是先开本地实时界面,确认实际命中的主机与分类:
curl -fsSL https://raw.githubusercontent.com/truefoundry/aitori/main/install.sh | sh sudo aitori up --ui sudo aitori down
up 会安装设备专属 CA、设置系统代理并运行服务;down 用于撤销代理和相关设置。若直接关闭终端或进程被异常结束,系统代理仍可能指向已经停止的本地监听器,应用网络就会失败。因此,试验前应先安排恢复方式,而不是只关注安装成功。
只有确认流量范围后,再加入自有主机和网关。例如下面的配置把一个额外 API 主机纳入选择性解密,并把被识别的模型/MCP 请求交给网关:
version: 1
gateway:
url: https://gateway.example.com/api/llm
on_error: fail_open
auth:
token_file: ~/.aitori/token
intercept_hosts:
- api.example.com
ui:
enabled: true
这里的 intercept_hosts 是隐私和可用性的核心边界,不应把“所有域名”当作方便的默认值。对于未列出的主机,aitori 不会解密;对于列出的主机,还可进一步用路径和 HTTP 方法收窄规则。配置模式是严格校验的,未知字段会导致 aitori config validate 失败,这比拼错字段后静默失效更适合承载治理策略。
从观察模式走到策略模式:把失败语义写清楚
aitori 支持 reroute、passthrough 和 block 三种请求动作。规则可按主机、路径前缀、路径模式、方法和浅层 JSON 条件匹配。例如,团队可以对已被解密的目标 API 阻断文件上传路径:
rules:
- name: block-uploads
hosts: ["api.openai.com"]
path_prefixes: ["/v1/files"]
methods: ["POST"]
action: block
命中后客户端会收到 HTTP 403,且请求不会继续转发。但这不等于“按应用授权”:当前项目的应用配置主要用于归因,尚没有“只允许某个特定应用、禁止另一个应用”的完整 per-app allow/block 策略。另一个边界是证书固定(certificate pinning):若客户端不信任本机 CA,TLS 握手会在策略执行前失败;项目状态页明确说明,此类情形当前不是可靠的 fail-closed 拦截。
网关不可用时也必须提前决定语义。默认 fail_open 会把请求送回原始上游,优点是不会因治理设施故障让开发完全中断,代价是出现未受治理的窗口;fail_closed 则以可用性换取更严格边界。生产环境不宜只凭“安全优先”选择其一:对非关键的交互式开发可先采用 fail-open 并告警,对必须经过审计或预算控制的工作负载再评估 fail-closed 与明确的降级流程。
不同客户端到达代理的方式也不同
默认的 Tier 1 依赖系统代理。对不遵循系统代理或自带 CA 包的客户端,aitori 提供设置注入:在 up 时为客户端设置代理和 CA 信任相关环境变量,down 时再回退。Linux 上还存在实验性的 Tier 2 透明捕获,通过 nftables 重定向处理忽略系统代理的应用;它仍应先在隔离机器验证,而不是直接作为桌面环境的默认配置。
项目当前已端到端验证的范围并不均匀:README 的矩阵显示,macOS 已验证 Claude Code、Claude Desktop、Claude 网页(Chrome)与 ChatGPT 网页;Linux 已验证终端中的 Claude Code;Windows 的部分能力及 Linux 的透明捕获仍标注为未完成真实硬件验证。部署设计应按这张矩阵做试点,不能把“可以跨平台编译”误写成“所有组合都已验证”。
上线前做一轮可回滚的验收
把代理启起来并不等于已经具备治理能力。建议在一台测试设备上建立一份小型验收清单:分别从 CLI、桌面客户端和浏览器发起一次已知的模型请求;在本地 UI 中确认它们被分类为预期类别;再查看网关侧是否收到原始 URL 与归因信息。对于计划阻断的路径,应使用无害的测试请求确认 HTTP 403 的行为、前端提示和日志都符合预期,而不是直接拿生产文件上传或长时间流式会话做第一次实验。
配置也应像代码一样进入版本控制,但令牌文件和设备专属 CA 不能提交。修改规则后先运行项目提供的校验命令,再重启或重新载入对应服务;未知字段会被拒绝,正好能避免拼写错误把策略悄悄降级。更关键的是记录一份回退操作:谁可以执行 sudo aitori down、网关故障时采用哪种 on_error、以及如何恢复原有系统代理。这样即使某个客户端因证书固定或代理兼容性失败,团队也能先恢复开发网络,再基于日志调整范围。
aitori config validate ./aitori.yaml sudo aitori up --ui -c ./aitori.yaml sudo aitori down
适合什么场景,不适合什么场景
aitori 适合解决“本机有多种 AI 客户端,但团队希望统一看到并治理模型/MCP 出口流量”的问题:先补齐归因和实时观察,再将合规、预算或阻断规则逐步交给后端网关。它也适合在不改业务代码的前提下,为无法配置网关地址的客户端建立受控入口。
但它不是沙箱,也不是万能的数据防泄漏系统。拥有本机管理员权限的人能够绕过它;透明捕获仍有平台限制;HTTP/3/QUIC 走 UDP,普通 TCP 代理看不到;项目的每条内置 host/path 规则都应先用真实抓包验证。最稳妥的落地顺序是:选择少量设备 → 只观察 → 核对分类与漏网流量 → 接入网关并配置告警 → 最后才对高风险路径启用阻断。
把治理点放在设备出口,并不意味着放弃网关,而是让网关终于能接到原本绕过它的请求。对使用浏览器、桌面端和 CLI Agent 混合开发的团队,这一层补齐后,策略、成本和审计才有共同的事实基础。
相关链接