Обновить

Интеграция ИИ уровня предприятия: встраивание LLM в бизнес-процессы крупных компаний — redb.Route.Llm 3.1.1

Уровень сложностиСложный
Время на прочтение29 мин
Охват и читатели9.9K
Всего голосов 3: ↑2 и ↓1+3
Комментарии5

Комментарии 5

Интересная тема. У нас в StudyQA (EdTech, 4M+ пользователей/год) прошли похожий путь, но без enterprise-уровня ресурсов — полезно было сверить опыт.

Что оказалось важнее всего:

  1. Stateful контекст на уровне домена. Для нас это Telegram-топик на каждый тип задачи (контент, поддержка, аналитика). Без изоляции контекста модель смешивает домены и деградирует по качеству за несколько сессий.

  2. Fallback-цепочка важнее retry. Недетерминированность на продакшне лечится не “попробовать снова”, а упрощённым промптом с меньшей степенью свободы. В критичных задачах: validate → retry с simplified prompt → escalate to human.

  3. Observability трека агента, не только финального ответа. Мы начали с логирования только выхода, но отладка без промежуточных шагов — слепое угадывание. Сейчас пишем весь цикл: промпт, вызов, результат, применённое действие.

Из опыта: для mid-size команды самое ценное в enterprise-подходах — не сами паттерны, а понимание, где именно недетерминированность становится операционным риском. В контентных задачах терпимо. В финансовых и compliance — нет, и это надо закладывать в архитектуру с самого начала.

у нас то же, через ?conversation=header: id из хедера, история живёт в Postgres (ConversationProps). Один нюанс: внутри каждого чата у нас не плоская лента, а дерево — parentMessageId на каждом узле, продолжать можно от любой точки. Полезно при откате к моменту до неудачного решения модели - не «удаляем», а уходим в новую ветку от того же родителя. Ваш Telegram-топик отлично решает изоляцию доменов.

Второе - fallback вместо retry. Полностью так же. Retry на недетерминированной системе странная идея, если вдуматься: тот же промпт, тот же state, та же температура почему второй раз должно стать лучше? У нас .OnException().Continued().To("llm://...?systemPromptRef=#simplified"), упрощённый сломался — в очередь на человека.

Третье observability цепочки. Больно знакомо. весь цикл (промпт, вызов, результат, действие) пишется в MessageProps + ToolAuditProps, плюс wire-tap в Kafka — через год можно поднять «а что мы 15 апреля чего наотвечали».

и про «недетерминированность как операционный риск только в одних доменах, и архитектурно надо закладывать сразу» — лучшая формулировка, я бы её в эпиграф вынес. В EdTech контент косячит — переписали и забыли. В финансах ту же ошибку трактуют как fraud, в медицине — как смертельный исход. Поэтому в статье 10 паттернов, а не «вот правильный способ делать AI».

"LLM как 24-й транспорт наравне с Kafka" – звучит красиво, пока не приходит аудитор с вопросом: "Почему в логах за вторник агент одобрил заявку, а за среду аналогичную отклонил?" Kafka честно хранит оффсет и партицию. LLM честно говорит: "Ну, настроение было другое". Sliding-window память в skip-list'е – намёк, что авторы сами нащупали этот разрыв. Как у вас решается версионирование модели для аудита?

Интересный вопрос, здесь-то почти никак...

Что закрывается из коробки. Каждое сообщение в MessageProps несёт provider_idmodel_idstop_reason, токены и полный контент (text + tool_use + tool_result, без потерь). Промпты живут в отдельном сторе PromptTemplateProps с (name, version, body) — то есть «промпт v7 от 14 апреля» это конкретный объект в Postgres, который нельзя перезаписать незаметно.

Что НЕ закрыто, но важно для аудитора. На уровне per-message сейчас не пишется temperature/maxTokens и нет явной FK на (prompt_name, prompt_version). Это известная дыра — то самое «нащупали разрыв».

План — добавить в MessageProps поля TemperaturePromptTemplateNamePromptTemplateVersionToolSetHash (чтобы зафиксировать, какой набор tool'ов был активен на момент вызова). И вот тут как раз тот случай, где REDB снимает обычную боль: добавляешь поля в C#-класс props — и всё, никаких миграций, alter table, версий схемы и прочей светотени. Стор сам подхватывает новые атрибуты. То есть это не «архитектурное решение на спринт», а реально пара коммитов. Возьму в работу.

Что закрыть нельзя в принципе — drift на стороне провайдера. Anthropic может молча пере-зарелизить claude-sonnet-4-5, и вы про это узнаете только по поведению. Единственный честный ответ для compliance-доменов — либо self-hosted (vLLM / llama.cpp / Ollama, у нас есть алиасы), либо явный pinning через провайдеров, у которых это есть в API (xAI, OpenAI через system_fingerprint, Cohere). У Anthropic такого пока нет, и это плохо для финансов/медицины. Я закладываю это как явную лимитацию в архитектурный контракт, а не пытаюсь магией скрыть.

Granulex Спасибо за развёрнутый ответ — взял в работу. В 3.1.1 (CHANGELOG уже обновлён) добавил per-message аудит-поля на MessageProps, проставляются движком на каждый persist:

  • TemperatureMaxTokensTopP — эффективные сэмплинг-параметры (override запроса → дефолт фабрики), на assistant-строках.

  • PromptTemplateName + PromptTemplateVersion — на всех строках прогона, если caller передал managed template.

  • ToolSetHash — SHA-256 канонического набора {name, description, InputSchema} (отсортирован по имени), на assistant-строках. Меняется набор/схема инструмента — меняется хеш.

  • ProviderSystemFingerprint — system_fingerprint из ответа провайдера (OpenAI/xAI/Together эхо-возвращают; Anthropic-compat / Gemini-compat / Ollama чаще null).

Про закрытые модели честно: фингерпринта от Anthropic нет → bit-exact replay невозможен в принципе, фиксируем (model_id, params, tool_set_hash, prompt_template) и помечаем как best-effort. Для жёсткого compliance — self-hosted (Ollama / vLLM / llama.cpp), там воспроизводимость честная.

Миграции не было — REDB схему props подхватывает автоматически, просто добавил поля в класс.

Детали и code-paths: CHANGELOG.md → раздел 3.1.1, per-message audit fields on MessageProps

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации