在 Cloudflare 上跑 Claude Agent:从部署到可观测的一站式方案

2026-05-28 24 预计阅读时间:1 分钟
来源:infoq.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:10 分钟

Anthropic 的 Claude Agent 能做复杂推理和多步骤任务,但真正把它放进生产环境,开发者要面对一堆琐碎问题:Agent 怎么安全地访问内网数据库?跑在哪个 runtime?执行日志怎么追踪?Cloudflare 最近上线了对 Claude Managed Agents 的支持,把这几件事打包到了同一套基础设施里——Workers 的边缘 runtime、Tunnel 的私有网络穿透、Logpush 的日志管道,全部可以直接对接 Agent 的生命周期。

Agent 不只是"调一次 API"

普通 LLM 调用是单轮请求-响应;Agent 则是自主规划、多步执行、中途可能调用外部工具。这意味着两件事:

  • Agent 需要长时间运行且可能重试——runtime 要能撑住几十秒甚至几分钟的执行,不能像普通 HTTP 请求那样 10 秒超时就断。
  • Agent 要访问你的私有资源——数据库、内部 API、消息队列,这些不该暴露到公网。

Cloudflare 的方案用 Workers 作为 Agent runtime,用 Tunnel 打通私有系统,用 Logpush / Workers Analytics 把执行过程变成可查询的结构化数据。开发者不用自己拼这套管道。

连接私有系统:Tunnel + Agent 的组合

传统做法是把内部服务开一个公网端口,再加 IP 白名单——风险高、维护成本大。Cloudflare Tunnel 的思路是反过来的:从内网主动建一条加密隧道到 Cloudflare 边缘,外部请求通过 Cloudflare 网关进入隧道,内网服务本身零暴露。

Agent 场景下,Tunnel 的价值更明显:Agent 在 Workers 上跑,需要调用内网的 PostgreSQL 或 Redis,直接走 Tunnel 路由,不需要任何公网入口。下面是一个最小化的 Tunnel + Agent 配置示例。

# cloudflare-tunnel-config.yml
tunnel: my-agent-tunnel
credentials-file: /etc/cloudflare/.tunnel-credentials.json

ingress:
  # Agent 调用内部用户查询 API
  - hostname: agent-internal-api.my-domain.com
    service: http://user-service:8080
  # Agent 读取内部 PostgreSQL(通过 PostgREST 暴露)
  - hostname: agent-db.my-domain.com
    service: http://postgrest:3000
  # 兜底规则
  - service: http_status:404

启动 Tunnel:

# 安装 cloudflared 后,创建并运行隧道
cloudflared tunnel create my-agent-tunnel
cloudflared tunnel route dns my-agent-tunnel agent-internal-api.my-domain.com
cloudflared tunnel route dns my-agent-tunnel agent-db.my-domain.com
cloudflared tunnel --config cloudflare-tunnel-config.yml run my-agent-tunnel

这样 Agent 在 Workers 里发请求到 https://agent-internal-api.my-domain.com,流量会经 Cloudflare 边缘进入 Tunnel,直达内网服务,全程 TLS 加密、零公网暴露。

在 Workers 上跑 Agent:一个可改造的完整示例

下面是一个在 Cloudflare Workers 中集成 Claude Agent 的最小项目。它演示了:初始化 Agent、让它调用内部 API(走 Tunnel)、返回结构化结果。你可以直接复制改造。

# 初始化 Workers 项目
npm create cloudflare@latest -- my-claude-agent
cd my-claude-agent
// src/index.ts — Cloudflare Worker 入口
interface Env {
  ANTHROPIC_API_KEY: string;
  INTERNAL_API_URL: string; // Tunnel 地址,如 https://agent-internal-api.my-domain.com
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // 1. 从请求中获取用户指令
    const { task } = await request.json() as { task: string };

    // 2. 定义 Agent 可用的工具
    const tools = [
      {
        name: "query_user_profile",
        description: "通过用户 ID 查询内部用户档案",
        input_schema: {
          type: "object",
          properties: {
            user_id: { type: "string", description: "内部用户 ID" },
          },
          required: ["user_id"],
        },
      },
    ];

    // 3. 调用 Claude Agent API(使用 tool_use 模式)
    const agentResponse = await fetch("https://api.anthropic.com/v1/messages", {
      method: "POST",
      headers: {
        "x-api-key": env.ANTHROPIC_API_KEY,
        "anthropic-version": "2023-06-01",
        "content-type": "application/json",
      },
      body: JSON.stringify({
        model: "claude-sonnet-4-20250514",
        max_tokens: 4096,
        system: "你是一个内部运营助手。收到任务后,按步骤调用工具完成,最后给出结构化总结。",
        messages: [{ role: "user", content: task }],
        tools,
      }),
    });

    const agentResult = await agentResponse.json() as any;

    // 4. 如果 Agent 请求调用工具,执行工具调用并继续对话
    if (agentResult.stop_reason === "tool_use") {
      const toolCall = agentResult.content.find((block: any) => block.type === "tool_use");
      const toolInput = toolCall.input as { user_id: string };

      // 调用内部 API(走 Cloudflare Tunnel)
      const internalRes = await fetch(`${env.INTERNAL_API_URL}/users/${toolInput.user_id}`, {
        headers: { "Authorization": "Bearer internal-token" },
      });
      const userProfile = await internalRes.json();

      // 把工具结果喂回 Claude,让它继续推理
      const followUp = await fetch("https://api.anthropic.com/v1/messages", {
        method: "POST",
        headers: {
          "x-api-key": env.ANTHROPIC_API_KEY,
          "anthropic-version": "2023-06-01",
          "content-type": "application/json",
        },
        body: JSON.stringify({
          model: "claude-sonnet-4-20250514",
          max_tokens: 4096,
          system: "你是一个内部运营助手。收到任务后,按步骤调用工具完成,最后给出结构化总结。",
          messages: [
            { role: "user", content: task },
            { role: "assistant", content: agentResult.content },
            {
              role: "user",
              content: [
                {
                  type: "tool_result",
                  tool_use_id: toolCall.id,
                  content: JSON.stringify(userProfile),
                },
              ],
            },
          ],
          tools,
        }),
      });

      const finalResult = await followUp.json() as any;
      return Response.json(finalResult);
    }

    // 5. Agent 直接给出文本回复
    return Response.json(agentResult);
  },
};
# wrangler.toml — Workers 部署配置
name = "my-claude-agent"
main = "src/index.ts"
compatibility_date = "2025-06-18"

[vars]
INTERNAL_API_URL = "https://agent-internal-api.my-domain.com"

# API Key 用 secret 管理,不要硬编码
# 运行: wrangler secret put ANTHROPIC_API_KEY

部署:

wrangler secret put ANTHROPIC_API_KEY   # 输入你的 Anthropic API Key
wrangler deploy

部署后用 curl 测试:

curl -X POST https://my-claude-agent.my-domain.com \
  -H "content-type: application/json" \
  -d '{"task": "查询用户 u-12345 的档案,判断是否满足升级条件"}'

Agent 会先调用 query_user_profile 工具,Worker 通过 Tunnel 拿到内网数据,再把结果喂回 Claude 做判断——整个过程在边缘 runtime 完成,内网服务不暴露。

可观测:知道 Agent 到底干了什么

Agent 的黑盒问题是生产环境最大的痛点。Cloudflare 的方案是让 Agent 的每一步执行都通过 Workers Analytics 和 Logpush 落地:

  • Workers Analytics:记录每次 Agent 请求的耗时、token 消耗、工具调用次数,可以在 Cloudflare Dashboard 直接看趋势图。
  • Logpush:把结构化日志推到你的 R2 存储、S3 或外部分析平台(如 Datadog),做更细的审计。

启用 Logpush 到 R2 的配置:

# 创建 R2 Bucket 接收日志
wrangler r2 bucket create agent-logs

# 启用 Logpush,把 Workers 日志推到 R2
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/logpush/jobs" \
  -H "Authorization: Bearer {cf_api_token}" \
  -H "content-type: application/json" \
  -d '{
    "name": "agent-activity-logs",
    "logpull_options": "fields=Event,EventTimestamp,Outcome,RequestPath,ResponseStatus,OriginIP&timestamps=rfc3339",
    "destination_conf": "r2://agent-logs/{zone_id}/{date}",
    "filter": "{\"where\": {\"key\": \"RequestPath\", \"operator\": \"startsWith\", \"value\": \"/my-claude-agent\"}}"
  }'

这样每次 Agent 调用内部 API、每次工具执行的结果,都会以 JSON 形式存进 R2,你可以用 Athena 或 DuckDB 做事后查询:

-- 用 DuckDB 查询最近 7 天 Agent 调用内部 API 的失败率
SELECT
  date,
  count(*) AS total_calls,
  count_if(ResponseStatus >= 400) AS failures,
  round(failures / total_calls * 100, 2) AS failure_pct
FROM read_json_auto('r2://agent-logs/*/*.json')
WHERE EventTimestamp >= current_timestamp - interval '7' day
GROUP BY date
ORDER BY date;

上线前的检查清单

把 Claude Agent 跑在 Cloudflare 上确实省了不少基础设施工作,但上线前有几件事必须确认:

检查项 说明
API Key 安全 wrangler secret 管理,绝不硬编码到代码或环境变量文件
Tunnel 认证 内网服务即使走 Tunnel,也应校验请求来源(如 Service Token),防止同一 Tunnel 上的其他路径被滥用
执行超时 Workers 有 CPU 时间限制(免费版 10ms,付费版 30s),Agent 多步推理可能超限——考虑用 Durable Objects 延长执行窗口
Token 成本 Agent 多轮推理的 token 消耗远高于单次调用,务必在 Analytics 里监控 max_tokens 实际使用量,设上限
日志脱敏 Agent 工具结果可能包含用户隐私数据,Logpush 到外部存储前做字段过滤或脱敏
回退策略 Agent 调用失败时(内部 API 挂了、Claude 超时),Worker 应返回明确错误码,不要静默吞掉

Cloudflare 把 runtime、网络穿透、可观测三件事串起来,确实让 Agent 从"能跑 demo"到"能上生产"的距离缩短了不少。但 Agent 的不确定性本身不会因为基础设施变好而消失——监控、限流、回退策略,这些仍然是开发者自己要守的底线。


相关推荐