【mitmproxy】提取 OpenCode 的 API 接口

前面介绍了 如何通过 mitmproxy的本地捕获代理模式获取 OpenCode 发起的 AI API 请求的详细信息

本文介绍如何提取 OpenCodeAPI 接口

捕获到opencode.ai的流量后,可以导出https://opencode.ai/zen/v1/messages接口的CURL

简化一下导出的CURL(譬如:简化系统提示词,工具列表),发给AI,让AI 转化为 Python 代码

然后再让AI优化微调一下(譬如:抽取函数send_message,创建SSLContext对象,添加重试机制)

调式成功:

示例代码:

python 复制代码
import json
import ssl
import time
from typing import Optional, Dict, Any

import httpx

URL = "https://opencode.ai/zen/v1/messages"
DEFAULT_HEADERS = {
    "Content-Type": "application/json",
    "User-Agent": "ai-sdk/anthropic/3.0.71 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.13",
    "anthropic-version": "2023-06-01",
    "x-api-key": "public",
    "x-opencode-client": "cli",
    "Connection": "close",
    "Accept": "*/*",
    "Host": "opencode.ai",
}
DEFAULT_PROJECT = "5941d5072d7e941c77cbda55b6a9a3a45bf3a089"
DEFAULT_SESSION = "ses_23ac15dd8ffeiKiFBtkudFHNd2"


def send_message(
        model: str,
        message: str,
        project: Optional[str] = None,
        session: Optional[str] = None,
        request_id: Optional[str] = None,
        system_prompt: Optional[str] = None,
        max_tokens: int = 32000,
        max_retries: int = 3,
        timeout: int = 60,
) -> Dict[str, Any]:
    """
    向 opencode.ai 发送消息并获取 AI 回复。

    参数:
        model: 模型名称,如 "big-pickle"
        message: 用户消息内容
        project: x-opencode-project(可选)
        session: x-opencode-session(可选)
        request_id: x-opencode-request(可选,默认自动生成)
        system_prompt: 系统提示词(可选)
        max_tokens: 最大 token 数
        max_retries: 失败重试次数
        timeout: 请求超时(秒)

    返回:
        包含以下键的字典:
            - text: AI 文本回复
            - thinking: AI 思考内容(如有)
            - full: 原始完整响应数据列表
    """
    if request_id is None:
        import uuid
        request_id = f"msg_{uuid.uuid4().hex[:20]}"

    headers = {
        **DEFAULT_HEADERS,
        "x-opencode-project": project or DEFAULT_PROJECT,
        "x-opencode-session": session or DEFAULT_SESSION,
        "x-opencode-request": request_id,
    }

    system_text = system_prompt or (
        "You are opencode, an interactive CLI tool that helps users with software engineering tasks. "
        "Use the instructions below and the tools available to you to assist the user."
    )

    payload = {
        "model": model,
        "max_tokens": max_tokens,
        "stream": True,
        "system": [{"type": "text", "text": system_text}],
        "messages": [
            {
                "role": "user",
                "content": [{"type": "text", "text": message}],
            }
        ],
    }

    ssl_context = ssl.create_default_context()

    for attempt in range(max_retries):
        try:
            full_response = []
            with httpx.Client(http2=False, verify=ssl_context, timeout=timeout) as client:
                with client.stream("POST", URL, headers=headers, json=payload) as response:
                    if response.status_code != 200:
                        raise RuntimeError(f"HTTP {response.status_code}: {response.text}")

                    text_parts = []
                    thinking_parts = []
                    current_event = None

                    for line in response.iter_lines():
                        if line.startswith("event:"):
                            current_event = line.split(":", 1)[1].strip()
                        elif line.startswith("data:") and current_event:
                            data_str = line.split(":", 1)[1].strip()
                            try:
                                data_obj = json.loads(data_str)
                                full_response.append(data_obj)
                                delta = data_obj.get("delta", {})
                                if delta.get("type") == "thinking_delta":
                                    thinking_parts.append(delta["thinking"])
                                elif delta.get("type") == "text_delta":
                                    text_parts.append(delta["text"])
                            except json.JSONDecodeError:
                                pass

            return {
                "text": "".join(text_parts),
                "thinking": "".join(thinking_parts),
                "full": full_response,
            }

        except (httpx.ConnectError, httpx.ReadError, httpx.RemoteProtocolError) as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt
                time.sleep(wait_time)
            else:
                raise RuntimeError(f"请求失败(已重试 {max_retries} 次): {e}") from e


if __name__ == "__main__":
    result = send_message("big-pickle", "你好")

    if result["thinking"]:
        print("<thinking>")
        print(result["thinking"])
        print("</thinking>")
    print(result["text"])
相关推荐
网络研究院16 天前
2026年网络安全
网络·安全·法律·法规·趋势·发展
酣大智16 天前
ARP代理--工作原理
运维·网络·arp·arp代理
treesforest16 天前
AI安全系统如何识别异常访问?IP风险识别正在成为关键能力
网络·人工智能·tcp/ip·安全·web安全
shushangyun_16 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
2601_9618451516 天前
粉笔行测题库|系统班|刷题
网络·百度·微信·微信公众平台·facebook·新浪微博
程序猿阿伟16 天前
《Chrome离线扩展安装的底层逻辑与场景落地指南》
服务器·网络·chrome
InHand云飞小白16 天前
无人值守站点网络困境?工业级路由器IR315破解连接难题
网络·物联网·4g·工业路由器·4g路由器·iiot·蜂窝路由器
森G16 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt
江华森16 天前
TCP/IP 协议栈实战 — 7 个实验详解
网络·tcp/ip·智能路由器
酉鬼女又兒16 天前
零基础入门计算机网络运输层:端到端通信核心作用、端口号分类规则、复用分用工作机制及UDP与TCP协议全方位对比详解
网络·网络协议·tcp/ip·计算机网络·考研·udp·php