# Как пережить снятие LLM-модели с продакшена: миграция ИИ-агента на новую модель

> AI Release · @ai_release1 · https://ai-release.org/guides/kak-perezhit-snyatie-llm-modeli-s-prodakshena-migratsiy.html

Если вендор объявляет, что ваша LLM (Large Language Model — большая языковая модель, та самая «нейросеть-чат») уходит с продакшена, это не значит, что ваш ИИ-агент (программа, которая сама вызывает модель, инструменты и базы знаний и выполняет задачу целиком) сломается в тот же день. Он сломается в момент, когда старый эндпоинт вернёт ошибку, а вы ещё не проверили ни промпты, ни RAG, ни парсер ответов. Гайд — про безопасный переезд: как зафиксировать текущее поведение, найти все места, где зашито имя модели, прогнать тесты на новой модели и переключить трафик так, чтобы откат занимал одну минуту. Подходит для любого агента на Python/Node с внешним API-ключом и для локальных сборок через Ollama или LM Studio — меняется только строка подключения.

## Требования и подготовка
![Иллюстрация к разделу «Требования и подготовка»](https://ai-release.org/guides/img/kak-perezhit-snyatie-llm-modeli-s-prodakshena-migratsiy-ru-1.jpg)


- Репозиторий с кодом агента и права на создание ветки (git).
- Доступ к панели вендора: актуальный API-ключ, лимиты, дата отключения старой модели (обычно приходит письмом или лежит в разделе Changelog/Deprecations).
- Файл с настройками: `.env`, `config.yaml` или `settings.py` — там указано имя модели.
- Тестовый набор (golden set) — 20–100 реальных запросов ваших пользователей вместе с ожидаемыми ответами. Это ваш эталон: без него вы не поймёте, стало хуже или лучше.
- Отдельное staging-окружение, куда можно лить тестовый трафик, не задев живых пользователей.
- Бэкап: ветка git с текущим кодом, копия конфигов и скриншот метрик «до» (задержка, стоимость, доля ошибок).
- Если нужен запасной вариант и локальный запуск — подготовьте его заранее, инструкция есть в гайде [Как запустить ИИ-модель локально на своём компьютере](https://ai-release.org/guides/kak-zapustit-ii-model-lokalno-na-svoem-kompyutere-gayd.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide).

## Пошаговая инструкция
![Иллюстрация к разделу «Пошаговая инструкция»](https://ai-release.org/guides/img/kak-perezhit-snyatie-llm-modeli-s-prodakshena-migratsiy-ru-2.jpg)


1. **Зафиксируйте текущее состояние (baseline).** Выпишите в файл `migration.md` три вещи: точное имя модели, её версию/дату и параметры генерации (temperature — «степень креативности», 0 — строго по делу, 1 — разбросанно). Добавьте дату отключения от вендора.
   **Пример:** `old-model-name`, версия `2024-06-01`, `temperature=0.2`, отключение `2026-02-01`.
   **Ожидаемый результат:** у вас на руках чек-лист «что именно меняем», а не абстрактное «переезжаем на новую модель».

2. **Найдите все места, где упомянута модель.** Одна забытая строка в тестах — и агент упадёт уже после переключения.
   **Пример:**
   ```bash
   grep -rn "MODEL_NAME\|model_name\|model:" ./app ./config .env* ./tests
   ```
   **Ожидаемый результат:** список вида `./app/llm_client.py:14`, `./config/.env:3`, `./tests/test_chat.py:9`. Если файлов больше пяти — вы точно не готовы к быстрой замене.

3. **Вынесите имя модели в одну переменную окружения.** Правило «одна точка правды»: меняете строчку в `.env` — меняется весь агент.
   **Пример:**
   ```env
   # .env
   LLM_PROVIDER=openai
   LLM_MODEL=old-model-name
   LLM_TEMPERATURE=0.2
   LLM_API_KEY=sk-...
   ```
   Почему работает: код читает `os.environ["LLM_MODEL"]`, и при миграции вам не нужно править логику — только переменную.

4. **Получите доступ к новой модели и проверьте его вручную.** Новый ключ может не иметь доступа к нужной модели или иметь другие лимиты по запросам в минуту.
   **Пример:**
   ```bash
   curl https://api.example.com/v1/chat/completions \
     -H "Authorization: Bearer $LLM_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"model":"new-model-name","messages":[{"role":"user","content":"Скажи привет"}]}'
   ```
   **Ожидаемый результат:** JSON с полем `choices[0].message.content`. Если приходит `404 model_not_found` — ключ не выписан на новую модель, и дальше идти нет смысла.

5. **Прогоните golden set на старой модели и сохраните ответы в файл.** Это ваш эталон для сравнения.
   **Пример:** сохраните `baseline_old.json` со структурой `{"запрос": "...", "ответ": "..."}`.
   **Ожидаемый результат:** 20–100 пар «вопрос-ответ» лежат на диске и закоммичены в git.

6. **Прогоните тот же набор на новой модели.** Меняете только `LLM_MODEL` и запускаете тот же скрипт.
   **Пример:**
   ```python
   resp = client.chat.completions.create(model=NEW_MODEL, messages=msgs)
   ```
   **Ожидаемый результат:** файл `baseline_new.json`. Дальше сравните его глазами или скриптом: где ответ стал короче, где потерял формат, где отвечает не по фактам.

7. **Проверьте служебные компоненты, а не только текст.** Отдельно посмотрите три вещи: поддержку tool calling (вызов инструментов агентом), JSON-режим (ответ строго в формате для парсера) и embeddings — «векторные отпечатки» текста для поиска в RAG (RAG — когда нейросеть сначала ищет нужные документы, а потом отвечает на их основе).
   **Пример:** если индекс RAG собран эмбеддингами старой модели, после смены модели поиск может отдавать нерелевантные документы — индекс придётся пересобрать теми же эмбеддингами, что и запросы.
   **Ожидаемый результат:** вы понимаете заранее, что пересобирать, а что нет. Как выглядит связка «агент + инструменты + база знаний», разобрано в гайде [Как превратить обычный чат с LLM в полноценного AI-агента](https://ai-release.org/guides/kak-prevratit-obychnyy-chat-s-llm-v-polnotsennogo-ai-ag.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide).

8. **Поправьте промпты под новую модель.** Новая модель может строже следовать системному промпту (инструкция «кто ты и что делать») или, наоборот, игнорировать часть указаний.
   **Пример:** если раньше вы писали «верни JSON», а новая модель добавляет текст вокруг — замените на явную схему и режим строгого JSON.
   **Ожидаемый результат:** те же 20–100 запросов снова проходят, ошибок парсинга нет.

9. **Включите канареечный деплой.** Canary — когда новая модель обслуживает только 5–10% трафика, а остальное идёт на старую.
   **Пример:** в конфиге `canary_weight=0.1`, держите так 24–48 часов.
   **Ожидаемый результат:** в логах видно разницу по задержке, стоимости и доле ошибок, но пользователи почти не затронуты.

10. **Переключите 100% трафика и держите rollback наготове.** Откат — это вернуть в `.env` старое имя модели и перезапустить сервис, пока старый эндпоинт ещё жив.
    **Ожидаемый результат:** метрики не хуже baseline; если хуже — одна правка и вы снова на старой модели.

**Мини-чек-лист перед полным переключением:**
- [ ] Имя модели вынесено в одну переменную окружения
- [ ] Baseline-ответы старой модели сохранены в файл
- [ ] Golden set прогнан на новой модели, расхождения разобраны
- [ ] Проверены tool calling и строгий JSON-режим
- [ ] Проверен и при необходимости пересобран индекс RAG
- [ ] Настроены канарейка, мониторинг и rollback
- [ ] Старое имя модели и старый ключ удалены из кода и тестов

## Возможные проблемы и решения
![Иллюстрация к разделу «Возможные проблемы и решения»](https://ai-release.org/guides/img/kak-perezhit-snyatie-llm-modeli-s-prodakshena-migratsiy-ru-3.jpg)


**Проблема 1: агент падает с ошибкой вида `404 model_not_found` или `model does not exist`.**
Симптом: в логах HTTP 404 сразу после переключения `.env`.
Решение: 1) проверьте имя модели посимвольно — частые опечатки в дефисах и датах версий; 2) убедитесь, что ключ выписан именно на новую модель; 3) проверьте, не осталось ли в тестах или в отдельном воркере старой строки — вернитесь к `grep` из шага 2.

**Проблема 2: ответы приходят, но парсер ломается — `Expecting value: line 1 column 1 (char 0)`.**
Симптом: новая модель добавляет пояснение или markdown-обёртку ```json вокруг объекта.
Решение: 1) включите строгий JSON-режим у вендора; 2) усильте промпт до «верни только объект без пояснений»; 3) добавьте в код защиту — если ответ не парсится, логировать сырой текст, а не молча падать.

**Проблема 3: RAG отвечает «мимо» — документы нерелевантные.**
Симптом: агенту приходят чужие или близкие по теме, но неверные куски текста.
Решение: 1) сравните, чьими эмбеддингами собран индекс; 2) пересоберите индекс эмбеддингами, совместимыми с новой моделью; 3) прогоните golden set заново и посмотрите, вернулся ли прежний уровень.

## FAQ

**Что делать, если до отключения старой модели осталась неделя?**
Переключитесь на минимальный план: вынесите имя модели в `.env` (шаг 3), прогоните golden set (шаги 5–6), задеплойте с канарейкой на короткое окно (шаг 9). Персборку индекса RAG можно отложить, но только если ваши эмбеддинги не меняются.

**Обязательно ли менять промпты при переходе на новую модель?**
Не всегда, но проверять нужно всем. Даже при похожем поведении меняется послушность инструкциям и формат ответа. Критерий простой: прошли ли те же 20–100 запросов без правок парсера.

**Можно ли оставить старую модель как запасной вариант?**
Да, до даты отключения. Пока эндпоинт жив, откат — это одна переменная в `.env` и перезапуск сервиса. После отключения запасным вариантом становится либо другая модель вендора, либо локальная сборка, о которой стоит позаботиться заранее.

**Как понять, что новая модель дешевле или дороже, а не просто «другая»?**
Смотрите не на цену за миллион токенов саму по себе, а на связку: длина промпта + длина ответа + число вызовов на один запрос пользователя. Выросшая длина ответов легко съедает экономию на тарифе. Замеряйте на своих golden set до и после.

| Что сравниваем | Где смотреть | Признак проблемы |
|---|---|---|
| Формат ответа | лог парсера JSON | `Expecting value: line 1` |
| Полнота ответа | golden set, сравнение с baseline | ответ обрывается, короче эталона |
| Вызов инструментов | логи агента | агент не вызывает нужный инструмент |
| RAG-поиск | выдача релевантных документов | приходят нерелевантные куски |
| Стоимость и задержка | панель вендора, метрики p95 | счёт вырос, ответы идут дольше |
