TL;

Back to Base
Computer ScienceYouTube Videollmагентыинструменты

Agents Week 2026 | Лекция 1.2 Tools. MCP

Agents Week 2026, Школа анализа данных, Яндекс
Алёна Зайцева
ШАД
Published on Apr 6, 2026

Contributed by

Timurez

Source

Инструменты и Протокол Контекста Модели (MCP) для LLM-Агентов

#LLM #Агенты #Инструменты #ToolCalling #MCP #Архитектура #Разработка

Введение

На этой лекции мы углубимся в концепцию инструментов (tools) для больших языковых моделей (LLM) и рассмотрим, как они трансформируют LLM из простых чат-ботов в полноценных агентов, способных выполнять действия. Мы дадим формальное определение инструментам, разберем механизм их вызова (tool calling) и обсудим ключевые принципы их проектирования. Далее мы перейдем к более продвинутой концепции — Протоколу Контекста Модели (MCP), объясним его необходимость, архитектуру и решаемые проблемы. В конце лекции нас ждет практическое занятие, где мы добавим инструменты к агенту, разработанному на предыдущей практике.

Что такое Инструменты (Tools)?

Как было установлено ранее, LLM без инструментов обладают сильно ограниченными возможностями:

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

Для преодоления этих ограничений были разработаны инструменты. Обучение LLM использованию инструментов стало переломным моментом, позволившим перейти от простых чат-ботов к агентам, способным выполнять действия от собственного имени.

Формальное Определение Инструмента

Инструмент — это функция, предоставляемая LLM. Эта функция должна решать четко определенную задачу и содержать следующие компоненты:

  1. Описание: Текстовое описание того, что инструмент может выполнять.
  2. Вызываемая сущность: Код, который будет фактически вызван для выполнения конкретных действий.
  3. Аргументы: Список входных аргументов с указанием их типов.
  4. Выходные данные: Описание ожидаемых выходных данных с указанием их типов.

Как работает Tool Calling?

LLM по своей сути является генератором текста. Как же она может выполнять действия от собственного имени? Рассмотрим это на примере функции ListAllAirports, которая перечисляет все аэропорты в конкретном городе.

Пример:

  1. Инициализация: Модели сообщается, что она является полезным помощником и имеет доступ к функции ListAllAirports.
  2. Запрос пользователя: Пользователь спрашивает: "Какие аэропорты есть в Лондоне?"
  3. Принятие решения моделью: Модель анализирует запрос и понимает, что для ответа уместно вызвать инструмент ListAllAirports.
  4. Генерация вызова инструмента: Модель генерирует текстовое описание вызова инструмента. Часто это происходит в формате JSON, содержащем название функции (ListAllAirports) и необходимые аргументы (например, {"city": "London"}).
  5. Распознавание и выполнение вызова: Внутри агента (кода, работающего после LLM) распознается намерение модели вызвать инструмент. Вызываемая сущность (функция) запускается с переданными аргументами.
  6. Обработка результата: После выполнения функции ее выходные данные передаются обратно в модель.
  7. Генерация финального ответа: Модель, учитывая результаты вызова инструмента (например, список аэропортов в Лондоне), формулирует корректный ответ для пользователя, избегая галлюцинаций.

Предоставление Инструментов Модели

Процесс предоставления инструментов модели включает два ключевых компонента:

  1. Информирование о наличии инструментов: Модели сообщается, какие инструменты ей доступны. Это обычно делается через системный промпт, который включает описания всех доступных функций.
  2. Обучение генерации вызовов: Модель должна быть обучена генерировать вызовы этих инструментов в правильном формате.
    • Обучение на этапе претрейна/файн-тюнинга: Модели учатся правильно выполнять tool calling на этапах предварительного обучения или дообучения. Важно подавать данные в том формате, в котором модель обучалась, чтобы она возвращала вызовы в ожидаемом формате (например, JSON), который затем может быть корректно распарсен.
    • Понимание работы инструмента: Модель должна понимать, как работает каждый конкретный инструмент. Именно поэтому в описании инструмента указываются ожидаемые входные и выходные данные с их типами, что позволяет модели правильно обрабатывать результаты вызова.

Ключевые Принципы Проектирования Инструментов

При проектировании инструментов следует придерживаться нескольких ключевых принципов:

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

    • Пример: Агент оформляет заказ: списывает деньги, резервирует товар, создает заявку на доставку. Если доставка не создалась, инструмент должен уметь откатить платеж и резерв, помечая операцию как отмененную.
  2. Идемпотентность и корректная обработка повторных вызовов: Инструмент должен безопасно переживать повторный вызов, например, если агент был перезапущен после сбоя или таймаута.

    • Пример: Если задача агента — отправить письмо, повторный вызов инструмента (при ретрае) не должен привести к отправке нескольких писем.
  3. Информативные и структурированные сообщения об ошибках: Сообщения об ошибках должны быть понятны не только разработчику, но и самой модели.

    • Пример: Если модель не указала обязательный параметр, следует сообщить ей об этом, чтобы она могла перевызвать инструмент с корректными данными. При ошибке авторизации агент должен получить информацию о нехватке токена.
  4. Гайды по взаимодействию с пользователем: В инструменте желательно передать модели рекомендации по взаимодействию с пользователем.

    • Пример: Если для вызова инструмента недостаточно данных, модель должна уметь запросить их у пользователя. Если дальнейшее взаимодействие невозможно, она должна выдать сообщение об ошибке и попросить начать запрос заново.
  5. Structured Outputs (Структурированные выходные данные): Инструменты должны возвращать не просто текстовые "полотна", а ответы в формате, удобном для переиспользования моделью (для генерации следующих вызовов или для ответа пользователю).

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

Протокол Контекста Модели (MCP)

После изучения инструментов мы готовы перейти на следующий уровень и рассмотреть Протокол Контекста Модели (MCP).

Зачем нужен протокол?

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

  • Жесткая связанность инструментов и агентов: Инструменты часто живут рядом с агентом и плотно с ним связаны, что затрудняет их переиспользование.
  • Проблемы с обновлением API: Изменение внешних API требует переписывания инструментов в каждом отдельном агенте.
  • Разнообразие форматов вызовов: Модели могут ожидать описания инструментов или генерировать вызовы в различных форматах, что делает всю цепочку сложно поддерживаемой, хрупкой и трудно масштабируемой.

Именно для решения этих задач был разработан протокол. 25 ноября 2024 года Anthropic опубликовала свой MCP, который они использовали внутри компании, что позволило агентам стать еще более мощными.

Что такое MCP?

MCP (Model Context Protocol) — это открытый стандарт, который позволяет разработчикам создавать безопасные двусторонние соединения между AI-моделями и внешним миром (различными API, инструментами, источниками данных и т.д.). MCP можно воспринимать как порт USB-C в среде агентов или как HTTP-слой в браузерах.

Архитектура MCP

Архитектура MCP проста: разработчики могут либо предоставлять свои данные через MCP-серверы, либо создавать AI-приложения (MCP-клиентов), которые будут подключаться к этим серверам. Это клиент-серверная архитектура с тремя основными ролями:

  1. MCP-Хост (Host):

    • Описание: Различные AI-приложения, служащие основным интерфейсом для взаимодействия с пользователями.
    • Функции:
      • Оркестрация AI-моделей: Взаимодействие с LLM для генерации ответов и координации рабочих процессов.
      • Управление клиентскими подключениями: Создание и поддержание по одному MCP-клиенту на каждое серверное соединение.
      • Контроль пользовательского интерфейса: Обработка потока диалогов, взаимодействия с пользователем и отображение ответов.
      • Обеспечение безопасности: Контроль разрешений, ограничений, аутентификация и определение доступных для пользователя задач.
      • Обработка согласия пользователя: Запрос дополнительного подтверждения у пользователя для выполнения критически важных действий (например, отмена бронирования).
    • Примеры: Cursor, пользовательские агенты.
  2. MCP-Клиент (Client):

    • Описание: Ключевые компоненты, поддерживающие соединения "один к одному" с серверами. Создаются хостом для подключения к конкретному MCP-серверу.
    • Функции:
      • Коммуникация: Обеспечение связи по протоколу JSON-RPC2, обмен данными с серверами, подсказками и инструкциями.
      • Согласование возможностей: Обсуждение поддерживаемых функций и версий протокола с серверами при инициализации.
      • Запуск выполнения инструментов: Непосредственный вызов инструментов.
      • Обновления в реальном времени: Обработка ответов и уведомлений.
    • Значение: Несколько клиентов позволяют хостам одновременно подключаться к нескольким серверам и распараллеливать действия, обеспечивая организованные и безопасные каналы связи.
  3. MCP-Сервер (Server):

    • Описание: Легковесные программы, предоставляющие конкретные возможности через стандартизированный протокол.
    • Функции:
      • Регистрация возможностей: Сообщение о доступных инструментах на этапе запуска приложения.
      • Обработка запросов: Прием и выполнение вызовов инструментов, возврат результатов.
      • Предоставление контекста: Предоставление данных из локальных (файлы, базы данных, сервисы компьютера) или удаленных (внешние системы, базы данных, интернет) источников.
      • Управление соединением: Поддержание связи с клиентом.
      • Отправка уведомлений: Уведомления в реальном времени об изменении возможностей или обновлений.
    • Значение: Серверы могут разрабатываться кем угодно и предоставляться для использования в различных агентах.

Как MCP работает вместе (Схема взаимодействия)

  1. Discovery возможностей:

    • Хост инициирует соединения с различными серверами через отдельных клиентов (один клиент на каждый сервер).
    • Каждый клиент обращается к соответствующему серверу для получения информации о протоколе и доступных инструментах.
    • Этот процесс может выполняться параллельно благодаря выделенным клиентам, что значительно ускоряет процедуру.
    • Полученные описания инструментов сохраняются в приложении и передаются агенту при начале новых действий.
  2. Вызов инструментов:

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

Решение проблем с помощью MCP

MCP решает ранее упомянутые проблемы:

  • Переиспользование инструментов: Вместо жесткой привязки к агентам, инструменты теперь находятся на серверах. Разработанный один раз сервер может обслуживать множество клиентских приложений, позволяя переиспользовать такие общие функции, как калькуляторы или доступ к поиску в интернете.
  • Обновление API: MCP разделяет зоны ответственности. Инструменты находятся на серверах, и разработчики серверов отвечают за их консистентную работу и уведомление клиентов об изменениях протокола. Изменение API требует обновления только в одном месте (на сервере), и клиенты узнают об этом при инициализации.
  • Гибкость и масштабируемость: MCP создает множество абстракций, что делает пайплайны менее хрупкими и жестко привязанными к конкретным моделям. Изменение одной части системы (например, модели) теперь требует изменения только соответствующего абстрактного слоя, а не всего пайплайна. Это ускоряет итерации, проверку гипотез и разработку новых агентов, делая систему менее запутанной.

Избегайте Overengineering

Несмотря на все преимущества MCP, важно не заниматься овер-инжинирингом. Если вы разрабатываете агента для личного использования, начинайте с минимальных компонентов. Внедряйте MCP только тогда, когда столкнетесь с проблемами, которые он призван решать (например, масштабирование, переиспользование, сложность поддержки).

Существуют промежуточные шаги и готовые библиотеки (например, из экосистемы LangChain), которые предоставляют готовые инструменты и упрощают их интеграцию без необходимости полной реализации протокола MCP.

Практика: Создание и Интеграция Инструментов

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

1. Настройка среды

Устанавливаем необходимые зависимости, получаем ключ для OpenAI, создаем клиента и обертку для вызова LLM.

# Установка зависимостей
# pip install openai langchain langchain-openai langgraph

# Настройка ключа OpenAI
# os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"

# Создание клиента и обертки LLM
# client = OpenAI()
# llm = ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0)

2. Ручная генерация инструментов и Tool Calling

LLM генерирует текст, и вызов инструмента также будет текстовой генерацией.

Промпт для модели:

  • Системный промпт: "Ты ассистент, который умеет использовать тулы."
  • Описание тулов: Добавляем описание доступных инструментов.
  • Инструкция по вызову: "Если ты хочешь вызвать инструмент, генерируй JSON с названием инструмента (tool_name) и параметрами (parameters). Тип сообщения должен быть Tool Call."
  • Инструкция по финальному ответу: "Если ты готова дать финальный ответ, тип сообщения должен быть Final Answer, а текст — в поле Answer."

Обработка вызова инструмента: Если модель генерирует JSON с типом Tool Call:

  1. Извлекаем название инструмента и аргументы.
  2. Вызываем соответствующий исполняемый код.
  3. Возвращаем результат.

Обертка для запуска агента:

  1. Вызываем LLM.
  2. Пытаемся распарсить ее вывод в JSON.
  3. Если тип Tool Call, вызываем функцию обработки инструмента, передаем результат обратно в LLM как tool_result и просим сгенерировать новый ответ.
  4. Если тип Final Answer, выводим его пользователю.

Пример: Инструмент multiplier

Создадим простой инструмент multiplier, который принимает два аргумента и возвращает их произведение.

# Описание инструмента вручную
tools = {
    "multiplier": {
        "name": "multiplier",
        "description": "Умножает два числа.",
        "input_schema": {"type": "object", "properties": {"a": {"type": "integer"}, "b": {"type": "integer"}}},
        "output_schema": {"type": "integer"},
        "function": lambda a, b: a * b
    }
}

# Пример запроса
# "Сколько будет 17 умножить на 23?"

Логирование процесса:

  1. Модель возвращает JSON: {"type": "tool_call", "tool_name": "multiplier", "parameters": {"a": 17, "b": 23}}.
  2. Выполняется функция multiplier(17, 23), результат: 391.
  3. Результат передается обратно в модель.
  4. Модель генерирует финальный ответ: {"type": "final_answer", "answer": "Результат умножения 17 на 23 равен 391."}.

Этот подход работает, но имеет проблемы:

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

3. Автоматизация описания инструментов с помощью оберток

Для решения этих проблем создадим обертки.

Класс Tool: Создадим класс Tool, который будет содержать все необходимые данные для описания инструмента и метод to_string() для единообразного преобразования инструмента в строку.

class Tool:
    def __init__(self, name, description, input_schema, output_schema, func):
        self.name = name
        self.description = description
        self.input_schema = input_schema
        self.output_schema = output_schema
        self.func = func

    def to_string(self):
        # Форматирование описания инструмента в строку
        return (f"Название: {self.name}\n"
                f"Описание: {self.description}\n"
                f"Входные параметры: {self.input_schema}\n"
                f"Выходные данные: {self.output_schema}")

    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)

# Создание экземпляра инструмента
multiplier_tool = Tool(
    name="multiplier",
    description="Умножает два числа.",
    input_schema={"a": "integer", "b": "integer"},
    output_schema="integer",
    func=lambda a, b: a * b
)
# print(multiplier_tool.to_string())

Декоратор для автоматического создания описаний: Для автоматического извлечения информации о функции (аргументы, типы, docstring) и создания описания инструмента можно использовать декоратор.

import inspect

def tool_decorator(func):
    """Декоратор для автоматического создания описания инструмента."""
    sig = inspect.signature(func)
    input_schema = {name: param.annotation.__name__ for name, param in sig.parameters.items()}
    output_schema = sig.return_annotation.__name__ if sig.return_annotation else "any"

    tool_instance = Tool(
        name=func.__name__,
        description=func.__doc__,
        input_schema=input_schema,
        output_schema=output_schema,
        func=func
    )
    return tool_instance

@tool_decorator
def multiplier(a: int, b: int) -> int:
    """Умножает два числа."""
    return a * b

# Теперь multiplier - это объект Tool, и его описание генерируется автоматически
# print(multiplier.to_string())

Теперь, если мы изменим сигнатуру функции (например, a: float), описание автоматически обновится.

4. Использование готовых библиотек (LangChain/LangGraph)

LangChain и LangGraph предоставляют удобные абстракции для работы с инструментами и агентами.

Создание инструмента в LangChain:

from langchain_core.tools import tool

@tool
def multiplier(a: int, b: int) -> int:
    """Умножает два числа."""
    return a * b

tools_list = [multiplier]

Состояние агента (LangGraph): Состояние агента будет списком сообщений, где каждое новое сообщение добавляется в конец.

from typing import TypedDict, Annotated, List
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage, FunctionMessage

class AgentState(TypedDict):
    messages: Annotated[List[BaseMessage], lambda x, y: x + y]

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

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0)
llm_with_tools = llm.bind_tools(tools_list)

Нода LLM: Нода, которая принимает предыдущее состояние, вызывает LLM и добавляет результат в состояние.

def call_llm(state: AgentState):
    messages = state["messages"]
    response = llm_with_tools.invoke(messages)
    return {"messages": [response]}

Нода инструментов: Нода, которая исполняет вызванные инструменты.

from langgraph.prebuilt import ToolExecutor

tool_executor = ToolExecutor(tools_list)

def call_tool(state: AgentState):
    last_message = state["messages"][-1]
    # Предполагаем, что last_message содержит tool_calls
    tool_calls = last_message.tool_calls
    results = []
    for tool_call in tool_calls:
        result = tool_executor.invoke(tool_call)
        results.append(FunctionMessage(name=tool_call.name, content=str(result)))
    return {"messages": results}

Построение графа (LangGraph):

from langgraph.graph import StateGraph, END
from langgraph.prebuilt import ToolInvocation

workflow = StateGraph(AgentState)

workflow.add_node("llm", call_llm)
workflow.add_node("tools", call_tool)

workflow.set_entry_point("llm")

# Роутер для определения следующего шага
def should_continue(state: AgentState):
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tools"
    return "end"

workflow.add_conditional_edges(
    "llm",
    should_continue,
    {"tools": "tools", "end": END}
)
workflow.add_edge("tools", "llm") # После выполнения инструмента возвращаемся в LLM

app = workflow.compile()

Вызов агента:

# app.invoke({"messages": [HumanMessage(content="Сколько будет 17 умножить на 23?")]})

Агент будет корректно вызывать инструмент multiplier и возвращать правильный ответ. Логирование покажет последовательность сообщений: пользовательский запрос -> вызов инструмента LLM -> результат инструмента -> финальный ответ LLM.

5. Добавление инструментов к агенту бронирования

Теперь мы добавим инструменты к агенту, разработанному на предыдущем занятии, который помогает с бронированиями.

"База данных" (словарь): Создадим простой словарь, имитирующий базу данных с рейсами и бронированиями.

flights_db = {
    "flight_1": {"from": "Хельсинки", "to": "Амстердам", "date": "2024-02-22", "seats": 10, "price": 200},
    "flight_2": {"from": "Хельсинки", "to": "Амстердам", "date": "2024-02-22", "seats": 5, "price": 250},
    # ... другие рейсы
}

bookings_db = {
    "123": {"flight_id": "flight_1", "user": "Иван", "confirmed": False},
    # ... другие бронирования
}

Инструменты для агента бронирования: Реализуем три функции-инструмента:

  1. get_booking_details(booking_id: str): Возвращает информацию о бронировании по ID.
  2. search_flights(departure: str, destination: str, date: str): Ищет перелеты по указанным параметрам.
  3. cancel_booking(booking_id: str): Отменяет бронирование.
@tool
def get_booking_details(booking_id: str) -> dict:
    """Возвращает подробную информацию о бронировании по его ID."""
    return bookings_db.get(booking_id)

@tool
def search_flights(departure: str, destination: str, date: str) -> List[dict]:
    """Ищет перелеты по указанным точке отправки, назначения и дате."""
    results = []
    for flight_id, flight_info in flights_db.items():
        if (flight_info["from"] == departure and
            flight_info["to"] == destination and
            flight_info["date"] == date):
            results.append({"id": flight_id, **flight_info})
    return results

@tool
def cancel_booking(booking_id: str) -> str:
    """Отменяет бронирование по его ID."""
    if booking_id in bookings_db:
        bookings_db[booking_id]["confirmed"] = False
        return f"Бронирование {booking_id} отменено."
    return f"Бронирование {booking_id} не найдено."

booking_tools = [get_booking_details, search_flights, cancel_booking]

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

system_prompt = (
    "Ты помощник по авиалиниям. У тебя есть доступ к инструментам для поиска рейсов, "
    "просмотра и отмены бронирований. Используй их аккуратно, не галлюцинируй. "
    "Если не хватает данных, запрашивай их у пользователя. "
    "Ты виртуальный ассистент, используй эти инструменты."
)

Обновленное состояние агента и LLM: Состояние агента теперь будет использовать редьюсер для добавления сообщений, а не перезаписи, что позволяет строить диалог. LLM будет связана с новыми инструментами.

# AgentState остается таким же, как выше

llm_booking = ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0)
llm_booking_with_tools = llm_booking.bind_tools(booking_tools)

def call_llm_booking(state: AgentState):
    messages = state["messages"]
    response = llm_booking_with_tools.invoke(messages)
    return {"messages": [response]}

tool_executor_booking = ToolExecutor(booking_tools)

def call_tool_booking(state: AgentState):
    last_message = state["messages"][-1]
    tool_calls = last_message.tool_calls
    results = []
    for tool_call in tool_calls:
        result = tool_executor_booking.invoke(tool_call)
        results.append(FunctionMessage(name=tool_call.name, content=str(result)))
    return {"messages": results}

Роутер и граф: Граф будет иметь роутер, который после работы LLM определяет, нужно ли вызывать инструменты или завершать диалог.

workflow_booking = StateGraph(AgentState)

workflow_booking.add_node("llm", call_llm_booking)
workflow_booking.add_node("tools", call_tool_booking)

workflow_booking.set_entry_point("llm")

def should_continue_booking(state: AgentState):
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tools"
    return END # Завершаем, если нет tool_calls

workflow_booking.add_conditional_edges(
    "llm",
    should_continue_booking,
    {"tools": "tools", END: END}
)
workflow_booking.add_edge("tools", "llm")

app_booking = workflow_booking.compile()

Демонстрация работы:

  1. Поиск рейсов:

    • Пользователь: "Найди рейсы из Хельсинки в Амстердам 22 февраля."
    • Агент вызывает search_flights, получает данные из flights_db и возвращает список рейсов.
  2. Просмотр бронирования:

    • Пользователь: "Покажи информацию о бронировании 123."
    • Агент вызывает get_booking_details, получает данные из bookings_db и возвращает детали бронирования.
  3. Отмена бронирования с подтверждением:

    • Пользователь: "Отмени бронирование 123."
    • Агент: "Я нашел бронирование 123. Вы уверены, что хотите его отменить?"
    • Пользователь: "Я подтверждаю."
    • Агент вызывает cancel_booking, обновляет bookings_db и сообщает об успешной отмене.

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

# Пример чат-обертки
class ChatInterface:
    def __init__(self, app):
        self.app = app
        self.messages = []

    def send_message(self, user_message: str):
        self.messages.append(HumanMessage(content=user_message))
        response = self.app.invoke({"messages": self.messages})
        self.messages.extend(response["messages"])
        # Здесь можно добавить логику для красивого вывода
        print(f"Агент: {response['messages'][-1].content}")

# chat = ChatInterface(app_booking)
# chat.send_message("Отмени бронирование 123.")
# chat.send_message("Я подтверждаю.")

Заключение

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


Generated by AI-powered TranscribeLecture.com • 4/6/2026

Share your knowledge!