Skip to content
Xeron
Go back

MiMo Code 免费模型反代

编辑此页

MiMo Code 是小米的 AI 编码工具,有免费额度。但使用 MiMo Code 才能使用,分析一下

认证逆向

MiMo Code 的免费 API 不需要登录。认证通过一个 bootstrap 接口完成:

POST https://api.xiaomimimo.com/api/free-ai/bootstrap
Body: {"client": "<设备指纹>"}
Response: {"jwt": "eyJhbG..."}

请求抓包就能看到。没有 OAuth、没有 API key、没有 session——一个 POST 拿 JWT,用它调 chat 接口

设备指纹

client 参数是设备指纹,由客户端本地生成:

import hashlib, platform, os

def get_fingerprint() -> str:
    raw = "|".join([
        platform.node(),                        # hostname
        platform.system().lower(),              # darwin / linux / windows
        platform.machine(),                     # arm64 / x86_64
        platform.processor() or "unknown-cpu",  # CPU 型号
        os.environ.get("USER") or "unknown",    # 用户名
    ])
    return hashlib.sha256(raw.encode()).hexdigest()

指纹会持久化到 ~/.local/share/mimocode/mimo-free-client,保证同一台机器每次 bootstrap 拿到同一个 token:

from pathlib import Path

FINGERPRINT_FILE = Path.home() / ".local/share/mimocode/mimo-free-client"

def get_fingerprint() -> str:
    if FINGERPRINT_FILE.exists():
        return FINGERPRINT_FILE.read_text().strip()
    fp = hashlib.sha256(...).hexdigest()
    FINGERPRINT_FILE.parent.mkdir(parents=True, exist_ok=True)
    FINGERPRINT_FILE.write_text(fp)
    FINGERPRINT_FILE.chmod(0o600)
    return fp

JWT 解析

bootstrap 返回的 JWT 需要解析 exp 字段来判断过期时间:

def _parse_jwt_exp(jwt: str) -> float:
    # JWT payload 是 base64url 编码的 JSON
    parts = jwt.split(".")
    pad = 4 - len(parts[1]) % 4
    payload = json.loads(base64.urlsafe_b64decode(parts[1] + "=" * pad))
    return payload.get("exp", time.time() + 3600) * 1000  # 毫秒

proxy 在过期前 5 分钟自动刷新:

async def get_token(self) -> str:
    if self._jwt and self._exp - time.time() * 1000 > 300_000:  # 还有 5 分钟
        return self._jwt
    # ... bootstrap 获取新 token

并发安全

多个并发请求同时发现 token 过期时,只触发一次 bootstrap:

async def get_token(self) -> str:
    if self._bootstrapping:  # 有请求正在 bootstrap
        return (await self._bootstrapping)[0]  # 等它完成,复用结果
    self._bootstrapping = asyncio.ensure_future(self._bootstrap())
    try:
        self._jwt, self._exp = await self._bootstrapping
        return self._jwt
    finally:
        self._bootstrapping = None

请求转发

拿到 token 后,转发到 chat 接口:

POST https://api.xiaomimimo.com/api/free-ai/openai/chat
Headers:
  Authorization: Bearer <jwt>
  X-Mimo-Source: mimocode-cli-free
  User-Agent: mimocode/0.1.0 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.14
Body: <OpenAI 格式 JSON>

但不能直接透传——客户端发的请求和标准 OpenAI 格式有差异

请求改写

def _prepare_body(body: bytes) -> bytes:
    payload = json.loads(body)

    messages = payload.get("messages", [])
    normalized = []
    has_system_prompt = False

    for msg in messages:
        item = dict(msg)

        # MiMo Code 用 developer role,标准格式是 system
        if item.get("role") == "developer":
            item["role"] = "system"

        # 检测是否已有 system prompt
        if item.get("role") == "system" and isinstance(item.get("content"), str):
            if item["content"].startswith("You are MiMoCode"):
                has_system_prompt = True

        normalized.append(item)

    # 没有 system prompt 时自动注入 MiMo Code 的默认 prompt
    if not has_system_prompt:
        normalized.insert(0, {
            "role": "system",
            "content": "You are MiMoCode, an interactive CLI tool..."
        })

    payload["messages"] = normalized

    # stream 请求自动加 stream_options(MiMo 要求的)
    if payload.get("stream"):
        payload.setdefault("stream_options", {"include_usage": True})

    return json.dumps(payload, separators=(",", ":"), ensure_ascii=False).encode()

错误重试

token 过期时自动重新 bootstrap:

resp = await client.send(req)
if resp.status_code in (401, 403):
    await jwt_mgr.invalidate()           # 作废旧 token
    token = await jwt_mgr.get_token()    # bootstrap 拿新的
    resp = await client.send(req)        # 重试

流式响应透传

SSE 流直接 pipe,不解码不改写:

async def _send_streaming(body: bytes):
    token = await jwt_mgr.get_token()
    client = httpx.AsyncClient(timeout=120)
    resp = await client.send(
        client.build_request("POST", CHAT_URL, headers=_build_headers(token), content=body),
        stream=True,
    )

    async def stream():
        try:
            async for chunk in resp.aiter_bytes():
                yield chunk
        finally:
            await resp.aclose()
            await client.aclose()

    return StreamingResponse(stream(), media_type="text/event-stream")

MiMo 的流式响应本身就是标准 SSE 格式,直接透传就行


编辑此页
Share this post on:

Previous Post
Coinglass 接口算法解密
Next Post
默会知识