Создание RAG-приложений без OpenAI — часть вторая: Mixtral, Milvus и OctoAI
Этот блог написан Yujian Tang и Thierry Moreau.
Retrieval Augmented Generation (RAG) — самый популярный сценарий использования LLM, появившийся в 2023 году. Хотя большинство примеров показывают, как можно создать RAG с помощью LLM GPT от OpenAI, эта серия посвящена тому, как создать RAG без OpenAI. См. Building RAG without OpenAI Part One здесь.
Это руководство — вторая часть этой серии, посвященная созданию RAG с Milvus, Mixtral, размещенным через OctoAI, и LangChain. В частности, в этом руководстве мы показываем лишь верхушку айсберга многочисленных преимуществ Mixtral: его многоязычные возможности.
В этом блоге мы рассмотрим:
- Технологический стек MMO(L) Open Source RAG
- Mixtral
- Milvus
- OctoAI
- LangChain
- Архитектура RAG-приложения
- Настройка ваших инструментов RAG
- Выбор и загрузка ваших данных
- Запрос к вашим данным с помощью OctoAI и Mixtral
- Резюме
Найдите ноутбук на GitHub.
Технологический стек MMO(L) Open Source RAG
Существует множество способов создавать RAG-приложения, и в моем последнем обзоре рынка я обнаружил более 50 различных инструментов в стеке LLM. В этом примере мы сосредоточимся на четырех: Mixtral как LLM, Milvus как векторная база данных, OctoAI для обслуживания LLM и модели эмбеддингов, а LangChain — как наш оркестратор. Прежде чем перейти к архитектуре, давайте немного узнаем об используемых инструментах.
Mixtral
Mixtral 8x7B, или для краткости просто “Mixtral”, — это новейшая модель, выпущенная французским AI-стартапом-первопроходцем Mistral. Запущенная в декабре 2023 года (с статьей, вышедшей в январе 2024 года), она представляет собой значительное расширение предыдущей базовой большой языковой модели, Mistral 7B. Mixtral — это языковая модель 8x7B Sparse Mixture of Experts (SMoE) с более существенными возможностями, чем у исходной Mistral 7B. Она больше: использует 13B активных параметров во время инференса из 47B параметров и поддерживает несколько языков, код и контекстное окно 32k. По состоянию на начало 2024 года Mixtral является open-source моделью с наивысшим баллом в рейтингах LLM.
Milvus
Основа памяти нашего RAG-приложения — это векторная база данных. Milvus — это высокомасштабируемая векторная база данных, ориентированная на корпоративные приложения. Ее встроенная структура распределенной системы обеспечивает бесшовное масштабирование по мере приближения к реальным производственным уровням объемов векторов. Milvus также предоставляет другие корпоративные функции, такие как мультитенантность, управление доступом на основе ролей и высокая доступность.
OctoAI
OctoAI предоставляет инфраструктуру для запуска LLM-моделей в производственном масштабе. OctoAI позволяет AI-разработчикам легко интегрировать размещенные модели OctoAI, которые предлагают выбор мощных open-source моделей, включая Mixtral, и дообученные сообществом модели, такие как Nous Hermes. Около 9 из 10 новых регистраций в OctoAI начинают с Mixtral в качестве предпочитаемой LLM-модели, и сегодня Mixtral на OctoAI ежедневно генерирует миллиарды токенов для клиентов. В этом руководстве мы заменим GPT на крайне популярную модель Mixtral.
LangChain
LangChain, пожалуй, самый популярный фреймворк для LLM-приложений на рынке. LangChain включает интеграции почти с каждым инструментом, который можно себе представить. Хотя его можно использовать многими способами, в этом примере мы используем его, чтобы соединить всё вместе. Мы загружаем Milvus и endpoint OctoAI через LangChain, а затем используем его, чтобы “связать” всё вместе.
Архитектура RAG-приложения
Каждое RAG-приложение имеет четыре критически важных компонента: LLM, векторную базу данных, модель эмбеддингов и оркестратор. Под всем этим находится инфраструктурный слой. В этой конфигурации мы используем Mixtral в качестве LLM, Milvus в качестве векторной базы данных, GTE Large в качестве модели эмбеддингов, LangChain в качестве оркестратора и OctoAI в качестве инфраструктурного слоя, который обслуживает GTE Large и Mixtral.
Настройте свои RAG-инструменты
Давайте начнем с настройки наших RAG-инструментов. В этом разделе мы настраиваем наши конечные точки инференса для LLM и эмбеддингов и запускаем нашу векторную базу данных. Начнем с установки предварительных зависимостей. Нам нужны pymilvus и milvus для работы с Milvus. Нам нужны langchain, sentence-transformers и tiktoken, чтобы использовать функциональность LangChain для этого примера. Наконец, нам также нужен octoai-sdk для взаимодействия с API эмбеддингов и завершения текста OctoAI.
Мы используем этот первый блок кода, чтобы загрузить большинство необходимых импортов из LangChain, включая импорты Milvus и OctoAI. Мы также загружаем модуль LLMChain, который позволяет нам объединять функции в цепочку, и модуль PromptTemplate, который мы используем для передачи промптов нашим LLM. Нам также нужно загрузить переменные окружения в память. Есть много способов сделать это, но для этого примера мы используем load_dotenv из библиотеки python-dotenv.
# ! pip install pymilvus milvus langchain sentence-transformers tiktoken octoai-sdk python-dotenv
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain_community.llms.octoai_endpoint import OctoAIEndpoint
from langchain_community.embeddings import OctoAIEmbeddings
from langchain_community.vectorstores import Milvus
from dotenv import load_dotenv
import os
load_dotenv()
# the line below is just to show that you need to have your OCTOAI_API_TOKEN
os.environ["OCTOAI_API_TOKEN"] = os.getenv("OCTOAI_API_TOKEN")
Следующий шаг — инициализация доступа к нашей LLM. OctoAI позволяет нам легко получать доступ к размещенным моделям и настраивать их под наш сценарий использования. Мы используем OctoAIEndpoint из LangChain и передаем конечную точку (показанную в коде), чтобы получить доступ к модели. Мы также передаем необходимые параметры LLM. Для этого примера это имя модели, максимальное количество токенов (насколько длинным будет выходной промпт), а также другие параметры, которые сообщают модели, что нужно сделать (например, системный промпт) и насколько креативной быть в выводе (“presence_penalty”, “temperature”, “top_p”). Для эмбеддингов мы просто передаем URL конечной точки OctoAI. По умолчанию будет использоваться GTE Large. Со временем в OctoAI будут добавлены дополнительные модели эмбеддингов.
llm = OctoAIEndpoint(
endpoint_url="https://text.octoai.run/v1/chat/completions",
model_kwargs={
"model": "mixtral-8x7b-instruct-fp16",
"max_tokens": 128,
"presence_penalty": 0,
"temperature": 0.01,
"top_p": 0.9,
"messages": [
{
"role": "system",
"content": "You are a helpful assistant. Keep your responses limited to one short paragraph if possible.",
},
],
},
)
embeddings = OctoAIEmbeddings(endpoint_url="https://text.octoai.run/v1/embeddings")
Последняя часть этого — векторная база данных. Мы используем Milvus Lite в качестве нашей векторной базы данных. Импортируйте default_server из Milvus, а затем вызовите функцию start(), чтобы запустить сервер.
from milvus import default_server
default_server.start()
Выберите и загрузите свои данные
Когда всё настроено, пора загрузить наши данные. Для этого примера вы можете найти данные в GitHub Repo. Если вы хотите получить данные, они просто извлечены из Wikipedia. Когда данные у нас есть, пора загрузить их в векторную базу данных. Для этой задачи мы используем LangChain и Milvus.
Два импорта, которые нам нужны из LangChain для загрузки этих документов, — это разделитель текста — CharacterTextSplitter в данном случае — и Document. Теперь мы можем загрузить весь каталог с данными как список “Documents”, абстракцию LangChain. Для этого примера мы загружаем каталог под названием “data”. Мы также создаём пустой список для хранения нашего списка Documents.
Далее мы проходим циклом по каждому из файлов в каталоге. Мы считываем файл и используем разделитель текста, чтобы разбить текст на фрагменты. Для этого примера мы используем размер фрагмента 512 и перекрытие фрагментов 64. Они были выбраны просто потому, что обычно имеют смысл. Не стесняйтесь настраивать их, как вам хочется, чтобы увидеть, как могут отличаться результаты.
После того как мы разбиваем текст на фрагменты, мы сохраняем его как документ с некоторыми метаданными. Метаданные, которые мы храним вместе с текстом, — это заголовок документа и номер фрагмента, чтобы мы знали, где фрагмент находится в документе.
from langchain.text_splitter import CharacterTextSplitter
from langchain.schema import Document
files = os.listdir("./data")
file_texts = []
for file in files:
with open(f"./data/{file}") as f:
file_text = f.read()
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
chunk_size=512, chunk_overlap=64,
)
texts = text_splitter.split_text(file_text)
for i, chunked_text in enumerate(texts):
file_texts.append(Document(page_content=chunked_text,
metadata={"doc_title": file.split(".")[0], "chunk_num": i}))
Когда Documents готовы, пора вставить их в векторную базу данных. Мы используем интеграцию Milvus в LangChain и вызываем функцию from_documents. Передайте документы, модель эмбеддингов, аргументы подключения для экземпляра Milvus Lite и имя для коллекций. Мы просто вызываем метод as_retriever(), чтобы поместить LLM поверх и начать работать с Milvus как с нашей векторной базой данных для этого базового примера RAG.
vector_store = Milvus.from_documents(
file_texts,
embedding=embeddings,
connection_args={"host": "localhost", "port": default_server.listen_port},
collection_name="cities"
)
retriever = vector_store.as_retriever()
Выполняйте запросы к своим данным с OctoAI и Mixtral
Всё готово. Теперь мы можем использовать LangChain для оркестрации части нашей головоломки, связанной с извлечением. Мы начинаем с того, что передаём LangChain шаблон. Мы должны передать две переменные в шаблон промпта — контекст, который мы извлекаем, и вопрос, который хотим задать. Мы можем обращаться со строкой шаблона как с f-string, а затем передать её в функцию from_template из PromptTemplate.
После шаблона мы настраиваем часть “chain”. Нам нужен модуль RunnablePassthrough, чтобы передавать контекст, и StrOutputParser, чтобы разбирать вывод. Затем мы настраиваем chain. Сначала мы сообщаем LangChain, где получить контекст и вопрос, затем передаём их по конвейеру в промпт, который передаётся в LLM и наконец в парсер строкового вывода для разбора. Чтобы задать вопрос, мы просто invoke chain.
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = PromptTemplate.from_template(template)
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
chain.invoke("How big is the city of Seattle?")
В примере «Насколько велик город Сиэтл» мы можем увидеть ожидаемый результат ниже. Ответ точен и подкреплен информацией из Wikipedia, которую мы сохранили в векторной базе данных.
Использование многоязычных возможностей Mixtral через OctoAI
Поскольку мы используем Mixtral, давайте задействуем некоторые уникальные возможности, например многоязычную экспертизу. Приятное преимущество использования OctoAI заключается в том, что мы можем использовать один и тот же endpoint с другой инструкцией для выполнения разных задач. В данном случае мы скажем модели отвечать на французском, а не на английском.
# Let's make this a bit more fun and showcase the multilingual capabilities of Mixtal which really outshine other open source models
# Our Vector DB is populated with entries from english text - even the embedding model we're using here, GTE-Large
# works best on english text. However Mixtral has good mutlilingual capabilities in French, German, Spanish and Italian.
# So what we'll do is ask the assistant to only answer in french in the system and user prompt. RAG here is performed based on
# english text, but upon producing the user response, the Mixtral LLM will generate tokens in a different language here (french)
llm = OctoAIEndpoint(
endpoint_url="https://text.octoai.run/v1/chat/completions",
model_kwargs={
"model": "mixtral-8x7b-instruct-fp16",
"max_tokens": 128,
"presence_penalty": 0,
"temperature": 0.1,
"top_p": 0.9,
"messages": [
{
"role": "system",
"content": "You are a helpful assistant who responds in french and not in english.",
},
],
},
)
Мы также используем немного измененный шаблон, чтобы попросить Mixtral отвечать на французском. Prompt нужно заново создать на основе нового шаблона, а chain — заново создать из нового prompt, шаблона и LLM. Chain можно вызвать тем же способом. Мы задаем тот же вопрос на английском и ожидаем ответ на французском.
template = """Answer the question in french based only on the following context:
{context}
Question: {question}
"""
prompt = PromptTemplate.from_template(template)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
chain.invoke("How big is the city of Seattle?")
Ответ должен выглядеть примерно как на изображении ниже.
Итоги
В этом руководстве мы рассмотрели еще один способ построить RAG без OpenAI. В части 1 мы использовали Symbl.AI в качестве LLM, а в этой части использовали Mixtral от Mistral, размещенный на OctoAI. Другие компоненты фреймворка RAG, которые мы использовали, — это Milvus в качестве векторной базы данных, LangChain в качестве оркестратора и GTE-Large, также размещенный на OctoAI, в качестве embedding-модели.
Мы настроили наши инструменты RAG и загрузили часть данных из Wikipedia в качестве примерных данных. Затем мы используем LangChain, чтобы считать данные в Milvus и наложить сверху «le big model». В конце мы также уделили время изучению одной из уникальных возможностей Mixtral — способности работать на нескольких языках. Для этого примера мы использовали французский. В следующий раз мы также рассмотрим некоторые другие языки!
Читать далее

A Few Notes from Databricks Data + AI Summit 2026: Why the Data Layer Matters Again
James Luan shares notes from Databricks Data + AI Summit 2026 on why production AI is pushing the data layer back to the center of infrastructure.

Zilliz Cloud Just Landed in Claude Code
The Zilliz Cloud Plugin brings the full power of Zilliz Cloud directly into your Claude Code terminal as natural-language conversations.

Zilliz Cloud Audit Logs Goes GA: Security, Compliance, and Transparency at Scale
Zilliz Cloud Audit Logs are now GA, giving enterprises real-time visibility, compliance-ready trails, and stronger security across AWS, GCP, and Azure.



