Skip to main content
Glama
XD06
by XD06
README.md
# google-ai-mode

本地调用 Google AI Mode(`udm=50`),提供 **OpenAI 兼容 API**、MCP 与 CLI。

双层请求引擎:`curl_cffi`(快速路径)→ 被 TLS 指纹检测拦截时**自动回退到真实 Chrome 浏览器**(CDP 连接),绕过 Google SG_REL soft-block。

> 违反 Google ToS,仅供个人研究。上游随时可能改协议。

## 文档导航

| 文档 | 内容 |
|------|------|
| [README.md](README.md) | 安装、配置、启动、OpenAI 用法 |
| [DESIGN.md](DESIGN.md) | 模块划分与数据流 |
| [docs/PROTOCOL.md](docs/PROTOCOL.md) | **抓包路径 / folwr·folif / cookie / 风控(接手必读)** |
| [docs/REFERENCES.md](docs/REFERENCES.md) | 外部参考(精简) |

## 快速开始

### 1. 安装

```bash
cd google-ai-mode
python -m venv .venv
.venv\Scripts\activate
pip install -e ".[api]"
```

**可选依赖**(浏览器回退需要):

```bash
pip install playwright
playwright install chromium
```

### 2. 配置

```bash
copy config.example.json ai-mode.config.json
```

```json
{
  "cookie_file": "cookies.json",
  "proxy": "http://127.0.0.1:10808",
  "host": "www.google.com",
  "bind_host": "127.0.0.1",
  "port": 18080,
  "verbose": false
}
```

优先级:**环境变量 > 配置文件 > 默认值**。
也支持 `config.json` / `.ai-mode.json`,或 `AI_MODE_CONFIG=路径`。

### 3. 导出 Cookies

Chrome **没有**「全选 → Copy as JSON」。用 Cookie-Editor:

1. 安装 [Cookie-Editor](https://cookie-editor.com/)
2. 登录 https://www.google.com
3. Export → **JSON**(数组格式即可)
4. 放到项目根,命名 `cookies.json`

加载时只读每条的 `name` + `value`,多余字段无妨。

最少需要:

| Cookie | 说明 |
|--------|------|
| `__Secure-1PSID` | 长期登录 |
| `__Secure-1PSIDTS` | 短期签名;会尝试 `RotateCookies` 续 |

**只保证 PSID 不过期不够**。建议全量导出 SID/HSID/APISID 等。

### 4. 启动 API

**推荐**:双击项目根 `start-api.bat`(先 cd 到根再启,窗口保持开着)。
**停止**:双击 `stop-api.bat`(读配置里的 `port`,结束占用进程;默认 18080)。

```bash
ai-mode-api
# 或
.venv\Scripts\ai-mode-api.exe
```

```bash
curl --noproxy "*" http://127.0.0.1:18080/health
```

Cherry Studio / 任意 OpenAI 客户端:

```
base_url = http://127.0.0.1:18080/v1
model    = google-ai-mode
API Key  = 任意非空占位即可
```

## 双层请求引擎

```
请求 → curl_cffi (impersonate=chrome*)  ─── 快速路径
         │
         ├─ 200 + AI Mode tokens → 正常返回
         │
         └─ SG_REL soft-block → 自动回退
                                   │
                                   ▼
                        BrowserBridge (真实 Chrome via CDP)
                          ├─ 启动 Chrome + 代理 + cookies
                          ├─ 预热首页 (关键:直接访搜索页会被 /sorry 拦截)
                          ├─ page.goto() → 搜索页 → 解析 tokens
                          └─ fetch() → /async/folif → AI 回答
```

### 为什么需要浏览器回退?

Google 于 2026 年升级了 TLS/HTTP2 指纹检测。`curl_cffi` 的所有 impersonate profile(chrome131~146)均被识别为自动化流量,返回 `SG_REL` soft-block(HTTP 200 但无 AI Mode tokens)。

真实 Chrome 浏览器的 TLS 指纹无法被 Google 拦截(因为就是真实浏览器)。通过 CDP(Chrome DevTools Protocol)连接到 Chrome 进程不会注入 `navigator.webdriver` 等自动化标志,因此可以绕过检测。

### 浏览器回退的关键细节

- **预热必须**:直接导航到 `/search` 会被重定向到 `/sorry/index`;必须先访问首页再搜索
- **Playwright headless 无效**:Playwright 控制的浏览器(即使 `channel="chrome"`)仍被检测
- **subprocess + CDP 有效**:用 `subprocess` 启动 Chrome,再通过 CDP 连接,不注入自动化标志

## OpenAI 兼容

```bash
curl --noproxy "*" -X POST "http://127.0.0.1:18080/v1/chat/completions" ^
  -H "Content-Type: application/json" ^
  -d "{\"model\":\"google-ai-mode\",\"stream\":false,\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]}"
```

- `GET /v1/models`
- `POST /v1/chat/completions`(`stream=false|true`;流式为**真渐进** SSE:chunked HTML → 稳定 MD 前缀 → delta)
- 另有:`GET /search`、`POST /v1/chat`、`POST /rotate`、`GET /health`

### system 消息

上游无 system 角色。**`role=system` 会被忽略**,只取最后一条 user 文本发给 Google。

### 多轮(无需 thread_id)

客户端只传标准 `messages` 历史即可。服务端用 assistant 正文指纹 + user 问题映射 + `.ai_mode_threads.json` 落盘自动挂 Google thread。

## 错误码(OpenAI `error` 体)

| code | HTTP | 处理 |
|------|------|------|
| `cookie_expired` | 401 | 从 Chrome 重导 `cookies.json` |
| `rate_limit` | 429 | 冷却 1–5 分钟 |
| `soft_block` | 503 | 引擎已自动回退到浏览器模式;若仍失败,刷新 cookies/换代理 |
| `blocked` | 403 | 换 IP、人工过验证后重导 cookie |
| `incomplete_answer` | 502 | 上游答案结构不完整,服务已自动重试仍失败 |
| `bootstrap_tokens` / `upstream_http` | 502 | 查网络/host/登录态 |
| `internal_error` | 500 | 看服务端日志 |

## 核心原理

```
GET /search?udm=50  → tokens (stkp / garc / xsrf_folif / srtst / ei)
GET /async/folwr    → 首答 HTML + mstk  (legacy, 已弃用)
GET /async/folif    → 首答/续聊 HTML + mstk  (当前协议)
HTML → Markdown([[cite](url)] + Images)
```

Google ~2026-08 移除了 `data-lro-token` / `data-lro-signature`,弃用 `/async/folwr`。新对话也改用 `/async/folif`。

## 项目结构

```
google-ai-mode/
├── ai-mode.config.json     # 本地配置(gitignore,从 example 复制)
├── config.example.json
├── cookies.example.json
├── start-api.bat           # Windows 推荐启动
├── stop-api.bat            # 按配置端口结束 API
├── DESIGN.md
├── docs/
│   ├── PROTOCOL.md         # 协议与逆向结论
│   └── REFERENCES.md
├── scripts/
│   ├── build_cookies.py
│   └── extract-cookies.js
├── tests/
│   ├── test_answer_structure.py
│   ├── test_stream_delta.py
│   └── test_thread_store.py
└── src/ai_mode_mcp/
    ├── config.py
    ├── cookie_manager.py
    ├── browser_backend.py   # 浏览器回退:真实 Chrome via CDP
    ├── engine.py            # 协议 + 解析 + Markdown + 线程 + 流式
    ├── models.py
    ├── cli.py
    └── handlers/
        ├── api_server.py    # FastAPI / OpenAI
        └── mcp_server.py
```

## MCP / CLI

```bash
ai-mode-mcp          # stdio:search / chat / rotate_cookies
ai-mode-cli "query" -c cookies.json -v
```

## 常见问题

**Q: 浏览器回退时 Chrome 窗口会弹出来?**
不会。`BrowserBridge` 使用 `--headless` 模式(若 Playwright 可用)或 `subprocess` 启动真实 Chrome(带 `--remote-debugging-port`),在后台运行。

**Q: 浏览器回退很慢?**
首次回退需要启动 Chrome(~3 秒)。之后 Chrome 保持运行,后续请求复用。整体比 `curl_cffi` 慢约 5-10 秒,但能绕过 SG_REL。

**Q: PSID 不过期还要重导吗?**
TS 失效或 soft-block 时仍要重导。RotateCookies 不能解决所有失效。

**Q: 和网页答案差很多?**
解析依赖 HTML 片段结构;引用已统一为 `[[标题](url)]`。若缺图/表,开 `verbose` 对照上游 HTML。

**Q: 商业使用?**
不建议;违反 ToS,且协议不稳定。