Когда начинаешь обсуждать AI внутри старого проекта, довольно быстро появляется соблазн решить сразу две проблемы. Раз уж система всё равно написана десять лет назад, плохо документирована, местами держится на старом PHP или Java и никто до конца не понимает некоторые модули, можно заодно всё это переписать на современный стек и уже поверх новой архитектуры добавить AI.
Звучит логично. И примерно так же начиналось огромное количество обычных legacy rewrite задолго до появления LLM.
Проблема в том, что работающая legacy-система обычно содержит гораздо больше знаний о бизнесе, чем видно из её архитектуры. Правила могут находиться в коде, stored procedures, cron-задачах, обработчиках старых интеграций и десятках странных условий, которые кто-то добавил семь лет назад после конкретного production-инцидента. Иногда никто уже не помнит, зачем условие существует, но убрать его всё равно нельзя.
Поэтому необходимость добавить AI сама по себе совершенно не означает необходимость переписать систему. Наоборот, чаще всего я бы начинал с противоположной идеи: legacy остаётся system of record, а AI появляется рядом с ним как новый слой.
Это намного скучнее большого AI transformation. Зато значительно безопаснее.
Сначала нужно понять, что именно мы хотим сделать с AI
Формулировка «нам нужно внедрить AI» почти бесполезна с архитектурной точки зрения. Это примерно как сказать «нам нужно внедрить базу данных».
Гораздо полезнее начать с одного конкретного workflow.
Например:
оператор поддержки тратит двадцать минут, чтобы найти историю клиента и подготовить ответ;
разработчик ищет информацию о старом модуле в нескольких репозиториях и документации;
менеджер вручную собирает данные из пяти внутренних систем;
пользователь хочет задавать вопросы по своей истории операций естественным языком.
Это уже задачи, вокруг которых можно проектировать систему.
Мне вообще кажется, что один из самых безопасных способов внедрения AI в legacy — начинать не с автоматизации действий, а с сокращения времени на получение информации. Поиск, summarization, классификация, подготовка черновика или объяснение существующих данных дают ценность, но почти не требуют отдавать модели возможность что-либо менять.
Условно:
Legacy system
↓
existing data
↓
AI layer
↓
search / summary / recommendation
↓
human
На таком этапе AI ещё вообще не участвует в критическом business flow. Если модель ошиблась, человек увидит плохой ответ. Если AI-сервис временно недоступен, старая система продолжит выполнять свою основную работу.
Это довольно хорошее свойство первой версии.
Самая дорогая часть legacy — обычно не код
Thoughtworks в своей работе по GenAI и legacy modernization отдельно отмечает интересную вещь: большую ценность LLM могут давать не при генерации нового кода, а при понимании существующего. Старые системы дорого модернизировать в первую очередь потому, что сложно восстановить их реальные requirements, зависимости и capability map.
AWS в материалах по modernization пишет примерно о той же проблеме: business logic в зрелых системах часто распределена между модулями и сервисами, документация неполная, а существенные зависимости обнаруживаются уже во время изменений. Поэтому анализ codebase становится отдельной фазой модернизации.
И вот здесь AI действительно полезен даже до появления первой AI-функции для пользователя.
Можно использовать его для:
- анализа большого codebase;
- восстановления связей между модулями;
- поиска похожей business logic;
- построения документации;
- объяснения старых участков кода;
- поиска потенциально мёртвых компонентов;
- подготовки capability map;
- анализа migrations, schemas и интеграций.
Только я бы не путал это с доказательством истины.
Если AI написал:
этот метод отвечает за расчёт комиссии;
это полезная гипотеза для инженера.
Это ещё не specification.
В legacy особенно опасно превращать красивое объяснение модели в новое бизнес-правило. Код мог содержать edge cases, которые модель не увидела, а важная часть процесса вообще может выполняться ночным batch job в другом репозитории.
Поэтому AI хорошо ускоряет reverse engineering, но подтверждать найденную картину всё равно приходится через код, данные, tests, runtime behavior и людей, которые знают систему.
AI не обязан жить внутри legacy
Допустим, у нас есть старый монолит:
┌────────────────────────────┐
│ Legacy App │
│ │
│ Billing │
│ Users │
│ Orders │
│ Reports │
│ Integrations │
└────────────────────────────┘
Самый очевидный способ добавить AI — установить SDK выбранной модели прямо внутрь приложения:
Legacy App
↓
OpenAI / Claude / Gemini
Иногда это нормально. Если проект поддерживается, стек позволяет нормально работать с API и задача маленькая, нет никакого архитектурного закона, запрещающего вызвать LLM прямо из старого приложения.
Но по мере роста AI-функциональности внутри начинают появляться вещи, которые legacy изначально вообще не должен был знать:
prompts
model routing
embeddings
vector search
agent state
tool definitions
token budgets
LLM retries
evals
guardrails
И тогда мне больше нравится отдельная граница.
┌─────────────────┐
│ AI Layer │
│ │
│ LLM │
│ RAG │
│ Agents │
│ MCP / Tools │
└────────┬────────┘
│
Adapter / API
│
┌────────▼────────┐
│ Legacy App │
└─────────────────┘
Legacy продолжает отвечать за то, что умеет хорошо: business rules, transactions, данные и существующие workflows.
AI layer отвечает за probabilistic часть.
AWS в своём Agentic AI Lens рекомендует примерно такую же границу: существующие системы подключаются через adapters и abstraction interfaces, а agent получает уже ограниченный tool contract вместо прямого знания внутренних legacy-протоколов. Там же на adapter layer предлагается применять rate limiting и access control.
Мне эта архитектура нравится ещё по одной причине. AI меняется значительно быстрее legacy.
Сегодня одна модель.
Через полгода другая.
Сегодня простой completion.
Завтра agent.
Послезавтра часть workflow вообще снова становится deterministic.
Если AI layer отделён от основной системы, всё это можно менять, почти не трогая ядро.
Adapter важнее самой модели
Представим старую CRM, которой пятнадцать лет. У неё есть внутренний endpoint:
/customer/get.php?id=123
или вообще SOAP, XML-RPC, database procedure и что-нибудь ещё из истории enterprise-разработки.
Agent совершенно не обязательно должен об этом знать.
Ему гораздо полезнее предоставить нормальный контракт:
get_customer(customer_id)
find_orders(customer_id)
create_support_note(customer_id, text)
Внутри adapter может происходить всё что угодно:
AI Agent
↓
get_customer()
↓
Adapter
↓
SOAP
↓
Legacy CRM
Если legacy вообще не имеет нормального API, adapter становится особенно ценным. Можно постепенно обернуть несколько действительно необходимых операций, не пытаясь одновременно API-фицировать весь проект.
AWS в 2026 году показывал похожий modernization pattern, где agentic AI capability добавляется к существующему приложению через внешний gateway вообще без изменения исходного кода legacy-приложения.
По сути это старый добрый anti-corruption layer, просто новым потребителем стал AI.
И если у компании уже появляется несколько AI-клиентов, поверх такого adapter layer можно использовать MCP. Тогда legacy вообще остаётся за границей:
Claude ──┐
Cursor ──┼→ MCP Server → Adapter → Legacy
Agent ──┘
Внутренняя система по-прежнему ничего не знает про MCP или LLM.
Это мне кажется здоровой архитектурой.
Сначала read, потом write
Я бы вообще разделил внедрение AI на несколько уровней риска.
Первый:
AI читает
Второй:
AI предлагает изменение
Третий:
AI выполняет изменение после подтверждения
И только потом:
AI выполняет ограниченные действия самостоятельно
Переходить сразу на последний уровень обычно нет никакой необходимости.
Допустим, у нас есть support system. Можно начать с того, что AI собирает информацию о клиенте и готовит draft ответа.
Customer data
↓
AI
↓
Draft
↓
Operator
Следующая версия может предложить:
добавить тег
refund_requested.
Но применять его будет человек.
После накопления нормальных данных о качестве можно разрешить agent самостоятельно выполнять несколько безопасных операций:
add_tag
create_internal_note
assign_category
А условный:
refund_payment
по-прежнему оставить за человеком или deterministic workflow.
Мне нравится такой подход потому, что autonomy здесь становится не свойством технологии, а уровнем доверия к конкретной операции.
Не бывает просто:
наш агент автономный.
Гораздо полезнее:
эту операцию он может выполнять самостоятельно, эту — только после approval, а эту вообще никогда.
Не надо отдавать модели business invariants
Допустим, есть правило:
возврат возможен только в течение 30 дней и только для transaction определённых типов.
Можно передать это правило в prompt и попросить LLM решать:
should_refund(transaction)
Возможно, даже будет работать довольно хорошо.
Я бы всё равно так не делал.
Если правило можно выразить обычным deterministic кодом:
$refundPolicy->canRefund($transaction);
именно код и должен принимать это решение.
AI может понять запрос пользователя:
мне списали деньги два раза, хочу вернуть одно списание.
Может найти transaction.
Может определить intent.
Может собрать аргументы для операции.
Но окончательная проверка должна пройти через существующую business logic:
User
↓
LLM
↓
refund_payment(transaction_id)
↓
Application Service
↓
RefundPolicy
↓
Payment System
То есть tool не должен быть обходным путём вокруг архитектуры.
Наоборот, хороший AI integration layer должен вести модель внутрь тех же application services и policies, которыми пользуется обычный интерфейс.
Это особенно важно в legacy, потому что именно внутри старой логики часто спрятаны те самые десять лет edge cases.
Если нужен только контекст, legacy вообще можно почти не трогать
Многие AI-сценарии не требуют выполнения операций. Им нужны данные.
Например есть большая внутренняя knowledge base, старые инструкции и документы пользователей. Не обязательно учить legacy каждый раз разговаривать с LLM.
Можно построить отдельный retrieval pipeline:
Legacy / Documents
↓
export / CDC / connector
↓
indexing
↓
embeddings
↓
vector search
↓
AI
Legacy остаётся authoritative source.
Vector database становится производным индексом.
Если завтра Qdrant исчезнет, данные не потеряются — индекс можно построить заново.
Это очень важное разделение.
Я бы избегал архитектуры, где после появления AI vector database внезапно начинает считаться новой главной базой продукта. Embeddings, chunks и summaries — обычно derived data. Источник истины по-прежнему находится в основной системе.
То же относится к RAG. Его задача — помочь модели найти нужный кусок информации. Он не должен незаметно превращаться в альтернативную бизнес-модель данных.
А если у legacy нет API вообще
Это довольно распространённая ситуация.
Система может быть настолько старой, что единственным нормальным интерфейсом остаётся database или набор файлов.
Для чтения вариантов всё равно довольно много:
- read replica;
- CDC;
- scheduled export;
- event stream;
- materialized view;
- отдельный reporting database;
- безопасный read-only database adapter.
Для первой AI-функции этого часто достаточно.
С записью я был бы намного осторожнее.
Прямой:
AI → SQL → production database
выглядит очень заманчиво, особенно во время prototype. Вся система доступна, никакого API писать не надо, агент может сделать практически что угодно.
Именно поэтому в production я бы этого почти всегда избегал.
Database schema не является полноценным business API. Constraint в таблице — только маленькая часть реальных правил системы. Часть логики может находиться в application code, часть — в events, часть — в другом сервисе.
AI может технически выполнить:
UPDATE orders SET status = 'refunded';
и создать состояние, которое обычное приложение вообще не умеет производить.
Поэтому write path лучше специально проектировать.
Если API нет — написать узкий application facade для нескольких разрешённых действий всё равно безопаснее, чем разрешить agent напрямую менять system of record.
Strangler pattern хорошо подходит и для AI
Strangler Fig появился задолго до LLM и обычно используется для постепенной замены монолита: перед старой системой появляется façade, затем отдельные capabilities постепенно переносятся в новые компоненты. AWS и Microsoft рекомендуют этот подход именно для incremental modernization, потому что старое приложение продолжает работать во время миграции, а функциональность вытесняется по частям.
AI можно внедрять примерно по той же логике.
Не:
Legacy
↓
REWRITE
↓
AI-native platform
А:
┌→ Legacy workflow
User → Facade
└→ New AI-assisted workflow
Например старый support search продолжает работать.
Рядом появляется новый semantic search.
Потом AI summary.
Потом recommendation.
Потом несколько controlled actions.
Если новая система не работает, traffic или workflow можно вернуть обратно.
Google в свежем материале о mainframe modernization тоже делает упор на iterative modernization вместо выбора между вечным сохранением старого mainframe и большим единовременным rewrite. Они отдельно отмечают, что modernization — это не просто задача code-to-code conversion.
Мне кажется, для AI это особенно актуально.
Модель через год почти наверняка изменится.
А бизнес не должен ждать год, пока мы перепишем ERP, чтобы попробовать summarization.
Shadow mode гораздо полезнее красивого demo
На prototype всё обычно выглядит великолепно.
Есть двадцать заранее выбранных запросов.
Agent на восемнадцать отвечает правильно.
Демо проходит.
Потом появляется production.
Я бы поэтому до автоматизации действий старался запускать AI в shadow mode.
Допустим, оператор вручную классифицирует ticket. AI параллельно делает то же самое:
Ticket
├→ Human → category
└→ AI → category
AI-ответ пока ни на что не влияет.
Через несколько недель можно посмотреть реальные данные:
- где совпали;
- где ошиблась модель;
- какие категории путаются;
- какие данные ей не хватало;
- что происходит на редких кейсах.
То же самое можно делать для recommendations или решений.
Сначала AI говорит:
я бы сделал X.
Система продолжает работать по старому алгоритму.
Потом сравниваем.
Так намного проще понять реальную цену ошибки до того, как ошибка начнёт что-то менять.
Для write-операций нужны обычные скучные гарантии
Если мы всё-таки разрешаем agent менять систему, вокруг каждого важного tool появляются знакомые требования.
Idempotency.
Authorization.
Rate limits.
Timeouts.
Audit log.
Validation.
Transactional boundaries.
Retry policy.
Human approval.
Например tool:
create_refund(transaction_id, amount)
не должен внутри просто отправлять HTTP request в payment provider.
Он должен пройти через обычный application service, где проверяются permissions, policy, idempotency key и текущее состояние transaction.
Кроме того, желательно сохранить:
who initiated
which agent/model
which tool
arguments
result
timestamp
approval
Не потому, что AI какой-то особенно подозрительный пользователь.
Просто теперь внутри системы появился новый actor, который способен принимать решения быстрее человека и иногда делать это непредсказуемо.
AWS в своих guidance для agent integration отдельно рекомендует ограничивать legacy interfaces через adapters, access control и rate limits. OWASP для agentic systems добавляет к этому least privilege, allowlisting разрешённых действий, human approval для необратимых операций и audit trail.
В общем, все скучные engineering practices внезапно снова оказываются очень полезными.
Отдельно нужно проектировать отказ AI
Если AI стал частью продукта, полезно заранее ответить на вопрос:
Что произойдёт, если завтра модель недоступна?
Особенно если используется внешний provider.
Для вспомогательной функции ответ простой:
AI unavailable
↓
показываем старый интерфейс
Гораздо хуже, если без ответа LLM перестаёт создаваться заказ или обрабатываться платёж.
Мне нравится правило: чем критичнее business flow, тем меньше его correctness должно зависеть от probabilistic external service.
AI может помогать принять решение.
Но там, где возможно, core transaction лучше оставить deterministic.
Для некоторых новых AI-native продуктов это, конечно, невозможно. Но в legacy мы обычно начинаем с уже работающей системы, и ломать её устойчивость ради новой возможности довольно странно.
Что я бы точно не делал
Первое — не начинал бы AI integration с большого rewrite. Если система действительно требует модернизации, это отдельная задача с собственным business case. AI может помочь её ускорить, но связывать две большие трансформации одной зависимостью рискованно.
Второе — не давал бы модели прямой write-доступ к production database только потому, что так проще сделать prototype.
Третье — не переносил бы business rules в prompt. Prompt удобен для probabilistic reasoning, но deterministic invariant лучше оставить кодом.
Четвёртое — не отправлял бы в LLM весь доступный контекст. Legacy-система может содержать огромное количество данных, но Context Engineering всё равно остаётся Context Engineering: модели нужна релевантная часть.
Пятое — не выдавал бы agent permissions обычного backend-service. Если ему нужны три операции, значит он получает три операции.
Шестое — не строил бы систему без fallback. AI layer должен уметь отказать так, чтобы legacy продолжал выполнять основную работу.
И последнее — не оценивал бы внедрение по принципу:
модель отвечает вроде хорошо.
Нужно измерять конкретный workflow: время выполнения задачи, accuracy, количество human corrections, cost, latency и реальные ошибки.
Как бы я строил внедрение по шагам
Если собрать всё вместе, у меня получился бы примерно такой путь.
Сначала выбрать один конкретный workflow, где AI способен дать понятную ценность.
Потом разобраться, какие данные и business capabilities ему для этого нужны. На этом этапе AI можно использовать и для reverse engineering самого legacy.
Дальше построить отдельную integration boundary:
AI
↓
Adapter / API / MCP
↓
Legacy
Первую версию по возможности оставить read-only.
После этого запустить её на реальных данных, желательно в assistive или shadow режиме, и начать собирать измерения.
Если нужно выполнение действий, добавить несколько узких tools, которые используют существующую application logic и имеют least privilege.
Только после накопления доверия увеличивать autonomy для конкретных операций.
Получается примерно такая лестница:
1. Understand
2. Read
3. Recommend
4. Act with approval
5. Act autonomously within limits
Мне нравится, что на каждом шаге уже можно получить пользу.
Не нужно ждать окончания трёхлетней модернизации.
Вместо заключения
Legacy иногда воспринимается как препятствие для AI, потому что старая система не имеет красивого REST API, написана не на том языке и вообще появилась задолго до современных моделей.
Но LLM на самом деле не особенно важно, на чём написан core system.
Ей нужен понятный интерфейс.
Если между старой системой и AI провести нормальную границу, внутри legacy по-прежнему могут жить SOAP, stored procedures, cron jobs и двадцатилетняя business logic. Снаружи агент будет видеть пять аккуратных tools.
И мне кажется, именно так AI интереснее всего внедрять в зрелые системы.
Не пытаться сначала сделать старый проект современным.
Не превращать LLM в новую business logic.
Не переписывать то, что уже десять лет приносит компании деньги.
А постепенно создать вокруг существующей системы слой, через который AI получает ровно столько данных и возможностей, сколько ему действительно нужно.
Иногда лучшая модернизация начинается не с переписывания старого кода.
А с хорошей границы вокруг него.