Gemini API на Python: запросы через OpenAI SDK и OpenAI-формат
Рабочий пример Gemini API на Python без отдельной библиотеки: меняем base_url в OpenAI SDK, добавляем стриминг и JSON и сравниваем с google-genai.
5 мин · · разработка · API-ключи
Если вы ищете, как вызвать Gemini API на Python, у вас два пути: нативная библиотека Google или привычный OpenAI SDK с другим адресом. Ниже разберём второй путь на рабочем коде: клиент, обычный запрос, стриминг, JSON-ответ, обработка ошибок и расчёт стоимости. В конце сравним его с нативным google-genai и скажем, когда что удобнее.
Все примеры идут через шлюз Zukko: один ключ fetch_..., формат OpenAI и модель gemini-3.8-flash. Цены в статье указаны на 18 октября 2026.
Зачем вызывать Gemini через OpenAI SDK
Главное преимущество в том, что код не привязан к одному поставщику. Клиент OpenAI(...) знает только три вещи: адрес, ключ и имя модели. Чтобы перейти с Gemini на GPT или Claude, достаточно поменять строку model. Вы не переписываете ни разбор ответа, ни стриминг, ни обработку ошибок.
Это удобно в трёх случаях:
- в проекте уже есть код на
openai, и вы хотите добавить дешёвую модель для массовых задач; - вы сравниваете несколько моделей на своих данных и не хотите писать по адаптеру на каждую;
- инструмент (LangChain, LlamaIndex, ваш собственный сервис) умеет только OpenAI-совместимый API.
Сама Google тоже поддерживает такой режим: в документации Gemini API есть раздел про совместимость с OpenAI-библиотеками, где меняются три строки (ключ, base URL и модель). Одновременно там сказано, что если вы не используете OpenAI-библиотеки, проще вызывать Gemini API напрямую. Мы вернёмся к этому в разделе про сравнение.
Установка и первый запрос
pip install openaiСоздайте ключ на странице API-ключей и положите его в переменную окружения, а не в код:
export OPENAI_BASE_URL="https://api.zukko.pro/v1"
export OPENAI_API_KEY="fetch_ваш_ключ"Теперь минимальный запрос:
from openai import OpenAI
client = OpenAI() # возьмёт OPENAI_BASE_URL и OPENAI_API_KEY
MODEL = "gemini-3.8-flash"
resp = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": "Отвечай коротко и по делу."},
{"role": "user", "content": "Чем list отличается от tuple в Python?"},
],
)
print(resp.choices[0].message.content)
print(resp.usage)Если хотите задать адрес явно, не используя переменные окружения:
client = OpenAI(base_url="https://api.zukko.pro/v1", api_key="fetch_ваш_ключ")Адрес оканчивается на /v1: OpenAI SDK сам добавляет только /chat/completions. Подробнее про клиент — в разделе Python справочника API, про сам эндпоинт — в описании chat completions там же.
Стриминг
Для интерфейсов и чат-ботов ответ удобно получать кусками:
stream = client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": "Расскажи про генераторы в Python"}],
stream=True,
)
for chunk in stream:
if chunk.choices:
piece = chunk.choices[0].delta.content
if piece:
print(piece, end="", flush=True)
elif chunk.usage:
print(f"\n[вход: {chunk.usage.prompt_tokens}, выход: {chunk.usage.completion_tokens}]")Проверка if chunk.choices: обязательна. В конце потока сервер присылает последний чанк с usage и пустым списком choices, и обращение к chunk.choices[0] без проверки упадёт с IndexError.
JSON вместо свободного текста
Если ответ нужно разобрать программой, просите JSON явно и всё равно проверяйте результат:
import json
resp = client.chat.completions.create(
model=MODEL,
messages=[
{
"role": "system",
"content": "Верни только JSON-объект с ключами name, date, participants (массив строк).",
},
{"role": "user", "content": "Анна и Борис идут на конференцию по ИИ в пятницу."},
],
response_format={"type": "json_object"},
)
try:
data = json.loads(resp.choices[0].message.content)
except json.JSONDecodeError:
data = None # повторите запрос или отправьте в очередь на ручной разбор
print(data)Параметр response_format относится к OpenAI-формату. В документации Google для совместимого режима есть примеры структурированного вывода по схеме, но то, как именно параметр доходит до модели через шлюз, лучше проверить на своём запросе. Если получите ошибку 400, уберите response_format и оставьте только инструкцию в промпте и json.loads: на практике этого хватает для простых схем.
Ошибки и повторы
from openai import OpenAI, APIStatusError, APIConnectionError
try:
resp = client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": "Привет!"}],
)
except APIStatusError as e:
if e.status_code == 401:
print("Неверный ключ")
elif e.status_code == 402:
print("Не хватает баланса")
elif e.status_code == 404:
print("Модели нет в каталоге, сверьтесь с GET /v1/models")
elif e.status_code in (429, 503):
print("Лимит ключа или провайдер недоступен, повторите позже")
else:
raise
except APIConnectionError:
print("Сеть недоступна")Повторять запрос имеет смысл при 429 и 503, причём с растущей паузой. Ошибки 401, 402 и 403 повторами не лечатся. Если модель выключена, сервер вернёт 503 с кодом model_disabled: тогда возьмите другую модель из GET /v1/models. Список моделей каталога всегда можно получить запросом client.models.list().
Сколько это стоит
Цены Zukko на 18 октября 2026 для gemini-3.8-flash: $0.125 за 1M входных токенов и $0.6 за 1M выходных. Контекст — 1M токенов, на вход принимается только текст.
Пример с условными объёмами: 1000 запросов по 2000 входных и 500 выходных токенов.
- вход: 1000 × 2000 = 2M токенов, 2 × 0.125 = $0.25;
- выход: 1000 × 500 = 0.5M токенов, 0.5 × 0.6 = $0.30;
- итого: 0.25 + 0.30 = $0.55.
По официальным ценам из нашей таблицы (вход $0.75, выход $3.75) тот же объём стоил бы 2 × 0.75 + 0.5 × 3.75 = $3.375. Реальную сумму по каждому запросу показывает заголовок X-Zukko-Cost-Micros (в микродолларах) через with_raw_response:
raw = client.chat.completions.with_raw_response.create(
model=MODEL,
messages=[{"role": "user", "content": "Привет!"}],
)
print(raw.headers.get("x-zukko-cost-micros"))
resp = raw.parse()Заголовок есть только у обычных (не потоковых) ответов. Актуальный список моделей и цен — GET https://api.zukko.pro/v1/models или страница «Модели» в кабинете. Если модель рассуждает перед ответом, эти токены учитываются в выходе, поэтому на сложных запросах смотрите на usage, а не на длину видимого ответа.
Нативный google-genai или OpenAI SDK
| Критерий | OpenAI SDK через шлюз | Нативный google-genai |
|---|---|---|
| Установка | pip install openai | pip install google-genai |
| Формат запроса | messages, chat.completions | input, interactions.create |
| Смена поставщика | меняется строка model | придётся переписывать код |
| Специфика Gemini | через параметры совместимого слоя | полный набор возможностей Google |
| Ключ | fetch_... шлюза | ключ Google AI Studio |
Нативный клиент выглядит так (по текущему quickstart Google, ключ берётся из GEMINI_API_KEY):
from google import genai
client = genai.Client()
interaction = client.interactions.create(
model="gemini-3.8-flash",
input="Чем list отличается от tuple в Python?",
)
print(interaction.output_text)Берите нативную библиотеку, если нужны функции, которых нет в совместимом слое, например настройки мышления в полном виде и всё, что Google выпускает раньше других. Берите OpenAI SDK, если важны переносимость кода, единый формат для разных моделей и общий баланс. Оговорка по параметрам: на странице диагностики Google указано, что у новых моделей линейки (3.6 и новее) собственные значения temperature и top_p игнорируются, так что не рассчитывайте на них как на ручку управления.
Попробуйте на своих данных: создайте ключ в кабинете, подставьте его в пример выше и сравните ответы gemini-3.8-flash с gpt-6.1-sol или deepseek-v4.1-flash, поменяв одну строку. Про выбор между моделями по цене и индексу силы читайте в статье Индекс силы моделей, а о подключении Gemini как отдельной модели — в материале Gemini 3.8 Flash через API.
Частые вопросы
Нужен ли отдельный ключ Google, чтобы вызвать Gemini по OpenAI SDK?
Через шлюз Zukko — нет, достаточно ключа fetch_.... Напрямую к Google нужен ключ из Google AI Studio, и доступность сервиса зависит от региона.
Какой base_url указывать?
https://api.zukko.pro/v1, с суффиксом /v1. Для Anthropic SDK адрес другой (без /v1), но к Gemini это не относится.
Работает ли стриминг и вызов функций?
Стриминг работает в OpenAI-формате, пример выше. Для вызова функций и других возможностей совместимого слоя ориентируйтесь на документацию Google и проверяйте поведение на своей задаче.
Как узнать точное имя модели?
Отправьте GET https://api.zukko.pro/v1/models со своим ключом или откройте страницу «Модели» в кабинете. Неизвестное имя даст ошибку 404 model_not_found.
zukko
Платите в 25×
меньше
за Claude Code & ChatGPT
Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.
Похожие статьи
- Свой прокси к нейросети на Node.js: не показывать API-ключ во фронтендеНебольшой сервер на Express между вашим фронтендом и API нейросети: ключ остаётся на сервере, а модели, длина запроса и частота ограничены.
- DeepSeek API на Python: запросы, стриминг, JSON и обработка ошибокГотовый код для DeepSeek V4.1 Flash и V4 Pro на OpenAI SDK: запрос, стриминг, разбор JSON и аккуратная обработка ошибок.
- Anthropic SDK для Python: base_url, ключ и первый запрос через шлюзОфициальный пакет anthropic для Python нужно только направить на другой адрес. Разбираем base_url, ключ, стриминг, подсчёт токенов, кэш и ошибки.
- Безопасность Claude Code: чек-лист перед запуском агента в проектеАгент читает файлы и запускает команды, поэтому настройки безопасности нужны до первого запуска. Чек-лист: разрешения, секреты, песочница, отдельный ключ с лимитом.