Інтеграція LangChain для AI-пайплайнів

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1566 послуг
Інтеграція LangChain для AI-пайплайнів
Середній
від 1 тижня до 3 місяців
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    901
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1119
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    853

Інтеграція LangChain для AI-конвеєрів

LangChain — це фреймворк для побудови LLM-додатків, що надає абстракції над моделями, документами, інструментами та пам'яттю. Ключова концепція — ланцюги (chains), які об'єднують компоненти в відтворювані конвеєри обробки. LCEL (LangChain Expression Language) — це декларативний інтерфейс, який унісує синтаксис для будь-якої комбінації компонентів.

LCEL: Основа сучасного LangChain

LCEL використовує оператор | для композиції компонентів. Будь-який об'єкт, що реалізує Runnable, можна з'єднати в ланцюг:

from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
from langchain_core.runnables import RunnablePassthrough, RunnableParallel
from langchain_community.vectorstores import Chroma

llm = ChatOpenAI(model="gpt-4o", temperature=0)

# Простий ланцюг
prompt = ChatPromptTemplate.from_messages([
    ("system", "Ви — експерт у {domain}."),
    ("human", "{question}"),
])

chain = prompt | llm | StrOutputParser()
result = chain.invoke({"domain": "фінансовий аналіз", "question": "Що таке EBITDA?"})

# Паралельний ланцюг
parallel_chain = RunnableParallel({
    "summary": prompt | llm | StrOutputParser(),
    "keywords": ChatPromptTemplate.from_template("Виконайте екстракцію ключових слів: {question}") | llm | StrOutputParser(),
})

Інтеграція з LLM-провайдерами

LangChain підтримує єдиний інтерфейс для різних провайдерів:

# OpenAI
from langchain_openai import ChatOpenAI
llm_openai = ChatOpenAI(model="gpt-4o-mini", temperature=0.2)

# Anthropic
from langchain_anthropic import ChatAnthropic
llm_claude = ChatAnthropic(model="claude-3-5-sonnet-20241022")

# Google
from langchain_google_genai import ChatGoogleGenerativeAI
llm_gemini = ChatGoogleGenerativeAI(model="gemini-2.0-flash")

# Локальна Ollama
from langchain_ollama import ChatOllama
llm_local = ChatOllama(model="llama3.2:3b", temperature=0)

# Hugging Face
from langchain_huggingface import HuggingFaceEndpoint
llm_hf = HuggingFaceEndpoint(repo_id="mistralai/Mistral-7B-Instruct-v0.3")

Зміна провайдера не потребує зміни логіки ланцюга — лише заміна об'єкту llm.

RAG-конвеєр з LangChain

from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_qdrant import QdrantVectorStore
from langchain_core.runnables import RunnablePassthrough
import json

# Завантаження та розділення документів
loader = DirectoryLoader("./docs", glob="**/*.pdf", loader_cls=PyPDFLoader)
docs = loader.load()

splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=100)
chunks = splitter.split_documents(docs)

# Індексування
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = QdrantVectorStore.from_documents(
    chunks,
    embedding=embeddings,
    url="http://localhost:6333",
    collection_name="knowledge_base",
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

# RAG-ланцюг
rag_prompt = ChatPromptTemplate.from_template("""Відповідьте на питання на основі контексту.

Контекст:
{context}

Питання: {question}

Якщо відповіді немає в контексті — скажіть про це явно.""")

def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | rag_prompt
    | llm
    | StrOutputParser()
)

answer = rag_chain.invoke("Які умови розірвання контракту?")

Керування пам'яттю в діалозі

from langchain.memory import ConversationBufferWindowMemory
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import RedisChatMessageHistory

# Історія чату в Redis
def get_session_history(session_id: str) -> BaseChatMessageHistory:
    return RedisChatMessageHistory(session_id, url="redis://localhost:6379")

chat_prompt = ChatPromptTemplate.from_messages([
    ("system", "Ви — асистент технічної підтримки."),
    ("placeholder", "{history}"),
    ("human", "{input}"),
])

chain_with_history = RunnableWithMessageHistory(
    chat_prompt | llm | StrOutputParser(),
    get_session_history,
    input_messages_key="input",
    history_messages_key="history",
)

# Використання
config = {"configurable": {"session_id": "user_123"}}
chain_with_history.invoke({"input": "Мій додаток не запускається"}, config=config)
chain_with_history.invoke({"input": "Помилка: 'connection refused'"}, config=config)

Structured Output та валідація

from pydantic import BaseModel, Field
from typing import Literal

class TicketClassification(BaseModel):
    category: Literal["billing", "technical", "account", "other"]
    priority: Literal["low", "medium", "high", "critical"]
    summary: str = Field(description="Коротке описання проблеми (1-2 речення)")
    requires_human: bool

structured_llm = llm.with_structured_output(TicketClassification)

classify_prompt = ChatPromptTemplate.from_messages([
    ("system", "Класифікуйте звернення до техпідтримки."),
    ("human", "{ticket_text}"),
])

classifier_chain = classify_prompt | structured_llm
result: TicketClassification = classifier_chain.invoke({
    "ticket_text": "Я не можу увійти в систему, пароль не підходить уже другий день"
})

LangSmith: Трасування та налагодження

import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "ls__..."
os.environ["LANGCHAIN_PROJECT"] = "production-rag"

# Всі виклики автоматично логуються в LangSmith
# Доступні: вхідні/вихідні дані, latency, токени, вартість, трейс

LangSmith дозволяє аналізувати промпти, знаходити вузькі місця в ланцюгах та порівнювати версії конвеєрів через dataset-evaluation.

Практичний приклад: Уніфікація 5 LLM-інтеграцій

Ситуація: продуктова команда підтримувала 5 окремих інтеграцій (OpenAI, Claude, корпоративний YandexGPT, локальний Llama, Gemini) з дублюванням коду retry-логіки, форматування промптів та обробки помилок.

Рішення: рефакторинг на LangChain LCEL з єдиним інтерфейсом.

Архітектура:

  • Конфігурований провайдер через env-змінну LLM_PROVIDER
  • Загальні промпт-шаблони в YAML-файлах
  • Єдиний шар обробки помилок через .with_fallbacks()
from langchain_core.runnables import RunnableWithFallbacks

primary_llm = ChatOpenAI(model="gpt-4o")
fallback_llm = ChatAnthropic(model="claude-3-5-sonnet-20241022")

robust_llm = primary_llm.with_fallbacks([fallback_llm])

Результати:

  • Обсяг коду інтеграцій: -67%
  • Час додавання нового провайдера: 3 дні → 4 години
  • Uptime конвеєра (за рахунок fallback): 99.1% → 99.8%
  • Видимість у LangSmith: час налагодження інцидентів скоротився з 2ч на 20хв

Коли LangChain надмірний

LangChain додає абстракцію, яка обґрунтована при складних конвеєрах. Для простого одноразового виклику LLM прямого використання SDK (OpenAI, Anthropic) простіше та передбачуваніше. LangChain оптимальний коли: кілька компонентів (retriever + LLM + parser), кілька провайдерів, потрібні трасування та пам'ять.

Графік реалізації

  • Базова інтеграція LangChain + 1 провайдер: 2–4 дні
  • RAG-конвеєр з векторною БД: 1–2 тижні
  • Діалоговий агент з пам'яттю: 1–2 тижні
  • Рефакторинг існуючого коду на LCEL: 1–3 тижні