不用自建代理,国内直连 Gemini API:Aisoui 接入指南与定价说明

背景

最近在做多模态能力整合,需求可以概括为三点:

  1. 对话:希望继续用 OpenAI SDK / LangChain 等现有生态,不想重写 HTTP 层;
  2. 生图 / 生音乐 :需要 Gemini 原生 v1betagenerateContent,参数与官方文档一致;
  3. 鉴权统一:一套 API Key,对话和多模态分开端点但密钥相同。

本文把实际跑通的请求格式和踩坑点记下来,方便同类项目对照。相关服务端实现与 README 已放在 Gitee 开源仓库(见文末「开源参考」),读者可 clone 后本地阅读接口设计与示例。下文代码里的 BASE_URL 请替换为你自己的网关地址。


整体架构:两套端点、一套密钥

能力 协议形态 典型路径
对话补全 OpenAI 兼容 POST /v1/chat/completions
模型列表 OpenAI 兼容 GET /v1/models
图片 / 音乐等 Gemini 原生 POST /v1beta/models/{model}:generateContent

鉴权头统一为:

http 复制代码
Authorization: Bearer <你的API密钥>

对话侧模型 ID 示例:gemini-3.5-flashgemini-3.1-pro-preview

图片侧示例:gemini-2.5-flash-image

音乐侧示例:lyria-3-clip-preview


第一步:确认模型列表

先用 GET 拉模型,确认 ID 与权限(不要用 POST):

bash 复制代码
curl "${BASE_URL}/v1/models" \
  -H "Authorization: Bearer ${API_KEY}"

返回结构与 OpenAI /v1/models 类似,客户端可按 id 字段筛选。


第二步:非流式对话

bash 复制代码
curl "${BASE_URL}/v1/chat/completions" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.5-flash",
    "messages": [
      {"role": "user", "content": "用一句话解释什么是 SSE"}
    ]
  }'

Python(OpenAI 官方 SDK):

python 复制代码
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["API_KEY"],
    base_url=os.environ.get("BASE_URL", "https://api.example.com/v1"),
)

resp = client.chat.completions.create(
    model="gemini-3.5-flash",
    messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)

迁移要点 :若项目里已有 OpenAI(api_key=..., base_url=...),通常只需改 base_urlapi_keymodel 三个参数,业务层 messages 结构可保持不变。


第三步:流式对话(SSE)

流式是最容易「看起来没响应」的一环,需要同时满足:

  • 请求体:"stream": true
  • 请求头:Accept: text/event-stream
bash 复制代码
curl "${BASE_URL}/v1/chat/completions" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "model": "gemini-3.5-flash",
    "stream": true,
    "messages": [
      {"role": "user", "content": "写一首关于调试的短诗"}
    ]
  }'

Python 流式读取:

python 复制代码
stream = client.chat.completions.create(
    model="gemini-3.5-flash",
    stream=True,
    messages=[{"role": "user", "content": "写一首关于调试的短诗"}],
)
for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)

若前端自行解析 SSE,注意按 data: 行拆分,并以 [DONE] 结束。


第四步:图片 generateContent(v1beta)

图片不走 OpenAI 的 /images/generations,而是 Gemini 原生 JSON。响应里图片通常在 candidates[0].content.parts[].inlineData.data,值为 Base64

bash 复制代码
curl "${BASE_URL}/v1beta/models/gemini-2.5-flash-image:generateContent" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [{
      "parts": [{"text": "一只在星空下奔跑的柴犬,赛博朋克风格"}]
    }]
  }'

Python 解码示例:

python 复制代码
import base64
import json
import urllib.request

url = f"{os.environ['BASE_URL'].rstrip('/v1')}/v1beta/models/gemini-2.5-flash-image:generateContent"
req = urllib.request.Request(
    url,
    data=json.dumps({
        "contents": [{"parts": [{"text": "一只在星空下奔跑的柴犬,赛博朋克风格"}]}]
    }).encode(),
    headers={
        "Authorization": f"Bearer {os.environ['API_KEY']}",
        "Content-Type": "application/json",
    },
    method="POST",
)
with urllib.request.urlopen(req) as resp:
    body = json.load(resp)

b64 = body["candidates"][0]["content"]["parts"][0]["inlineData"]["data"]
with open("out.png", "wb") as f:
    f.write(base64.b64decode(b64))

图生图、多轮编辑可在 contents 里追加带 inlineDataparts,与 Google 官方 Gemini 文档结构相同。


第五步:音乐模型(同为 v1beta)

音乐模型同样走 generateContent,模型 ID 如 lyria-3-clip-preview(短片段)、lyria-3-pro-preview(完整曲)。请求体结构与官方一致;响应中音频同样可能以 inlineData 或官方定义的字段返回,需按实际 JSON 解析。

建议:先用 curl 打印完整 JSON,确认音频字段路径,再封装到业务代码。


与 LangChain 对接(可选)

python 复制代码
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="gemini-3.5-flash",
    openai_api_key=os.environ["API_KEY"],
    openai_api_base=os.environ["BASE_URL"],
)
print(llm.invoke("用三句话介绍 RAG").content)

本质仍是 OpenAI 兼容层;多模态 generateContent 需单独写 HTTP 客户端或封装 Tool。


调试清单(FAQ)

现象 可能原因 处理
流式无输出 未设 stream: true 或缺少 Accept: text/event-stream 两项同时检查
/v1/models 报错 误用 POST 改为 GET
图片接口 404 路径写成 /v1/images 改用 /v1beta/models/{model}:generateContent
图片无法显示 按 URL 取图 实际为 Base64,需 b64decode
401 / 403 Key 无该模型权限 在控制台检查 Key 的能力授权

安全与工程建议

  1. 密钥不要进仓库 :用环境变量或密钥管理服务,git push 前跑 secret scan。
  2. 前端不要直挂 Key:浏览器暴露密钥会被盗刷;走自有后端转发。
  3. 日志脱敏 :打印请求日志时截断 Authorization
  4. 超时与重试:流式连接建议单独设 read timeout;非幂等写操作谨慎自动重试。

开源参考

本次实践对应的开源项目:Aisoui 模型中转站(Java 后端 + 控制台 + API 文档示例)。

仓库地址(Gitee):

复制代码
https://gitee.com/mtq851/aisoui-model-transfer-station

Clone 命令:

bash 复制代码
git clone https://gitee.com/mtq851/aisoui-model-transfer-station.git

仓库内可参考:

  • README.md --- 端点说明、模型列表、curl / Python 示例
  • demo/stream-chat.html --- 浏览器侧 SSE 流式对话 Demo
  • server/ --- Spring Boot 网关实现(OpenAI 兼容层 + Gemini v1beta 转发)

若你自建部署,将本文中的 ${BASE_URL} 指向自己的服务即可;仅阅读接口格式,看 README 与 Demo 足够。


小结

  • 对话:OpenAI 兼容 /v1/chat/completions,迁移成本低。
  • 多模态:Gemini 原生 /v1beta/...:generateContent,与官方参数一致。
  • 流式:记得 SSE 请求头;图片:记得 Base64 解码。

以上为个人接入笔记,模型 ID、配额与错误码以你所用网关控制台为准。欢迎在评论区交流具体报错栈与集成问题。


免责声明

本文为个人技术实践记录,仅供开发参考。开源仓库按现有 License 使用;自建部署请自行评估合规与安全。第三方网关的上游能力、可用性及政策以各模型厂商实际为准;请勿将 API Key 提交至公开仓库,并自行承担密钥保管与数据安全责任。


相关推荐
AmberSoulAnswersAI占星1 小时前
# 为什么AI本命盘报告很难做好——Soul Answers的解题思路
人工智能
jkyy20141 小时前
AI赋能业态革新,助力大健康新零售开启智能化新赛道
人工智能·零售
relis1 小时前
AI使用小技巧: 用zed和MinerU本地版,同时学习PDF文档的文字和图片
ai·pdf·大模型·agent
wengqidaifeng1 小时前
2. OpenClaw 架构落地指南:部署、渠道集成与安全边界全解
安全·ai·架构·openclaw
阿瑞IT1 小时前
AI Agent 从 Demo 到生产:被低估的四个工程问题
人工智能
小锋java12341 小时前
【技术专题】LangChain4j 开发Java Agent智能体 - 整合SpringBoot4
java·人工智能
MemOS1 小时前
产品更新 |MemOS CLI 上线:让能跑命令行的 Agent 更轻量接入长期记忆
人工智能
独秀不如众秀1 小时前
AI Coding 的最大问题不是写错代码,而是反复犯同一个错
人工智能
CV实验室1 小时前
Remote Sensing 29个SITS基准数据集综述:多模态遥感分类的新起点
人工智能·深度学习·计算机视觉·音视频