返回首页

OpenClaw 的 Claude API 代理:代码和工具使用

代理服务器在 Anthropic 屏蔽后恢复 openclaw 中对 Claude 的访问。使用 curl_cffi 的浏览器模拟,支持通过 XML 提示和自动修复 JSON 的工具使用。完整代码、配置和开发者集成。

在 OpenClaw 中恢复 Claude:带工具使用的代理
Advertisement 728x90

通过 Web 会话代理 Claude API:OpenClaw 集成工具调用

Anthropic 已屏蔽 Claude 在第三方应用如 OpenClaw 中的使用。Pro 订阅用户(每月 100 美元)获得 100 美元额外使用额度,但这无法解决代理集成问题。解决方案?一个模拟 Claude.ai 浏览器会话的代理服务器,提供 OpenAI 兼容 API。这样,你就能在 OpenClaw 中运行 Claude Sonnet/Opus,并支持完整工具调用功能。

使用 Python 构建,结合 curl_cffi 实现 Chrome TLS 指纹。Cookie 和设备 ID 来自你的活跃会话。每次请求启动全新对话,通过 SSE 流式传输完成内容。

基本会话和头部设置

会话伪装成 Chrome,使用真实浏览器 Cookie。通过反检测浏览器 Camoufox 测试。

Google AdInline article slot
def make_session() -> cf_requests.Session:
    """创建带 Chrome TLS 指纹的新 curl_cffi 会话。"""
    cookies = get_cookies()
    session = cf_requests.Session(impersonate=IMPERSONATE)
    session.cookies.update(cookies)
    return session

def get_headers(cookies: dict) -> dict:
    return {
        "User-Agent": (
            "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
            "(KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36"
        ),
        "Origin": "https://claude.ai",
        "Referer": "https://claude.ai/new",
        "anthropic-device-id": cookies.get("anthropic-device-id", ""),
        "sec-fetch-dest": "empty",
        "sec-fetch-mode": "cors",
        "sec-fetch-site": "same-origin",
    }

完成请求逻辑

  • POST 到 /api/organizations/{org_id}/chat_conversations 创建对话。
  • POST 到 /chat_conversations/{conv_id}/completion,使用 text/event-stream
def claude_complete(
    prompt: str,
    internal_model: str,
) -> Generator[str, None, None]:
    """同步生成器,从 claude.ai 完成中产生 SSE 行。"""
    cookies = get_cookies()
    org_id = cookies["lastActiveOrg"]
    headers = get_headers(cookies)

    session = make_session()

    # 1. 创建对话
    r = session.post(
        f"https://claude.ai/api/organizations/{org_id}/chat_conversations",
        json={"uuid": None, "name": ""},
        headers=headers,
        timeout=15,
    )
    r.raise_for_status()
    conv_id = r.json()["uuid"]
    log.info(f"Conv created: {conv_id} model={internal_model}")

    # 2. 流式传输完成
    payload = {
        "prompt": prompt,
        "model": internal_model,
        "timezone": "Europe/Moscow",
        "attachments": [],
        "files": [],
    }
    r2 = session.post(
        f"https://claude.ai/api/organizations/{org_id}/chat_conversations/{conv_id}/completion",
        json=payload,
        headers={**headers, "Accept": "text/event-stream"},
        stream=True,
        timeout=60,
    )
    r2.raise_for_status()
    for line in r2.iter_lines():
        yield line

API 服务器使用 aiohttp,提供 /v1/models/v1/chat/completions/health 路由。运行在 127.0.0.1:8787。

def make_app() -> web.Application:
    app = web.Application()
    app.router.add_get("/v1/models", handle_models)
    app.router.add_get("/health", handle_health)
    app.router.add_post("/v1/chat/completions", handle_chat_completions)
    return app

OpenClaw 集成

提供者配置:

"claude-web": {
    "baseUrl": "http://127.0.0.1:8787/v1",
    "apiKey": "dummy",
    "api": "openai-completions",
    "models": [
      {
        "id": "claude-sonnet-4-6-web",
        "name": "Claude Sonnet 4.6 (Web)",
        "reasoning": false,
        "input": ["text"],
        "cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0},
        "contextWindow": 200000,
        "maxTokens": 32000
      }
    ]
}

文本生成开箱即用。工具调用需小幅调整。

Google AdInline article slot

工具调用支持:提示注入

系统提示强制 Claude 以 XML 格式输出工具调用:

TOOL_SYSTEM_PROMPT = """你有工具可用。需要调用工具时,仅输出工具调用块 — 无解释、无前后文本:

<tool_call>
{{
"name": "tool_name_here", "arguments": {{"param1": "value1", "param2": "value2"}}
}}
</tool_call>

规则:
- <tool_call> 内 JSON 必须有效 — 无尾随逗号、无注释
- 可连续输出多个 <tool_call> 块
- 收到 <tool_result> 块后,继续正常响应
- 不调用工具时,正常响应无 <tool_call> 标签

可用工具:
{tools_json}"""

解析使用正则,自动修复 JSON 错误(尾随逗号、注释)。

最终工具调用和结果处理

  • 解析器提取 <tool_call> 块,修复 JSON,转换为 OpenAI 格式。
  • 工具结果注入用户消息中,作为 XML <tool_result id="...">content</tool_result>
def parse_tool_calls(text: str) -> tuple[list[dict], str]:
    tool_calls = []
    for match in TOOL_CALL_RE.finditer(text):
        raw_json = match.group(1).strip()
        obj = None
        try:
            obj = json.loads(raw_json)
        except json.JSONDecodeError:
            fixed = _try_fix_json(raw_json)
            obj = json.loads(fixed)
        if obj:
            tool_calls.append({
                "id": f"call_{uuid.uuid4().hex[:12]}",
                "type": "function",
                "function": {
                    "name": obj.get("name", ""),
                    "arguments": json.dumps(obj.get("arguments", {})),
                },
            })
    remaining = TOOL_CALL_RE.sub("", text).strip()
    return tool_calls, remaining

def inject_tool_results(messages: list[dict], tools: list[dict]) -> list[dict]:
    # 将 OpenAI tool_calls/results 转换为 Claude XML
    # ... (批处理和 XML 生成逻辑)

核心特性

  • 完全兼容:OpenAI API 支持工具调用,适用于 OpenClaw/Claude Sonnet 4.6(20 万上下文)。
  • 隐身模式:curl_cffi + 真实 Cookie/设备 ID,Chrome TLS。
  • 自动修复:处理 Claude 常见 JSON 问题(尾随逗号、注释)。
  • 流式传输:Web API SSE,每次请求全新对话。
  • 限额内:符合 Pro 订阅,无额外消耗。

局限性和改进

依赖 Claude.ai Web API 稳定性。潜在问题:

Google AdInline article slot
  • 站点验证码。
  • 会话超时。
  • 端点变更。

应对措施:自动化刷新 Cookie、设备 ID 轮换、错误处理。

— Editorial Team

Advertisement 728x90

继续阅读