AI-база: модели, агенты, агентные механизмы

от автора

Привет, хабр, меня зовут Кияшева Екатерина. Вообще я из QA, но сегодня сделаю шаг в сторону и разберу AI‑базу.

За последний год встречалась масса литературы об AI, она, или теоретическая — не ясно, как это пощупать, или углубленная в одну тему — не сразу ясно какую задачу решает. Эта статья — обзор теоретической базы, но с прикладным характером. 

На ур. QA важно знать «как эта штука работает», чтоб осмысленно применять паттерны тест‑дизайна. На человеческом ур. надоела маска «волшебства» вокруг ИИ, хочется смахнуть ее и рассмотреть инструмент предметно: как устроен, какой бывает, через что с ним работать без VPN из России. 

Модели

Определения и классификация

Модели бывают:  

  • языковые; 

  • аудио; 

  • компьютерное зрение (Computer Vision — CV); 

  • мультимодальные. 

Как ясно из названий, они отличаются по типу модальностей, с которыми работают. Языковые — берут на вход текст, аудио — звуковую дорожку, CV — картинку. Мультимодальные умеют работать больше, чем с одним типом информации. 

Примеры:

  • Оцифровка текста с фотографий — мультимодальная (CV + Языковая);

  • Генерация видео по фото — мультимодальная (CV + Аудио/Видео);

  • Генерация картинки по текстовому описанию — мультимодальная (Языковая + CV);

  • Генерация программного кода по текстовому описанию — языковая модель (LLM).

Отдельное направление работы с моделями — их обучение (Model Learning — ML). Берем данные, семейство функций по которым будет рассуждать модель, измеритель ошибок этих рассуждений, алгоритм отбора наилучшего рассуждения, запускаем процесс отбора. На тему ML есть отличная серия статей от автора @ysrgsyn, излагает доступно, по полочкам, небольшими частями. 

Большие языковые модели (Large Language Model — LLM), всем известные GPT, Gemini, DeepSeek, Claude, Kimi, Qwen, Llama, и т.д. — предобученные языковые модели от разных производителей. 

Классифицировать модели можно по функциям и по возможностям:

  • Функциональную классификацию удобно смотреть на Hugging Face: это “старая” площадка, задуманная, как аналог GitHub. Создана, когда модели имели свою специализацию: генерировать, суммаризировать, анализировать, работать с таблицами и т.д. Эти и многие др. функции со временем вобрали в себя LLM.   

  • Инструментальную классификацию удобно смотреть на Ollama: более новая площадка, работает как менеджер моделей. В ее реестре есть всего три фильтра:

    • thinking — LLM функция мыслительного процесса Chain-of-Thought. Когда модель думает по цепочке, проверяет каждый вывод, прежде чем дать ответ. 

    • tool — LLM функция вызова действия. Когда модель самостоятельно вызывает выданные ей инструменты, например пушить код или открывать браузер. 

    • embeddings — тип модели, нацеленный на извлечение смыслов из текста. В отличие от LLM — эти модели возвращают на выход не текст, а координаты смысла. 

Выбор модели

На сегодня есть целая линейка моделей с полным набором функциональностей и инструментов. Они конкурируют между собой: по интеллекту, стоимости, стабильности, ресурсоемкости. Ситуация непрерывно меняется, так что невозможно сказать, какая модель лучше. Но можно отслеживать динамику развития по лидербордам: следить за трендами изменений последних лет, оценивать на что упирает производитель; подбирать модель под свои нужды, опираясь на прогноз. 

Лидерборд

Тип модели

Фокус сравнения

Artificial Analysis

Генеративная

Бизнес-ориентированный. Динамика инвестиций в модели, их развитие, стоимость токенов, интеллектуальность, предсказуемость и т.д. Информация, чтобы подобрать баланс между стоимостью и возможностями модели.

benchlm.ai 

Генеративная

Прикладной. Рейтинг моделей в разрезе способностей — Agentic, Coding, Multimodal, Reasoning и т.д. Информация, чтобы подобрать баланс между стоимостью, скоростью вместительностью в контексте прикладной задачи. 

MTEB

Векторная

Функциональный. Сравнение моделей по качеству понимания смыслов. Информация, чтобы подобрать баланс между точностью поиска, скоростью обработки и объемом векторных данных для построения систем RAG.

Агенты

Агентные механизмы

Итак, современные нейронки умеют мыслить, кодировать, выполнять любые команды за человека, полностью самостоятельно. Рассмотрим подкапотное пространство: что, кроме модели, необходимо для этой деятельности. 

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

  • отправляет запрос,

  • записывает ответ в историю диалога,  

  • на каждом круге дополняет историю последним запросом юзера и ответом LLM, 

  • отправляет новый запрос с накопленной историей и доп. инструкциями — контекстом

В простом виде взаимодействие с генеративной моделью выглядит как-то так:

Пользователь написал свой запрос (user-prompt) агент взял запрос + контекст, сформировал все в  промпт  и отправил LLM сгенерировала ответ агент, получив ответ, пополнил контекст и вернул ответ пользователю. 

О правилах и практиках составления промтов есть отличный ресурс Prompt Engineering Guide. Там доступно и по шагам излагаются паттерны промптинга, актуальные для любой модели. Паттерн-исключение “Chain-of-Thought”: неактуален и даже вреден в работе с thinking моделями, поскольку механизм “думать по шагам” в них встроен.  

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

Задача агентного механизма

  • проконтролировать заполненность контекстного окна, чтобы не получить ошибку переполнения вроде ‘400: «Request payload size exceeds the limit’,

  • сформировать такой промпт, чтобы ответ модели был предельно уместным с учетом предыдущего контекста. 

Далее я буду использовать примеры кода, надерганные из личных экспериментов. Это фрагменты и винегрет из разных библиотек. Прошу воспринимать, как псевдокод, только для передачи мысли. 

Генеративная функция

Уместность ответа регулируется не только контекстном, но и параметрами. Через параметры можно управлять ресурсоемкостью и софт характеристиками ответа. Рассмотрим типовой запрос в LLM с параметрами ответа. 

Пример работы с параметрами
# Формируем историю сообщенийmessages = [    {"role": "system", "content": "<системная инструкция>"},]# Получаем и добавляем в историю user-promptquery = "<запрос пользователя>"messages.append({"role": "user", "content": query})# Создаем финальный промпт с параметрами для запроса в LLMpayload = {    "model": "deepseek-v4-flash",       "messages": messages,                "stream": True,                                               "options": {        "temperature": 0.1,                 "top_k": 400,                       "top_p": 0.5,                        "min_p": 0.05,                                "repeat_penalty": 1.1,                    "presence_penalty": 0.0,               "frequency_penalty": 0.0,              "num_predict": 2048,                     "stop": ["Пользователь"]                         }}# Отправляем финальный промпт в LLMtry:    response = requests.post(        "https://ollama.com/api/chat",         headers=headers,         json=payload,         timeout=120    )# Извлекаем ответ модели и добавляем в историю    data = response.json()    answer = data["message"]["content"]    messages.append({"role": "assistant", "content": answer})

UX-параметры:

  • stream: True — модель будет набирать ответ в режиме реального времени, при false вернула бы его целиком;

  •  Num_predict (или max_token): 2048 — ограничение длины ответа (токенов, шт.), позволяет управлять стоимостью работы с моделью; 

  • stop: [«Пользователь»]  — модель остановит набор и отправит ответ, как только напишет стоп-слово. Здесь дополнительная защита от бесконечной переписки самой с собой. 

Модель набирает ответ, последовательно выбирая токены с наибольшей вероятностью. Вероятность — это производная величина, числовая оценка того, каким именно должно быть продолжение. 

Вычисляется вероятность примерно так: сначала модель определяет смысловой “вес” токенов (логиты), потом Softmax-функцией пересчитывает вес в вероятности. По ходу вычисления, можно подкручивать веса, так чтоб модель увеличивала и уменьшала диапазон вероятных продолжений. 

Штраф-параметры (подкручивают логиты): 

  • repeat_penalty: 1.1 — “мягкий цензор”: уменьшает вес слов, уже встречавшихся в контексте, в 1,1 раза. При repat_penalty = 1, никакого воздействия, при repat_penalty меньше 1 слово-дубликат увеличивает вес; 

  • presence_penalty: 0.0 — “штраф за факт”: уменьшает вес слова-дубликата на 0,1;

  • frequency_penalty: 0.0 — “штраф за частоту”: уменьшает вес слова-дубликата пропорционально количеству повторений. Если слово встречается 5 раз, штраф будет 0,5.

Параметр креативности (подкручивает логиты):

  • temperature: 0,1 — управляет “азартом”: здесь модель заостряет вероятности выбора, возводит их в 10 степень (=1/0,1), так что разница между вариантами ответов становится более видимой. При температуре больше 1 наоборот бы сглаживала в сторону уравнения. 

Параметры адекватности (фильтрует вероятности):

  • top_k: 400 — ограничивает выборку “штуками”: модель смотрит только на 400 самых релевантных вариантов;

  • top_p: 0.5 — ограничивает выборку “качеством”: оставляет варианты, чья суммарная вероятность достигает 50%;

  • min_p: 0.05 — отсекает «мусор»: выбрасывает токены, вероятность которых меньше 5% от вероятности самого лучшего варианта.

Параметры работают друг за другом, сначала группа штрафов, потом температура, и в конце осечка по адекватности. 

Комбинации на примерах: top_p: 0,1 и temperature:2 — вернет самые необычные ответы из самых адекватных; temperature:0 вернет самый логичный ответ; temperature:1,2 и min_p: 0,4 вернет что-то на грани безумия, но без откровенной дичи.  

MCP: выполнение действий 

LLM с функцией tool, умеет вызывать действие. Для этого программируем в агентной прослойке обертки для выполнения действий — тулы,  передаем в модель набор тулов вместе с промптом. В ответ нейронка сама будет выбирать инструмент и возвращать команды для активации того или иного действия. 

MCP (Model Context Protocol) — способ пакетировать тулы в комплекты: унифицированные, переносимые, безопасные. Собираем комплект, запускаем на сервере и юзаем его различными моделям по API. 

Пример работы механизма LLM tool
# Формируем список доступных инструментов для LLM с call-to-action инструкциейtools = []for t in mcp_tools:    tools.append({        "type": "function",        "function": {            "name": t["<название инструмента>"],            "description": t.get("<инструкция, когда использовать>"),            "parameters": t.get("inputSchema", {"type": "object", "properties": {}, "required": []}),        },    })# Формируем финальный промпт со списком доступных инструментовpayload = {    "model": "deepseek-v4-flash",    "messages": messages,    "tools": tools,            # Передача перечня инструментов    "stream": False,    "options": {        "temperature": 0.1,         "num_predict": 2048,         "num_ctx": 16000    },}# Отправляем финальный промпт в LLMtry:    resp = requests.post(        "https://ollama.com/api/chat",         headers=headers,         json=payload,         timeout=120    )    resp.raise_for_status()    msg = resp.json()["message"]    # Если модель вызвала инструмент - исполняем его    if msg.get("tool_calls"):        for tc in msg["tool_calls"]:            name = tc["function"]["name"]            args = tc["function"]["arguments"]            result = mcp_client.call_tool(name, args) 

RAG: внешняя память и семантический поиск

RAG (Retrieval-Augmented Generation) — LLM дает ответы не из своей нейросети, а какие-то конкретные, из кастомной базы знаний. Актуально, когда  база знаний существенно больше, чтоб влезть в один промпт целиком и существенно отличается, чтобы удовлетвориться предобученным ответом LLM.

Общая схема работы: агентный механизм получает запрос юзера делает выборку из БД добавляет в промпт результат выборки отправляет обогащенный промпт в генеративную модель.

Центральное звено в схеме занимает векторная база данных. База может быть любой, но векторная получила большое распространение благодаря функции семантического поиска. Данные в ней хранятся в виде коллекций, есть поддержка функции “перевода” текста в смыслы (эмбеддинг). Рассмотрим типовую схему данных векторной БД.

  • Ids — идентификатор элемента в коллекции;

  • Embeddings — массив чисел, смысловой вектор элемента, чтобы искать кусок текста по смыслу;

  • Metadatas — служебная информация, любой набор маркеров текста, чтобы искать текст по кастомным значимым признакам;

  • Documents — исходный кусок текста сохраненный в БД, именно он эмбедится в вектора и потом передается в LLM в виде промпта. 

Непосредственный перевод текста в смыслы выполняет векторная модель. На вход она получает текст в виде токенов определяет координаты этого текста на каждой своей оси возвращает массив координат (вектор). 

Например, на вход имеем слово “кот”. Векторная модель ищет  его в осях координат:

  • Живое — неживое, 

  • Пушистое — гладкое,

  • Сладкое — соленое,

  • Мягкое — твердое,

  • И т.д.

Размерность модели = количество измерительных осей. Чем больше размерность, тем больше признаков, по которым модель будет оценивать слово. 

Работа с векторной БД глобально состоит из 2 частей:

1. Индексация: порезать исходный текст, перевести в смыслы и сохранить в базу данных
# Режем текст на куски, каждый кусок - один элемент коллекции в ChromaDB…..# Создаем/вызываем коллекцию и передаем в нее функцию эмбеддинга   embed_fn = LocalEmbeddingFunction(embed_model)    chroma_client = chromadb.PersistentClient(path=vector_store_path)    try:        collection = chroma_client.get_collection(name=collection_name, embedding_function=embed_fn)        logger.info("   Reusing existing collection '%s'", collection_name)    except Exception:        collection = chroma_client.create_collection(            name=collection_name,            embedding_function=embed_fn,            metadata={"hnsw:space": "cosine"},        )        # Добавляем элементы в коллекцию, эмбеддинг происходит автоматическиcollection.add(ids=ids, metadatas=metadatas, documents=documents)
2. Поиск: находить в бд куски по смыслу или тексту, и подставлять в промпт.
# Получаем запрос пользователяquery = "<текст вопроса пользователя>"n_results = 600      #орграничитель первичной выборки в шт.# Эмбеддим запрос пользователя и выбираем n_result с наиближайшими векторамиresults = collection.query(query_texts=[query], n_results=n_results, include=["documents", "distances"])# Фильтруем полученную выборку по дистанции м-у векторами запроса и выборки# отбрасываем все, что больше max_distance filtered_docs = [] for doc, dist in zip(results['documents'][0], results['distances'][0]):  if dist <= max_distance:     filtered_docs.append(doc)# Фильтруем вектора в оставшейся выборке по релевантностиfinal_context = filtered_docs[:top_k]# Добавляем в итоговый промпт текст Documents из выборкиcontext_text = "\n\n--- {{заголовок ответа}} ---\n\n".join(final_context)prompt = f"""КОНТЕКСТ:{context_text}ВОПРОС:{query}"""# Отправляем промпт в LLM...

NLP: дешифровка подтекста

NLP (Natural Language Processing) — извлечение из текста непрямых посланий. Возможно замечали, как  LLM меняет тон разговора, когда ей пишешь весело или грубо — это проявление NLP.

Небольшой пример из жизни: на скрине финальное сообщение из цепочки запросов о стандартах ISO (perplexity).

В сообщении нет прямой информации, только подтекст. Что тут видно: подтекст считали LLM и агентный механизм: 

  • LLM пересобрала смысловые акценты и выдала, наконец, точный ответ,

  • Агентный механизм проверил культуру взаимодействия.

Базовая утилитарная функция NLP в агентах  — собирать данные о пользователе: как зовут, где находится, чем занимается, что умеет, чем интересуется, и т.д. Все это позволяет формировать по-настоящему персонифицированные промпты, так чтобы LLM буквально видела, кому отвечает. 

Общая схема работы: агентный механизм парсит сообщение юзера извлекает из сообщения важный подтекст маркирует его и сохраняет в базу данных берет из базы информацию с наибольшим весом и добавляет ее в промпт в виде инструкции отправляет промт в LLM. 

Центральное звено в схеме занимают NLP-экстракторы: паттерны и NER модели, которые могут разбивать и нормализовать текст, маркировать в нем важную информацию о пользователе. 

Пример работы с экстракторами
# Инициализируем NER нейронку Natashasegmenter = Segmenter()              # функция разбивки на предложения и словаmorph_vocab = MorphVocab()           # словарь словоформemb = NewsEmbedding()                # функция-эмбеддер текстаmorph_tagger = NewsMorphTagger(emb)  # морфологический словарь ner_tagger = NewsNERTagger(emb)      # NER экстракторNER_TYPES = {"PER": "person", "ORG": "company", "LOC": "place"} #словарь маркеров# Получаем запрос пользователяtexts = [    "Привет! Меня зовут Маша, я — frontend-разработчик.",    "Работаю в Яндексе, интересуюсь React.",    "Сейчас делаю проект Grafika.",    "React — это библиотека для UI.",    "Кстати, переезжаю в новый офис, буду ближе к команде.",]# Разбираем и маркируем запрос по NER признакамfor text in texts:    doc = Doc(text)    doc.segment(segmenter)          # разбиваем текст на слова    doc.tag_morph(morph_tagger)     # извелкаем ключевые слова     doc.tag_ner(ner_tagger)         # ищем слова про персону, компанию, локацию    seen = set()    entities = []    for span in doc.spans:               # перебираем все слова        ntype = NER_TYPES.get(span.type) # получаем NER маркер слова        if not ntype:            continue        span.normalize(morph_vocab)      # приводим слово к начальной форме        key = (span.normal.lower(), ntype)         if key not in seen:              # дополняем массив словом и его маркером            seen.add(key)            entities.append({"name": span.normal, "type": ntype})

В качестве хранилища — используются графовые базы данных. В отличие от реляционных (SQL) и документ-ориентированных (NoSQL), они умеют в нелинейные связи: позволяют связывать между собой объекты любого типа и легко доставать эти объекты по коротким описаниям связей.

Ниже пример-представление статьи “Чит-лист функционального тестирования, памятка тестировщику” в графовой базе. Здесь:

  • “Статья” главное звено, от нее идут связи к векторам — слоям тестирования: Данные, Операции, Функциональности, Технология, 

  • “Вектора”  связаны с сетами: группами тестов с общим признаком в конкретном слое,

  • “Сеты” связаны с “Тестами”: конкретными проверками внутри сета

  • “Теги”  воспроизводят нелинейные связи к любым объектом из иерархии.

Контекст

Резюмируем:

  • LLM живет одним запросом, она генерирует ответ ровно на тот запрос, какой получила, каждый раз, как в первый раз,

  • Уместность ответов и эффект связанного диалога создается через промпт, который обогащается после каждого взаимодействия (запроса — ответа),

  • Промпт — это инструкция с запросом юзера И контекстом (информацией о юзере, историей диалога, кастомными данными юзера, параметрами генерации ответа, системными инструкциями для LLM о форме, тоне и ограничениях ведения диалога).

Промпт должен быть достаточно точным, чтобы создавать эффект связанного процесса и не слишком большой, чтобы уместиться в контекстное окно модели. 

Рассмотрим несколько известных подходов сокращения длины контекста: 

  1. Buffer Memory — хранит последние N сообщений истории диалога, при достижении границ контекстного окна старая история стирается в пользу новой. 

  2. Summary Memory — раз в N сообщений суммаризирует историю диалога в краткий пересказ. За счет этого может хранить более длинную историю, но не очень конкретную — детали и полутона стираются.  

  3. Buffer + Summary — свежую историю диалога хранит в исходном виде, а старые сообщения суммаризирует в конспект. Компромисс между длинной контекста и его точностью. 

  4. Vector Memory — сохраняет ключевые участки диалога в векторную базу данных, по запросу пользователя может найти их семантическим поиском и добавить в контекст фрагментарно. 

  5. Graph Memory — управляет данными о пользователе через структуру связей. Извлекает характеристики юзера из подтекста, сохраняет факты в графовую БД, связывает их между собой и ранее добавленным фактами, назначает связям веса. Чем актуальней информация — тем больше связей с бОльшим весом она имеет. В промпт отправляет факты с наибольшим весом. Для поддержания актуальности — у фактов, в которым долго не обращались, переписывает веса в меньшую сторону или совсем обрывает связи. 

  6. Episodic vs Semantic — ранжирует данные о пользователе на постоянные характеристики и события. Постоянные характеристики всегда имеют высокий вес, событийные данные со временем теряют в весе и перестают добавляться в контекст. 

Агентное ПО

Сейчас наблюдается чехарда с терминами, поэтому здесь изложу свою логику и классификацию. Споры, вопросы, уточнения — приветствуются. 

Агентное ПО — программа, которая взаимодействует с моделью и организовывает контекст. Глобально выделяется 2 класса:

  • бизнес-приложения — модель подключается для выполнения бизнес — функции, например записи в парикмахерскую, консультирование, на простые служебные операции. 

  • сервисные “приложения” — модель подключается для автоматизации производственных процессов, разработки другого ПО или других агентов. Слово “приложение” здесь условно, поскольку это ПО активно прорастает в операционные системы и железо.

Оба типа под капотом содержат агентные механизмы, различаются по цели использования, арсеналу и сложности агентных механик. Отдельного внимания требуют сервисные приложения.

Тип 

Комментарии

Примеры 

Чат  асисстент

Чаты с функциями настройки диалога, внешней памятью RAG, действиями в интернете. 

Автоматизируют работу с информацией: ее поиском, анализом, преобразованием, позволяют кастомизировать контекст под себя. 

Чат-ассистенты 

Perplexity 

Конструктор-среда 

Среда разработки в виде конструктора. Содержит пред подготовленные модули-коннекторы для интеграции с нейронкой, различными корпоративными системами и между собой. 

Упрощает автоматизацию производственных процессов: проверку, преобразование, передачу информацию по цепочке. Действия реализуются через API. 

LangFlow 

n8n

CLI-среды

Открытая среда разработки, заточенная под создание агентов. 

Из коробки: подстраивается под пользователя (формирует контекст), содержит инструменты bash и web (MCP), знает известные языки разработки (механизм LSP). 

Позволяет:

донастраивать контекст (AGENTS.md, SKILLS, COMMAND)

подключать собственные инструменты (MCP, LSP)

чтобы создавать ролевую модель из  агентов и делегировать им любые операции. 

Арсенал позволяет делать любые агентные механизмы, разрабатывать агентный слой любой сложности. 

OpenCode 

Hermes 

IDE-среды 

Среда разработки с GUI интерфейсом, изначально заточенная  под написание кода.  Теперь IDE- среды перенимают все больше функциональностей CLI-среды и вероятно станут одним и тем же.

Cursor

OpenCode

Hermes 

Все сервисные приложения имеют собственную базу подключенных нейронок: покупаешь подписку на использование и получаешь доступ ко всему реестру моделей (из России и в некоторых инструментах почти ко всему).

Бизнес-приложениям необходимо специальное подключение. Нужно выбрать модель, определиться, где она будет хоститься, оценить на перспективу, сколько это будет стоить. Ценообразование напрямую зависит от хостинга: 

  • Локальное — требует покупки и обслуживания своих стоек, важна ресурсоемкость модели;

  • Облачное — плата за использование серверов хостера;

  • Онлайн  — оплата потраченных токенов.

Провайден

Комментарий

Hugging Face

Площадка — экосистема. 

Модели можно скачать, использовать удаленно на ресурсах Huggin Face или онлайн. Варианты использования зависят от провайдера и модели. 

Ollama

Площадка — аппстор.

Модели можно скачать в локаль или использовать облачное хранилище олламы. 

Open Router

Провайдер моделей. 

Подписка позволяет использовать модели из реестра онлайн, плата взимается за токены. 

ссылка на оригинал статьи https://habr.com/ru/articles/1054412/