Anthropic claude-agent-sdk — egress proxy 配方
Anthropic 的
claude-agent-sdk是 Anthropic 唯一官方发布的 agent SDK。它有点特别: 这个 SDK 以子进程方式拉起claudeCLI 二进制 来跑 agent 循环,所以每个messages请求都是从 CLI 进程内部发出的 HTTPS 调用, 离开的是 Python(或 Node)进程,而不是 SDK。SpendGuard 管控它的方式 和管控任何遵守 HTTPS 的 CLI 一样:一个跑在localhost:9000的正向 代理,加一张 CLI 接受的受信任根 CA。 D02 的spendguard install步骤这两件事都帮你做好。
为什么没有 SDK adapter
Section titled “为什么没有 SDK adapter”SDK 的 PreToolUse 钩子是 tool 粒度 的:它在 agent
决定使用某个 tool(Bash、Edit、Read、WebFetch)时运行。它
看不到 底层的 POST /v1/messages 请求。等到下一个 tool 的
PreToolUse 触发时,LLM 早就调过了,token 也已经计费了,模型也已经
产出了响应。
所以在 SDK 这一层根本没有什么可包的,包了也拦不住真正花出去的钱。真正
管用的闸门在下一层——CLI 遵守 HTTPS_PROXY 和 NODE_EXTRA_CA_CERTS 的那个
HTTPS 边界。这个边界正是 D02 已经配好的,也正是 SpendGuard egress
proxy 已经在终结的那一个。Anthropic 流量走代理里现成的 per-provider
路由(routing.rs)。
D30 就是把这些串起来的配方。
闸门怎么工作
Section titled “闸门怎么工作”your code (Python or TypeScript) uses claude_agent_sdk / @anthropic-ai/claude-agent-sdk │ subprocess ▼ `claude` CLI binary (Node) │ HTTPS_PROXY=http://localhost:9000 │ NODE_EXTRA_CA_CERTS=<spendguard CA> ▼ SpendGuard egress proxy ── route: api.anthropic.com/v1/messages │ │ PRE: sidecar RequestDecision → CONTINUE / STOP │ ↳ forward to api.anthropic.com │ POST: sidecar ConfirmPublishOutcome (commit_estimated) ▼ audit_outbox: one RESERVE_RESPONSE row + one matching COMMIT_OUTCOME rowCLI 是 HTTPS 客户端。egress proxy 是闸门。audit_outbox
里的那几行把审计链闭合。
- 一个跑在
http://localhost:9000的 SpendGuard egress proxy。 Quickstart 能在 5 分钟内把整套栈拉起来。 - 这台主机上
spendguard install已经干净跑通(D02)。CLI 安装器会把 SpendGuard 根 CA 写进操作系统信任库,并把HTTPS_PROXY+NODE_EXTRA_CA_CERTS写进你的 shell rc。 ANTHROPIC_API_KEY里有一个 Anthropic API key。这个配方只支持 BYOK——Claude Code Pro / Max 订阅计量 是另一套独立集成。- Python 端:Python 3.11 或更新。TypeScript 端:Node.js 20 或更新。
配方 — Python
Section titled “配方 — Python”pip install claude-agent-sdk
# spendguard install already wired your shell. Verify:echo "$HTTPS_PROXY" # → http://localhost:9000echo "$NODE_EXTRA_CA_CERTS" # → /etc/ssl/spendguard/ca.crt (or your platform path)import anyiofrom claude_agent_sdk import query, ClaudeAgentOptions
PROMPT = "List two ways to reverse a string in Python in under 30 words."
async def main() -> None: async for msg in query( prompt=PROMPT, options=ClaudeAgentOptions(model="claude-sonnet-4-5", max_turns=1), ): print(msg)
if __name__ == "__main__": anyio.run(main)跑起来。CLI 子进程从你的 shell 环境继承 HTTPS_PROXY,所以
messages 调用会流经 SpendGuard egress proxy。代理会在
audit_outbox 里写出一行 RESERVE_RESPONSE 加一行匹配的
COMMIT_OUTCOME——用下面
确认 SpendGuard 抓到了这次调用
里的 SQL 来对账。
配方 — TypeScript
Section titled “配方 — TypeScript”npm install @anthropic-ai/claude-agent-sdk
echo "$HTTPS_PROXY" # → http://localhost:9000echo "$NODE_EXTRA_CA_CERTS" # → /etc/ssl/spendguard/ca.crt (or your platform path)import { query } from "@anthropic-ai/claude-agent-sdk";
const PROMPT = "List two ways to reverse a string in Python in under 30 words.";
for await (const msg of query({ prompt: PROMPT, options: { model: "claude-sonnet-4-5", maxTurns: 1 },})) { console.log(msg);}TypeScript SDK 跟 Python SDK 形状一样,底下用的也是同一个 claude
CLI 二进制。两边都遵守 HTTPS_PROXY 和
NODE_EXTRA_CA_CERTS,产出的审计链行也一样。
确认 SpendGuard 抓到了这次调用
一次 query(...) 跑完之后,SpendGuard 已经往 audit_outbox
写了两行——PRE 时刻一行 RESERVE_RESPONSE,POST 时刻一行
COMMIT_OUTCOME,共享同一个 request_id。直接查它们来确认:
SELECT payload->>'event_type' AS event_type, payload->>'provider' AS provider, payload->>'model' AS model, payload->>'committed_input_tokens' AS input_tokens, payload->>'committed_output_tokens' AS output_tokens, payload->>'request_id' AS request_idFROM audit_outboxWHERE payload->>'provider' = 'anthropic' AND payload->>'model' LIKE 'claude-%'ORDER BY created_at DESCLIMIT 2;这次调用你应该正好看到两行:一行 event_type = RESERVE_RESPONSE
(调用前的预留)和一行 event_type = COMMIT_OUTCOME(调用后的
提交)——两行带同一个 request_id,而且提交那行
committed_input_tokens > 0、committed_output_tokens > 0。
SpendGuard 仪表盘在
Operations → Dashboard
下也会呈现这同样的几行。
PreToolUse 是什么——以及不是什么
PreToolUse 是 agent 即将 调用某个 tool(Bash、Edit、Read、
WebFetch、自定义 MCP tool)时触发的 SDK 钩子。它 不会 在底层
LLM 调用上触发。这个区别对预算控制很关键:
- 一个拒绝昂贵 tool 的
PreToolUse钩子是 tool 策略 闸门。它能 拦住Bash("rm -rf /")或WebFetch("https://...")。这地方很适合 编码”这个 agent 不许跑代码”或”这个 agent 不许调这个域名”。 - 一个想靠它来强制预算的
PreToolUse钩子就是 自欺欺人。等到下一个 tool 触发时,LLM 早就响应过了。token 也已经计费了。这个钩子没法把那次 产生 tool-use 决定的 messages 交互倒带回去。
要做 LLM 粒度的管控——也就是 SpendGuard 的调用前预留真正省下花费的那个
地方——跑在 api.anthropic.com/v1/messages 上的 egress proxy 才是
唯一正确的切入点。本页这个配方默认这个切入点已经通过 D02 就位了。
- CLI 子进程报
ssl.SSLCertVerificationError。 SpendGuard 根 CA 不在 CLI 读取的那个信任库里。重跑spendguard install;Linux 上确认update-ca-certificates跑过; macOS 上确认证书通过security add-trusted-cert加进了系统钥匙串。 Node 端确认NODE_EXTRA_CA_CERTS指向一个当前用户能读的 PEM 文件。 - 调用直接打到了
api.anthropic.com——没有审计行。 你当前的 shell 没有吃到spendguard install写的那段 rc snippet。开一个新 终端,或者source ~/.zshrc/~/.bashrc,再重新检查echo "$HTTPS_PROXY"。如果你是从 IDE 里启动 SDK 的,重启 IDE 让它 继承更新后的环境。 HTTPS_PROXY设了但NODE_EXTRA_CA_CERTS是空的。 CLI 基于 Node,会拿代理的叶子证书去校验 Node 自带的 CA 列表。没有NODE_EXTRA_CA_CERTS,连接就会以unable to verify the first certificate失败。两个环境变量都得设;spendguard install两个都设。PreToolUse拦住了某个 tool,但 LLM 调用还是发生了。 这是设计如此——见PreToolUse是什么——以及不是什么。 把预算上限挪到 egress proxy(就是这个配方)。
- Quickstart — 5 分钟拉起整套 SpendGuard 栈。
- Drop in 14 tools(总览) — Pattern 2,给其他 OpenAI 兼容 CLI 和 IDE 的速效方案。
- 订阅档计量 — 给 Claude Code Pro / Max 套餐用(不在这个 BYOK 配方覆盖范围内)。
- Operations → Dashboard — 找你这次 运行的审计链行。
- Anthropic 上游:
claude-agent-sdk-python·claude-agent-sdk-typescript。 - 可运行示例:
examples/claude-agent-sdk/。