本文记录在 Google Cloud (GCP) 申请永久免费(Free Tier)e2-micro 实例,并通过配置 SSH 密钥与搭建 WireGuard 专有网络的极简实践流程。


一、GCP 免费实例创建与避坑要点

在 GCP Compute Engine 中创建 VM 时,严格按以下配置以防产生扣费:

  1. 机器配置:
    • 区域(Region):仅限 us-west1(俄勒冈)、us-central1(爱荷华)、us-east1(南卡罗来纳)。
    • 机器类型:e2-micro(2 vCPU,1 GB 内存)。
  2. 启动磁盘:
    • 磁盘类型:标准永久性磁盘(Standard persistent disk)(切勿选平衡或 SSD)。
    • 大小:≤ 30 GB。
    • 系统推荐:Debian 12 或 Ubuntu 24.04 LTS 或 Ubuntu 26.04 LTS 。
  3. 网络与防火墙:
    • 网络服务层级:默认标准/优质均可(每月 200GB 免费出网流量,注意避开大陆及澳洲高费率流量出口)。
    • 外部 IP:选择预留静态外部 IP 或默认附带的临时外部 IP(运行期间免费,关机释放前注意解绑以免闲置计费)。

二、SSH 密钥生成与元数据上传

1. 本地生成密钥对

在本地终端生成高强度 Ed25519 或 RSA 密钥:

1
2
# 生成 ed25519 密钥(推荐),注意替换 username 为你期望在服务器上的登录用户名
ssh-keygen -t ed25519 -f ~/.ssh/gcp_key -C "username"

2. 将公钥添加至 GCP 元数据

  1. 查看并复制公钥全文:
    1
    cat ~/.ssh/gcp_key.pub
  2. 打开 GCP 控制台:进入 Compute Engine -> 元数据 (Metadata) -> SSH 密钥。
  3. 点击 添加 SSH 密钥,粘贴公钥内容(格式为 ssh-ed25519 AAAA... username),点击保存。

    注:在元数据中添加为「项目级全局密钥」,后续创建的所有实例均可直接免密登录。

3. 连接验证

1
ssh -i ~/.ssh/gcp_key username@<GCP_EXTERNAL_IP>

三、GCP 防火墙规则放行

WireGuard 默认使用 UDP 端口,需在 GCP 网络中开放入站规则:

  1. 打开 VPC 网络 -> 防火墙 -> 创建防火墙规则。
  2. 配置参数:
    • 名称:allow-wireguard
    • 方向:入站(Ingress)
    • 操作:允许
    • 目标:网络中的所有实例(或指定目标标记)
    • 来源 IPv4 范围:0.0.0.0/0
    • 协议与端口:指定的协议和端口 -> 勾选 UDP,输入 51820。
  3. 保存规则。

四、WireGuard 专网搭建

1. 开启内核 IPv4 流量转发

登录 GCP 实例后执行:

1
2
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf

2. 自动化部署 WireGuard 服务端

使用主流开源脚本一键安装并初始化配置:

1
2
3
curl -O https://raw.githubusercontent.com/angristan/wireguard-install/master/wireguard-install.sh
chmod +x wireguard-install.sh
sudo ./wireguard-install.sh
  • 提示输入外部 IPv4 时,确认自动识别的 GCP 公网 IP。
  • 端口保持默认 51820 (UDP)。
  • 客户端名称随意输入(如 client-pc),DNS 可设置为 1.1.1.1 或 8.8.8.8。

3. 客户端连接

脚本执行完成后会在当前目录生成客户端 .conf 文件及终端 QR Code:

  • 移动端:使用 WireGuard App 直接扫描终端生成的二维码添加。
  • 桌面端:将生成的 .conf 文件下载至本地并导入 WireGuard 客户端,激活后即可建立安全专网隧道。

五、参考文档

  1. Google Cloud - 创建新的 SSH 密钥
  2. Google Cloud - 添加或移除实例元数据 SSH 密钥
  3. 知乎 - Google Cloud 免费服务器申请教程
  4. OOOL 博客 - Google Cloud 免费层 200GB 流量终极指南与避坑总结

今天,我们正式开放了 Cloudflare Monetization Gateway(商业化网关)的测试(Closed Beta),并展示了目前已在生产环境中落地的四个典型客户案例。自三个月前我们公布该计划以来,我们一直在与客户紧密合作,致力于让该网关兼具高速、灵活与易用性。

只需轻点几下鼠标,域名所有者即可通过 Monetization Gateway 对访问其网站、API、MCP(Model Context Protocol)工具或数据集的 AI Agent 进行计费。现在即可前往 Cloudflare Dashboard 申请测试权限。

阅读全文 »

参考 AIClient-2-API README-ZH.md 的「Grok Cookie/SSO 配置」章节。

获取步骤:

  1. 获取 SSO 令牌:登录 Grok 官网,打开浏览器开发者工具(F12),进入 Application → Cookies,找到并复制 sso 字段的值。
  2. 填入配置:在 Web UI 的「配置管理」页面,或直接修改配置文件,将令牌填入 GROK_COOKIE_TOKEN 字段。
  3. 注意事项:务必确保 GROK_USER_AGENT 与你获取 Cookie 时使用的浏览器 User-Agent 一致,否则可能被 Cloudflare 拦截导致 403 错误。

支持功能:

  • 聊天与思考模型(Grok 3 Thinking)
  • 图片生成(Grok Imagine)
  • 视频生成(Grok Video)

如果遇到 403 错误,可参考 README 中的 TLS Sidecar 配置 章节开启 TLS 指纹绕过。

在vscode中使用

添加自定义模型,最好自己部署个网关(cc-swich,sub2api等),配置里添加网关地址就行,在网关里配置模型和订阅更方便,apiType使用chat-completions,responses在vscode里不支持,或者部分功能无法使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"name": "自部署",
"vendor": "customendpoint",
"apiKey": "${input:chat.lm.secret.-34e43f49}",
"apiType": "chat-completions",
"models": [
{
"id": "grok-4.5",
"name": "grok-4.5",
"url": "http://localhost:28080/v1",
"toolCalling": true,
"vision": true,
"maxInputTokens": 128000,
"maxOutputTokens": 16000
},
{
"id": "grok-4.6",
"name": "grok-4.6",
"url": "http://localhost:28080/v1",
"toolCalling": true,
"vision": true,
"maxInputTokens": 128000,
"maxOutputTokens": 16000
}
]
}

比如function call或报错400

Request Failed: 400 {“error”:{“message”:”function_call_output requires item_reference ids matching each call_id on HTTP requests; continuation via previous_response_id is only supported on Responses WebSocket v2”,”type”:”invalid_request_error”}}: Err

这是因为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这个报错基本可以确定是 **Grok / xAI Responses API 的 Function Calling 状态续接方式出了问题**。

核心错误:

> `function_call_output requires item_reference ids matching each call_id on HTTP requests; continuation via previous_response_id is only supported on Responses WebSocket v2`

### 你现在遇到的是什么问题

你的调用链大概率是:

```text
请求 1
↓
Grok 返回 function_call
↓
你执行 function/tool
↓
请求 2:提交 function_call_output
+ previous_response_id
↓
HTTP 400

问题在于:HTTP 模式下,xAI 对 function_call_output 的上下文引用有额外要求,而 previous_response_id 这种续接方式目前属于 WebSocket v2 的能力。

xAI 官方文档对 WebSocket 模式明确说明:在 WebSocket 上可以通过:

1
2
3
4
5
6
7
8
9
10
{
"previous_response_id": "resp_xxx",
"input": [
{
"type": "function_call_output",
"call_id": "call_xxx",
"output": "tool result"
}
]
}

继续对话。(SpaceXAI)

而 xAI 官方 Function Calling 的 HTTP 示例虽然也展示了 previous_response_id,但你这个错误说明你当前实际使用的 HTTP 接口/版本已经要求 function call output 带对应的 item reference,而不是单纯依赖 previous_response_id。(SpaceXAI)


最可能的修复方案

如果你现在代码类似:

1
2
3
4
5
6
7
8
9
10
11
response = client.responses.create(
model="grok-4.5",
input=[
{
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(result)
}
],
previous_response_id=response.id,
)

不要继续这么做。

方案 A:HTTP 模式,完整携带上下文

不要依赖:

1
"previous_response_id": "xxx"

而是把上一轮的 response.output 中相关的 function_call item 一起带上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
response = client.responses.create(
model="grok-4.5",
input=[
# 上一轮模型产生的 function_call
{
"type": "function_call",
"call_id": item.call_id,
"name": item.name,
"arguments": item.arguments,
"item_reference": item.id
},

# function 执行结果
{
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(result)
}
],
tools=tools,
)

但这里有一个关键点:

你需要确认你实际使用的 xAI API 版本对 item_reference 的字段名和格式要求。

因为你这个错误不是普通的 call_id 不存在,而是明确提示:

1
function_call_output requires item_reference ids matching each call_id

也就是说服务端正在要求:

1
2
3
4
5
function_call_output
│
├── call_id
│
└── item_reference → 对应上一轮 function_call 的 item id

方案 B:如果你是自己做 Agent,推荐直接改成 WebSocket

如果你这个 Grok 是用于 Coding Agent / MCP / 自动执行工具 / 多轮 Function Calling,我反而建议直接用 xAI 的 Responses WebSocket v2。

官方就是针对这种场景设计的:

agentic workloads with many sequential tool calls

(SpaceXAI)

流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
WebSocket
│
▼
response.create
│
▼
Grok
│
├── function_call
│
▼
你的程序执行 Tool
│
▼
function_call_output
│
▼
response.create
│
▼
Grok继续

续接时:

1
2
3
4
5
6
7
8
9
10
11
{
"type": "response.create",
"previous_response_id": "resp_123",
"input": [
{
"type": "function_call_output",
"call_id": "call_123",
"output": "tool result"
}
]
}

这是 xAI 官方 WebSocket 文档给出的模式。(SpaceXAI)


如果你是 OpenAI SDK 调 xAI

还有一个非常值得检查的地方。

如果你的代码是:

1
2
3
4
5
6
from openai import OpenAI

client = OpenAI(
api_key=...,
base_url="https://api.x.ai/v1"
)

然后:

1
client.responses.create(...)

那么你实际上是在使用 OpenAI SDK + xAI Responses API。

这种情况下尤其容易出现:

1
2
3
4
5
6
7
8
9
10
11
OpenAI SDK
↓
Responses API
↓
xAI
↓
Function Calling
↓
HTTP continuation
↓
400

xAI 官方目前仍提供 OpenAI SDK 兼容方式,所以 SDK 本身不一定有问题,但 Responses API 的 HTTP/WebSocket 行为不能完全按照 OpenAI 的实现假设处理。(SpaceXAI)


另外一个容易踩坑的地方:旧会话

如果这个错误是在某个已经存在很久的 Agent/Coding 会话中突然出现的,建议:

直接新建一个 conversation/session 测试。

因为 Function Calling 的历史 item 已经可能和当前 call_id / item_reference 对不上。

类似问题在一些基于 OpenAI Responses API 的第三方客户端中也出现过,常见处理方式就是升级客户端后重新建立新会话,不要继续复用损坏的历史状态。(LINUX DO)


我建议你这样判断

你的场景 建议
普通 Grok 对话 不要用 previous_response_id
单次 Function Calling HTTP + 完整 input history
多轮 Function Calling WebSocket v2
Coding Agent WebSocket v2
MCP Agent WebSocket v2
OpenAI SDK → xAI 检查 Responses API 的续接实现
已经报错的旧会话 新建 session

如果你把你现在调用 Grok 的那段代码贴出来(尤其是 responses.create() / function_call_output 那部分),我可以直接帮你定位是哪一行导致这个 400,并给你改成可以直接运行的 xAI Grok Function Calling 版本。

```