Разработка AI-агентов с помощью LangChain и LangGraph

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

1. Основы LangChain: архитектура, промпты и простые цепочки вызовов

Основы LangChain: архитектура, промпты и простые цепочки вызовов

Добро пожаловать в курс «Разработка AI-агентов с помощью LangChain и LangGraph». Это первая статья, в которой мы заложим фундамент для создания сложных интеллектуальных систем. Сегодня мы разберем, что такое LangChain, зачем он нужен, если у нас уже есть API от OpenAI или Anthropic, и как создать свое первое приложение на базе языковой модели.

Зачем нам нужен LangChain?

Представьте, что большая языковая модель (LLM) — это мощный двигатель. Он способен выдавать огромную энергию (генерировать текст, код, идеи). Но двигатель сам по себе не является автомобилем. Чтобы он приносил пользу, ему нужны колеса, руль, трансмиссия и топливная система.

LangChain — это шасси и трансмиссия для этого двигателя. Это фреймворк, который позволяет разработчикам объединять LLM с другими источниками вычислений или знаний. Он решает следующие проблемы:

* Абстракция: Позволяет легко менять одну модель на другую (например, GPT-4 на Claude 3) без переписывания всего кода. * Контекст: Упрощает управление историей диалога и памятью. * Цепочки (Chains): Позволяет выстраивать логику, где выход одного шага становится входом для следующего. * Инструменты: Дает модели возможность взаимодействовать с внешним миром (поиск в интернете, базы данных).

!Схема потока данных в простейшей цепочке LangChain: от пользователя через шаблон и модель к результату.

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

Современный LangChain строится вокруг концепции LCEL (LangChain Expression Language). Это декларативный способ описания цепочек. Но прежде чем мы перейдем к синтаксису, давайте разберем основные кирпичики, из которых строится любое приложение.

1. Модели (Models)

В LangChain существует два основных типа моделей:

* LLMs (Large Language Models): Принимают на вход строку текста и возвращают строку текста. Это классический режим автодополнения. * Chat Models: Принимают на вход список сообщений (сообщения могут быть от системы, пользователя или ассистента) и возвращают сообщение ассистента. Это более современный подход, используемый в GPT-3.5/4.

2. Промпты (Prompts)

Мы редко передаем ввод пользователя в модель напрямую. Обычно нам нужно добавить инструкции, примеры (few-shot learning) или контекст. Для этого используются Prompt Templates (шаблоны промптов).

Шаблон — это заготовка текста с переменными, которые подставляются в момент выполнения.

3. Парсеры вывода (Output Parsers)

Модель всегда возвращает текст (или объект сообщения). Но в программировании нам часто нужны структурированные данные: JSON, список, дата или число. Парсеры берут сырой текст от модели и преобразуют его в нужный формат.

Установка окружения

Для работы с примерами в этом курсе мы будем использовать язык Python. Вам понадобятся базовые библиотеки.

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

Создание первой цепочки (Chain)

Давайте создадим простейшее приложение: переводчик, который переводит сленг на литературный язык. Мы будем использовать синтаксис LCEL, который напоминает конвейер в Unix-системах (использование символа |).

Шаг 1: Создание модели

Сначала инициализируем модель чата.

Шаг 2: Создание шаблона промпта

Мы хотим, чтобы модель вела себя как профессиональный лингвист. Используем ChatPromptTemplate.

Здесь {text} — это переменная, которую мы передадим позже.

Шаг 3: Добавление парсера

Обычно ответ модели приходит в виде объекта AIMessage, содержащего метаданные. Если нам нужен просто текст (строка), мы используем StrOutputParser.

Шаг 4: Сборка цепочки через LCEL

Теперь самое интересное. Мы объединяем компоненты в единую цепочку с помощью оператора | (pipe). Данные текут слева направо: от шаблона к модели, а затем к парсеру.

Этот синтаксис делает код чистым и читаемым. Он скрывает сложную логику вызовов методов под капотом.

Шаг 5: Запуск цепочки

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

Ожидаемый вывод: > Молодой человек, данное торжество поистине великолепно, я пребываю в крайнем изумлении!

Как работает LCEL под капотом?

LangChain Expression Language (LCEL) — это не просто синтаксический сахар. Это протокол. Каждый объект, участвующий в цепочке (Prompt, Model, Parser), реализует интерфейс Runnable. Это гарантирует, что у них есть стандартные методы:

* invoke: синхронный вызов. * ainvoke: асинхронный вызов. * stream: потоковая передача ответа (по токенам). * batch: пакетная обработка списка запросов.

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

!Визуализация того, как интерфейс Runnable объединяет разные компоненты в единую последовательность.

Работа с переменными и сложными промптами

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

В данном случае метод invoke ожидает словарь с двумя ключами: product и audience. Если вы забудете один из них, LangChain выдаст ошибку валидации.

Почему это важно для AI-агентов?

В этом курсе мы стремимся к созданию агентов — систем, которые могут принимать решения. Цепочки (Chains), которые мы рассмотрели сегодня, являются атомарными действиями агента.

Агент — это, по сути, цикл, который выбирает, какую цепочку запустить в данный момент. Например:

  • Пользователь задал вопрос.
  • Агент решает: «Мне нужно сначала найти информацию в Google» (Цепочка 1).
  • Получив информацию, агент решает: «Теперь нужно суммаризировать текст» (Цепочка 2).
  • Без понимания того, как строятся простые цепочки Prompt | Model | Parser, невозможно построить сложного агента на LangGraph.

    Заключение

    Сегодня мы познакомились с основами LangChain:

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

    2. Расширение возможностей: память, инструменты и Retrieval Augmented Generation (RAG)

    Расширение возможностей: память, инструменты и Retrieval Augmented Generation (RAG)

    В предыдущей статье мы научились строить простые линейные цепочки (Chains) с использованием LangChain Expression Language (LCEL). Мы создали конвейер: Промпт → Модель → Парсер. Этого достаточно для простых задач вроде перевода или классификации текста.

    Однако, если вы попробуете построить чат-бота на базе такой цепочки, вы столкнетесь с двумя фундаментальными проблемами:

  • Амнезия: Модель не помнит, что вы сказали ей секунду назад. Каждый запрос для нее — как первый.
  • Изоляция: Модель ограничена знаниями, на которых она обучалась (обычно это данные годичной давности). Она не знает о ваших личных документах, текущих курсах валют или погоде за окном.
  • В этой статье мы решим эти проблемы, добавив в наш арсенал три мощных концепции: Память, Инструменты и RAG.

    1. Память (Memory): Преодоление амнезии

    Большие языковые модели (LLM) по своей природе stateless (не сохраняют состояние). Когда вы отправляете запрос в API (например, OpenAI), сервер обрабатывает его и тут же «забывает». Чтобы создать иллюзию диалога, мы должны сами передавать историю переписки вместе с каждым новым сообщением.

    Как это работает?

    Вместо того чтобы отправлять только последнее сообщение пользователя, мы отправляем список:

    * System: "Ты полезный ассистент." * User: "Меня зовут Алекс." * AI: "Привет, Алекс!" * User: "Как меня зовут?"

    LangChain автоматизирует этот процесс с помощью компонента RunnableWithMessageHistory.

    !Схема работы памяти в LangChain: история подгружается перед вызовом модели и обновляется после ответа.

    Реализация памяти в коде

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

    Теперь наш агент способен поддерживать контекст беседы, различая пользователей по session_id.

    2. Инструменты (Tools): Руки для модели

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

    Современные модели (OpenAI, Anthropic) поддерживают Function Calling. Это означает, что модель не выполняет код сама, а возвращает структурированный запрос (обычно JSON), говоря: «Пожалуйста, вызови функцию get_weather с аргументом Moscow».

    Создание собственного инструмента

    В LangChain любой Python-функции можно придать статус инструмента с помощью декоратора @tool.

    В ответе tool_calls будет содержаться имя функции и аргументы. В реальном агенте (о котором мы поговорим в статье про LangGraph) мы должны будем перехватить этот вызов, выполнить функцию multiply(55, 12) и вернуть результат модели, чтобы она сформулировала окончательный ответ.

    3. RAG (Retrieval Augmented Generation): Доступ к знаниям

    Самый популярный способ расширить знания модели — это RAG (Генерация с дополненной выборкой). Это техника, при которой мы сначала ищем релевантную информацию в базе знаний, а затем «скармливаем» её модели вместе с вопросом.

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

    Процесс состоит из двух этапов: Индексация (подготовка данных) и Поиск и Генерация (работа с запросом).

    !Архитектура RAG: преобразование документов в векторы, поиск релевантных частей и генерация ответа на их основе.

    Ключевое понятие: Эмбеддинги (Embeddings)

    Чтобы компьютер мог найти текст по смыслу (а не просто по ключевым словам), мы превращаем текст в векторы — длинные списки чисел. Близкие по смыслу тексты будут иметь близкие векторы в многомерном пространстве.

    Математически близость часто определяется через косинусное сходство:

    Где: * и — это векторы (эмбеддинги) двух текстов. * — скалярное произведение векторов. * и — длины (нормы) векторов. * — косинус угла между векторами. Если он равен 1, векторы сонаправлены (смысл идентичен), если 0 — ортогональны (смысл не связан).

    Реализация простого RAG на LangChain

    Для реализации нам понадобятся:

  • Loader: Загрузчик документов.
  • Splitter: Разделитель текста на куски (chunks).
  • VectorStore: База данных для векторов (например, Chroma).
  • Retriever: Интерфейс поиска.
  • В этой цепочке retriever автоматически берет вопрос, ищет похожие куски текста и передает их в переменную {context}. Модель получает уже готовую «шпаргалку» для ответа.

    Подготовка к LangGraph

    Мы рассмотрели три кита современного AI-приложения: * Память позволяет вести диалог. * Инструменты позволяют действовать. * RAG позволяет знать.

    Однако, пока что наши цепочки линейны. Мы жестко задаем последовательность: «Найди → Вставь в промпт → Ответь». Но что, если информации не нашлось? Что, если нужно уточнить вопрос у пользователя? Что, если нужно вызвать инструмент, проверить его результат и, в случае ошибки, попробовать снова?

    Здесь линейные цепочки (Chains) становятся слишком громоздкими. Нам нужна циклическая логика и графы. Именно для этого был создан LangGraph, к изучению которого мы перейдем в следующей статье.

    Заключение

    Сегодня вы узнали, как превратить «глупую» модель в осведомленного собеседника. Вы научились сохранять контекст беседы, подключать внешние функции и использовать векторный поиск для работы с документами. Попробуйте выполнить домашнее задание, чтобы закрепить материал перед переходом к созданию полноценных агентов.

    3. Введение в LangGraph: переход от линейных цепочек к циклическим графам

    Введение в LangGraph: переход от линейных цепочек к циклическим графам

    В предыдущих статьях мы успешно освоили LangChain. Мы научились создавать цепочки (Chains), подключать память и использовать RAG для работы с документами. Наши приложения стали умнее, но они всё ещё ограничены одной фундаментальной особенностью: они линейны.

    Классическая цепочка LangChain (LCEL) работает как конвейер: входные данные поступают в начало, проходят через серию жестко заданных шагов и выходят в конце. Но что, если первый шаг выдал ошибку и его нужно повторить? Что, если агент должен сам решить, сколько раз ему нужно обратиться к поиску Google, прежде чем ответить?

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

    Проблема линейности

    Представьте, что вы пишете скрипт для менеджера по продажам. В LangChain это выглядит так:

  • Получить письмо клиента.
  • Сгенерировать ответ.
  • Отправить ответ.
  • Это направленный ациклический граф (DAG). Данные текут только вперед.

    !Сравнение линейной цепочки LangChain и циклического графа LangGraph.

    А теперь представьте реальный процесс:

  • Получить письмо.
  • Сгенерировать черновик ответа.
  • Проверка: Хороший ли ответ?
  • Если да* — отправить. Если нет* — переписать (вернуться к шагу 2).

    В стандартном LangChain реализовать цикл «попробуй снова» сложно и неудобно. LangGraph был создан специально для решения этой задачи. Он позволяет добавлять циклы (loops) и условные переходы в логику вашего приложения.

    Теоретическая основа: Графы

    Чтобы понять LangGraph, нужно вспомнить определение графа из информатики. Формально граф можно описать следующим образом:

    Где: * — сам граф (наша система агента). * (Vertices) — множество вершин или узлов. В контексте LangGraph узлы — это функции или шаги обработки (например, вызов LLM или поиск в базе данных). * (Edges) — множество ребер. Это связи между узлами, определяющие поток выполнения программы.

    В LangGraph мы строим StateGraph (Граф Состояния). Это означает, что все узлы графа обмениваются единым объектом состояния, который они могут читать и обновлять.

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

    LangGraph строится на трех китах:

  • State (Состояние): Структура данных (обычно Python словарь или Pydantic модель), которая передается между узлами. Она хранит контекст, историю сообщений и результаты работы инструментов.
  • Nodes (Узлы): Python-функции, которые выполняют работу. Они принимают текущее состояние, делают вычисления и возвращают обновленное состояние.
  • Edges (Ребра): Логика перехода. Бывают обычные ребра (всегда переходим от А к Б) и условные ребра (Conditional Edges), где путь зависит от решения модели.
  • 1. Определение Состояния (State)

    Начнем с создания состояния. Обычно это TypedDict.

    Здесь messages будет хранить историю переписки, а current_step — служебную информацию.

    2. Создание Узлов (Nodes)

    Узел — это просто функция. Давайте создадим два простых узла: один генерирует идею, другой её критикует.

    Обратите внимание: узлы возвращают словарь, который объединяется с текущим состоянием.

    3. Построение Графа

    Теперь самое интересное. Мы используем StateGraph для сборки конструкции.

    Метод .compile() превращает граф в объект, который можно запускать так же, как обычную цепочку LangChain — через метод .invoke().

    Сила циклов и условных переходов

    Пример выше все еще линеен: Генератор -> Критик -> Конец. Давайте добавим логику агента: если критик недоволен, мы возвращаемся к генератору.

    Для этого используются Conditional Edges (Условные ребра).

    !Визуализация условного ребра, создающего цикл обратной связи.

    Теперь наша система стала циклической. Она будет крутиться в цикле «Генерация -> Критика», пока критик не одобрит результат. Это и есть базовая механика работы автономных агентов.

    LangChain vs LangGraph: Когда переходить?

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

    | Характеристика | LangChain (Chains) | LangGraph | | :--- | :--- | :--- | | Структура | Линейная (DAG) | Циклическая (Graph) | | Сложность | Низкая / Средняя | Высокая | | Управление состоянием | Передача контекста | Глобальный State Object | | Принятие решений | Жестко задано (RouterChain) | Динамическое (в узлах и ребрах) | | Идеально для | Чат-ботов, простых RAG | Автономных агентов, симуляций, сложных процессов |

    Заключение

    LangGraph — это эволюция ваших навыков разработки AI. Он позволяет перейти от простых скриптов «вопрос-ответ» к созданию систем, способных размышлять, исправлять свои ошибки и работать итеративно.

    Мы разобрали основные понятия:

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

    4. Управление состоянием и создание мульти-агентных систем в LangGraph

    Управление состоянием и создание мульти-агентных систем в LangGraph

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

    Однако, когда мы пытаемся создать действительно сложного помощника — например, такого, который умеет и писать код, и искать научные статьи, и рисовать графики, — мы сталкиваемся с проблемой. Если дать одной модели (одному агенту) слишком много инструментов и инструкций, она начинает «путаться». Качество ответов падает, а контекст переполняется.

    Решение этой проблемы лежит в архитектуре Мульти-агентных систем (Multi-Agent Systems). Сегодня мы разберем, как управлять сложным состоянием и как создать «команду» специализированных агентов под руководством супервизора.

    Глубокое погружение в State (Состояние)

    В LangGraph Состояние (State) — это сердце вашего приложения. Это структура данных, которая передается от узла к узлу. В прошлом уроке мы использовали простой TypedDict, который перезаписывался на каждом шаге. Но в реальных системах нам часто нужно не заменять данные, а дополнять их.

    Проблема перезаписи

    Представьте, что у вас есть список сообщений. Если Узел А вернет список из двух сообщений, а затем Узел Б вернет одно новое сообщение, стандартное поведение словаря Python — просто заменить значение по ключу. В итоге история от Узла А пропадет.

    Чтобы этого избежать, LangGraph использует концепцию Reducers (редукторов). Это функции, которые определяют, как объединять старое состояние с новым.

    Математически процесс обновления состояния можно описать следующей формулой:

    Где: * — новое состояние системы после выполнения узла. * — функция-редуктор (например, сложение списков). * — текущее состояние системы. * — обновление (update), которое вернул узел.

    Использование Annotated

    В Python мы реализуем это с помощью Annotated и функции add_messages (или operator.add).

    Теперь, когда любой узел вернет {"messages": [new_msg]}, это сообщение будет добавлено в конец списка messages в общем состоянии.

    Архитектура Мульти-агентных систем

    Зачем создавать несколько агентов вместо одного? Ответ прост: Разделение ответственности.

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

    Мы будем реализовывать паттерн Supervisor (Супервизор).

    !llm.bind_tools(tools) return agent python

    Инициализация модели

    llm = ChatOpenAI(model="gpt-4o")

    Создание агентов

    research_agent = create_agent(llm, [tavily_search
    , "Ты — исследователь. Ищи точные данные.") code_agent = create_agent(llm, [python_repl], "Ты — программист. Пиши безопасный код.")

    Обертка в узлы графа

    Узел должен не только вызвать агента, но и пометить сообщение именем отправителя

    import functools from langchain_core.messages import HumanMessage

    def agent_node(state, agent, name): result = agent.invoke(state) # Превращаем результат в сообщение с именем агента return {"messages": [HumanMessage(content=result.content, name=name)]}

    research_node = functools.partial(agent_node, agent=research_agent, name="Researcher") code_node = functools.partial(agent_node, agent=code_agent, name="Coder") python from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser

    members = ["Researcher", "Coder"] system_prompt = ( "Ты — менеджер проекта. Твоя задача — управлять командой из: {members}. " "Для следующего шага выбери работника или закончи работу (FINISH)." )

    options = ["FINISH"] + members

    Описываем функцию выбора для OpenAI

    function_def = { "name": "route", "description": "Select the next role.", "parameters": { "title": "routeSchema", "type": "object", "properties": { "next": { "title": "Next Role", "anyOf": [ {"enum": options} ] } }, "required": ["next"] } }

    prompt = ChatPromptTemplate.from_messages([ ("system", system_prompt), MessagesPlaceholder(variable_name="messages"), ("system", "Кто должен действовать следующим? Выбери из: {options}") ]).partial(options=str(options), members=", ".join(members))

    supervisor_chain = ( prompt | llm.bind_functions(functions=[function_def], function_call="route") | JsonOutputFunctionsParser() ) python from langgraph.graph import StateGraph, END

    workflow = StateGraph(AgentState)

    Добавляем узлы

    workflow.add_node("Researcher", research_node) workflow.add_node("Coder", code_node) workflow.add_node("Supervisor", supervisor_chain)

    Добавляем ребра

    Все работники всегда возвращают отчет Супервизору

    workflow.add_edge("Researcher", "Supervisor") workflow.add_edge("Coder", "Supervisor")

    Точка входа

    workflow.set_entry_point("Supervisor")

    Условные ребра от Супервизора

    workflow.add_conditional_edges( "Supervisor", lambda x: x["next"], # Функция читает выбор супервизора { "Researcher": "Researcher", "Coder": "Coder", "FINISH": END } )

    app = workflow.compile() python from langgraph.checkpoint.memory import MemorySaver

    memory = MemorySaver() app = workflow.compile(checkpointer=memory)

    Запуск с thread_id

    config = {"configurable": {"thread_id": "unique_conversation_id"}} app.invoke({"messages": [...]}, config=config) ``

    thread_id работает как сессия в браузере. Вы можете остановить выполнение графа, а затем продолжить его с того же места, просто передав тот же thread_id. Это позволяет реализовать логику «Человек в контуре» (Human-in-the-loop), где граф ставится на паузу перед критическим действием, и оператор должен явно разрешить продолжение.

    Заключение

    Сегодня мы разобрали архитектуру сложных AI-систем. Мы узнали:

  • Как использовать Annotated и редукторы для накопления истории сообщений.
  • Как работает паттерн Supervisor для оркестрации нескольких агентов.
  • Как сохранять состояние графа с помощью MemorySaver`.
  • Теперь вы готовы создавать не просто чат-ботов, а целые виртуальные отделы сотрудников, работающих над одной задачей. Это вершина текущего развития технологий LLM-агентов.

    В следующих материалах курса мы рассмотрим развертывание этих агентов в продакшн и мониторинг их работы с помощью LangSmith.

    5. Практикум: проектирование и развертывание полноценного AI-ассистента

    Практикум: проектирование и развертывание полноценного AI-ассистента

    Мы прошли долгий путь. Мы начали с простых линейных цепочек в LangChain, научили модели помнить контекст, дали им инструменты и доступ к документам через RAG. Затем мы перешли к LangGraph, освоив циклическую логику и мульти-агентные системы.

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

    Наша цель — создать приложение, которое не просто живет в Jupyter Notebook, а доступно как веб-сервис API, готовый к интеграции с фронтендом или мессенджерами.

    Этап 1: Проектирование архитектуры

    Прежде чем писать код, нужно определить, что именно мы строим. Наш агент поддержки интернет-магазина должен уметь:

  • Отвечать на общие вопросы (политика возврата, часы работы) — используя RAG.
  • Проверять статус заказа — используя инструмент (Tool) с доступом к базе данных.
  • Переводить на человека, если проблема слишком сложная.
  • Мы будем использовать архитектуру графа с маршрутизацией.

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

    Этап 2: Реализация логики на LangGraph

    Начнем с импорта необходимых библиотек и настройки окружения. Нам понадобятся langchain, langgraph и langchain-openai.

    Определение состояния и инструментов

    Сначала создадим инструменты. В реальном проекте это были бы запросы к SQL или API, но для практикума мы сделаем заглушки.

    Создание графа

    Теперь свяжем модель с инструментами и создадим граф.

    Теперь у нас есть рабочий объект app, который можно вызывать через app.invoke. Но как сделать его доступным для внешнего мира?

    Этап 3: Развертывание с помощью LangServe

    Многие разработчики совершают ошибку, пытаясь вручную обернуть агента в Flask или Django, самостоятельно обрабатывая потоковую передачу (streaming) и типы данных. Экосистема LangChain предлагает готовое решение — LangServe.

    LangServe — это библиотека, которая автоматически превращает любой объект LangChain или LangGraph в REST API на базе FastAPI. Она «из коробки» поддерживает: * Потоковую передачу токенов (Streaming). * Асинхронность. * Документацию Swagger. * Встроенную песочницу (Playground).

    Создание сервера (server.py)

    Создайте файл server.py и поместите туда следующий код:

    Запустив этот файл, вы получите готовый API по адресу http://localhost:8000/agent и красивый интерфейс для тестирования по адресу http://localhost:8000/agent/playground.

    Этап 4: Мониторинг и оптимизация (LangSmith)

    Когда ваш агент уходит в продакшн, вы теряете возможность видеть print() в консоли. Вы перестаете понимать, почему бот ответил грубо или почему он потратил 10 секунд на простой вопрос.

    Здесь на помощь приходит LangSmith — платформа для трейсинга (отслеживания) и оценки LLM-приложений.

    Почему это важно?

    В инженерии AI-систем критически важны две метрики: задержка (Latency) и стоимость (Cost). Рассмотрим упрощенную формулу расчета стоимости одного взаимодействия:

    Где: * — итоговая стоимость запроса в валюте (например, в долларах). * — количество токенов во входном промпте (включая историю переписки и системные инструкции). * — цена за 1 входной токен для выбранной модели. * — количество сгенерированных моделью токенов. * — цена за 1 выходной токен (обычно она выше, чем ).

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

    Подключение LangSmith

    Для подключения достаточно установить переменные окружения перед запуском вашего скрипта:

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

  • Видеть точные входные и выходные данные каждого узла.
  • Отлавливать ошибки в реальном времени.
  • Собирать датасеты из неудачных ответов для дальнейшего дообучения (Fine-tuning) или улучшения промптов.
  • Управление сессиями в продакшене

    В коде выше мы использовали MemorySaver. Это хранилище in-memory — оно хранит данные в оперативной памяти. Если вы перезагрузите сервер, вся история переписок пользователей исчезнет. Это недопустимо для продакшена.

    Для реального развертывания необходимо использовать персистентные хранилища, такие как PostgreSQL или Redis.

    LangGraph предоставляет готовые классы для этого, например AsyncPostgresCheckpointer. Схема работы меняется незначительно:

  • Вы создаете пул соединений с базой данных.
  • Передаете чейкпоинтер в метод .compile(checkpointer=db_checkpointer).
  • При вызове агента обязательно передаете thread_id в конфигурации.
  • Именно thread_id является ключом, по которому агент «вспоминает» предыдущие реплики конкретного пользователя из базы данных.

    Заключение курса

    Поздравляю! Вы прошли путь от понимания того, что такое промпт, до создания архитектуры масштабируемого AI-сервиса.

    Мы изучили: * LangChain как фундамент для работы с моделями. * RAG для наделения моделей знаниями. * LangGraph для создания сложного поведения и циклов. * LangServe и LangSmith для развертывания и контроля качества.

    Мир AI-агентов развивается стремительно. То, что сегодня мы делаем с помощью кода, завтра может стать встроенной функцией моделей. Однако принципы архитектуры — разделение ответственности, управление состоянием и мониторинг — останутся неизменными. Продолжайте экспериментировать и создавайте агентов, которые приносят реальную пользу.