Являясь LLM активистом, регулярно обсуждаю всякое про новости\инструменты\тренды в ИИ. И к моему удивлению зачастую люди из IT не понимают базовых вещей в работе LLM и сопутствующих инструментах. Эта статья — переложение доклада на внутреннем митапе. Основная ее цель - обозначить как из сервера с моделью получаются полноценные агентные системы.
А начнем мы с того, что представим сервер с развернутой LLM, как рыбку Дори.

И у нее:
Есть долгосрочная память. Те самые веса, полученные в результате обучения в AI лабораториях за сумасшедшие деньги.
Не помнит, о чем говорила только что.
Не знает, что было в ближайшем прошлом. Например, последние новости.
Даже лапок нет. Поэтому она не может сделать ничего, о чем вы ее попросите.
А все потому, что она сервер, она не хочет хранить состояние, она хочет общаться вопрос-ответ.
И читатель справедливо заметит, что его пользовательский опыт работы с LLM отличается от написанного. Он вполне успешно поддерживает длительные диалоги с LLM, возвращается к ним спустя время и модель все помнит.
Чаты и хранение контекста в чате
И тут мы подходим к первому элементу поддержки нашей LLM - обвязка, обеспечивающая работу в режиме чата. Основная задача этой обвязки - сохранение контекста текущего общения, его обобщение и длительное хранение. Модель при этом работает в том же режиме, как и раньше, но у нас появляется кратковременная память, позволяющая поддерживать диалог. И вот тут всплывает окно контекста. Общаясь с LLM, мы чаще всего отправляем ей совсем небольшие по меркам окна контекста сообщения. Но забивать его будет все, что дальше будет упомянуто в статье.

Интернет поиск
Вторым важным шагом, который привнесли нам чаты - дополнение контекста через интернет поиск. То, что было изначально киллер фичей Perplexity и позже стало одним из базовых компонентов в работе любого чата. Любой запрос неплохо было бы начать с поиска в интернете, вероятно, там есть данные, которых нет в обучающей выборке или актуальные новости по теме. И вот наша LLM знает все, что случалось в мире в последнее время. Бонусом мы получаем фокусировку на том, что мировая общественность считает важным в запрашиваемой тематике и о чем активно пишет в интернете. При этом весь поиск также может работать в цепочке вызовов самой LLM, чтобы иметь возможность корректировать запрос и уточнять данные, которых не хватает.

Локальный поиск
Очевидно, что не все данные, которые нам могут понадобиться, есть в открытом интернете. Например, локальные базы знаний, внутренние регламенты, файлы, базы данных, корпоративный код и т.п. Тут возникает потребность искать еще и внутри своего периметра.
Именно при работе с приватными данными чаще всего и применяется RAG (Retrieval-Augmented Generation). В классическом понимании RAG — это когда мы извлекаем (Retrieval) релевантные куски текста из локальных векторных баз данных и подмешиваем (Augment) их в контекст перед отправкой в LLM.
Альтернативой RAG выступают Ресурсы (Resources). Концептуально они решают одну и ту же проблему — обогащение запроса локальными данными. Оба термина появлялись параллельно. RAG — как архитектурный подход к извлечению данных для модели, включающий векторизацию и поиск. Ресурсы — как перечень доступных источников.
Глобально и интернет-поиск, и локальный RAG, и работа с ресурсами решают одну задачу — Grounding («заземление» модели). Мы не даем модели галлюцинировать, подсовываем ей готовые факты, на которые она может опереться. Так мы даем нашей рыбке специфические знания.

Инструменты
И вот наша LLM уже помнит, о чем общалась, знает последние новости и понимает контекст текущей работы, читая локальные источники. С ней уже интересно общаться, она почти не говорит глупостей и не подменяет факты. Но хочется большего. Хочется, чтобы она что-то могла делать. Делать сама, а не просто давать рекомендации.
И тут появляются инструменты (tools). При этом, понятно, что LLM продолжает отдавать только текст, и сама ничего не делает. Мы описываем доступные инструменты в контексте запроса, и модель, если сочтет нужным, возвращает структурированный запрос на их вызов, а обвязка исполняет этот запрос. Так у нашей LLM появляются лапки.

Роль и типовая задача
Наша LLM будет вести себя примерно одинаково при любом использовании. У нее есть накопленный опыт (данные обучения), кратковременная память (Grounding). Но мы хотим, чтобы она обрела еще определенные паттерны поведения в разных контекстах. Когда мы используем ее для генерации кода, нам хочется меньше креатива, но простое и рабочее решение. Если мы пишем статьи с ее помощью, то мы можем захотеть придерживаться определенных стилевых приемов. Мы можем захотеть для решения определенных проблем сфокусировать LLM на одних нюансах, а другие игнорировать. Так появится постоянный контекст использования или системный промпт.

Самостоятельность и свобода воли
И вот уже вроде бы все хорошо. LLM понимает нас с полуслова, дает нужную информацию и делает что-то по нашему поручению. Но чего-то не хватает. Хочется, чтобы в типовых сценариях LLM не ждала от нас запроса в чате, а сама реагировала на происходящее. Передавала данные по цепочкам вызовов, строила планы и могла жить своей жизнью. И вот тут появляется часть оркестрации. Эта часть может быть элементом агентского CLI или чата. Может быть полноценным внешним оркестратором (n8n и подобные). Но именно это сделает нашу LLM самостоятельнее и отпустит ее в свободное плавание.
Обычно оркестраторы оборачивают в подобие классического цикла управления (PDCA) Планировать (Plan) -> Действовать (Do) -> Наблюдать за результатом (Check). Последний шаг Act, включающий улучшение процесса, почему-то в известных кейсах не включают, но как будто зря.
Отпуская нашу рыбку в свободное плавание, мы точно захотим обвесить ее действия валидацией, требованием явных разрешений на отдельные действия или изоляцией в окружении, где она не сможет натворить бед.

Один язык, чтобы управлять всеми
И вот мы уже готовы выделить LLM набор функций для работы с чем-то обособленным, например, с нашим ПО. Мы понимаем, что у нас есть основной контекст (system prompt), источники информации о его текущем состоянии (resources), есть ручки, за которые можно подергать (tools) и ситуации в которых эти ручки надо дергать. И мы понимаем, что у нас есть множество мест, куда мы хотели бы это прикрутить: IDE, чат, CLI. И тут к нам приходит унификация в виде протокола MCP. Он позволяет оформить работу с нашим ПО в виде MCP-сервера и подключать его ко всему, что может выполнять функции MCP-клиента (на сегодняшний момент это фактически любая обвязка вокруг LLM).
Сценарии автоматизации изначально были частью MCP, но в последних спецификациях удалены из него, для поддержания концепции, что MCP сервер должен работать без состояния.

Где мы сейчас
И вот наша рыбка-LLM, которая вначале пути казалась беспомощной и нелепой, обзавелась нехитрым окружением. И уже представляется всемогущим воплощением Искусственного Интеллекта из фантастических произведений прошлого столетия, которые пророчат человечеству скорую гибель под гнетом машин. Но мы понимаем, что внутри все та же милая глупышка Дори.

Модели сами по себе становятся умнее, и сами по себе умеют все больше (какое-то время назад с инструментами могли работать единицы моделей), со временем вокруг них все придумывают все больше обвязок, практик и протоколов, позволяющих делать невероятные вещи:
Фреймворки создания агентов (LangChain, CrewAI, Dify)
Готовые RAG компоненты (LlamaIndex)
Валидация результата работы LLM с помощью LLM
Открытые модели huggingface
Развертывание локальных моделей в один клик (Llama, LMstudio)
Универсальные и специализированные обвязки OpenCode, OpenClaw, AI-native IDE и т.п.
Страшно представить, как далеко мы еще сможем зайти со всем этим, а может, это уже потолок?
Но кажется, что первый этап становления технологии AI мы уже прошли.