AI-инжиниринг
LangChain и LlamaIndex: оркестрация LLM pipeline
Цели урока
- Понять ключевые абстракции LangChain: Runnable, Chain, LCEL и когда они оправданы
- Освоить LlamaIndex: типы индексов, Query Engine, NodePostprocessors
- Сравнить LangChain, LlamaIndex и raw SDK по объективным критериям
- Написать custom chain и кастомный post-processor для production pipeline
- Распознавать ловушки over-abstraction и проектировать фреймворк-агностичную архитектуру
LangChain появился в январе 2023 - за 2 месяца до того как большинство людей узнало что такое LLM. Поэтому он везде. И поэтому он переусложнён - проектировался без понимания куда всё идёт. Стартап потратил 3 месяца на LangChain-based RAG. При дебаге production-бага инженер нашёл 14 уровней абстракции между HTTP-запросом и вызовом OpenAI API. Причина - embedding dimension mismatch - была скрыта за 8 обёртками. Переписали на raw SDK за 2 дня. Баг нашли за 5 минут. Фреймворки экономят время - пока не начинают его красть.
- Vercel AI SDK - осознанный минимализм: thin wrapper без 200 зависимостей, используется в Next.js AI apps именно потому что не LangChain
- Perplexity AI (100M+ запросов/месяц) - начинали на LangChain, мигрировали на собственную инфраструктуру при масштабе: абстракции стали bottleneck
- Cursor - naked Anthropic SDK без фреймворков. Полный контроль над каждым токеном, минимальная latency
- Notion AI - LlamaIndex для indexing документов (data connectors + VectorStoreIndex), собственный retrieval pipeline для production-трафика
Предварительные знания
LangChain и LlamaIndex: два инструмента с одного хакатона
Осенью 2022 в Robust Intelligence прошёл внутренний хакатон по работе с LLM, и из него выросли сразу два инструмента, ставшие опорой AI-инженерии. 24 октября 2022 Harrison Chase выложил первую версию LangChain как Python-пакет: библиотека склеивала промпты, цепочки, память и tools вокруг модели и быстро набрала популярность. Примерно тогда же Jerry Liu начал проект под названием GPT Index: первый коммит и анонс пришлись на ноябрь 2022, ранние версии включали идеи вроде tree index для организации документов. Позже GPT Index был переименован в LlamaIndex. Фокус у проектов разный: LangChain - про оркестрацию вызовов модели, LlamaIndex - про загрузку данных, индексирование и RAG поверх собственных документов.
LangChain: Chains, LCEL и ядро фреймворка
LangChain появился в январе 2023 - за 2 месяца до того как большинство людей узнало что такое LLM. Поэтому он везде. И поэтому он переусложнён - проектировался без понимания куда всё идёт. За 2023-2024 годы он вырос от набора утилит до экосистемы со своим языком композиции - **LCEL (LangChain Expression Language)**. 90K звёзд на GitHub. И столько же жалоб на абстракции поверх абстракций.
Ядро LangChain строится на трёх абстракциях:
| Абстракция | Что делает | Аналог в backend |
|---|---|---|
| Runnable | Единица вычисления с .invoke(), .stream(), .batch() | Express middleware |
| Chain | Последовательность Runnables, связанных через pipe | Pipeline паттерн |
| Retriever | Интерфейс для поиска документов (vector DB, BM25, hybrid) | Repository паттерн |
**LCEL** - это способ соединять Runnables в цепочки через `.pipe()` (или `|` в Python). Каждый элемент принимает выход предыдущего, передаёт дальше. Streaming, batching и async - бесплатно, без дополнительного кода. Звучит как магия - и выглядит как магия, пока не нужно что-то продебажить.
Выглядит элегантно. Четыре импорта, три объекта, один chain - и рабочий RAG. Теперь посмотрим на **тот же самый pipeline** без LangChain - чистый OpenAI SDK и pgvector:
Два примера выше делают **абсолютно одно и то же**. LangChain - 25 строк + 4 зависимости. Raw SDK - 20 строк + 2 зависимости. Для простого RAG фреймворк добавляет сложность, не давая ничего взамен. Ценность LangChain начинается там, где появляется сложность: fallback, routing, memory, сложный tool calling.
Где LangChain реально оправдан:
- **Agents с tools** - LangChain Agent loop с автоматическим tool calling и парсингом
- **Memory** - встроенные стратегии управления историей (buffer, summary, token window)
- **Callbacks/Tracing** - LangSmith интеграция из коробки для debugging и мониторинга
- **Быстрое прототипирование** - собрать MVP за час, потом переписать на raw SDK
Какое главное преимущество LCEL в LangChain?
LlamaIndex: индексация и query engine
LangChain - швейцарский нож. **LlamaIndex** - скальпель. Один инструмент, одна задача: **подключить LLM к данным**. Фреймворк вырос из проекта "GPT Index" 2022 года - идея была простая: LLM умный, но слепой. Нужна инфраструктура, которая кладёт релевантные документы прямо в контекст. LlamaIndex строит эту инфраструктуру с data connectors, индексами и query engine из коробки.
Центральная абстракция - **Index**. Структура данных, оптимизированная для LLM-запросов. Четыре основных типа:
| Index Type | Как работает | Когда использовать |
|---|---|---|
| VectorStoreIndex | Embedding каждого chunk → cosine similarity при поиске | 90% случаев: Q&A, поиск по документам, RAG |
| SummaryIndex (ListIndex) | LLM последовательно читает каждый node | Суммаризация документа, когда нужен весь контекст |
| TreeIndex | Иерархическое дерево: листья → summary → root | Длинные документы с иерархической структурой |
| KeywordTableIndex | Keyword extraction → inverted index | Поиск по ключевым словам, когда embedding не нужен |
Сила LlamaIndex - в абстракции **Query Engine**. Не просто поиск - полный pipeline: retrieval (text-embedding-3-small, 1536 dim, cosine similarity) → post-processing (reranking, фильтрация) → response synthesis (итоговый вызов LLM с найденным контекстом). Три шага, один вызов.
LlamaIndex - это **3 строки до рабочего RAG**: загрузить документы, создать индекс, задать вопрос. Для прототипа - идеально. Но за магией скрываются жёсткие дефолты: SentenceSplitter с chunk_size=1024, text-embedding-3-small, стандартный prompt template. В production это нужно переопределять - иначе качество будет случайным.
Что отличает LlamaIndex от LangChain: специализированные query engine, которых у конкурента нет из коробки:
- **Sub-Question Query Engine** - разбивает сложный вопрос на подвопросы и агрегирует ответы
- **Router Query Engine** - автоматически выбирает нужный index для вопроса
- **Citation Query Engine** - каждое утверждение в ответе ссылается на конкретный chunk
- **Agentic RAG** - комбинация RAG + tool calling для сложных аналитических запросов
Какой тип индекса LlamaIndex подходит для классического RAG (вопрос-ответ по документам)?
LangChain vs LlamaIndex vs Raw SDK: дерево принятия решений
State of AI Engineering 2024: **43% команд** используют raw SDK как основной подход. Ещё 31% используют LangChain - но 60% из них планируют уменьшить зависимость. Twitter заполнен мемами про "LangChain hell": простой API-вызов в 15 абстракциях. За хейтом - реальный вопрос: **когда фреймворк экономит время, а когда создаёт технический долг?**
Объективная матрица сравнения:
| Критерий | Raw SDK (OpenAI/Anthropic) | LangChain | LlamaIndex |
|---|---|---|---|
| Простой API-вызов | ★★★ 3 строки | ★★ 8 строк + 2 зависимости | ★ Не для этого |
| RAG pipeline | ★★ 20-30 строк | ★★★ 10-15 строк LCEL | ★★★ 3 строки до MVP |
| Agent с tools | ★★ Нужен свой loop | ★★★ Готовый agent executor | ★★ Через agent API |
| Memory/History | ★ Ручная реализация | ★★★ 5+ стратегий из коробки | ★★ Через chat engine |
| Debugging | ★★★ Всё прозрачно | ★ Абстракции скрывают ошибки | ★★ Умеренная прозрачность |
| Vendor lock-in | ★★ SDK конкретного провайдера | ★★★ Унифицированный интерфейс | ★★★ Унифицированный интерфейс |
| Bundle size (Node) | ★★★ ~2 MB | ★ ~50 MB | ★★ ~20 MB |
| Production stability | ★★★ API не меняется | ★ Breaking changes каждый месяц | ★★ Реже ломается |
На практике выбор прямой. Простое правило: начинать с raw SDK, добавлять фреймворк только когда raw-код становится неуправляемым. Дерево решений:
Многие production-системы используют **гибридный подход**: LlamaIndex для indexing и retrieval (data connectors + VectorStoreIndex), raw OpenAI SDK для generation, и минимальную обвязку LangChain только для agent loop. Фреймворки не конкурируют - они решают разные части одной задачи.
Стартап строит AI-ассистента для юристов: поиск по 50K контрактам + суммаризация + ответы на вопросы. Какой подход оптимален?
Custom chains и расширение фреймворков
Готовые абстракции покрывают 70% случаев. Оставшиеся 30% - бизнес-логика конкретного продукта: проверка прав доступа, фильтрация по тенанту, compliance-проверки, кастомный reranking. Здесь фреймворк перестаёт помогать и начинает мешать - если не уметь его расширять.
В LangChain любой объект, реализующий интерфейс **Runnable**, участвует в LCEL-цепочке. `RunnableLambda` - способ завернуть любую async-функцию в Runnable без написания класса:
В LlamaIndex аналогичный механизм - **NodePostprocessors**. Они стоят между retrieval и synthesis: фильтруют, переранжируют, обогащают найденные чанки до передачи в LLM:
Custom chains - это точка, где абстракция фреймворка становится по-настоящему полезной. Подменяется один компонент (retriever, post-processor, output parser), а остальная инфраструктура - streaming, error handling, callbacks в LangSmith - остаётся от фреймворка. Не нужно строить всё с нуля, достаточно встроить свою логику в нужное место pipeline.
Для добавления проверки прав доступа в RAG pipeline на LangChain LCEL нужно:
Ловушки абстракций: когда фреймворк вредит
Январь 2024. Hacker News. Пост "Please stop using LangChain" набирает 800+ upvotes за день. Автор - senior engineer из AI-стартапа - показал: замена LangChain на raw OpenAI SDK сократила кодовую базу на 40% и убрала 3 production-бага. Не один баг случайно нашли - три системных. Это не хейт, это симптом: **over-abstraction** в AI-фреймворках стала настоящей проблемой.
Анти-паттерн 1: "Абстракция ради абстракции"
Анти-паттерн 2: "Чёрный ящик"
Абстракции скрывают детали реализации. Удобно, пока всё работает. Когда что-то ломается - debugging через 8 уровней наследования. И главное: **неясно, что именно уходит в API**. Какой промпт? Сколько токенов? Почему ответ пустой? Без LangSmith это чёрный ящик.
Анти-паттерн 3: "Версионный ад"
LangChain проектировался в 2023 году с нулевым пониманием куда пойдёт экосистема. Результат - постоянная смена API. Код из туториала трёхмесячной давности может не компилироваться:
Правила здоровой работы с фреймворками
- **Начинать с raw SDK** - понять, что происходит под капотом. Фреймворк добавлять, когда raw-код становится неуправляемым
- **Изолировать фреймворк** - обернуть LangChain/LlamaIndex в собственные интерфейсы. При смене фреймворка меняется только одна обёртка, бизнес-логика не трогается
- **Пинить версии** - lockfile + точная версия, никаких `^` и `~` для AI-фреймворков. Особенно для LangChain
- **Держать escape hatch** - в критических местах raw SDK. Фреймворк - для boilerplate и прототипа, не для core pipeline
- **Мониторить промпты** - через LangSmith, Langfuse или свой логгер. Иначе непонятно что уходит в API, сколько стоит каждый запрос и где теряется качество
Золотое правило: **фреймворк должен быть деталью реализации, а не архитектурой приложения**. Если удаление LangChain требует переписывания более 20% кодовой базы - зависимость слишком глубокая. Фреймворк - слуга, не хозяин.
LangChain абстракции упрощают код
В production они усложняют debugging и скрывают что именно уходит в API
На прототипе LangChain экономит время - цепочка собирается за минуты. В production начинаются вопросы: какой именно промпт отправился? Почему ответ пустой? Сколько токенов потратили? Без LangSmith это чёрный ящик. Stack trace при ошибке - 14 уровней LangChain internals вместо одной строки с реальной причиной. Raw SDK даёт полную прозрачность: видно каждый байт запроса, каждый токен ответа, каждый статус-код.
Какой подход защищает от vendor lock-in при использовании AI-фреймворков?
Итоги
- LangChain появился в январе 2023 переусложнённым - проектировался без понимания куда идёт экосистема. Знать нужно, копировать - нет
- LCEL (LangChain Expression Language) - pipe-композиция Runnables с бесплатным streaming и async. Полезно для сложных agent pipeline
- LlamaIndex - специализирован для данных: data connectors, VectorStoreIndex, Sub-Question Query Engine. 3 строки до рабочего RAG
- 43% команд используют raw SDK как основной подход - это не ретроградство, это прозрачность и отсутствие версионного ада
- LangChain абстракции упрощают прототип, но усложняют debugging в production: скрывают промпты, стоимость, причины ошибок
- Фреймворк должен быть деталью реализации, не архитектурой. Изоляция через собственный интерфейс + DI - защита от vendor lock-in
Вопросы для размышления
- Perplexity мигрировал с LangChain при масштабе - на каком моменте фреймворк становится bottleneck? Что именно ломается первым?
- LangChain популярен и ненавидим одновременно. Как инструмент с 90K GitHub-звёзд вызывает столько жалоб - это проблема фреймворка или ожиданий?
- Cursor использует naked Anthropic SDK без фреймворков и является одним из лучших AI-продуктов. Что это говорит о связи между сложностью инструментов и качеством продукта?
Что дальше
Выбор фреймворка - это инструмент. Следующий шаг - паттерны оркестрации: как строить complex pipeline с routing, fallback, parallel execution и map-reduce.
- Паттерны оркестрации — Sequential, parallel, routing, map-reduce - архитектурные паттерны для AI pipeline
- Model Routing — Автоматический выбор модели (GPT-4 vs Claude vs local) в зависимости от задачи
- Agent Frameworks — LangGraph, CrewAI, AutoGen - фреймворки для multi-step agents
Связанные уроки
- aie-12-rag-fundamentals — Ретриверы и цепочки это строительные блоки RAG
- aie-16-tool-calling — Абстракции инструментов оборачивают function calling
- aie-21-orchestration-patterns — Фреймворки выражают паттерны оркестрации в коде
- aie-18-agent-frameworks — Фреймворки агентов пересекаются с этими библиотеками оркестрации
- sd-12-service-mesh — Фреймворк это связующий middleware, как service mesh
- dl-01