aioffice 反向代理开发:将 AI 编程工具额度转化为 OpenAI 兼容 API

aioffice 是一款基于 VSCode 二次开发的 AI 编程工具,提供了 AI 对话、代码补全等功能。为了能在其他工具(如 opencode、Continue 等)中复用 aioffice 的 AI 调用额度,我开发了一个反向代理服务,将 aioffice 的后端 API 转化为标准的 OpenAI 兼容格式。

技术分析

通信架构分析

通过分析 aioffice 的源代码和配置文件,发现:

项目
后端服务器地址 http://14.103.247.146:8094
API 格式 OpenAI 兼容(/v1/chat/completions
认证方式 Bearer Token(sk- 前缀的 API Key)
Token 存储位置 SQLite 数据库

Token 存储在 SQLite 数据库中:

  • 路径%APPDATA%/AiOffice/User/globalStorage/state.vscdb
  • 键名coai.auth.token(登录凭证)、coai.api.key(API 调用密钥)

源码定位方法

aioffice 基于 Void Editor 开发,代码位于安装目录的 resources/app 下(未打包为 asar)。通过搜索关键字符串定位到核心逻辑:

1
resources/app/out/vs/workbench/workbench.desktop.main.js

关键代码片段:

1
2
3
var COAI_API_URL = "http://14.103.247.146:8094";
// ...
this.apiClient = new CoaiApiClient(() => COAI_API_URL, () => this.getToken(), this.requestService);

架构设计

1
2
3
4
5
6
7
8
9
10
┌─────────────────┐      ┌──────────────────┐      ┌─────────────────┐
│ 任意客户端 │ ──→ │ 本地代理服务 │ ──→ │ aioffice 后端 │
│ (Cursor等) │ │ localhost:18273 │ │ 14.103.247.146 │
└─────────────────┘ └──────────────────┘ └─────────────────┘


┌──────────────┐
│ 自动提取 Token│
│ (SQLite读取) │
└──────────────┘

核心模块

模块 职责
token.js 从 SQLite 数据库读取认证信息,支持自动刷新
proxy.js 转发请求到 aioffice 后端,处理流式响应
chat.js /v1/chat/completions 路由处理
models.js /v1/models 路由处理

踩坑记录

坑一:better-sqlite3 编译失败

问题:最初选择 better-sqlite3 作为 SQLite 驱动,但 Windows 上需要 Visual Studio 编译工具:

1
gyp ERR! find VS could not find Visual Studio installation to use

解决:改用纯 JavaScript 实现的 sql.js,无需编译:

1
2
3
4
5
6
// package.json
{
"dependencies": {
"sql.js": "^1.10.0" // 替代 better-sqlite3
}
}

sql.js 的 API 略有不同,需要注意:

1
2
3
4
5
6
7
8
9
10
11
12
13
const initSqlJs = require('sql.js');
const fs = require('fs');

// 初始化(异步)
const SQL = await initSqlJs();

// 读取数据库文件
const fileBuffer = fs.readFileSync(dbPath);
const db = new SQL.Database(fileBuffer);

// 查询(返回格式不同)
const result = db.exec("SELECT value FROM ItemTable WHERE key = ?");
// result[0].values[0][0] 获取第一行第一列的值

坑二:Payload Too Large 错误

问题:在 opencode 中使用时报错:

1
PayloadTooLargeError: request entity too large

原因:Express 的 body-parser 默认限制请求体为 100kb,而 AI 对话的上下文可能很大。

解决:增加请求体大小限制:

1
2
3
4
5
// 原来
app.use(express.json());

// 修改为
app.use(express.json({ limit: '50mb' }));

坑三:opencode 配置缺少 apiKey

问题:即使代理会自动处理认证,opencode 仍需要一个 apiKey 字段才能发送请求。

解决:在 opencode 配置中添加任意 apiKey:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"aioffice": {
"name": "ao",
"npm": "@ai-sdk/openai-compatible",
"models": {
"claude-sonnet-4-6-thinking": { "name": "claude-sonnet-4-6-thinking" },
"glm-4.7": { "name": "glm-4.7" }
},
"options": {
"apiKey": "sk-fandai",
"baseURL": "http://localhost:18273/v1"
}
}
}

坑四:后台进程不稳定

问题:在 Windows 上使用 & 后台运行 Node.js 进程不稳定,容易退出。

解决:使用 start 命令在新窗口中运行:

1
cmd //c "start /min cmd /c node src/index.js"

最终实现

项目结构

1
2
3
4
5
6
7
8
9
10
11
12
fandai/
├── src/
│ ├── index.js # 入口,Express 服务
│ ├── config.js # 配置(端口、后端地址)
│ ├── routes/
│ │ ├── chat.js # /v1/chat/completions
│ │ └── models.js # /v1/models
│ └── services/
│ ├── token.js # Token 自动提取
│ └── proxy.js # 请求转发
├── package.json
└── README.md

核心代码

Token 自动提取 (services/token.js):

1
2
3
4
5
6
7
8
9
10
11
const initSqlJs = require('sql.js');
const fs = require('fs');

async function readFromDatabase() {
const SQL = await initSqlJs();
const fileBuffer = fs.readFileSync(DB_PATH);
const db = new SQL.Database(fileBuffer);

const result = db.exec("SELECT value FROM ItemTable WHERE key = 'coai.api.key'");
return result.length > 0 ? result[0].values[0]?.[0] : null;
}

请求转发 (services/proxy.js):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
async function proxyChatCompletion(req, res) {
const apiKey = await getApiKey();

const response = await axios.post(
`${COAI_API_URL}/v1/chat/completions`,
req.body,
{
headers: { 'Authorization': `Bearer ${apiKey}` },
responseType: req.body.stream ? 'stream' : 'json'
}
);

if (req.body.stream) {
res.setHeader('Content-Type', 'text/event-stream');
response.data.on('data', chunk => res.write(chunk));
response.data.on('end', () => res.end());
} else {
res.json(response.data);
}
}

使用方式

1
2
3
4
5
6
7
8
9
# 安装依赖
npm install

# 启动代理
npm start

# 配置其他工具
export OPENAI_API_BASE=http://localhost:18273/v1
export OPENAI_API_KEY=any

可用模型

代理支持 aioffice 后端的所有模型,包括:

模型 说明
glm-4.7 / glm-5 智谱 GLM 系列
gpt-5.2 / gpt-5.3-codex GPT 系列
claude-sonnet-4-6-thinking Claude 思维链模型
gemini-3-pro-preview Gemini 3 Pro

经验总结

这个项目的核心价值在于:

  • 协议转换:将私有 API 转化为标准 OpenAI 格式
  • 认证自动化:自动提取和刷新 Token,用户无感知
  • 通用兼容:任何支持 OpenAI API 的工具都能使用

开发过程中主要踩了以下几个坑:

  1. SQLite 驱动在 Windows 上编译问题 → 用纯 JS 实现的 sql.js
  2. Express 请求体大小限制 → 增加到 50mb
  3. 客户端配置要求 → 填充任意 apiKey
  4. Windows 后台进程不稳定 → 用 start 命令

最终都用比较简单的方式解决了,整个项目代码量不大,但实用性很强。


相关链接项目仓库 - GitHub