✅ Решения

← К оглавлению урока

⚡ Кратко

WebBaseLoader + create_stuff_documents_chain для суммаризации; TextLoader + InMemoryVectorStore + similarity_search для Q&A по файлу.

Часть 1. Ответы

  1. Сложные приложения (несколько шагов, внешние данные, выбор инструмента) тяжело кодировать вручную. LangChain даёт готовые модульные компоненты и берёт на себя рутину оркестрации.
  2. Цепочка — последовательность операций, выполняемых одна за другой (промпт → LLM → обработка → инструмент). Аналогия: производственная линия — деталь проходит станции и на выходе готовый продукт.
  3. Models — единый интерфейс к разным LLM; Prompts — создание/управление промптами; Chains — сборка шагов в единый поток обработки.
  4. Document Loaders читают данные из форматов (PDF, web, CSV) и дают «документы»; Vector Stores хранят эмбеддинги и ищут похожие. Вместе: загрузили → разбили → сделали эмбеддинги → сохранили в хранилище → ищем по вопросу.
  5. Версионирование позволяет безопасно экспериментировать: новую версию промпта можно протестировать и откатить, если хуже. Как Git для кода — PromptHub для промптов: история, сравнение, командная работа.

Часть 2. Эталон кода

Задание 1 — суммаризация веб-страницы

# summarize.py
import os
from dotenv import load_dotenv
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_community.document_loaders import WebBaseLoader

load_dotenv()
llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash",
                             google_api_key=os.getenv("GEMINI_API_KEY"))

docs = WebBaseLoader("https://habr.com/ru/articles/883604/").load()
prompt = ChatPromptTemplate.from_template(
    "Напишите краткое изложение следующего текста: {context}")
chain = create_stuff_documents_chain(llm, prompt)

print(chain.invoke({"context": docs}))

Задание 3 — вопрос-ответ по текстовому файлу

# qa_file.py
import os
from dotenv import load_dotenv
from langchain_community.document_loaders import TextLoader
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_google_genai import (
    ChatGoogleGenerativeAI, GoogleGenerativeAIEmbeddings)

load_dotenv()
api_key = os.getenv("GEMINI_API_KEY")
if "GOOGLE_API_KEY" not in os.environ:
    os.environ["GOOGLE_API_KEY"] = api_key

# 1. Загрузка документа
docs = TextLoader("notes.txt", encoding="utf-8").load()

# 2. Эмбеддинги + векторное хранилище
store = InMemoryVectorStore.from_documents(
    docs, GoogleGenerativeAIEmbeddings(model="models/embedding-001"))

# 3. Поиск релевантных фрагментов под вопрос
question = "О чём говорится в заметках про дедлайны?"
context = "\n\n".join(d.page_content
                       for d in store.similarity_search(question, k=3))

# 4. Ответ LLM строго по контексту
llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", google_api_key=api_key)
prompt = ChatPromptTemplate.from_template(
    "Ответь по контексту.\nКонтекст:\n{context}\nВопрос: {question}")
chain = prompt | llm | StrOutputParser()

print(chain.invoke({"context": context, "question": question}))

Часть 3. Со звёздочкой — LCEL + чанки

# split_demo.py (фрагмент)
from langchain_text_splitters import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
chunks = splitter.split_documents(docs)          # вместо целых страниц — чанки
store = InMemoryVectorStore.from_documents(chunks, embeddings)
# дальше — как в задании 3: similarity_search -> промпт -> LLM
⚠️ Имена моделей/пакетов и API LangChain зависят от версий (langchain-text-splitters, имена эмбеддинг-моделей). Сверяйтесь с документацией.