Главная / Статьи / Практическое применение LangChain 1.x: цепочки обработки данных, RAG, инструменты и агенты в локальной среде

Практическое применение LangChain 1.x: цепочки обработки данных, RAG, инструменты и агенты в локальной среде

Научитесь создавать цепочки обработки данных, методы генерации с улучшением на основе поиска, инструменты и агентные системы RAG с использованием LangChain 1.x в рамках бесплатной локальной установки Ollama без необходимости API-ключей.

3586 слов

Это третья часть серии практических уроков, продолжающая предыдущие работы по созданию RAG и агентов с нуля на чистом Python. Подход здесь намеренно отличается: вместо того чтобы самостоятельно собирать каждую составляющую, вы увидите, как LangChain объединяет всю эту технику в несколько строк кода. Поскольку вы уже сами создавали основные компоненты, у вас есть хорошая возможность понять, что на самом деле делает каждая абстракция, вместо того чтобы рассматривать её как что-то магическое. Это понимание важно — оно определяет разницу между разработчиками, которые эффективно используют LangChain, и теми, кто постоянно сталкивается с его сложностями.

Всё в этом уроке работает локально и бесплатно, с использованием локальной модели через Ollama вместе с локальными эмбеддингами. Не требуются API-ключи, и нет необходимости беспокоиться о лимитах использования.

Примечание о версиях: данный учебник предназначен для LangChain 1.x и протестирован с использованием версий langchain==1.3.11 и langchain-core==1.4.8. Версия LangChain 1.0 принесла существенные изменения в структуре — текущий API агентов основан на функции create_agent, в то время как более старые компоненты, такие как AgentExecutor и initialize_agent, были перенесены в отдельный пакет langchain-classic. Многие учебные материалы, доступные в Интернете, по-прежнему демонстрируют подходы, характерные для версий до 1.0; приведённые здесь импорты соответствуют текущим версиям, и каждый из них был проверен на правильность работы.

Как следовать инструкциям: откройте файл с именем lc.py, запустите каждый блок кода по порядку и выполняйте упражнения «Ваша очередь», когда они появятся. Каждый раз, когда вы увидите фразу «это вы создали», речь идет об реализации из предыдущих уроков этой серии.

Шаг 0 — Что такое LangChain

LangChain лучше всего понимать как совокупность стандартизированных, взаимозаменяемых компонентов для создания приложений на основе больших языковых моделей — таких как обертки для моделей, шаблоны запросов, механизмы поиска информации, хранилища векторов, инструменты и агенты. Все эти компоненты соответствуют общему интерфейсу, что позволяет объединять их между собой и заменять один другим (например, использовать другую модель или хранилище векторов) без необходимости переписывать логику приложения.

Концепция, объединяющая всё воедино, — это Runnable. Каждый компонент предоставляет один и тот же метод .invoke(), и любые два компонента могут быть связаны друг с другом с помощью оператора трубки |. Этот механизм связи называется LCEL — сокращение от LangChain Expression Language. Как только каждая часть вашей системы будет использовать интерфейс Runnable, весь пайплайн RAG или агент можно будет описать всего в нескольких строках.

Откровенный компромисс, который стоит упомянуть сразу: LangChain сокращает количество повторяющегося кода и предоставляет доступ к обширному каталогу готовых интеграций. Взамен он вводит слои абстракции, которые могут затруднить отладку — бывают моменты, когда хочется просто смотреть на обычный цикл, написанный вручную. Настоящим навыком является понимание того, когда такая абстракция оправдывает свою стоимость, и мы снова вернемся к этому компромиссу на шаге 7.

Настройка (бесплатная локальная среда)

pip install langchain langchain-core langchain-ollama langchain-huggingface langchain-text-splitters sentence-transformers

Также потребуется установленный Ollama (он бесплатен и работает локально); после этого следует загрузить модель, способную выполнять вызовы инструментов:

ollama pull llama3.2     # ~2 GB; needs ~8 GB RAM. qwen2.5 also works well.

Если вы предпочитаете обойтись без Ollama, вы всё равно можете запустить разделы chain и RAG, используя локальную модель Hugging Face через библиотеку langchain-huggingface. Однако разделы agent требуют надёжной обработки вызовов инструментов, что маленькие модели с ограниченными ресурсами CPU обычно делают плохо. Для шагов с 4 по 6 настоятельно рекомендуется использовать Ollama.

Шаг 1 — Основной механизм: цепочка операций с использованием символа трубки |

В предыдущем уроке по RAG вы вручную формировали запрос с помощью f-string, передавали его модели и очищали результат с помощью метода .strip(). LangChain предоставляет возможность использовать точно такую же последовательность операций в виде выражения с трубкой. Добавьте следующий код в файл lc.py:

from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOllama(model="llama3.2", temperature=0)

prompt = ChatPromptTemplate.from_template(
    "Explain {topic} in exactly one sentence."
)

# The chain: prompt -> model -> plain-string parser
chain = prompt | llm | StrOutputParser()

print(chain.invoke({"topic": "retrieval-augmented generation"}))

Чтение данных по трубопроводу слева направо: функция prompt преобразует введённый словарь в сообщение с правильным форматированием, llm превращает это сообщение в ответ модели, а функция StrOutputParser() извлекает обычный текст из объекта ответа.

Вы уже создали это ранее. Данный трубопровод функционально идентичен последовательности f"Explain {topic}...", затем generator(prompt) и в конце [0]["generated_text"].strip() из предыдущего обзора RAG — три ручных шага, теперь представленные в виде трёх компонентов, соединённых трубопроводом. Логика не изменилась; была лишь стандартизирована интерфейсная часть.

Ваша очередь: каждый компонент типа Runnable изначально поддерживает методы .batch() и .stream(). Попробуйте это:

for piece in chain.stream({"topic": "vector embeddings"}):
    print(piece, end="", flush=True)   # tokens arrive as they're generated
print()
print(chain.batch([{"topic": "agents"}, {"topic": "chunking"}]))  # two at once

Обратите внимание, что стриминг и группировка данных появились бесплатно просто потому, что вы использовали стандартный интерфейс Runnable. Этот момент «бесплатности» в миниатюре и является основанием для использования LangChain.

Шаг 2 — RAG по-методу LangChain

Пришло время воссоздать вашу ручную схему RAG с использованием элементов конструкции LangChain. Каждый из этих элементов напрямую соответствует тому, что вы уже писали вручную.

from langchain_huggingface import HuggingFaceEmbeddings
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_text_splitters import RecursiveCharacterTextSplitter

# Same Nimbus knowledge base from the RAG tutorial
DOCUMENTS = [
    "Nimbus is a fictional note-taking app. The free plan, Nimbus Lite, allows up to 50 notes and 1 GB of storage.",
    "Nimbus Pro costs 8 dollars per month billed annually, or 10 dollars billed monthly. It includes 50 GB of storage and collaboration for up to 5 people.",
    "Nimbus stores notes encrypted at rest with AES-256. End-to-end encryption is Pro-only and must be enabled in Settings > Security.",
    "Nimbus offers a 30-day refund policy on all paid plans. Refunds reach the original payment method within 5 business days.",
    "Nimbus live chat support is staffed for Pro customers, Monday to Friday, 9am-6pm UTC. Free users get email support with a 48-hour response time.",
]

# 1. Split (↔ your chunk_text function)
splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=40)
chunks = splitter.create_documents(DOCUMENTS)

# 2. Embed locally (↔ your sentence-transformers model)
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")

# 3. Store + index (↔ your numpy array of vectors). No server needed.
vectorstore = InMemoryVectorStore.from_documents(chunks, embeddings)

# 4. Retriever (↔ your retrieve() with cosine top-k)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

for doc in retriever.invoke("How much does Pro cost?"):
    print("-", doc.page_content[:70], "...")

↔ вы сами это создали — всю эту систему целиком. RecursiveCharacterTextSplitter выполняет функцию разбиения текста на части, но делает это более тщательно: он разделяет текст по границам абзацев и предложений, а не просто считает слова. HuggingFaceEmbeddings представляет собой обертку вокруг той же модели all-MiniLM-L6-v2, которую вы использовали ранее. InMemoryVectorStore заменяет ваш массив векторов в формате numpy, а его метод .as_retriever() выполняет тот же поиск по косинусному сходству типа top-k, который вы реализовывали вручную. Четыре строки здесь описывают всё, что вы создали на этапах с 2 по 4 ранее.

Далее соедините процесс поиска с генерацией с помощью LCEL:

from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

rag_prompt = ChatPromptTemplate.from_template(
    "Answer using only the context. If it's not there, say you don't know.\n\n"
    "Context:\n{context}\n\nQuestion: {question}\nAnswer:"
)

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

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

print(rag_chain.invoke("How much does Nimbus Pro cost per month?"))

Словарь в начале цепочки обрабатывает два пути параллельно: question просто передаёт входные данные без изменений, тогда как context направляет эти же данные через механизм поиска и форматирует результаты. Оба результата затем поступают в промпт. ↔ вы сами это создали — это по сути ваша старая функция rag_answer(): поиск данных, вставка их в промпт, генерация ответа — всё это сведено к одному выражению.

Ваша очередь: Попробуйте вызвать rag_chain.invoke("Могут ли свободные пользователи пользоваться чатом в реальном времени?"), а затем задайте не связанный с этим вопрос, например rag_chain.invoke("Какая столица Франции?"). Обратите внимание на ответ «Я не знаю» — это тот же самый проверочный вопрос, что и в предыдущем уроке RAG, подчеркивающий одну и ту же мысль: качество поиска определяет качество ответа. После этого вызовите retriever.invoke(...) отдельно, чтобы узнать, что именно было извлечено, если ответ кажется некорректным. Такое разделение — проверка поиска независимо от генерации ответа — является привычкой при отладке, которую вы уже использовали ранее, и LangChain сохраняет её, оставляя эти два шага как отдельные объекты типа Runnable.

Шаг 3 — Инструменты

В учебном руководстве по агентам вы определили инструменты как словарь TOOLS и сами написали парсер на основе регулярных выражений для извлечения названия инструмента и его входных данных из необработанного текстового вывода модели. LangChain полностью устраняет необходимость в таком парсере благодаря встроенному вызову инструментов: вы описываете, что делает инструмент, модель отвечает структурированным вызовом, а LangChain занимается маршрутизацией. Определение инструмента выглядит следующим образом с использованием декоратора @tool:

from langchain_core.tools import tool
import ast, operator, datetime

_OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul,
        ast.Div: operator.truediv, ast.Pow: operator.pow, ast.USub: operator.neg}
def _ev(n):
    if isinstance(n, ast.Constant): return n.value
    if isinstance(n, ast.BinOp):   return _OPS[type(n.op)](_ev(n.left), _ev(n.right))
    if isinstance(n, ast.UnaryOp): return _OPS[type(n.op)](_ev(n.operand))
    raise ValueError("unsupported")

@tool
def calculator(expression: str) -> str:
    """Evaluate a basic arithmetic expression like '8 * 12'."""
    return str(_ev(ast.parse(expression, mode="eval").body))

@tool
def get_today(_: str = "") -> str:
    """Return today's date in ISO format."""
    return datetime.date.today().isoformat()

Вот то, что стоит рассмотреть подробнее. Вы можете увидеть, что именно сгенерировал LangChain из вашей функции:

print(calculator.name)         # 'calculator'
print(calculator.description)  # the docstring
print(calculator.args)         # {'expression': {'title': 'Expression', 'type': 'string'}}

Эта последняя строка — это подлинный, проверенный результат. LangChain проанализировал ваше указание типа (expression: str) вместе с документацией и на основе этого создал схему — именно эта схема используется моделью для определения того, следует ли вызывать инструмент и как это сделать. ↔ вы сами создали её; раньше вы вручную писали описания инструментов внутри своего SYSTEM_PROMPT и сами анализировали вывод модели. Теперь сама документация становится описанием, а анализ происходит автоматически. Это объясняет, почему документация и указания типов имеют огромное значение — они не просто документация, а определяют, как модель понимает и использует инструмент. Небрежная документация приводит к тому, что модель неправильно вызывает инструмент.

Ваша очередь: Замените документацию калькулятора на что-то бесполезное, например """делает математику""", затем снова проверьте значение .description. На 4-м шаге вы сами увидите, как более слабая документация приводит к худшим решениям модели при выборе инструментов. Описание, которое вы пишете, служит своего рода рулём для управления поведением модели.

Шаг 4 — Агенты в одном вызове

Именно здесь окупаются предыдущие усилия. Агент, созданный вами вручную, требовал цикла, временной памяти, парсера, обработки ошибок, ограничения по количеству шагов и системного промпта, который обучал модель формату ReAct. В LangChain 1.x всё это сводится к одному вызову функции: create_agent.

from langchain.agents import create_agent

agent = create_agent(
    model=llm,                                   # your ChatOllama from Step 1
    tools=[calculator, get_today],               # the @tool functions from Step 3
    system_prompt="You are a helpful assistant. Use tools for math and dates.",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What is 8 times 12, and what is today's date?"}]}
)
print(result["messages"][-1].content)

Это весь агент, от начала до конца. ↔ вы сами его создали — полностью. Функция create_agent внутри себя выполняет цикл «причина-действие-наблюдение», направляет задачу в соответствующий инструмент, подает полученные данные обратно в модель, проверяет условия остановки и соблюдает лимит шагов — всё то, что вы вручную собрали в функции run_agent. В основе всего лежит LangGraph, именно поэтому поведение алгоритма настолько надежно.

Если вы хотите наблюдать за процессом принятия решений — так же, как это показывал режим verbose=True — передавайте промежуточные шаги в реальном времени, а не просто ждите окончательного ответа:

inputs = {"messages": [{"role": "user", "content": "How much is a year of Nimbus Pro?"}]}
for chunk in agent.stream(inputs, stream_mode="updates"):
    print(chunk)

По мере его работы вы увидите каждое решение, принятое моделью, и каждый результат, возвращаемый инструментом; они будут выводиться один за другим. Это тот же самый паттерн «Мысль/Действие/Наблюдение», что и в ручном отслеживании, только теперь информация предоставляется в виде структурированных объектов обновлений, а не в виде сырого текста, который приходилось парсить самостоятельно.

Ваша очередь: Попробуйте задать вопрос, который заставит модель использовать два инструмента подряд — например, попросите её определить дату окончания 30-дневного срока возврата средств, если пробный период начался сегодня. Посмотрите, правильно ли она сначала вызывает функцию get_today, а затем calculator. После этого вернитесь к шагу 7 материала об агентах — все способы сбоев, которые вы там описали (изменение формата вывода, выдуманные названия инструментов, бесконечные циклы), могут проявиться и здесь. Фреймворк не улучшает способность слабой модели к логическим рассуждениям; он просто скрывает внутренние механизмы. Именно понимание этой разницы позволит вам быстрее отлаживать этих агентов, чем тем, кто сразу переходит к использованию фреймворка, не создав модель сначала.

Шаг 5 — Собираем всё вместе: агент, выполняющий поиск информации (агентный RAG)

Здесь сходятся все три предыдущих урока. Возьмите своего поискового агента и представьте его в виде инструмента, затем передайте этот инструмент агенту. Начиная с этого момента сам агент решает, когда необходимо выполнять поиск документов — он может искать несколько раз или сочетать процесс поиска с вычислениями в зависимости от потребностей.

@tool
def search_nimbus_docs(query: str) -> str:
    """Search the Nimbus product documentation for facts about plans, pricing, refunds, security, and support."""
    docs = retriever.invoke(query)
    return "\n\n".join(d.page_content for d in docs)

smart_agent = create_agent(
    model=llm,
    tools=[search_nimbus_docs, calculator, get_today],
    system_prompt=(
        "You answer questions about the Nimbus app. "
        "Use search_nimbus_docs for any product facts, and calculator for arithmetic. "
        "Base answers only on retrieved facts."
    ),
)

q = "How much would Nimbus Pro cost a team of 4 for a full year?"
result = smart_agent.invoke({"messages": [{"role": "user", "content": q}]})
print(result["messages"][-1].content)

Чтобы правильно ответить на подобный вопрос, агенту сначала необходимо поискать цену месячной подписки, а только затем выполнить вычисления по формуле 8 * 12 * 4. Это и есть процесс поиска (из первого урока), представленный в виде инструмента (из третьего урока) и используемый агентом (из второго урока) — три отдельные концепции, работающие вместе как единая система. Возможность для агента самостоятельно решать, когда выполнять поиск, значительно гибче, чем использование фиксированной последовательности операций rag_chain из второго шага, и это подход, часто встречающийся в реальных производственных системах.

Ваша очередь: Также транслируйте выполнение этого агента с помощью smart_agent.stream(..., stream_mode="updates") и подтвердите порядок действий — поиск происходит до вычислений. Если ваш локальный модель пытается решать арифметические задачи самостоятельно вместо того, чтобы использовать инструмент калькулятора (что часто бывает у менее мощных моделей), усильте системное указание, добавив что-то вроде "Вы ОбЯЗАНЫ использовать калькулятор на каждом этапе арифметических вычислений." Это тот же метод, который сработал в учебном пособии по агентам.

Шаг 6 — Краткий обзор остальных компонентов

На этом этапе у вас уже есть основная структура. Стоит ознакомиться с несколькими дополнительными элементами LangChain, каждый из которых соответствует чему-то, что вы уже создавали вручную:

  • Загрузчики документов (langchain-community) — позволяют напрямую вставлять PDF-файлы, веб-страницы, страницы Notion и подобные источники в те же объекты Document, которые уже использует инструмент для разбиения текста. Это заменяет ручную вставку текста в список на реальную, структурированную обработку данных.
  • Хранилища векторов производственного уровня — позволяют заменить внутреннее хранилище в памяти на Chroma или FAISS (импортируемые с помощью from langchain_chroma import Chroma) для сохранения векторных представлений на диске и масштабирования за пределы возможностей оперативной памяти. Поскольку оба инструмента предоставляют одинаковый интерфейс .as_retriever(), ничего в последующих этапах работы с цепочкой не требуется менять — именно такая согласованность является основной целью замены.
  • История памяти и сообщений — позволяет сохранять контекст предыдущих взаимодействий, превращая однократные диалоги в непрерывные беседы.
  • Парсеры вывода помимо простых строк — принудительная конвертация ответа модели в JSON или проверенный объект Pydantic вместо ожидания того, что необработанный текст будет иметь правильную структуру.
  • LangGraph — когда встроенная логика циклов в функции create_agent становится недостаточной (например, при наличии ветвящихся путей, этапов утверждения с участием человека или сотрудничестве нескольких агентов), используется LangGraph — более низкоуровневый движок графов, на котором построена сама функция create_agent.
  • Шаг 7 — Когда использовать LangChain, а когда нет (честный взгляд)

    На этом этапе вы уже дважды создавали похожую систему — один раз с нуля, другой раз с использованием фреймворка — что позволяет вам самостоятельно выполнить этот вызов. Именно в этом и заключалась цель рассмотрения обеих версий.

    LangChain оправдывает себя, когда необходимо объединить множество существующих интеграций — несколько загрузчиков документов, несколько хранилищ векторов, более одного поставщика моделей — и вы не хотите вручную реализовывать логику потоковой обработки, группировки данных, повторных попыток и отслеживания для каждой из них. Он также полезен, когда вы планируете часто менять компоненты и нуждаетесь в стабильном интерфейсе для их замены, или когда вы создаете агента и предпочитаете не заниматься самостоятельной реализацией логики принятия решений.

    Писать код вручную часто более разумно, когда приложение достаточно маленькое, и изучение абстракций LangChain займёт больше времени, чем просто написание пятидесяти с лишним строк, которые вы уже умеете писать. Это также лучший вариант, когда необходим полный контроль над происходящим — пошаговое прослеживание уровней фреймворка для отладки проблем действительно создаёт трудности, и эта жалоба обоснованна — или когда добавление слоя косвенности скроет логику, которая на самом деле более понятна в чистом Python. Пайплайн RAG и агент, созданный вручную в предыдущих уроках, полностью пригодны для использования в производственных условиях; использование фреймворка никак не делает код, написанный вручную, худшим.

    Здесь нет единственно правильного ответа. Причина, по которой вы сначала изучили ручную версию, заключается в том, чтобы выбор данной рамки стал осознанным решением, принятым при полном понимании того, что она заменяет, а не стандартным вариантом, к которому обращаются из-за неясности внутреннего устройства.

    Шаг 8 — Куда двигаться дальше

    • Если ваша локальная настройка кажется слишком медленной, существуют бесплатные тарифы для хостинга моделей от Groq и Google Gemini. Переключение осуществляется одной строкой кода — замените ChatOllama на ChatGroq или используйте init_chat_model("gemini-...", model_provider="google_genai") — поскольку всё остальное работает через один и тот же стандартный интерфейс. Для использования любого из вариантов потребуется API-ключ, но их бесплатные тарифы не стоят ничего.
  • LangSmith — это инструмент отслеживания и отладки от LangChain. Когда цепочка или агент ведут себя необычно, он позволяет проверить каждый шаг, каждый входной и выходной параметр. Существует бесплатный тариф, и он является прямым решением проблемы «Я не могу увидеть внутреннюю структуру фреймворка».
  • LangGraph стоит изучить, если вам нужны рабочие процессы с состоянием, несколько взаимодействующих агентов или контрольные точки с участием человека, выходящие за рамки простого цикла вызовов инструментов.
  • Официальная документация находится по адресу docs.langchain.com. Обязательно убедитесь, что материалы, которые вы читаете, относятся к версии 1.x — всё, что было написано до версии 1.0, содержит упоминания AgentExecutor, initialize_agent или LLMChain, которые с тех пор были изменены или устарели.
  • Модель мышления, которую стоит сохранить

    LangChain по сути представляет собой ваши собственные разработанные компоненты, стандартизированные под единый интерфейс — Runnable — и соединённые с помощью символа |. Ничего из того, что в нём есть, не является по-настоящему новой идеей, если вы сами создали эти элементы:

    • «Цепочка» — это последовательность от запроса к модели до парсера, которую вы уже написали, просто объединённая вместе.
    • «Ретривер» — это ваша логика встраивания данных и косинусного поиска, обёрнутая в общий интерфейс.
    • «Инструмент» — это функция, которую вы написали, плюс автоматически сгенерированная схема, позволяющая модели вызывать её напрямую вместо того, чтобы вы сами парсили её текстовый вывод.
    • «Агент» с помощью функции create_agent — это весь ваш цикл «анализировать-действовать-наблюдать», сведённый к одному вызову.

    Когда что-то идет не так, вы отлаживаете проблему тем же способом, как всегда: выделяете неисправный компонент. Тестируйте механизм получения данных отдельно, выводите значения параметров инструмента .args или отслеживайте промежуточные шаги агента. Фреймворк лишь изменяет объем кода, который необходимо вводить — он не меняет самих процессов, и вы уже понимаете, что происходит.

    Устранение неполадок

    • Если возникает ошибка ImportError при вызове функций create_agent или langchain_ollama, скорее всего, у вас установлена версия раньше 1.0 или отсутствует какой-то пакет. Запустите команду pip install -U langchain langchain-ollama и проверьте, что значение langchain.__version__ начинается с 1..
  • Если в руководстве, которое вы читаете, используются AgentExecutor или initialize_agent, это старый API. В версии 1.x он был перенесён в langchain-classic; новый код должен использовать вместо этого create_agent.
  • Ошибка «connection refused» от Ollama означает, что сервер не запущен — запустите его с помощью команды ollama serve или откройте приложение и убедитесь, что ваша модель отображается в списке с помощью команды ollama list.
  • Если агент игнорирует инструменты или пытается выполнять арифметические операции самостоятельно, скорее всего, модель ненадёжно вызывает инструменты, что является распространённым ограничением более мелких моделей, или документация к инструментам слишком расплывчата. Уточните системный промпт и документацию к инструментам или попробуйте более мощную модель, такую как qwen2.5.
  • HuggingFaceEmbeddings кажется медленным при первом использовании, поскольку он загружает модель эмбеддингов (примерно 80 МБ) и сохраняет её во временной памяти. После этого сам процесс поиска данных выполняется быстро.
  • Первый вызов модели через Ollama также медленный, так как происходит загрузка модели в оперативную память; последующие вызовы выполняются быстро.
  • Теперь вы создали систему RAG, агентов и фреймворк, объединяющий их — сначала вручную, затем с помощью LangChain. Вы понимаете ту составляющую, к которой большинство людей обращаются только снаружи. Приятного использования.

    Связанные материалы

  • Управление LLM в роли судьи как живой производственной системой — Узнайте, как четырехэтапный цикл жизни Netflix — данные с проверенной точностью, обучение с использованием специальных критериев, безопасное внедрение и постоянный мониторинг — обеспечивает высокую точность LLM в роли судьи в масштабах.