LangChain RAG-Agent erstellen

In den beiden vorherigen Artikeln haben wir den Vektorspeicher und den Retriever vorbereitet.

Dieser Artikel integriert sie in einen Agenten, um einen vollständigen RAG-Agenten zu erstellen — einen intelligenten Assistenten, der Fragen auf Basis einer privaten Wissensdatenbank beantworten kann.


Erstellen eines Retriever-Tools

Verpacke den Retriever in ein Tool, und der Agent kann bei Bedarf automatisch die Wissensdatenbank durchsuchen.

Wenn du keinen OpenAI-Schlüssel hast, kannst du den Embedding-Dienst von Alibaba Bailian verwenden; siehe Konfiguration.https://www.example.com/langchain/langchain-alibailian.html:

# OpenAI 的文本嵌入模型
# 将文本转换为向量(一组浮点数)

# 使用阿里云百炼(DashScope)的通义千问 Embedding 服务
embeddings = OpenAIEmbeddings(
    model="text-embedding-v4",
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    check_embedding_ctx_length=False,
    chunk_size=10,
)

Beispiel (OpenAI)

import os
from dotenv import load_dotenv
load_dotenv()

from langchain.tools import tool
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain_text_splitters import RecursiveCharacterTextSplitter

# ----- Schritt 1: Wissensbasis vorbereiten -----

# Simuliere die Wissensdokumente von EXAMPLE
knowledge_docs = [
    "EXAMPLE wurde 2013 gegründet und ist eine völlig kostenlose Programmier-Lernplattform.",
    "Die Plattform hat 300+ Tutorials veröffentlicht, die Frontend, Backend, Datenbanken, mobile Entwicklung und weitere Bereiche abdecken.",
    "Das Python3-Grundlagen-Tutorial ist der beliebteste Kurs auf der Plattform, mit über 5 Millionen Lernenden insgesamt.",
    "Das Python3-Grundlagen-Tutorial hat 30 Kapitel, darunter Umgebungseinrichtung, grundlegende Syntax, Funktionen, Klassen, Ausnahmebehandlung und mehr.",
    "Das HTML-Grundlagen-Tutorial hat 25 Kapitel und deckt alles von der grundlegenden HTML-Struktur bis hin zu Formularen und Multimedia-Elementen ab.",
    "EXAMPLE unterstützt das Ausführen von Code online; Lernende können Code schreiben und ausführen, ohne Software installieren zu müssen.",
    "Die Plattform ist mobilfreundlich und ermöglicht es Nutzern, jederzeit und überall auf ihren Handys Programmieren zu lernen.",
    "Der Mitgliedschaftsservice von EXAMPLE bietet Mehrwertdienste wie Videokurse, praktische Projekte und Einzel-Fragen-und-Antworten.",
]

# Aufteilen
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=200, chunk_overlap=30
)
chunks = text_splitter.create_documents(knowledge_docs)

# Vektorisierte Speicherung -- dies kann zu Alibaba Bailian geändert werden, wenn Sie keinen OpenAI-Schlüssel haben
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")


vector_store = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
)
retriever = vector_store.as_retriever(search_kwargs={"k": 3})

# ----- Schritt 2: Ein Abrufwerkzeug erstellen -----

@tool
def search_knowledge_base(query: str) -> str:
    """Suche nach relevanten Informationen in der EXAMPLE-Wissensdatenbank.

Wenn Benutzer nach bestimmten Informationen über EXAMPLE fragen (wie Anzahl der Kurse, Plattformhistorie, Funktionen usw.),
müssen Sie dieses Tool verwenden, um die Wissensdatenbank nach genauen Informationen abzufragen.

    Argumente:
query: Suchbegriff oder Frage
    """

    docs = retriever.invoke(query)
    if not docs:
        return "Keine relevanten Informationen in der Wissensdatenbank gefunden."

    results = []
    for i, doc in enumerate(docs, 1):
        results.append(f"[{i}] {doc.page_content}")

    return "\n\n".join(results)


# ----- Schritt 3: Den RAG-Agenten erstellen -----

model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    tools=[search_knowledge_base],
    system_prompt="""Du bist der intelligente Kundenservice-Assistent von EXAMPLE.

## Regeln
1. Wenn Benutzer nach spezifischen Informationen über EXAMPLE fragen, musst du das Tool search_knowledge_base verwenden, um abzufragen.
2. Antworte auf Grundlage der abgerufenen Informationen; erfinde keine Inhalte, die nicht in der Wissensdatenbank stehen.
3. Wenn die Wissensdatenbank keine relevanten Informationen enthält, teile dies dem Benutzer ehrlich mit.
4. Sei freundlich, prägnant und genau in deinen Antworten."""
,
)

# ----- Schritt 4: Test -----

questions = [
    "When was EXAMPLE founded?",
    "Wie viele Kapitel hat das Python3-Basistutorial?",
    "Wie viele Tutorials hat EXAMPLE insgesamt?",
]

for q in questions:
    result = agent.invoke({"messages": [HumanMessage(content=q)]})
    print(f"Q: {q}")
    print(f"A: {result['messages'][-1].content}")
    print("-" * 60)

Ausführungsergebnisse:

Q: Example是什么时候创立的?
A: Example创立于 2013 年,是一个完全免费的编程学习平台。
------------------------------------------------------------
Q: Python3 基础教程有多少章?
A: Python3 基础教程共 30 章,包含环境搭建、基本语法、函数、类、异常处理等内容。
------------------------------------------------------------
Q: Example一共有多少套教程?
A: Example已上线 300+ 套教程,涵盖前端、后端、数据库、移动开发等多个领域。
------------------------------------------------------------

Ausführungsablauf des RAG-Agenten

Für die dritte Frage oben, "Wie viele Tutorials hat EXAMPLE insgesamt?", ist der Ausführungsablauf des Agenten:

  1. Der Benutzer stellt eine Frage
  2. Das Modell stellt fest, dass es die Wissensdatenbank abfragen muss → ruft search_knowledge_base("EXAMPLE Anzahl der Tutorials") auf
  3. Der Retriever durchsucht die Vektordatenbank nach den semantisch ähnlichsten Dokumentabschnitten.
  4. Gibt die Abrufergebnisse an das Modell zurück.
  5. Das Modell generiert eine präzise Antwort basierend auf den Abrufergebnissen.

Hinzufügen von Zitationsquellen

Professionelle RAG-Systeme enthalten normalerweise Zitationsquellen, damit Benutzer wissen, woher die Informationen stammen:

Beispiel

from langchain_core.documents import Document


@tool
def search_with_sources(query: str) -> str:
    """Durchsuche die EXAMPLE-Wissensdatenbank und gib Ergebnisse mit Quellenangaben zurück.

    Argumente:
query: Suchbegriff
    """

    docs = retriever.invoke(query)
    if not docs:
        return "Keine relevanten Informationen gefunden."

    results = []
    for i, doc in enumerate(docs, 1):
        source = doc.metadata.get("source", "BEISPIEL Wissensdatenbank")
        results.append(f"[Quelle {i}: {source}]"\n{doc.page_content}")

    return "\n\n".join(results)


# Um Quellinformationen im Dokument zu behalten, können Sie beim Erstellen Metadaten hinzufügen.
doc_with_meta = Document(
    page_content="Das Python3-Basistutorial hat 30 Kapitel...",
    metadata={"source": "Python3-Basistutorial - Kurs-Einführung", "url": "https://www.example.com/python3/"}
)

Persistenz des Vektorspeichers

In echten Projekten bauen Sie den Vektorindex nicht jedes Mal neu auf. Chroma unterstützt das Persistieren im lokalen Speicher:

Beispiel

# Einen persistenten Vektorspeicher erstellen (erster Lauf)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./example_vector_db",  # Persistenzverzeichnis
)

# Bei nachfolgenden Ausführungen direkt laden
loaded_store = Chroma(
    persist_directory="./example_vector_db",
    embedding_function=embeddings,
)
retriever = loaded_store.as_retriever()

# Vektoren müssen nicht neu berechnet werden!

Das Persistieren des Vektorspeichers kann die Startgeschwindigkeit erheblich verbessern. Bei großen Dokumentmengen (Zehntausende von Dokumenten) kann die Neuberechnung der Embeddings für alle Vektoren Dutzende von Minuten dauern. Sobald er persistiert wurde, müssen Sie ihn nur noch laden.

Andere Erweiterungen