
Разработка с использованием больших языковых моделей (LLM) начинается с простого цикла «запрос-ответ». Но как только задача выходит за рамки чат-бота и требует от модели реальных действий — интеграции внешних инструментов (tools), работы с базами данных или файловой системой — мы сталкиваемся с фундаментальной проблемой. Стандартный API модели по своей природе stateless и не имеет встроенных механизмов для управления сложной логикой.
Простая задача вроде «проанализируй этот файл, найди в интернете нужные данные и составь отчет» превращается в сложную задачу оркестрации:
- Как управлять состоянием и передавать контекст между множественными вызовами LLM?
- Как реализовать циклическую логику, где агент многократно обращается к инструментам, пока не достигнет цели?
- Как стандартизировать подключение разных моделей (OpenAI, Gemini, локальные) и инструментов, не переписывая код каждый раз?
Чтобы облегчить разработку таких систем и предоставить разработчикам стандартизированный подход к оркестрации, и были созданы фреймворки LangChain и LangGraph:
- LangChain предоставляет унифицированный инструментарий: интерфейсы к моделям, компоненты для работы с промптами и инструментами.
- LangGraph — это фреймворк поверх LangChain, который позволяет строить саму логику принятия решений агента в виде графа состояний, элегантно решая проблему циклов и ветвлений.
Чтобы лучше понять их роли, воспользуемся аналогией.
Представьте, что вы строите что-то из LEGO. У вас есть отдельные кубики (моторы, колёса, блоки), но сами по себе они — просто детали. Чтобы собрать из них рабочую машину, вам нужна инструкция и понимание, как соединить эти детали вместе.
LangChain предоставляет вам строительные блоки, а LangGraph — интеллектуальную систему для управления этими блоками, позволяя создавать по-настоящему автономных и полезных ИИ-агентов.
В мире ИИ-агентов:
- LangChain — это ваш набор высокотехнологичных LEGO-кубиков.
- LangGraph — это продвинутая инструкция, которая позволяет собирать из этих кубиков не просто статичные модели, а динамические, «умные» механизмы, способные принимать решения.
Давайте разберем каждый из этих инструментов по отдельности.
Часть 1: LangChain — Инструментарий для работы с LLM
Основная цель LangChain: упростить и стандартизировать взаимодействие между вашим кодом и большими языковыми моделями (LLM). Он предоставляет готовые компоненты («кубики») для решения типовых задач.
Ключевые компоненты LangChain (наши «кубики»):
1. Модели (Models)
Это обёртки для прямого взаимодействия с нейросетями. LangChain делит их на два типа:
LLMs: Старый интерфейс. Принимает на вход строку, возвращает строку.- Пример:
llm.invoke("Какой цвет у неба?")→"Небо голубое."
- Пример:
ChatModels: Современный и более мощный интерфейс. Работает со списком сообщений (HumanMessage,AIMessage,SystemMessage). Это позволяет модели лучше понимать контекст диалога.- Пример:
chat.invoke([HumanMessage(content="Какой цвет у неба?")])→AIMessage(content="Небо обычно голубое...")
- Пример:
LangChain унифицирует API. Вам не нужно изучать, как работать с OpenAI, Gemini или локальной Ollama по-отдельности. Вы просто меняете один объект
ChatOpenAIнаChatGoogleGenerativeAIилиChatOllama, а остальной код продолжает работать.
2. Промпты (Prompts)
Это шаблоны для ваших запросов к модели. Вместо того чтобы каждый раз вручную собирать текст запроса, вы создаете шаблон с переменными.
from langchain_core.prompts import ChatPromptTemplate
template = ChatPromptTemplate.from_messages([
("system", "Ты — полезный ассистент, который переводит текст на {output_language}."),
("human", "{text_to_translate}")
])
prompt_value = template.invoke({"output_language": "французский", "text_to_translate": "Я люблю программирование."})
Промпты делают ваши запросы воспроизводимыми, безопасными и легко изменяемыми. Вы отделяете логику формирования запроса от логики вызова модели.
3. Цепочки (Chains и язык LCEL)
Это сердце раннего LangChain. Цепочка — это последовательное соединение нескольких компонентов. Сегодня для этого используется LangChain Expression Language (LCEL), который выглядит как конвейер (|).
Простейшая цепочка: промпт | модель.
chain = template | get_gemini_llm()
response = chain.invoke({"output_language": "немецкий", "text_to_translate": "Привет, мир!"})
# response.content будет содержать "Hallo, Welt!"
Цепочки позволяют создавать простые рабочие процессы. Например, сначала получить данные от пользователя, потом сформировать промпт, затем отправить его модели, а после — обработать ответ.
4. Парсеры вывода (Output Parsers)
Модели возвращают текст, но в приложениях нам часто нужны структурированные данные (JSON, список, число). Парсеры преобразуют «сырой» текстовый ответ модели в нужный формат.
from langchain_core.output_parsers import JsonOutputParser
# ... создаем промпт, который просит модель ответить в формате JSON
parser = JsonOutputParser()
chain = template | get_openai_llm() | parser
# Теперь chain.invoke(...) вернет не текстовый объект, а Python-словарь (dict)
Чтобы ваш код мог программно работать с результатом. Вместо того чтобы пытаться вытащить нужные данные из строки, вы сразу получаете готовый объект.
5. Инструменты (Tools)
Это то, что даёт модели «руки». Инструмент — это любая функция, которую может вызвать агент. Это может быть:
- Поиск в интернете (
TavilySearch,BraveSearch). - Калькулятор.
- Функция для чтения файла с диска.
- Обращение к вашему внутреннему API.
Модель сама по себе не знает, какая сегодня погода или что написано в вашем файле
report.docx. Инструменты — это единственный способ для неё получить доступ к внешней информации и выполнять действия в реальном мире.
Часть 2: LangGraph — Оркестратор для создания агентов
Если LangChain — это набор деталей, то LangGraph — это система управления, которая решает, какую деталь и в какой момент использовать.
Проблема, которую решает LangGraph: Классические цепочки (chains) в LangChain — линейные. Они идут от точки А к точке Б. Но настоящие задачи нелинейны. Они требуют циклов, ветвлений и принятия решений.
Например, агент-исследователь должен:
- Понять запрос.
- Решить: нужно ли искать в интернете?
- Если да → использовать инструмент поиска.
- Проанализировать результаты.
- Решить: достаточно ли информации?
- Если нет → вернуться к шагу 3 с уточненным запросом (это цикл).
- Если да → сгенерировать финальный ответ.
Такую сложную логику невозможно описать простой цепочкой.
Основная идея LangGraph: представить работу агента как граф состояний (или блок-схему).
Ключевые компоненты LangGraph (элементы блок-схемы):
1. Состояние (State)
Это центральная память всего процесса. Обычно это Python-словарь (TypedDict), который передается от одного шага к другому. Каждый шаг может читать из него данные и записывать в него новые.
Пример состояния:
{"user_request": "...", "search_results": [], "final_answer": None}.
2. Узлы (Nodes)
Это блоки действий на вашей блок-схеме. Каждый узел — это Python-функция, которая:
- Принимает на вход текущее
состояние. - Выполняет какое-то действие (вызывает LLM, использует инструмент).
- Возвращает обновленное
состояние.
Примеры узлов:
call_model_node,execute_tool_node,analyze_results_node.
3. Рёбра (Edges)
Это стрелки, которые соединяют узлы. Они определяют, какой узел будет выполняться следующим. Рёбра бывают двух видов:
- Обычные рёбра: Просто соединяют узел А с узлом Б. После завершения А всегда будет запущен Б.
- Условные рёбра (
Conditional Edges): Это самая важная часть. После узла А запускается специальная функция-«маршрутизатор», которая смотрит на текущеесостояниеи решает, куда идти дальше: к узлу Б, В или Г.
Пример условного ребра:
- После вызова модели (узел
agent_node) мы проверяемсостояние.- Если в ответе модели есть вызов инструмента → идём к узлу
execute_tool_node.- Если вызова инструмента нет → идём к конечному узлу
END.
LangChain vs. LangGraph: Когда что использовать?
| Критерий | LangChain (LCEL Chains) | LangGraph |
|---|---|---|
| Основное применение | Простые, линейные задачи | Сложные, циклические задачи (агенты) |
| Структура | Конвейер (A → B → C) | Граф (блок-схема с ветвлениями и циклами) |
| Поток управления | Детерминированный, заранее заданный | Динамический, определяется в реальном времени |
| Пример задачи | 1. Взять текст. 2. Суммаризировать его. 3. Перевести на другой язык. | 1. Получить вопрос. 2. Искать в интернете, пока не найдется ответ. 3. Обобщить найденное и ответить. |
| Аналогия | Сборочная линия на заводе | Команда людей, совещающаяся и принимающая решения |
Собираем всё вместе
- Пользовательский ввод попадает в начальное Состояние LangGraph.
- Узел «Агент» получает состояние. Внутри этого узла находится цепочка LangChain (
промпт | модель | парсер). Модель, используя Инструменты из LangChain, решает, что делать дальше (например, «вызвать поиск»). Её решение записывается в Состояние. - Условное Ребро анализирует состояние и направляет поток к Узлу «Исполнитель Инструментов».
- Этот узел выполняет реальный вызов инструмента (например, делает веб-поиск) и записывает результат обратно в Состояние.
- Поток возвращается к Узлу «Агент» (это цикл). Теперь модель видит результат поиска и принимает новое решение.
- Цикл повторяется, пока модель не решит, что задача выполнена. Тогда Условное Ребро направит поток к завершению.