LLM сами по себе — это просто генераторы текста. Чтобы превратить их в полезные приложения, нужен «клей» между моделью и вашими данными, API, базами знаний. Этот клей — фреймворки LangChain и LlamaIndex. В этом руководстве разберём оба, напишем рабочий код и определим, когда какой использовать.
Что такое AI-фреймворки и зачем они нужны
Представьте задачу: пользователь задаёт вопрос по вашей документации из 500 страниц. Нужно:
- Разбить документацию на фрагменты
- Превратить каждый фрагмент в числовой вектор (embedding)
- Найти фрагменты, релевантные вопросу
- Передать их LLM вместе с вопросом
- Отформатировать и вернуть ответ
Без фреймворка это сотни строк кода. С LangChain или LlamaIndex — десятки. Они берут на себя типовые операции: работу с разными LLM, разбиение текста, хранение векторов, оркестрацию вызовов.
LangChain: цепочки, агенты, инструменты
Архитектура LangChain
LangChain построен вокруг нескольких ключевых абстракций:
- Model — обёртка над LLM (OpenAI, Anthropic, Ollama, Hugging Face)
- Prompt Template — шаблон промпта с переменными
- Chain — последовательность шагов (промпт → модель → парсинг)
- Agent — LLM, который сам решает, какие инструменты использовать
- Tool — функция, доступная агенту (поиск, калькулятор, API)
- Retriever — получение релевантных документов из базы знаний
Установка
pip install langchain langchain-openai langchain-community
# Для работы с Ollama
pip install langchain-ollama
Простая цепочка (Chain)
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# Инициализация модели
llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
# Шаблон промпта
prompt = ChatPromptTemplate.from_messages([
("system", "Ты эксперт по {topic}. Отвечай на русском."),
("user", "{question}")
])
# Цепочка: промпт → модель → парсинг
chain = prompt | llm | StrOutputParser()
# Запуск
result = chain.invoke({
"topic": "машинное обучение",
"question": "Объясни, что такое gradient descent"
})
print(result)
RAG с LangChain
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
# 1. Загрузка документа
loader = TextLoader("docs/manual.txt", encoding="utf-8")
docs = loader.load()
# 2. Разбиение на чанки
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200
)
chunks = splitter.split_documents(docs)
# 3. Векторная база
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(chunks, embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
# 4. RAG-цепочка
prompt = ChatPromptTemplate.from_template("""
Ответь на вопрос, используя только контекст ниже.
Если ответа нет в контексте, скажи "Не знаю".
Контекст: {context}
Вопрос: {question}
""")
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
answer = chain.invoke("Как настроить уведомления?")
print(answer)
Агенты с инструментами
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
@tool
def search_database(query: str) -> str:
"""Поиск информации в базе данных компании."""
# Ваша логика поиска
return f"Результат поиска по запросу: {query}"
@tool
def send_email(to: str, subject: str, body: str) -> str:
"""Отправка email."""
return f"Email отправлен на {to}"
llm = ChatOpenAI(model="gpt-4o")
tools = [search_database, send_email]
prompt = ChatPromptTemplate.from_messages([
("system", "Ты полезный ассистент. Используй инструменты."),
("user", "{input}"),
("placeholder", "{agent_scratchpad}")
])
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = executor.invoke({
"input": "Найди контакты клиента Иванов и отправь ему email с напоминанием о встрече"
})
LlamaIndex: RAG и индексирование документов
Архитектура LlamaIndex
LlamaIndex специализируется на RAG (Retrieval-Augmented Generation) — ответах на вопросы по вашим данным. Ключевые абстракции:
- Document — единица данных (файл, страница, запись)
- Node — фрагмент документа с метаданными
- Index — структура для быстрого поиска по нодам
- Query Engine — интерфейс для вопросов к индексу
- Retriever — стратегия поиска релевантных нодов
Установка
pip install llama-index llama-index-llms-openai
# Для работы с Ollama
pip install llama-index-llms-ollama llama-index-embeddings-ollama
Быстрый старт
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
# Загрузить все файлы из папки
documents = SimpleDirectoryReader("./data").load_data()
# Создать индекс (автоматически разбивает, создаёт эмбеддинги)
index = VectorStoreIndex.from_documents(documents)
# Задать вопрос
query_engine = index.as_query_engine()
response = query_engine.query("Какие условия гарантии?")
print(response)
Продвинутый RAG с настройкой
from llama_index.core import (
VectorStoreIndex,
SimpleDirectoryReader,
Settings,
StorageContext,
load_index_from_storage,
)
from llama_index.core.node_parser import SentenceSplitter
from llama_index.llms.ollama import Ollama
from llama_index.embeddings.ollama import OllamaEmbedding
# Локальная модель через Ollama
Settings.llm = Ollama(model="llama3.2", request_timeout=120)
Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text")
# Настройка разбиения
splitter = SentenceSplitter(chunk_size=512, chunk_overlap=50)
documents = SimpleDirectoryReader("./data").load_data()
index = VectorStoreIndex.from_documents(
documents,
transformations=[splitter],
show_progress=True,
)
# Сохранение индекса на диск
index.storage_context.persist(persist_dir="./storage")
# Загрузка сохранённого индекса
# storage_context = StorageContext.from_defaults(persist_dir="./storage")
# index = load_index_from_storage(storage_context)
query_engine = index.as_query_engine(
similarity_top_k=5,
response_mode="compact",
)
response = query_engine.query("Как оформить возврат товара?")
print(response)
print(f"\nИсточники: {[n.metadata for n in response.source_nodes]}")
Сравнение LangChain и LlamaIndex
| Параметр | LangChain | LlamaIndex |
|---|---|---|
| Фокус | Оркестрация, агенты, цепочки | RAG, индексирование данных |
| RAG | Хороший, но требует настройки | Лучший из коробки |
| Агенты | Мощные, гибкие | Базовые |
| Кривая обучения | Крутая (много абстракций) | Плавная |
| Документация | Обширная, но хаотичная | Структурированная |
| Экосистема | Огромная (500+ интеграций) | Средняя (200+ интеграций) |
| Production-ready | Да (LangSmith для мониторинга) | Да (LlamaCloud) |
Когда что использовать
Выбирайте LangChain, если:
- Нужны AI-агенты с инструментами (поиск, API, базы данных)
- Строите сложный pipeline с несколькими шагами
- Нужна интеграция с множеством сервисов
- Проект требует гибкой оркестрации
Выбирайте LlamaIndex, если:
- Основная задача — RAG (ответы по документам)
- Нужен быстрый старт без глубокого погружения
- Работаете с большим количеством документов
- Важна качественная индексация и поиск
Используйте оба вместе
LangChain и LlamaIndex отлично работают вместе. Типичный паттерн: LlamaIndex для индексирования и поиска по документам, LangChain для оркестрации и агентов.
from langchain_core.tools import tool
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
# LlamaIndex для RAG
documents = SimpleDirectoryReader("./docs").load_data()
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine()
# LangChain tool с LlamaIndex под капотом
@tool
def search_docs(query: str) -> str:
"""Поиск по документации компании."""
response = query_engine.query(query)
return str(response)
# Используем tool в LangChain-агенте
# ... (код агента из примера выше)
Альтернативы
- Haystack — фреймворк от deepset, хорошо подходит для production RAG
- Semantic Kernel — от Microsoft, интегрируется с .NET и Python
- DSPy — программирование LLM как обычных функций, автоматическая оптимизация промптов
FAQ
Нужно ли знать Python для работы с фреймворками?
Да, оба фреймворка — Python-библиотеки. Базового знания Python достаточно для простых задач, но для production-приложений нужен уверенный уровень.
Можно ли использовать с локальными моделями?
Да, оба поддерживают Ollama, llama.cpp, Hugging Face Transformers. Просто замените модель OpenAI на локальную.
Какой фреймворк популярнее?
LangChain — по GitHub-звёздам и размеру сообщества. Но LlamaIndex растёт быстрее и имеет более довольных пользователей в нише RAG.