L
| leo_msk |
| Junior |
Сообщения: 30 |
Репутация: 15 |
| Дата регистрации: |
| 12.09.2026 |
АВТОР ТЕМЫ03 нояб. 2026 г., 18:07 (GMT+3)
Есть у меня небольшой VPS: n8n, рядом ollama, всё в docker compose. Главный сценарий скучный и поэтому полезный — разбор входящих писем. Текстом он выглядит так:
1. IMAP Trigger забирает новое письмо.
2. Code-нода обрезает подписи, цитаты и html-мусор, оставляет первые ~2000 символов.
3. HTTP Request идёт в ollama (/api/generate). Промпт: «верни JSON с полями category и urgent», категории: счёт, договор, вопрос, спам.
4. Set разбирает ответ.
5. Switch по category: счета — в папку и таблицу, договоры — мне в телеграм, вопросы — в очередь, спам — в архив.
6. Fallback-ветка Switch: «не понял», уходит в отдельную метку.
Полгода работало. На прошлой неделе я поставил на сервер ещё одну модель для другой задачи и заодно сделал ollama pull для той, что уже стояла. Без задней мысли: тег тот же, пусть подтянется свежее. В n8n при этом ничего не трогал.
Заметил через три дня, и то случайно: метка «не понял» распухла. Открыл executions. Ошибок нет, всё зелёное. Только модель стала иногда оборачивать JSON в ```json, иногда писать «Счёт» с большой буквы, а один раз вернула category: "invoice", видимо, решив, что так солиднее. Set это проглатывал, Switch честно не находил совпадения и отправлял письмо в fallback. Сценарий не падал, он просто перестал делать свою работу. Самый неприятный вид поломки: мониторить нечего, всё «успешно».
Смешно, что я сам на прошлой работе требовал у разработчиков фиксировать версии зависимостей. А тут у меня в продакшене зависимость весом в несколько гигабайт, и закреплена она словом «latest» в голове.
Что поменял:
— Имя модели теперь в одном месте, в переменной окружения n8n, а не в каждой HTTP-ноде. Раньше их было три, и в одной, как выяснилось, стояла вообще другая модель.
— В запросе к ollama включил "format": "json" и temperature 0 в options. Строго это ничего не гарантирует, но обёртки в markdown пропали.
— После разбора ответа поставил нормализацию: lower-case, trim и словарь синонимов. invoice → счёт. Да, я написал словарь синонимов для собственного классификатора, гордиться тут нечем.
— Записал ID модели из ollama list в заметку к сценарию. Если ID сменился, значит, это другая модель, даже если имя то же.
И главное, ради чего пишу. Я собрал «золотой набор»: около сорока старых писем, обезличенных, с категорией, которую поставил руками. Отдельный сценарий берёт их из таблицы, прогоняет через указанную модель тем же промптом и считает, сколько совпало и какие ответы вообще не распарсились. Запускаю вручную перед тем, как переключать переменную на новую модель. Получился такой бедный staging для промпта.
Но тут начинаются вопросы, на которые у меня нет хорошего ответа.
Первый: сорок писем — это много или смешно? Редкие категории вроде договоров там встречаются раза три, и одна ошибка сразу роняет процент. Добирать набор специально под редкие случаи или смотреть только на общий итог?
Второй: как сравнивать, если ответы не строго детерминированы? Сейчас гоняю каждое письмо дважды и считаю расхождение отдельной метрикой. Выглядит как костыль.
Третий, организационный: где у вас лежит промпт? У меня он внутри ноды, то есть живёт в экспорте workflow вместе со всем остальным, и в git дифф изменения одной фразы тонет среди сдвинутых координат нод. Думаю вынести промпт в файл или в таблицу и подтягивать по версии, но не уверен, что это не усложнение ради усложнения.
Если кто-то держит локальные модели в рабочих сценариях не ради эксперимента, расскажите, как у вас устроено обновление. Закрепляете конкретный digest, держите две модели параллельно и сравниваете, или просто не обновляете, пока работает?
1. IMAP Trigger забирает новое письмо.
2. Code-нода обрезает подписи, цитаты и html-мусор, оставляет первые ~2000 символов.
3. HTTP Request идёт в ollama (/api/generate). Промпт: «верни JSON с полями category и urgent», категории: счёт, договор, вопрос, спам.
4. Set разбирает ответ.
5. Switch по category: счета — в папку и таблицу, договоры — мне в телеграм, вопросы — в очередь, спам — в архив.
6. Fallback-ветка Switch: «не понял», уходит в отдельную метку.
Полгода работало. На прошлой неделе я поставил на сервер ещё одну модель для другой задачи и заодно сделал ollama pull для той, что уже стояла. Без задней мысли: тег тот же, пусть подтянется свежее. В n8n при этом ничего не трогал.
Заметил через три дня, и то случайно: метка «не понял» распухла. Открыл executions. Ошибок нет, всё зелёное. Только модель стала иногда оборачивать JSON в ```json, иногда писать «Счёт» с большой буквы, а один раз вернула category: "invoice", видимо, решив, что так солиднее. Set это проглатывал, Switch честно не находил совпадения и отправлял письмо в fallback. Сценарий не падал, он просто перестал делать свою работу. Самый неприятный вид поломки: мониторить нечего, всё «успешно».
Смешно, что я сам на прошлой работе требовал у разработчиков фиксировать версии зависимостей. А тут у меня в продакшене зависимость весом в несколько гигабайт, и закреплена она словом «latest» в голове.
Что поменял:
— Имя модели теперь в одном месте, в переменной окружения n8n, а не в каждой HTTP-ноде. Раньше их было три, и в одной, как выяснилось, стояла вообще другая модель.
— В запросе к ollama включил "format": "json" и temperature 0 в options. Строго это ничего не гарантирует, но обёртки в markdown пропали.
— После разбора ответа поставил нормализацию: lower-case, trim и словарь синонимов. invoice → счёт. Да, я написал словарь синонимов для собственного классификатора, гордиться тут нечем.
— Записал ID модели из ollama list в заметку к сценарию. Если ID сменился, значит, это другая модель, даже если имя то же.
И главное, ради чего пишу. Я собрал «золотой набор»: около сорока старых писем, обезличенных, с категорией, которую поставил руками. Отдельный сценарий берёт их из таблицы, прогоняет через указанную модель тем же промптом и считает, сколько совпало и какие ответы вообще не распарсились. Запускаю вручную перед тем, как переключать переменную на новую модель. Получился такой бедный staging для промпта.
Но тут начинаются вопросы, на которые у меня нет хорошего ответа.
Первый: сорок писем — это много или смешно? Редкие категории вроде договоров там встречаются раза три, и одна ошибка сразу роняет процент. Добирать набор специально под редкие случаи или смотреть только на общий итог?
Второй: как сравнивать, если ответы не строго детерминированы? Сейчас гоняю каждое письмо дважды и считаю расхождение отдельной метрикой. Выглядит как костыль.
Третий, организационный: где у вас лежит промпт? У меня он внутри ноды, то есть живёт в экспорте workflow вместе со всем остальным, и в git дифф изменения одной фразы тонет среди сдвинутых координат нод. Думаю вынести промпт в файл или в таблицу и подтягивать по версии, но не уверен, что это не усложнение ради усложнения.
Если кто-то держит локальные модели в рабочих сценариях не ради эксперимента, расскажите, как у вас устроено обновление. Закрепляете конкретный digest, держите две модели параллельно и сравниваете, или просто не обновляете, пока работает?
0