Gemini API вызывается из Python через официальный пакет google-genai, а ключ должен приходить из переменной окружения, а не из файла с кодом. Сделаем консольный чат, сохраним связь реплик через previous_interaction_id и не отправим секрет в Git. Код отделит ввод, запрос и обработку ответа, чтобы сетевой сбой не выглядел пустым сообщением.
Первый запрос к модели часто копируют одной строкой вместе с ключом. Потом непонятно, где хранится история, как остановить цикл и что делать при ошибке сети. В этой статье вы соберёте консольный чат из одного Python-файла. Финальный результат можно проверить без догадок: вторая реплика учитывает первую, команда /exit завершает цикл, а отсутствие GEMINI_API_KEY обнаруживается до запроса.
Client читает GEMINI_API_KEY из окружения, код остаётся безопасным для репозитория.
previous_interaction_id связывает новый запрос с предыдущим ответом.
Сетевой вызов обёрнут отдельно, а пустой output_text не считается успехом.
Как Python-запрос проходит до Gemini API
Терминал получает текст пользователя, функция ask вызывает client.interactions.create, API возвращает interaction с id и output_text. Следующая итерация передаёт прошлый id. Программа не сохраняет ключ, полную историю и ответы в исходнике. Для Gemini API держите этапы раздельно: ввод, проверка, основное действие и вывод. Такой маршрут позволяет остановиться в конкретной точке, увидеть фактические данные и исправить одну причину вместо случайной перестановки строк.
| Этап | Действие | Проверяемый результат |
|---|---|---|
| Окружение | Client читает GEMINI_API_KEY | Секрет не находится в main.py |
| Ввод | input получает очередной вопрос | Пустая строка не отправляется |
| Запрос | interactions.create передаёт input и previous id | Сервер связывает контекст |
| Ответ | output_text печатается, id сохраняется | Следующая реплика продолжает диалог |
Клиент хранит только идентификатор предыдущего interaction, а серверный API управляет связью реплик. У Gemini API каждый этап оставляет наблюдаемый след, поэтому следующий шаг начинается только после проверки предыдущего.

От входных данных до видимого результата. Контекст обновляется только после успеха
.env всё равно нельзя коммитить. Добавьте .env в .gitignore, но для простого запуска задайте переменную в оболочке. Если ключ попал в историю Git, удаление строки из последнего commit не отменяет утечку: ключ нужно отозвать.Пишем чат с историей
Создайте проект uv init gemini-chat и добавьте uv add google-genai. Получите ключ в Google AI Studio и задайте GEMINI_API_KEY в своей оболочке. Для модели используйте переменную GEMINI_MODEL: документация и доступность моделей меняются быстрее учебного кода. Пример по умолчанию использует имя из актуального quickstart на дату проверки статьи.
import os
import sys
from google import genai
MODEL = os.getenv("GEMINI_MODEL", "gemini-3.8-flash")
if not os.getenv("GEMINI_API_KEY"):
sys.exit("Set GEMINI_API_KEY before starting the chat")
client = genai.Client()
previous_id: str | None = None
while True:
message = input("you> ").strip()
if message == "/exit":
break
if not message:
continue
try:
interaction = client.interactions.create(
model=MODEL,
input=message,
previous_interaction_id=previous_id,
)
except Exception as error:
print(f"request failed: {type(error).__name__}")
continue
answer = (interaction.output_text or "").strip()
if not answer:
print("assistant> empty response")
continue
print(f"assistant> {answer}")
previous_id = interaction.id- Без ключа программа завершается до сетевого запроса.
- Первая реплика создаёт interaction.id.
- Вторая реплика получает previous_interaction_id.
- Ошибка запроса не стирает последний успешный контекст.
Имя исключения выводится без полного объекта запроса, чтобы случайно не напечатать конфигурацию или содержимое чувствительного сообщения. Пример Gemini API специально ограничен одним пользовательским сценарием, чтобы назначение каждой строки оставалось видимым.

Что отличает устойчивый проект от случайного запуска. Секрет не попадает в репозиторий
Где хранится контекст и что отправляет SDK
Официальный SDK создаёт HTTP-запрос и аутентифицирует его ключом из окружения. Stateful Interactions API позволяет продолжить диалог по id, поэтому пример не пересылает весь список реплик вручную. Это удобно, но означает серверное состояние и срок его жизни. Для приложения, где нужен полный аудит или переносимость между провайдерами, историю стоит хранить в собственной базе и контролировать размер контекста. output_text является удобным сокращением для текстового ответа, однако сложный ответ может содержать другие части.
| Часть | За что отвечает | Что проверить |
|---|---|---|
| Environment | Хранит GEMINI_API_KEY и имя модели | Секрет отсутствует в git diff |
| Client | Создаёт соединение SDK | Инициализируется один раз |
| Interaction | Хранит id и output_text | Пустой текст обработан |
| previous id | Продолжает серверную историю | Обновляется только после успеха |
| try/except | Ловит сетевой сбой | Цикл остаётся управляемым |
Не перехватывайте KeyboardInterrupt общим Exception, если хотите останавливать программу Ctrl+C. В примере Exception относится только к сетевому вызову. Для production задайте тайм-аут, ограничение длины ввода, журнал без секретов и политику повторов только для временных ошибок. Не повторяйте запрос автоматически после неизвестного сбоя: он мог выполниться на сервере. Стоимость и лимиты зависят от выбранной модели и аккаунта, поэтому их проверяют в актуальной панели, а не копируют из старой статьи.
Проверяем ключ, пустой ответ и новый диалог
Запустите чат, сообщите один вымышленный факт и спросите о нём второй репликой. Затем обнулите previous_id после команды /new и убедитесь, что новый диалог не обязан помнить старый. Удалите переменную ключа и проверьте ранний отказ. Задайте неверное имя модели и прочитайте тип ошибки без stack trace. Добавьте ограничение в 500 символов и счётчик успешных реплик. Последний шаг: сохраните только роли, время и короткий preview локально, не записывая ключ.
- Проверьте ранний отказ без ключа.
- Получите первый interaction.id.
- Продолжите контекст второй репликой.
- Добавьте команду /new.
- Проверьте неверное имя модели.
- Ограничьте длину пользовательского ввода.
- Ключ не хранится в коде.
- История продолжается по id.
- Пустой ответ обработан.
- Новый диалог сбрасывается явно.
Чат становится приложением, когда состояние, ошибки и границы ввода видны в коде, а не спрятаны за одним вызовом SDK. После этой проверки измените одно правило Gemini API и заранее запишите ожидаемый результат. Так копирование превращается в понимание.

Четыре проверки перед следующим шагом. Ошибки являются отдельным состоянием
Как развивать чат без утечки секретов
Для интерфейса вынесите функцию запроса из input-цикла и отдавайте события загрузки, ответа и ошибки отдельно. Если добавляете streaming, собирайте части ответа и корректно завершайте отменённый запрос. Модель выбирайте через конфигурацию. Не логируйте заголовки авторизации и полные пользовательские сообщения. Для публичного веб-приложения ключ никогда не должен попадать в браузер: запрос идёт через ваш сервер с авторизацией и лимитами.
Как изучить тему в Кодике
Повторите переменные окружения, циклы, функции и исключения Python, затем разберите асинхронную сеть отдельно. В Кодике сначала восстановите чистую логику без фреймворка, затем верните библиотеку и интерфейс Gemini API.
| Шаг | Что разобрать | Мини-проверка |
|---|---|---|
| 1 | Окружение | Прочитать ключ через os.getenv |
| 2 | Цикл ввода | Обработать /exit и пустую строку |
| 3 | Объекты SDK | Прочитать id и output_text |
| 4 | Исключения | Отделить сетевой сбой |
| 5 | Состояние диалога | Добавить /new |
Сначала сделайте устойчивый однопоточный цикл, потом переходите к streaming и GUI. Финальная проверка для Gemini API: закрыть статью, объяснить путь данных и добавить одну функцию без копирования готового блока.
Используйте GEMINI_API_KEY и отзовите уже опубликованный секрет.
Читайте имя из GEMINI_MODEL и сверяйте доступность.
Сохраняйте interaction.id только после успешного ответа.
Показывайте безопасное имя ошибки, подробности отправляйте в защищённый лог.
Что получится в итоге

Консольный чат безопасно читает ключ, продолжает историю по идентификатору и переживает пустой или неуспешный ответ.
Где хранить ключ Gemini API в Python-проекте?
Ключ Gemini API храните в переменной окружения или менеджере секретов, а не в исходном коде.
Как продолжить историю Interactions API?
Передайте id предыдущего успешного interaction в previous_interaction_id нового запроса.
Можно ли вызывать Gemini API прямо из браузера с постоянным ключом?
Нет, постоянный ключ нельзя отдавать клиенту. Браузер должен обращаться к вашему защищённому серверу.
Как понять, что учебный проект Gemini API действительно работает?
Проверьте основной сценарий Gemini API, неверный ввод, повторный запуск и один граничный случай. Затем объясните путь данных своими словами.
Можно ли начать с готового кода Gemini API из статьи?
Да. Сначала добейтесь результата Gemini API, затем измените одно правило и восстановите ключевой файл без копирования.
Python и работу с API закрепите в курсе Python, а основы генеративных моделей в курсе по ИИ.
Сравните архитектуру с MCP-сервером на Python, локальный интерфейс с Streamlit-приложением и агентный цикл с ИИ-агентом на Python.