Почему графы — это новый хайп, и почему он оправдан
Если ты хотя бы раз писал цепочку вызовов LLM вручную — с условиями, циклами, вызовом инструментов — ты знаешь, как быстро код превращается в спагетти. Линейные pipeline не справляются: реальные сценарии требуют ветвления, возврата на предыдущий шаг, параллельных вызовов, state-machine логики. LangChain предложил графовую абстракцию — задачу разбивают на узлы, каждый узел — функция, а ребра описывают переходы. Но в 2026 году этого мало: нужен production-ready сервер с REST API, автоматической документацией и встроенным трейсингом.
Здесь на сцену выходят LangGraph Server и LangSmith. Первый — это рантайм для выполнения графов, который сам генерирует эндпоинты и управляет состоянием. Второй — платформа для отладки и мониторинга. И главное — оба работают с локальными LLM, если их правильно прикрутить. Забудь про облачных провайдеров: мы построим инфраструктуру, которая не утечет данные и не сожжет бюджет на API.
Спойлер: В конце ты получишь работающий сервер, который можно запустить на своем железе, а вместо OpenAI там будет локальная модель через Ollama. И всё это с трейсингом в LangSmith.
Проблема: Продакшн-деплой графов — это ад
Ты наколдовал граф в Jupyter, он работает — магия. Но вот задача: выкатить это как микросервис с красивым API, очередями, обработкой ошибок, логами и версионированием. Вариантов два:
- Писать FastAPI-обертку самому — это еще 500 строк кода, которые нужно тестировать.
- Использовать облачные решения типа LangGraph Cloud — но они тащат за собой vendor lock и плату за каждый вызов.
А если модель локальная — third option? На самом деле, третий вариант — самостоятельный хостинг LangGraph Server. С версии 0.3.x (апрель 2026) он стал стабильным и поддерживает подключение любого провайдера LLM через LangChain SDK. Проблема лишь в том, что документация размазана, а примеры заточены под OpenAI. Мы это исправим.
Решение: три кита инфраструктуры
Нам понадобятся:
- LangGraph Server — разворачивается как Python-пакет или Docker-контейнер. Автоматически создает REST API на основе твоего графа.
- LangSmith SDK — клиентская библиотека для отправки трейсов (трассировок) на выбранный сервер. Можно хостить свой LangSmith (OpenAPI версия) или использовать SaaS.
- Локальная LLM — через Ollama, vLLM или llama.cpp. Мы возьмем Ollama, как самый простой вариант. Если не знаком — полный гайд по Ollama есть здесь.
Звучит логично, но есть нюанс: LangGraph Server по умолчанию хочет видеть модель с API, совместимым с OpenAI. Ollama с версии 0.3.0 (февраль 2026) поддерживает такой эндпоинт из коробки. Если у вас старая версия — придется ставить адаптер litellm, но лучше обновить Ollama.
Пошаговый план (если не хотите сломать себе голову)
1 Поднимаем локальную LLM через Ollama
Убедись, что Ollama установлена. Запусти модель. Я рекомендую llama3.1:8b или mistral-nemo:12b — они отлично справляются с инструментами (tool calling). Если модель не поддерживает вызов функций, граф не сможет адекватно передавать аргументы. Об этом подробнее в обзоре лучших LLM с Tool Calling.
# Установка и запуск
curl -fsSL https://ollama.com/install.sh | sh
ollama pull llama3.1:8b
ollama serve # запускает сервер на localhost:11434
Проверяем, что API совместим с OpenAI:
curl http://localhost:11434/v1/chat/completions -d '{
"model": "llama3.1:8b",
"messages": [{"role":"user","content":"Hi"}]
}'
Если получаешь ответ — готово.
2 Ставим LangGraph Server и пишем граф
Установим пакеты:
pip install langgraph langgraph-server langchain-ollama langsmith
Теперь создаем файл agent.py с графом. Возьмем простой граф: пользователь задает вопрос, агент решает, нужно ли вызвать инструмент (например, поиск в БД), и формирует финальный ответ.
from langgraph.graph import StateGraph, MessagesState
from langgraph.checkpoint.memory import MemorySaver
from langchain_ollama import ChatOllama
from langchain_core.tools import tool
# 1. Инициализация локальной модели
llm = ChatOllama(
model="llama3.1:8b",
base_url="http://localhost:11434",
temperature=0.7,
)
# 2. Определяем инструмент
@tool
def get_user_info(user_id: int) -> str:
"""Возвращает имя пользователя по ID"""
users = {1: "Alice", 2: "Bob"}
return users.get(user_id, "Unknown")
# 3. Строим граф
class AgentState(MessagesState):
pass
def call_model(state: AgentState):
messages = state["messages"]
response = llm.invoke(messages)
return {"messages": [response]}
workflow = StateGraph(AgentState)
workflow.add_node("agent", call_model)
workflow.set_entry_point("agent")
workflow.set_finish_point("agent")
# 4. Важно: подключаем persistence (MemorySaver) для сессий
app = workflow.compile(checkpointer=MemorySaver())
Уже здесь многие спотыкаются: не забывайте про checkpointer. Без него LangGraph Server не сможет поддерживать состояние между вызовами (историю чата).
3 Запускаем сервер с нашим графом
LangGraph Server читает конфигурацию из файла langgraph.json в корне проекта. Создаем его:
{
"graphs": {
"agent": "./agent.py:app"
},
"dependencies": ["."]
}
Теперь команда:
langgraph serve
# Сервер запустится на порту 8123 (по умолчанию)
Проверяем:
curl http://localhost:8123/health
# Вернет {"status":"ok"}
Автоматически генерируется OpenAPI-документация в /docs. Открой в браузере — увидишь Swagger. Эндпоинт для вызова графа: POST /runs/agent. Тело запроса:
{
"input": {
"messages": [{"role": "user", "content": "Hello, who am I?"}]
},
"config": {
"configurable": {"thread_id": "1"}
}
}
Ошибка №1: Если не указать thread_id, сервер не будет сохранять историю. Каждый запрос будет восприниматься как новый диалог. thread_id — это строка, которая идентифицирует сессию.
4 Подключаем трейсинг через LangSmith SDK
Теперь самое интересное: мониторинг. Установка LangSmith не обязательна, но без ней ты будешь гадать, почему граф вернул не то. Я рекомендую самостоятельно хостить LangSmith (открытая версия, Docker образ langsmith/langsmith:latest), но можно и облачный — он все еще бесплатен для небольших проектов.
Настроим клиентский SDK. Создай файл .env в корне проекта:
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT=http://localhost:1984 # если локальный сервер
LANGSMITH_API_KEY=lsv2_... # генерируется на сервере
LANGSMITH_PROJECT=my-local-chat
Импорт SDK не нужен отдельно — он автоматически проставляется через переменные окружения, если установлен langsmith. Проверяем:
python -c "import langsmith; print('OK')"
Теперь сделай один вызов к LangGraph Server через curl или Python. В веб-интерфейсе LangSmith (открой http://localhost:1984) увидишь трейс: шаги, время выполнения, токены. Это бесценно для отладки.
5 Интеграция с клиентским SDK (Python/JS)
LangGraph Server генерирует OpenAPI, и ты можешь сгенерировать клиент через openapi-generator. Но проще использовать LangGraph SDK (Python или TypeScript). Установка:
pip install langgraph-sdk
Пример клиента:
from langgraph_sdk import get_client
client = get_client(url="http://localhost:8123")
# Создаем потоковый ран
async for chunk in client.runs.stream(
"agent",
input={"messages": [{"role": "user", "content": "What's my user id?"}]},
config={"configurable": {"thread_id": "test1"}},
stream_mode="updates",
):
print(chunk)
SDK сам управляет thread_id — можно передать свой, если хочешь продолжить диалог.
Нюансы и ошибки, на которых я обжегся
- Не ставь
temperature=0для агентов с инструментами — модель может зациклиться на одном действии. 0.7 — золотая середина. - LangGraph Server не рестартует граф автоматически при изменении кода. Придется перезапускать
langgraph serveили использовать hot-reload (флаг--reloadдля разработки). - Не забудь про CORS — если фронтенд на другом порту, добавь в
langgraph.jsonнастройки CORS:"cors": {"origins": ["*"]}. - Ограничение контекста — локальные модели часто имеют малое окно контекста (4096 или 8192). Добавь обрезку сообщений до вызова LLM в узле графа. Иначе получишь ошибку out-of-context.
- Трейсинг может падать, если LangSmith не работает. Используй переменную
LANGSMITH_TRACING=falseдля отключения без изменения кода.
Продвинутый сценарий: асинхронный граф с Long-Running операциями
В реальных продакшенах LLM может думать минутами (RAG, multi-step reasoning). LangGraph Server поддерживает асинхронные ранны: ты посылаешь запрос, получаешь ID, а потом опрашиваешь статус. Для этого граф должен быть объявлен как async. В call_model используй await llm.ainvoke(). Сервер сам подхватит асинхронность.
Примерный код уже есть в документации, но ключевой момент: если граф синхронный, сервер вешает поток на каждый запрос. При нагрузке это убьёт производительность. Делай все узлы асинхронными, особенно те, что вызывают LLM.
Мониторинг без компромиссов: свой LangSmith или облачный?
Облачный LangSmith (saas) для тестов — норм, но если модель локальная ради приватности, логично и трейсинг хранить локально. Подними Docker-контейнер:
docker run -p 1984:8080 \
-e LANGCHAIN_ENDPOINT=http://localhost:1984 \
-e LANGCHAIN_API_KEY=my-secret \
langsmith/langsmith:latest
Не забудь сгенерировать API ключ через его веб-интерфейс. Все данные останутся на твоём сервере.
Что дальше? И куда бежать?
Мы построили минимальный production-ready стек: локальная LLM, граф, REST API, трейсинг. Теперь можно добавлять:
- Авторизацию (JWT) через middleware LangGraph Server.
- Кастомные checkpointer (PostgreSQL вместо памяти).
- Деплой на k8s — LangGraph Server отлично масштабируется горизонтально.
- Интеграцию с существующими CI/CD — например, тестируй граф с помощью LangSmith eval.
Если понадобится power-user setup на дорогом железе — прочитай гайд по сборке станции за $15 000. Для небольших проектов хватит одной RTX 4090.
Главное — не пытайся объять необъятное. Начни с этого туториала, а потом усложняй. Графы — это мощно, но их надо уметь готовить. Удачи и меньше багов в логах!