От «Hello World» до AI-агента: что под капотом ChatGPT

Однажды я решил разобраться, как устроены AI-системы изнутри, ну и как положено программисту принялся писать код для работы с Ollama. Вот мои очередные записи в формате "мысли вслух" по итогам тестов.

0. Ollama и HttpClient

Для изучения основ LLM я решил не использовать готовые SDK, а подключить Ollama через обычный HttpClient на C#: var response = await client.PostAsJsonAsync( "ваш url", new { model = "llama3.1", messages = new[] { new { role = "user", content = "Привет!" } }, stream = false } ); Так я разобрался с Messages & Roles, Context Window, Conversation History, Streaming и System Prompt. Главное открытие: LLM не хранит состояние приложения. Контекст и историю нужно организовывать самостоятельно.

1. LLM - ещё не AI-агент

Модель умеет генерировать текст, но сама не может обратиться к базе данных или вызвать API. Для этого нужны Tools - инструменты, которые предоставляет приложение. Модель выбирает инструмент, backend запускает инструмент на выполнение и возвращает результат. Так обычный чат превращается в агента.

2. Function Calling - контракт между LLM и приложением

Например, я предоставляю модели функцию get_customer_orders. Модель формирует json c названием нужного инструмента, список аргументов, backend проверяет их, обращается к инструменту, а уже внутри прописана логика работы с базой и возврат результата. LLM только инициирует вызов. Исполнение и безопасность остаются ответственностью приложения. Также выяснилось, что разные локальные модели по-разному справляются, а некоторые и вообще не поддерживают Tool Calling. Так что это отдельный критерий выбора LLM.

3. История чата - не память

Передавать всю историю диалога при каждом запросе — плохо масштабируемый подход. Я разделил память на три уровня: Conversation History - текущий диалог. Long-term Memory - факты о пользователе. RAG - поиск информации во внешних документах. Хорошая память - не способность хранить всё, а умение находить нужное в нужный момент.

4. AI Agent Harness - инфраструктура вокруг модели

Самое интересное открытие - понятие Harness. Тогда, правда, еще не было устоявшегося термина Harness в русскоязычных комюнити, да и вообще мне больше по душе термин "обвязка" чем его англоязычный аналог. И так, Harness - это среда выполнения, которая управляет взаимодействием LLM с контекстом, памятью и инструментами. User | Backend | Agent Harness / | \ Memory Tools Context | Ollama | LLM Harness отвечает за Agent Loop, вызов инструментов, обработку ошибок и ограничения действий модели. Если LLM - мозг, то Harness - система, которая позволяет ему взаимодействовать с внешним миром.

5. Harness медленнее обычного AI агента.

Когда я реализовал Harness в несколько строк на основе готовой библиотеки, столкнулся с неожиданностью: агент стал работать в несколько раз дольше на аналогичных запросах, чем моя минимальная реализация. Harness добавляет абстракции, преобразование сообщений, middleware и дополнительные обработчики. В агентном сценарии накладные расходы накапливаются. А лишний вызов LLM может стоить гораздо дороже десятка запросов на бэкэнде. На этом этапе я потестировал концепции harness, попробовал основные паттерны разработки Ai агентов

Вместо вывода

В итоге я понял, что создать свой AI-чат - не значит просто подключить LLM и отправлять ей сообщения. Это лишь первый шаг, который помогает разобраться в механике работы модели и основных терминах. Настоящая сложность начинается тогда, когда нужно превратить генерацию текста в выполнение задач: дать модели инструменты, научить её работать с памятью, управлять контекстом, обрабатывать ошибки и контролировать весь цикл взаимодействия. Именно здесь появляется AI Agent Harness.

Ну а дальше UI. Там, кстати, уже есть стандарты описывающие взаимодействие UI и AI агента, голосом Леонида Каневского но это уже совсем другая история.