RAG-Anwendungen ohne OpenAI erstellen – Teil Zwei: Mixtral, Milvus und OctoAI
Dieser Blog wurde von Yujian Tang und Thierry Moreau verfasst.
Retrieval Augmented Generation (RAG) ist der beliebteste Anwendungsfall für LLMs, der 2023 hervorgegangen ist. Während die meisten Beispiele zeigen, wie man RAG mit den GPT-LLMs von OpenAI erstellen kann, behandelt diese Reihe, wie man RAG ohne OpenAI erstellt. Siehe Building RAG without OpenAI Part One hier.
Dieses Tutorial ist der zweite Teil dieser Reihe und behandelt den Aufbau von RAG mit Milvus, Mixtral, gehostet über OctoAI, und LangChain. Insbesondere zeigen wir in diesem Tutorial nur die Spitze des Eisbergs der zahlreichen Vorteile von Mixtral: seine mehrsprachigen Fähigkeiten.
In diesem Blog behandeln wir:
- MMO(L) Open-Source-RAG-Tech-Stack
- Mixtral
- Milvus
- OctoAI
- LangChain
- Die RAG-App-Architektur
- Richten Sie Ihre RAG-Tools ein
- Wählen und laden Sie Ihre Daten
- Fragen Sie Ihre Daten mit OctoAI und Mixtral ab
- Zusammenfassung
Finden Sie das Notebook auf GitHub.
MMO(L) Open-Source-RAG-Tech-Stack
Es gibt viele Möglichkeiten, RAG-Apps zu erstellen, und in meiner letzten Marktübersicht habe ich über 50 verschiedene Tools im LLM-Stack gefunden. In diesem Beispiel konzentrieren wir uns auf vier: Mixtral als LLM, Milvus als Vektordatenbank, OctoAI zum Bereitstellen des LLM und des Embedding-Modells sowie LangChain als unseren Orchestrator. Bevor wir in die Architektur eintauchen, erfahren wir ein wenig über die beteiligten Tools.
Mixtral
Mixtral 8x7B, oder kurz „Mixtral“, ist das neueste Modell des wegweisenden französischen KI-Startups Mistral. Es wurde im Dezember 2023 veröffentlicht (mit dem Paper, das im Januar 2024 erschien) und stellt eine bedeutende Erweiterung des vorherigen grundlegenden Large Language Model, Mistral 7B, dar. Mixtral ist ein 8x7B Sparse Mixture of Experts (SMoE)-Sprachmodell mit deutlich umfangreicheren Fähigkeiten als das ursprüngliche Mistral 7B. Es ist größer, verwendet während der Inferenz 13B aktive Parameter von insgesamt 47B Parametern und unterstützt mehrere Sprachen, Code und ein 32k-Kontextfenster. Anfang 2024 ist Mixtral das bestbewertete Open-Source-Modell auf LLM leaderboards.
Milvus
Der Kern des Speichers unserer RAG-App ist die Vektordatenbank. Milvus ist eine hochgradig skalierbare Vektordatenbank, die auf Enterprise-Anwendungen ausgerichtet ist. Ihre inhärente verteilte Systemstruktur ermöglicht nahtlose Skalierung, wenn Sie sich echten Produktionsniveaus von Vektoren nähern. Milvus bietet außerdem weitere Enterprise-Funktionen wie Multi-Tenancy, rollenbasierte Zugriffskontrolle und Hochverfügbarkeit.
OctoAI
OctoAI stellt die Infrastruktur bereit, um LLM-Modelle im Produktionsmaßstab auszuführen. OctoAI macht es KI-Entwicklern leicht, die gehosteten Modelle von OctoAI zu integrieren, die eine Auswahl leistungsstarker Open-Source-Modelle bieten, darunter Mixtral und Community-Finetunes wie Nous Hermes. Etwa 9 von 10 neuen OctoAI-Anmeldungen beginnen mit Mixtral als LLM-Modell ihrer Wahl, und heute generiert Mixtral auf OctoAI täglich Milliarden von Tokens für Kunden. In diesem Tutorial ersetzen wir GPT durch das äußerst beliebte Mixtral-Modell.
LangChain
LangChain ist wohl das beliebteste LLM-App-Framework auf dem Markt. LangChain umfasst Integrationen mit fast jedem Tool, das Sie sich vorstellen können. Während Sie es auf viele Arten nutzen können, verwenden wir es in diesem Beispiel, um alles zu verbinden. Wir laden Milvus und den OctoAI-Endpunkt über LangChain und verwenden es dann, um alles miteinander zu „verketten“.
Die RAG-App-Architektur
Jede RAG-App hat vier kritische Komponenten: das LLM, die Vektordatenbank, das Embedding-Modell und den Orchestrator. Darunter befindet sich die Infrastrukturebene. In diesem Setup verwenden wir Mixtral als LLM, Milvus als Vektordatenbank, GTE Large als Embedding-Modell, LangChain als Orchestrator und OctoAI als Infrastrukturebene, die GTE Large und Mixtral bereitstellt.
Richten Sie Ihre RAG-Tools ein
Beginnen wir damit, unsere RAG-Tools einzurichten. In diesem Abschnitt richten wir unsere Inferenz-Endpunkte für das LLM und Embeddings ein und starten unsere Vektordatenbank. Beginnen wir mit der Installation der Voraussetzungen. Wir benötigen pymilvus und milvus, um mit Milvus zu arbeiten. Wir benötigen langchain, sentence-transformers und tiktoken, um die LangChain-Funktionalität für dieses Beispiel zu nutzen. Schließlich benötigen wir auch octoai-sdk, um mit OctoAIs Embedding- und Text-Completion-APIs zu interagieren.
Wir verwenden diesen ersten Codeblock, um die meisten unserer notwendigen Importe aus LangChain zu laden, einschließlich der Milvus- und OctoAI-Importe. Außerdem laden wir das Modul LLMChain, mit dem wir Funktionen miteinander verketten können, und das Modul PromptTemplate, das wir verwenden, um Prompts an unsere LLMs zu übergeben. Außerdem müssen wir unsere Umgebungsvariablen in den Speicher laden. Es gibt viele Möglichkeiten, dies zu tun, aber für dieses Beispiel verwenden wir load_dotenv aus der Bibliothek 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")
Der nächste Schritt ist die Initialisierung unseres LLM-Zugriffs. OctoAI ermöglicht es uns, einfach auf gehostete Modelle zuzugreifen und sie an unseren Anwendungsfall anzupassen. Wir verwenden OctoAIEndpoint aus LangChain und übergeben den Endpunkt (im Code gezeigt), um auf ein Modell zuzugreifen. Außerdem übergeben wir die erforderlichen LLM-Parameter. Für dieses Beispiel sind das der Modellname, die maximale Anzahl an Tokens (wie lang der Ausgabe-Prompt ist) sowie weitere Parameter, um dem Modell mitzuteilen, was es tun soll (z. B. System-Prompt) und wie kreativ die Ausgabe sein soll („presence_penalty“, „temperature“, „top_p“). Für die Embeddings übergeben wir lediglich die OctoAI-Endpunkt-URL. Standardmäßig wird GTE Large verwendet. Im Laufe der Zeit werden OctoAI weitere Embedding-Modelle hinzugefügt.
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")
Das letzte Element davon ist die Vektordatenbank. Wir verwenden Milvus Lite als unsere Vektordatenbank. Importieren Sie default_server aus Milvus und rufen Sie dann die Funktion start() auf, um den Server zu starten.
from milvus import default_server
default_server.start()
Wählen Sie Ihre Daten aus und laden Sie sie
Nachdem alles eingerichtet ist, ist es an der Zeit, unsere Daten zu laden. Für dieses Beispiel findest du die Daten im GitHub-Repo. Wenn du die Daten erhalten möchtest: Sie wurden einfach von Wikipedia gescraped. Sobald wir unsere Daten haben, ist es an der Zeit, sie in eine Vektordatenbank zu laden. Für diese Aufgabe verwenden wir LangChain und Milvus.
Die zwei Importe, die wir aus LangChain benötigen, um diese Dokumente zu laden, sind ein Text-Splitter – in diesem Fall CharacterTextSplitter – und Document. Nun können wir das gesamte Datenverzeichnis als Liste von „Documents“ laden, einer Abstraktion von LangChain. Für dieses Beispiel laden wir ein Verzeichnis namens „data“. Außerdem erstellen wir eine leere Liste, um unsere Liste von Documents zu speichern.
Als Nächstes durchlaufen wir jede der Dateien im Verzeichnis. Wir lesen die Datei ein und verwenden einen Text-Splitter, um den Text in Chunks aufzuteilen. Für dieses Beispiel verwenden wir eine Chunk-Größe von 512 und eine Chunk-Überlappung von 64. Diese wurden einfach gewählt, weil sie in der Regel sinnvoll sind. Passe sie gerne nach Belieben an, um zu sehen, wie sich die Ergebnisse unterscheiden können.
Sobald wir den Text in Chunks aufgeteilt haben, speichern wir ihn als Dokument mit einigen Metadaten. Die Metadaten, die wir zusammen mit dem Text speichern, sind der Titel des Dokuments und die Chunk-Nummer, damit wir wissen, wo sich der Chunk im Dokument befindet.
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}))
Nachdem die Documents bereit sind, ist es an der Zeit, sie in die Vektordatenbank einzufügen. Wir verwenden LangChains Milvus-Integration und rufen die Funktion from_documents auf. Übergib die Dokumente, das Embedding-Modell, die Verbindungsargumente für die Milvus-Lite-Instanz und einen Namen für die Collections. Wir rufen einfach die Methode as_retriever() auf, um ein LLM darüberzulegen und mit Milvus als unserer Vektordatenbank für dieses grundlegende RAG-Beispiel zu arbeiten.
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()
Frage deine Daten mit OctoAI und Mixtral ab
Alles ist bereit. Wir können nun LangChain verwenden, um den Retrieval-Teil unseres Puzzles zu orchestrieren. Wir beginnen damit, LangChain eine Vorlage zu geben. Wir müssen zwei Variablen an die Prompt-Vorlage übergeben – den Kontext, den wir abrufen, und die Frage, die wir stellen möchten. Wir können den Template-String wie einen f-String behandeln und ihn dann an die Funktion from_template von PromptTemplate übergeben.
Nach der Vorlage richten wir den „Chain“-Teil ein. Wir benötigen das Modul RunnablePassthrough, um Kontext weiterzugeben, und den StrOutputParser, um die Ausgabe zu parsen. Dann richten wir die Chain ein. Zuerst sagen wir LangChain, woher Kontext und Frage kommen sollen, dann leiten wir diese an den Prompt weiter, der an das LLM und schließlich an den String-Ausgabeparser weitergeleitet wird, um geparst zu werden. Um eine Frage zu stellen, invoken wir einfach die 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?")
Für das Beispiel „Wie groß ist die Stadt Seattle?“ sehen wir unten eine erwartete Ausgabe. Die Antwort ist korrekt und wird durch die Wikipedia-Informationen gestützt, die wir in der Vektordatenbank gespeichert haben.
Nutzung der mehrsprachigen Fähigkeiten von Mixtral über OctoAI
Da wir Mixtral verwenden, sollten wir einige einzigartige Fähigkeiten nutzen, wie etwa die mehrsprachige Expertise. Das Schöne an der Verwendung von OctoAI ist, dass wir denselben Endpoint mit einer anderen Anweisung nutzen können, um unterschiedliche Dinge zu tun. In diesem Fall weisen wir das Modell an, auf Französisch und nicht auf Englisch zu antworten.
# 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.",
},
],
},
)
Wir verwenden außerdem ein leicht angepasstes Template, um Mixtral zu bitten, auf Französisch zu antworten. Der Prompt muss aus dem neuen Template neu erstellt werden, und die Chain muss aus dem neuen Prompt, Template und LLM neu erstellt werden. Die Chain kann auf dieselbe Weise aufgerufen werden. Wir stellen dieselbe Frage auf Englisch und erwarten eine Antwort auf Französisch.
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?")
Die Antwort sollte ungefähr wie im folgenden Bild aussehen.
Zusammenfassung
In diesem Tutorial haben wir eine weitere Möglichkeit erkundet, RAG ohne OpenAI zu erstellen. In Teil 1 haben wir Symbl.AI als LLM verwendet, in diesem Teil haben wir Mixtral von Mistral genutzt, gehostet von OctoAI. Die anderen Bestandteile des von uns verwendeten RAG-Frameworks sind Milvus als Vektordatenbank, LangChain als Orchestrator und GTE-Large, ebenfalls gehostet von OctoAI, als Embedding-Modell.
Wir haben unsere RAG-Tools eingerichtet und einige Wikipedia-Inhalte als Beispieldaten geladen. Dann verwenden wir LangChain, um die Daten in Milvus einzulesen und „le big model“ darüberzulegen. Am Ende haben wir uns außerdem die Zeit genommen, eine der einzigartigen Fähigkeiten von Mixtral zu erkunden – die Fähigkeit, in mehreren Sprachen zu arbeiten. Für dieses Beispiel haben wir Französisch verwendet. Beim nächsten Mal werden wir auch einige andere Sprachen erkunden!
Weiterlesen

Zilliz Skills Breakdown: How AI Agents Master Vector Databases
Zilliz's Milvus Skill (pymilvus, 7 files) and Zilliz Cloud Skill (zilliz-cli, 14 modules) bring vector-DB dev and ops into one Claude Code session.

Introducing Zilliz CLI and Agent Skills for Zilliz Cloud
Manage your vector database from your terminal or AI coding agent. Zilliz CLI and Agent Skills work with Claude Code, Cursor, Codex, and Copilot.

OpenAI o1: What Developers Need to Know
In this article, we will talk about the o1 series from a developer's perspective, exploring how these models can be implemented for sophisticated use cases.



