CrewAI: подключение агентов к Claude и GPT через один ключ
CrewAI тянет к OpenAI через LiteLLM, но agent.llm можно переставить на любую модель гейтвея. Разбираем настройку и типичные ошибки на старте.
5 мин · · Обновлено · агенты
CrewAI собирает агентов в команду: у каждого своя роль, своя память и свой llm. По умолчанию фреймворк ходит к OpenAI через LiteLLM, но LLM-класс принимает base_url и api_key, так что вместо десяти отдельных провайдерских ключей можно использовать один fetch_... и переключать модели прямо в коде агента.
На практике почти вся боль с CrewAI на старте — не в логике агентов, а в том, что фреймворк собирает запрос через LiteLLM, а тот по умолчанию рассчитан на официальные адреса провайдеров. Как только вы уходите на сторонний совместимый гейтвей, всплывают три вещи: правильный префикс в имени модели, правильный base_url (с /v1 или без — зависит от протокола) и то, что повторные попытки LiteLLM при сетевых сбоях могут задвоить списание, если не подстраховаться идемпотентностью. Дальше — по порядку.
Базовая настройка
CrewAI использует нотацию LiteLLM: провайдер указывается префиксом в model, а фактический адрес берётся из base_url. Для OpenAI-совместимого режима это выглядит так:
from crewai import Agent, Task, Crew, LLM
llm = LLM(
model="openai/gpt-5.6-sol",
base_url="https://api.zukko.pro/v1",
api_key="fetch_ваш_ключ",
)
researcher = Agent(
role="Researcher",
goal="Собрать факты по теме и оформить кратким списком",
backstory="Пишет по-русски, проверяет источники, не выдумывает цифры",
llm=llm,
)Префикс openai/ здесь не про модель, а про формат протокола: LiteLLM отправляет запрос на POST /v1/chat/completions, а какая модель за этим стоит — решает уже гейтвей по полю model. Поэтому тем же способом подключаются и Claude, и GLM:
claude_llm = LLM(
model="openai/claude-sonnet-5",
base_url="https://api.zukko.pro/v1",
api_key="fetch_ваш_ключ",
)Если написать model="claude-sonnet-5" без префикса openai/, LiteLLM попытается угадать провайдера сам и полезет в нативный Anthropic SDK со своими дефолтными адресами — получится путаница с base_url. Префикс обязателен именно потому, что вы работаете через OpenAI-совместимый путь /v1/chat/completions, а не через /v1/messages.
Разные модели для разных агентов
В команде обычно не нужен один и тот же уровень модели для всех ролей. Дешёвая GLM для черновой работы, Opus 5.5 — для финальной проверки:
drafter = Agent(
role="Drafter",
goal="Быстро накидать черновик по брифу",
llm=LLM(model="openai/glm-5.3", base_url="https://api.zukko.pro/v1", api_key=key),
)
reviewer = Agent(
role="Reviewer",
goal="Проверить черновик на фактические ошибки",
llm=LLM(model="openai/claude-opus-5-5", base_url="https://api.zukko.pro/v1", api_key=key),
)
crew = Crew(agents=[drafter, reviewer], tasks=[draft_task, review_task])
crew.kickoff()Если у ключей заданы разные дневные лимиты (настраивается в кабинете на странице ключа), удобно выдать каждому агенту свой fetch_... — тогда дорогой Opus не съест лимит, рассчитанный на дешёвые черновики.
Агент с доступом к вебу
Ни у GPT, ни у Claude, ни у GLM в этом каталоге нет встроенного веб-поиска — за это отвечает отдельный POST /v1/web-search. В CrewAI его удобно завернуть в обычный tool и выдать агенту-исследователю:
from crewai.tools import tool
import requests
@tool("web_search")
def web_search(query: str) -> str:
"""Ищет свежую информацию в интернете."""
resp = requests.post(
"https://api.zukko.pro/v1/web-search",
headers={"Authorization": "Bearer fetch_ваш_ключ"},
json={"query": query},
)
return resp.json()
researcher = Agent(
role="Researcher",
goal="Найти актуальные данные, которых нет в базовых знаниях модели",
llm=llm,
tools=[web_search],
)Это отдельный вызов со своей тарификацией, не часть чат-запроса, поэтому его стоимость видна в истории списаний отдельной строкой. Для агента, который сначала ищет, а потом суммирует найденное через LLM, итоговая стоимость задачи складывается из двух разных строк в GET /v1/usage, и это стоит учитывать при прикидке бюджета на прогон всей команды.
Сколько стоил конкретный запуск
CrewAI даёт доступ к сырому ответу через llm.call() при ручных вызовах вне Agent, и в заголовках обычного (нестримингового) ответа гейтвея есть X-Zukko-Cost-Micros (стоимость в микродолларах, 1,000,000 = $1) и X-Fetch-Balance-Cents (остаток после списания — несмотря на название, тоже в микродолларах; точный баланс в центах отдаёт GET /v1/balance). У потоковых ответов этих заголовков нет. Если оборачивать LLM.call собственным логированием, эти два заголовка удобно писать в лог рядом с именем агента — так видно, какая роль в команде тратит больше остальных, без похода в кабинет за каждой цифрой.
Такое логирование полезно ещё и для отчётности: если команда выставляет клиентам счёт за использование агентов, именно собственный лог X-Zukko-Cost-Micros по ключу или агенту даёт стоимость самой дорогой роли отдельно от черновой. GET /v1/usage такой разбивки не даст: история там общая на весь аккаунт (все ключи вместе, фильтра по ключу нет), а баланс — один на аккаунт. Если нужно жёсткое разделение по клиентам, заведите под клиента отдельный аккаунт.
404 вместо ответа
Самая частая жалоба на форумах CrewAI — агент "молчит" или падает с ошибкой соединения. В девяти случаях из десяти это base_url без /v1: OpenAI-совместимый путь гейтвея — https://api.zukko.pro/v1, а не https://api.zukko.pro. Второй адрес — только для Anthropic-совместимых клиентов, которые сами добавляют путь /v1/messages, и LiteLLM в режиме openai/ этого не делает.
Модель не найдена
Если в коде осталась модель из старого туториала CrewAI, вида gpt-4 или claude-3-opus, вернётся:
{"error": {"message": "The model 'gpt-4' does not exist", "code": "model_not_found"}}В каталоге этих моделей нет — актуальный список без ключа:
curl https://api.zukko.pro/v1/modelsРетраи и повторное списание
LiteLLM внутри CrewAI по умолчанию делает несколько повторных попыток при сетевых сбоях. Если сбой произошёл уже после того, как запрос доехал до модели, повтор с тем же телом может списать деньги дважды. Чтобы это исключить, нужен свой Idempotency-Key — но на каждый логический запрос, а не на весь LLM. Если передать его в конструктор LLM(..., extra_headers=...), он уйдёт во все вызовы агента, и второй же запрос с другим телом получит 422 idempotency_conflict. Для вызовов, которые вы делаете сами, задавайте ключ в конкретном вызове — один раз на запрос, без перегенерации при повторах:
import uuid, litellm
idem_key = str(uuid.uuid4()) # один ключ на один логический запрос
resp = litellm.completion(
model="openai/gpt-5.6-sol",
api_base="https://api.zukko.pro/v1",
api_key=key,
messages=[{"role": "user", "content": prompt}],
extra_headers={"Idempotency-Key": idem_key},
num_retries=2, # повторы LiteLLM уйдут с тем же ключом
)Повтор с тем же ключом идемпотентности в течение 24 часов вернёт тот же ответ без повторного списания. Для вызовов, которые агенты CrewAI формируют сами, общий ключ в конструкторе LLM не задавайте.
Проверка до запуска команды
Прежде чем собирать полную Crew, стоит убедиться, что ключ и модель работают сами по себе:
curl https://api.zukko.pro/v1/chat/completions \
-H "Authorization: Bearer fetch_ваш_ключ" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-5.6-sol","messages":[{"role":"user","content":"ping"}]}'Если ответ пришёл, дальше проблема будет только в логике агентов, не в подключении. Баланс и историю списаний по каждому вызову видно в кабинете (GET /v1/balance, GET /v1/usage), а по $0.50 на тесты начисляют один раз за подписку на @zukkopro. Если разворачиваете CrewAI для клиентов и приводите новых пользователей на этот же гейтвей, по реферальной программе идёт 10% от их пополнений — для агентства, которое ставит несколько команд агентов на разные проекты, это заметная экономия на общем инструменте, а не разовая скидка.
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-агент для поиска работы: резюме под вакансию и сопроводительные письмаСобираем небольшой инструмент: вы даёте текст вакансии и файл с реальным опытом, получаете адаптированное резюме, письмо и список пробелов. Без выдуманных навыков.