Microsoft AutoGen: настройка на своём ключе вместо OpenAI
AutoGen строит своего клиента поверх openai-python, поэтому base_url и api_key меняются в config_list напрямую. Разбираем настройку и типичные грабли.
5 мин · · Обновлено · агенты
AutoGen строит своего клиента поверх обычного openai Python-пакета, поэтому весь механизм переключения провайдера — это base_url и api_key в config_list. Никакого отдельного адаптера под Anthropic или GLM не нужно: любая модель гейтвея отвечает в формате /v1/chat/completions, который AutoGen понимает из коробки.
Это удобно ровно потому, что AutoGen не пытается угадывать провайдера по имени модели, как делают некоторые обёртки поверх LiteLLM. Он просто собирает openai.OpenAI(base_url=..., api_key=...) и дальше вызывает chat.completions.create() с тем model, который вы указали в конфиге. Значит, весь опыт настройки одинаковый что для GPT, что для Claude, что для GLM — разница только в строке с именем модели, а не в архитектуре подключения.
Базовый config_list
import autogen
config_list = [
{
"model": "gpt-5.6-sol",
"base_url": "https://api.zukko.pro/v1",
"api_key": "fetch_ваш_ключ",
"default_headers": {"X-Zukko-Cache": "true"},
}
]
assistant = autogen.AssistantAgent(
name="assistant",
llm_config={"config_list": config_list},
)
user_proxy = autogen.UserProxyAgent(name="user_proxy", code_execution_config=False)
user_proxy.initiate_chat(assistant, message="Составь план миграции базы данных")Заголовок X-Zukko-Cache: true в default_headers включает на гейтвее кэш ответов — это основной способ, он работает для любой модели (в отличие от Idempotency-Key, этот заголовок как раз можно ставить на весь клиент). temperature: 0 тоже включает кэш, но только для моделей, которые принимают это значение: новые модели Claude (claude-sonnet-5, claude-opus-5-5) могут отклонить temperature, отличную от 1, с ошибкой 400, поэтому для них temperature в llm_config не задаём. Запрос, тело которого полностью совпадает с предыдущим, при повторе возвращается мгновенно и бесплатно, в ответе будет заголовок X-Zukko-Cache: hit. «Почти одинаковые» запросы (например, с дописанной репликой в истории) уже не совпадают; попадания в кэш не пишутся в /v1/usage. Для чата кэш живёт до 7 суток — удобно, когда во время отладки AutoGen-сценария один и тот же промпт прогоняется по десять раз подряд.
Разные агенты — разные модели
Ключ, который принимает config_list, ожидает поле api_key, а не apiKey — опечатка в регистре тихо ломает подключение и AutoGen падает с ошибкой авторизации, которая выглядит так, будто ключ неверный, хотя ключ на самом деле правильный. Второй частый паттерн — свой набор моделей под каждого агента в GroupChat:
critic = autogen.AssistantAgent(
name="critic",
llm_config={
"config_list": [{
"model": "claude-opus-5-5",
"base_url": "https://api.zukko.pro/v1",
"api_key": "fetch_ваш_ключ",
}],
},
)
coder = autogen.AssistantAgent(
name="coder",
llm_config={Claude Opus 5.5, как и другие модели Claude и GPT в каталоге, держит контекст в 1,000,000 токенов и понимает изображения (у GLM — 128K и без vision, поэтому coder на glm-5.3 картинки не разберёт) — в критике кода это не нужно, но пригодится, если добавить агента, который разбирает скриншоты интерфейса:
message = {
"role": "user",
"content": [
{"type": "text", "text": "Что не так с этим макетом?"},
{"type": "image_url", "image_url": {"url": screenshot_data_url}},
],
}
user_proxy.initiate_chat(ui_reviewer, message=message)Формат сообщения с картинкой — стандартный OpenAI image_url, работает одинаково для любой модели с vision (Claude, GPT), которая стоит за config_list.
Модель выключили посреди прогона
Каталог обновляется, и модель может быть выключена, пока долгий сценарий с несколькими раундами уже запущен. В этом случае гейтвей отвечает 503 с кодом model_disabled (например, так было с gpt-5.4 — её замена gpt-5.6-sol):
{"error": {
"message": "...",
"code": "model_disabled"
}}В долгоживущих AutoGen-сценариях есть смысл ловить model_disabled отдельно от прочих ошибок и один раз автоматически подставлять заранее выбранную запасную модель, а не просто ронять весь GroupChat. Актуальный список моделей — GET https://api.zukko.pro/v1/models:
try:
user_proxy.initiate_chat(assistant, message=task)
except Exception as e:
if "model_disabled" in str(e):
assistant.llm_config["config_list"][0]["model"] = "gpt-5.6-sol"
user_proxy.initiate_chat(assistant, message=task)
else:
raiseСвои ретраи поверх ретраев openai-python
У openai.OpenAI, на котором построен AutoGen, есть собственный механизм повторов — по умолчанию до двух дополнительных попыток на сетевые ошибки и 5xx, ещё до того, как об этом узнает ваш код. Idempotency-Key при этом задаётся на каждый логический запрос — через extra_headers в конкретном вызове chat.completions.create(). Тогда все внутренние повторы этого вызова пойдут с одним и тем же значением заголовка — это ровно то, что нужно: гейтвей увидит повтор и не спишет второй раз. А вот в default_headers клиента ключ класть нельзя: он уйдёт со всеми запросами, и уже второй запрос с другим телом получит 422 idempotency_conflict. Вторая ошибка — генерировать ключ заново при каждом ретрае: тогда каждая попытка получит новый ключ, и идемпотентность перестанет работать именно там, где она нужнее всего: при нестабильном соединении.
401 при формально верном ключе
Если config_list собирается из переменных окружения через autogen.config_list_from_json, легко забыть переименовать поле api_type — AutoGen по умолчанию ждёт "openai", и если в JSON остался "azure" от старого конфига под Azure OpenAI, запрос уйдёт с другой структурой заголовков, и гейтвей ответит 401 с Invalid API key, хотя сам ключ скопирован верно.
429 в групповом чате
На практике групповой чат с четырьмя-пятью агентами и max_round под двадцать легко выходит на десятки вызовов за одну сессию отладки, а если запускать такие сессии по кругу во время разработки промптов — счёт идёт на сотни в час.
GroupChatManager может за секунды сделать десяток последовательных вызовов, когда агенты передают ход по кругу. Если на ключе в кабинете выставлен дневной или месячный лимит расхода (это настраивается отдельно для каждого fetch_... на странице ключа), групповой чат с большим max_round быстрее упрётся в key_daily_limit_reached, чем одиночный агент. Дневной лимит сбрасывается в 00:00 UTC; своего rate limit у шлюза нет, поэтому 429 без кодов key_daily_limit_reached / key_monthly_limit_reached приходит от провайдера модели. При отладке удобно временно снять лимит с тестового ключа или завести отдельный ключ без ограничений только для разработки.
Идемпотентность при повторных попытках
UserProxyAgent с включённым code_execution_config иногда переотправляет один и тот же запрос при таймауте контейнера с кодом. Не пытайтесь защититься от этого через default_headers в config_list: этот параметр уходит в конструктор openai.OpenAI, то есть один и тот же Idempotency-Key получат все запросы агента, и второй же раунд с новым телом упадёт с 422 idempotency_conflict. Ключ нужен на каждый логический запрос — уникальный для запроса и одинаковый при его повторах. Для вызовов, которые важно не задвоить, делайте их напрямую через клиент и передавайте ключ в конкретном .create():
import uuid
from openai import OpenAI
client = OpenAI(base_url="https://api.zukko.pro/v1", api_key="fetch_ваш_ключ")
idem_key = str(uuid.uuid4()) # один на логический запрос; при повторе — тот же
resp = client.chat.completions.create(
model="gpt-5.6-sol",
messages=[{"role": "user", "content": task}],
extra_headers={"Idempotency-Key": idem_key},
)Повтор с тем же значением Idempotency-Key в течение 24 часов вернёт прежний ответ без нового списания.
Проверка перед стартом сценария
curl https://api.zukko.pro/v1/chat/completions \
-H "Authorization: Bearer fetch_ваш_ключ" \
-H "Content-Type: application/json" \
-H "X-Zukko-Cache: true" \
-d '{"model":"gpt-5.6-sol","messages":[{"role":"user","content":"ping"}]}'Если в ответе есть X-Zukko-Cost-Micros — запрос дошёл до модели и списался; повторный такой же запрос вернёт X-Zukko-Cache: hit и ничего не спишет. Баланс и историю списаний видно через GET /v1/balance и GET /v1/usage, ключи выпускаются в кабинете https://zukko.pro/app/api-keys. Если конфиг собирается динамически из нескольких JSON-файлов и непонятно, на каком этапе потерялось поле, быстрее написать в поддержку в Telegram (https://t.me/zukkopro?direct), чем гадать по логам openai.OpenAI в одиночку.
zukko
Платите в 25×
меньше
за Claude Code & ChatGPT
Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.
Похожие статьи
- Агенты opencode: как настроить роли, модели и инструментыСвой агент в opencode — это роль, модель и список разрешений. Показываем конфиг и пример, где рутину делает дешёвая модель, а код правит сильная.
- Plan mode в Claude Code: сначала план, потом правки в кодеВ plan mode Claude Code читает код и предлагает план, но ничего не правит, пока вы не согласитесь. Как включить, использовать и во сколько это обходится.
- Промпт-инъекция: что это и как защитить бота и агентаОбъясняем, как работает промпт-инъекция через пользовательский ввод и чужие документы, и какие меры снижают ущерб: изоляция данных, права инструментов, лимиты ключа.
- AI-агент для поиска работы: резюме под вакансию и сопроводительные письмаСобираем небольшой инструмент: вы даёте текст вакансии и файл с реальным опытом, получаете адаптированное резюме, письмо и список пробелов. Без выдуманных навыков.