Teilen über


Tutorial: Teil 2: Erstellen einer benutzerdefinierte Chat-App mit dem Prompt Flow-SDK

In diesem Tutorial verwenden Sie das Prompt Flow SDK (und andere Bibliotheken), um eine Chat-App für Ihr Einzelhandelsunternehmen namens Contoso Trek zu bewerten, zu erstellen, zu konfigurieren und bereitzustellen. Ihr Einzelhandelsunternehmen ist auf Campingausrüstung und Outdoorkleidung spezialisiert. Die Chat-App soll Fragen zu Ihren Produkten und Diensten beantworten. Beispielsweise kann die Chat-App Fragen wie „Welches Zelt ist am wasserdichtesten?“ oder „Was ist der beste Schlafsack für kaltes Wetter?“ beantworten.

In diesem zweiten Teil erfahren Sie, wie Sie eine einfache Chatanwendung verbessern, indem Sie die Retrieval Augmented Generation (RAG) hinzufügen, um Ihre benutzerdefinierten Daten als Grundlage für die Antworten zu verwenden. Retrieval of Augmented Generation (RAG) ist ein Muster, das Ihre Daten mit einem großen Sprachmodell (LLM) verwendet, um Antworten speziell für Ihre Daten zu generieren. In diesem zweiten Teil erfahren Sie Folgendes:

  • Bereitstellen von KI-Modellen in Azure KI Studio zur Verwendung in Ihrer App
  • Entwickeln von benutzerdefiniertem RAG-Code
  • Testen Ihrer Chat-App mithilfe von Prompt Flow

Dieses Tutorial ist der zweite Teil eines dreiteiligen Tutorials.

Voraussetzungen

Anwendungscodestruktur

Erstellen Sie auf Ihrem lokalen Computer einen Ordner mit dem Namen rag-tutorial. In dieser Tutorialreihe werden schrittweise die Inhalte der einzelnen Dateien erstellt. Nach Abschluss der Tutorialreihe sieht Ihre Ordnerstruktur wie folgt aus:

rag-tutorial/
│   .env
│   build_index.py
│   deploy.py
│   evaluate.py
│   eval_dataset.jsonl
|   invoke-local.py
│
├───copilot_flow
│   └─── chat.prompty
|   └─── copilot.py
|   └─── Dockerfile
│   └─── flow.flex.yaml
│   └─── input_with_chat_history.json
│   └─── queryIntent.prompty
│   └─── requirements.txt
│
├───data
|   └─── product-info/
|   └─── [Your own data or sample data as described in the prerequisites.]

Die Implementierung in diesem Tutorial verwendet den Flex-Flow von prompt flow. Hierbei handelt es sich um den Code-First-Ansatz für die Implementierung von Flows. Sie geben eine Eingabefunktion an (wird in copilot.py definiert) und verwenden dann die Test-, Auswertungs- und Ablaufverfolgungsfunktionen von Prompt Flow für Ihren Flow. Dieser Flow befindet sich im Code und verfügt weder über einen gerichteten azyklischen Graphen (Directed Acyclic Graph, DAG) noch über eine andere visuelle Komponente. Weitere Informationen zur Entwicklung eines Flex-Flows finden Sie in der Dokumentation zu prompt flow auf GitHub.

Festlegen anfänglicher Umgebungsvariablen

Es gibt eine Reihe von Umgebungsvariablen, die in den verschiedenen Codeausschnitten verwendet werden. Fügen Sie alle zu einer .env- -Datei hinzu.

Wichtig

Wenn Sie dies in einem Git-Repository erstellen, stellen Sie sicher, dass sich .env in Ihrer .gitignore-Datei befindet, damit Sie sie nicht versehentlich in das Repository einchecken.

Beginnen Sie mit folgenden Werten: Beim Durchlaufen des Tutorials fügen Sie einige weitere Werte hinzu.

  1. Erstellen Sie eine Datei vom Typ .env im Ordner rag-tutorial. Fügen Sie folgende Variablen hinzu:

    AZURE_SUBSCRIPTION_ID=<your subscription id>
    AZURE_RESOURCE_GROUP=<your resource group>
    AZUREAI_PROJECT_NAME=<your project name>
    AZURE_OPENAI_CONNECTION_NAME=<your AIServices or Azure OpenAI connection name>
    AZURE_SEARCH_ENDPOINT=<your Azure Search endpoint>
    AZURE_SEARCH_CONNECTION_NAME=<your Azure Search connection name>
    

Ersetzen Sie die Platzhalter durch die folgenden Werte:

  • Suchen Sie die <your subscription id>, <your resource group> und <your project name> aus der Projektansicht in KI Studio:

    1. Wechseln Sie in KI Studio zu Ihrem Projekt, und wählen Sie im linken Bereich Einstellungen aus.
    2. Im Abschnitt Projekteigenschaften finden Sie die Abonnement-ID und die Ressourcengruppe. Das Feld Name ist <your project name>.
  • In Ihren Projekt-Einstellungen wird im Abschnitt Verbundene Ressourcen ein Eintrag für Azure AIServices oder Azure OpenAI angezeigt. Wählen Sie den Namen aus, um die Verbindungsdetails zu öffnen. Der Verbindungsname wird oben auf der Seite Verbindungsdetails angezeigt. Kopieren Sie diesen Namen, der für <your AIServices or Azure OpenAI connection name> verwendet werden soll.

  • Gehen Sie zurück zur Seite Projekteinstellungen. Wählen Sie im Abschnitt Verbundene Ressourcen den Link für den Azure KI-Suche-Dienst aus.

    • Kopieren Sie die unter Ziel angegebene URL für <your Azure Search endpoint>.
    • Kopieren Sie den Namen im oberen Bereich für <your Azure Search connection name>.

    Screenshot: Endpunkt- und Verbindungsname

Bereitstellen von Modellen

Sie benötigen zwei Modelle zum Erstellen einer RAG-basierten Chat-App: ein Azure OpenAI-Chatmodell (gpt-3.5-turbo) und ein Azure OpenAI-Einbettungsmodell (text-embedding-ada-002). Stellen Sie diese Modelle in Ihrem Azure KI Studio-Projekt mithilfe dieser Schritte für jedes Modell bereit.

Mit diesen Schritten wird ein Modell auf einem Echtzeitendpunkt aus dem KI Studio-Modellkatalog bereitgestellt:

  1. Melden Sie sich bei KI Studio an, und wechseln Sie zur Homepage.

  2. Wählen Sie Modellkatalog auf der linken Randleiste aus.

  3. Wählen Sie im Filter Sammlungen die Option Azure OpenAI aus.

    Screenshot: Filtern nach OpenAI-Modellen im Katalog.

  4. Wählen Sie ein Modell aus der Azure OpenAI-Sammlung aus. Wählen Sie beim ersten Mal das Modell gpt-3.5-turbo aus. Wählen Sie beim zweiten Mal das Modell text-embedding-ada-002 aus.

  5. Wählen Sie Bereitstellen aus, um das Bereitstellungsfenster zu starten.

  6. Wählen Sie den Hub aus, für den Sie das Modell bereitstellen möchten. Verwenden Sie denselben Hub wie Ihr Projekt.

  7. Geben Sie den Bereitstellungsnamen an, und ändern Sie andere Standardeinstellungen je nach Ihren Anforderungen.

  8. Klicken Sie auf Bereitstellen.

  9. Sie gelangen zur Seite mit den Bereitstellungsdetails. Wählen Sie In Playground öffnen aus.

  10. Wählen Sie Code anzeigen aus, um Codebeispiele abzurufen, die zum Verwenden des bereitgestellten Modells in Ihrer Anwendung verwendet werden können.

Wenn Sie das Modell gpt-3.5-turbo bereitstellen, suchen Sie die folgenden Werte im Bereich Codeansicht, und fügen Sie sie ihrer .env-Datei hinzu:

AZURE_OPENAI_ENDPOINT=<endpoint_value>
AZURE_OPENAI_CHAT_DEPLOYMENT=<chat_model_deployment_name>
AZURE_OPENAI_API_VERSION=<api_version>

Wenn Sie das Modell text-embedding-ada-002 bereitstellen, fügen Sie der .env-Datei den Namen hinzu:

AZURE_OPENAI_EMBEDDING_DEPLOYMENT=<embedding_model_deployment_name>

Installieren der Azure CLI und Anmelden

Installieren Sie die Azure-Befehlszeilenschnittstelle und die Anmeldung über Ihre lokale Entwicklungsumgebung, damit Sie Ihre Benutzeranmeldeinformationen verwenden können, um Azure OpenAI Service aufzurufen.

In den meisten Fällen können Sie die Azure CLI über Ihr Terminal mit dem folgenden Befehl installieren:

winget install -e --id Microsoft.AzureCLI

Sie können die Anweisungen unter Installieren der Azure CLI- befolgen, wenn diese Befehle für Ihr Betriebssystem oder Setup nicht funktionieren.

Melden Sie sich nach der Installation der Azure-Befehlszeilenschnittstelle mit dem Befehl az login über den Browser an:

az login

Jetzt erstellen wir unsere App und rufen Azure OpenAI Service über den Code auf.

Erstellen einer neuen Python-Umgebung

Zunächst müssen wir eine neue Python-Umgebung erstellen, mit der wir die Prompt Flow-SDK-Pakete installieren können. Installieren Sie KEINE Pakete in Ihrer globalen Python-Installation. Sie sollten beim Installieren von Python-Paketen immer eine virtuelle oder Conda-Umgebung verwenden, andernfalls können Sie die globale Python-Installation beschädigen.

Installieren Sie bei Bedarf Python.

Es wird empfohlen, Python 3.10 oder höher zu verwenden, aber mindestens Python 3.8 ist erforderlich. Wenn Sie keine geeignete Version von Python installiert haben, können Sie die Anweisungen im VS Code-Tutorial für Python befolgen, um Python auf Ihrem Betriebssystem zu installieren.

Erstellen einer virtuellen Umgebung

Wenn Sie Python 3.10 oder höher bereits installiert haben, können Sie mit den folgenden Befehlen eine virtuelle Umgebung erstellen:

py -3 -m venv .venv
.venv\scripts\activate

Wenn Sie die Python-Umgebung aktivieren, verwenden Sie beim Ausführen von python oder pip über die Befehlszeile den Python-Interpreter, der im Ordner .venv Ihrer Anwendung enthalten ist.

Hinweis

Sie können den Befehl deactivate verwenden, um die virtuelle Python-Umgebung zu beenden, und sie später bei Bedarf reaktivieren.

pip-Upgrade ausführen

Führen Sie den folgenden Befehl aus, um sicherzustellen, dass Sie über die neueste pip-Version verfügen:

python -m pip install --upgrade pip

Installieren des Prompt Flow-SDK

Prompt Flow bezeichnet eine Reihe von Entwicklungstools, die entwickelt wurden, um den gesamten Entwicklungszyklus von LLM-basierten KI-Anwendungen zu optimieren, von der Idee, der Prototyperstellung, dem Testen, der Auswertung bis hin zur Produktionsbereitstellung und -überwachung.

Verwenden Sie pip, um das Prompt Flow-SDK in der virtuellen Umgebung zu installieren, die Sie erstellt haben.

pip install promptflow
pip install azure-identity

Das Prompt Flow-SDK hat Abhängigkeiten von mehreren Paketen, die Sie separat installieren können, wenn Sie nicht alle benötigen:

  • promptflow-core: enthält die Hauptruntime für Prompt Flow, die für die Ausführung von LLM-Code verwendet wird
  • promptflow-tracing: schlanke Bibliothek, die für das Ausgeben von OpenTelemetry-Ablaufverfolgungen in Standards verwendet wird
  • promptflow-devkit: enthält die Prompt Flow-Tools für die Testumgebung and den Ablaufverfolgungsviewer für lokale Entwicklungsumgebungen
  • openai: Clientbibliotheken für die Verwendung von Azure OpenAI Service
  • python-dotenv: Wird verwendet, um Umgebungsvariablen festzulegen, indem sie aus .env-Dateien gelesen werden

Erstellen eines Azure KI-Suchindex

Ziel dieser RAG-basierten Anwendung ist es, Ihre benutzerdefinierten Daten als Grundlage für die Modellantworten zu verwenden. Sie verwenden einen Index von Azure KI-Suche, der vektorisierte Daten aus dem Einbettungsmodell speichert. Der Suchindex wird verwendet, um relevante Dokumente basierend auf der Frage des Benutzers abzurufen.

Wenn Sie noch keinen Index für Azure KI-Suche erstellt haben, erfahren Sie hier, wie Sie einen solchen Index erstellen. Wenn Sie bereits über einen Index verfügen, können Sie direkt mit dem Abschnitt Festlegen der Umgebungsvariable für die Suche fortfahren. Der Suchindex wird für den Azure KI-Suche-Dienst erstellt, der im vorherigen Schritt entweder erstellt oder referenziert wurde.

  1. Verwenden Sie Ihre eigenen Daten, oder laden Sie die exemplarischen Einzelhandelsproduktdaten für Contoso Trek in einer ZIP-Datei auf Ihren lokalen Computer herunter. Entzippen Sie die Datei in den Ordner rag-tutorial/data. Bei diesen Daten handelt es sich um eine Sammlung von Markdowndateien, die Produktinformationen darstellen. Die Daten sind so strukturiert, dass sie leicht in einem Suchindex erfasst werden können. Sie erstellen einen Suchindex auf der Grundlage dieser Daten.

  2. Mit dem RAG-Paket von prompt flow können Sie die Markdowndateien erfassen, lokal einen Suchindex erstellen und ihn im Cloudprojekt registrieren. Installieren Sie das RAG-Paket von prompt flow:

    pip install promptflow-rag
    
  3. Erstellen Sie die Datei build_index.py in Ihrem Ordner rag-tutorial.

  4. Kopieren Sie den folgenden Code, und fügen Sie ihn in Ihre Datei build_index.py ein:

    import os
    from dotenv import load_dotenv
    
    load_dotenv()
    
    from azure.ai.ml import MLClient
    from azure.identity import DefaultAzureCredential
    from azure.ai.ml.entities import Index
    
    from promptflow.rag.config import (
        LocalSource,
        AzureAISearchConfig,
        EmbeddingsModelConfig,
        ConnectionConfig,
    )
    from promptflow.rag import build_index
    
    client = MLClient(
        DefaultAzureCredential(),
        os.getenv("AZURE_SUBSCRIPTION_ID"),
        os.getenv("AZURE_RESOURCE_GROUP"),
        os.getenv("AZUREAI_PROJECT_NAME"),
    )
    import os
    
    # append directory of the current script to data directory
    script_dir = os.path.dirname(os.path.abspath(__file__))
    data_directory = os.path.join(script_dir, "data/product-info/")
    
    # Check if the directory exists
    if os.path.exists(data_directory):
        files = os.listdir(data_directory)  # List all files in the directory
        if files:
            print(
                f"Data directory '{data_directory}' exists and contains {len(files)} files."
            )
        else:
            print(f"Data directory '{data_directory}' exists but is empty.")
            exit()
    else:
        print(f"Data directory '{data_directory}' does not exist.")
        exit()
    
    index_name = "tutorial-index"  # your desired index name
    index_path = build_index(
        name=index_name,  # name of your index
        vector_store="azure_ai_search",  # the type of vector store - in this case it is Azure AI Search. Users can also use "azure_cognitive search"
        embeddings_model_config=EmbeddingsModelConfig(
            model_name=os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT"),
            deployment_name=os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT"),
            connection_config=ConnectionConfig(
                subscription_id=client.subscription_id,
                resource_group_name=client.resource_group_name,
                workspace_name=client.workspace_name,
                connection_name=os.getenv("AZURE_OPENAI_CONNECTION_NAME"),
            ),
        ),
        input_source=LocalSource(input_data=data_directory),  # the location of your files
        index_config=AzureAISearchConfig(
            ai_search_index_name=index_name,  # the name of the index store inside the azure ai search service
            ai_search_connection_config=ConnectionConfig(
                subscription_id=client.subscription_id,
                resource_group_name=client.resource_group_name,
                workspace_name=client.workspace_name,
                connection_name=os.getenv("AZURE_SEARCH_CONNECTION_NAME"),
            ),
        ),
        tokens_per_chunk=800,  # Optional field - Maximum number of tokens per chunk
        token_overlap_across_chunks=0,  # Optional field - Number of tokens to overlap between chunks
    )
    
    # register the index so that it shows up in the cloud project
    client.indexes.create_or_update(Index(name=index_name, path=index_path))
    
    • Legen Sie die Variable index_name auf den gewünschten Indexnamen fest.
    • Bei Bedarf können Sie die Variable path_to_data auf den Pfad aktualisieren, unter dem Ihre Datendateien gespeichert sind.

    Wichtig

    Standardmäßig erwartet das Codebeispiel die weiter oben in diesem Tutorial beschriebene Anwendungscodestruktur. Der Ordner data muss sich auf der gleichen Ebene befinden wie build_index.py und der heruntergeladene Ordner product-info mit den darin enthaltenen MD-Dateien.

  5. Führen Sie in Ihrer Konsole den folgenden Code aus, um Ihren Index lokal zu erstellen und ihn für das Cloudprojekt zu registrieren:

    python build_index.py
    
  6. Nach Ausführung des Skripts können Sie Ihren neu erstellten Index auf der Seite Indizes Ihres Azure KI Studio-Projekts anzeigen. Weitere Informationen finden Sie unter Erstellen und Nutzen von Vektorindizes in Azure KI Studio.

  7. Wenn Sie das Skript erneut mit dem gleichen Indexnamen ausführen, wird eine neue Version des gleichen Index erstellt.

Festlegen der Umgebungsvariablen für den Suchindex

Wenn Sie über den gewünschten Indexnamen verfügen (entweder durch Erstellen eines neuen Index oder durch Referenzieren eines bereits vorhandenen), fügen Sie ihn wie folgt Ihrer Datei vom Typ .env hinzu:

AZUREAI_SEARCH_INDEX_NAME=<index-name>

Entwickeln von benutzerdefiniertem RAG-Code

Als Nächstes erstellen Sie benutzerdefinierten Code, um einer einfachen Chatanwendung RAG-Funktionen (Retrieval Augmented Generation) hinzuzufügen. In der Schnellstartanleitung haben Sie die Dateien chat.py und chat.prompty erstellt. Hier wird dieser Code um RAG-Funktionen erweitert.

Die Chat-App mit RAG implementiert die folgende allgemeine Logik:

  1. Generieren einer Suchabfrage basierend auf Benutzerabfrageabsicht und ggf. vorhandenem Chatverlauf
  2. Verwenden eines Einbettungsmodells zum Einbetten der Abfrage
  3. Abrufen relevanter Dokumente aus dem Suchindex auf der Grundlage der Abfrage
  4. Übergeben des relevanten Kontexts an das Azure OpenAI-Chatvervollständigungsmodell
  5. Zurückgeben der Antwort des Azure OpenAI-Modells

Die Chat-App-Implementierungslogik

Die Chat-App-Implementierungslogik befindet sich in der Datei copilot.py. Diese Datei enthält die Kernlogik für die RAG-basierte Chat-App.

  1. Erstellen Sie im Ordner rag-tutorial einen Ordner namens copilot_flow.

  2. Erstellen Sie anschließend im Ordner copilot_flow eine Datei namens copilot.py.

  3. Fügen Sie der Datei copilot.py folgenden Code hinzu:

    import os
    from dotenv import load_dotenv
    
    load_dotenv()
    
    from promptflow.core import Prompty, AzureOpenAIModelConfiguration
    from promptflow.tracing import trace
    from openai import AzureOpenAI
    
    # <get_documents>
    @trace
    def get_documents(search_query: str, num_docs=3):
        from azure.identity import DefaultAzureCredential, get_bearer_token_provider
        from azure.search.documents import SearchClient
        from azure.search.documents.models import VectorizedQuery
    
        token_provider = get_bearer_token_provider(
            DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default"
        )
    
        index_name = os.getenv("AZUREAI_SEARCH_INDEX_NAME")
    
        #  retrieve documents relevant to the user's question from Cognitive Search
        search_client = SearchClient(
            endpoint=os.getenv("AZURE_SEARCH_ENDPOINT"),
            credential=DefaultAzureCredential(),
            index_name=index_name,
        )
    
        aoai_client = AzureOpenAI(
            azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
            azure_ad_token_provider=token_provider,
            api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
        )
    
        # generate a vector embedding of the user's question
        embedding = aoai_client.embeddings.create(
            input=search_query, model=os.getenv("AZURE_OPENAI_EMBEDDING_DEPLOYMENT")
        )
        embedding_to_query = embedding.data[0].embedding
    
        context = ""
        # use the vector embedding to do a vector search on the index
        vector_query = VectorizedQuery(
            vector=embedding_to_query, k_nearest_neighbors=num_docs, fields="contentVector"
        )
        results = trace(search_client.search)(
            search_text="", vector_queries=[vector_query], select=["id", "content"]
        )
    
        for result in results:
            context += f"\n>>> From: {result['id']}\n{result['content']}"
    
        return context
    
    
    # <get_documents>
    
    from promptflow.core import Prompty, AzureOpenAIModelConfiguration
    
    from pathlib import Path
    from typing import TypedDict
    
    
    class ChatResponse(TypedDict):
        context: dict
        reply: str
    
    
    def get_chat_response(chat_input: str, chat_history: list = []) -> ChatResponse:
        model_config = AzureOpenAIModelConfiguration(
            azure_deployment=os.getenv("AZURE_OPENAI_CHAT_DEPLOYMENT"),
            api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
            azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
        )
    
        searchQuery = chat_input
    
        # Only extract intent if there is chat_history
        if len(chat_history) > 0:
            # extract current query intent given chat_history
            path_to_prompty = f"{Path(__file__).parent.absolute().as_posix()}/queryIntent.prompty"  # pass absolute file path to prompty
            intentPrompty = Prompty.load(
                path_to_prompty,
                model={
                    "configuration": model_config,
                    "parameters": {
                        "max_tokens": 256,
                    },
                },
            )
            searchQuery = intentPrompty(query=chat_input, chat_history=chat_history)
    
        # retrieve relevant documents and context given chat_history and current user query (chat_input)
        documents = get_documents(searchQuery, 3)
    
        # send query + document context to chat completion for a response
        path_to_prompty = f"{Path(__file__).parent.absolute().as_posix()}/chat.prompty"
        chatPrompty = Prompty.load(
            path_to_prompty,
            model={
                "configuration": model_config,
                "parameters": {"max_tokens": 256, "temperature": 0.2},
            },
        )
        result = chatPrompty(
            chat_history=chat_history, chat_input=chat_input, documents=documents
        )
    
        return dict(reply=result, context=documents)
    

Die Datei copilot.py enthält zwei wichtige Funktionen: get_documents() und get_chat_response().

Beachten Sie, dass diese beiden Funktionen über den @trace-Decorator verfügen. Dieser ermöglicht es Ihnen, die prompt flow-Ablaufverfolgungsprotokolle der einzelnen Ein- und Ausgaben von Funktionsaufrufen anzuzeigen. @trace ist ein alternativer und erweiterter Ansatz für die in der Schnellstartanleitung gezeigten Ablaufverfolgungsfunktionen.

Die Funktion get_documents() ist der Kern der RAG-Logik.

  1. Sie erfasst die Suchabfrage und die Anzahl der abzurufenden Dokumente.
  2. Sie bettet die Suchabfrage mithilfe eines Einbettungsmodells ein.
  3. Sie fragt den Azure Search-Index ab, um die für die Abfrage relevanten Dokumente abzurufen.
  4. Sie gibt den Kontext der Dokumente zurück.

Die Funktion get_chat_response() baut auf der vorherigen Logik in der Datei chat.py auf:

  1. Sie erfasst die Chateingabe (chat_input) sowie jeglichen ggf. vorhandenen Chatverlauf (chat_history).
  2. Sie konstruiert die Suchabfrage basierend auf der Absicht der Chateingabe (chat_input) und dem Chatverlauf (chat_history).
  3. Sie ruft get_documents() auf, um die relevanten Dokumente abzurufen.
  4. Sie ruft das Chatvervollständigungsmodell mit Kontext auf, um eine fundierte Antwort auf die Abfrage zu erhalten.
  5. Sie gibt die Antwort und den Kontext zurück. Hier wird ein typisiertes Wörterbuch als Rückgabeobjekt für die Funktion get_chat_response() festgelegt. Die Rückgabe der Antwort durch Ihren Code kann optimal an Ihren Anwendungsfall angepasst werden.

Die Funktion get_chat_response() verwendet zwei Dateien vom Typ Prompty, um die erforderlichen LLM-Aufrufe (Large Language Model) auszuführen. Dies wird als Nächstes behandelt.

Promptvorlage für den Chat

Die Datei chat.prompty ist einfach und ähnelt der Datei chat.prompty aus der Schnellstartanleitung. Der Systemprompt wird aktualisiert, um das Produkt widerzuspiegeln, und die Promptvorlage enthält Dokumentkontext.

  1. Fügen Sie die Datei chat.prompty im Verzeichnis copilot_flow hinzu. Die Datei stellt den Anruf des Chatvervollständigungsmodells mit Angabe des Systemprompts, Chatverlaufs und Dokumentkontexts dar.

  2. Fügen Sie der Datei chat.prompty den folgenden Code hinzu:

    ---
    name: Chat Prompt
    description: A prompty that uses the chat API to respond to queries grounded in relevant documents
    model:
        api: chat
        configuration:
            type: azure_openai
    inputs:
        chat_input:
            type: string
        chat_history:
            type: list
            is_chat_history: true
            default: []
        documents:
            type: object
    
    ---
    system:
    You are an AI assistant helping users with queries related to outdoor outdooor/camping gear and clothing.
    If the question is not related to outdoor/camping gear and clothing, just say 'Sorry, I only can answer queries related to outdoor/camping gear and clothing. So, how can I help?'
    Don't try to make up any answers.
    If the question is related to outdoor/camping gear and clothing but vague, ask for clarifying questions instead of referencing documents. If the question is general, for example it uses "it" or "they", ask the user to specify what product they are asking about.
    Use the following pieces of context to answer the questions about outdoor/camping gear and clothing as completely, correctly, and concisely as possible.
    Do not add documentation reference in the response.
    
    # Documents
    {{documents}}
    
    {% for item in chat_history %}
    {{item.role}}
    {{item.content}}
    {% endfor %}
    
    user:
    {{chat_input}}
    

Promptvorlage für den Chatverlauf

Da wir eine RAG-basierte Anwendung implementieren, ist etwas zusätzliche Logik erforderlich, um relevante Dokumente nicht nur für die aktuelle Benutzerabfrage abzurufen, sondern auch den Chatverlauf zu berücksichtigen. Ohne diese zusätzliche Logik würde Ihr LLM-Aufruf zwar den Chatverlauf berücksichtigen. Sie würden aber nicht die richtigen Dokumente für diesen Kontext abrufen und nicht die erwartete Antwort erhalten.

Wenn der Benutzer beispielsweise die Frage „Ist es wasserdicht?“ stellt, muss das System den Chatverlauf untersuchen, um zu ermitteln, worauf sich das Wort „es“ bezieht, und diesen Kontext in die einzubettende Suchabfrage einbeziehen. Dadurch werden die richtigen Dokumente für „es“ (vielleicht das Alpine Explorer-Zelt) und die zugehörigen „Kosten“ abgerufen.

Anstatt nur die Abfrage des Benutzers für die Einbettung zu übergeben, müssen wir eine neue Suchabfrage generieren, die den Chatverlauf berücksichtigt. Wir verwenden eine weitere Datei vom Typ Prompty (einen weiteren LLM-Aufruf) mit der spezifischen Aufforderung, die Absicht der Benutzerabfrage anhand des Chatverlaufs zu interpretieren und eine Suchabfrage mit dem erforderlichen Kontext zu konstruieren.

  1. Erstellen Sie die Datei queryIntent.prompty im Ordner copilot_flow.

  2. Geben Sie den folgenden Code ein, um spezifische Details zum Promptformat und Few-Shot-Beispiele zu erhalten:

    ---
     name: Chat Prompt
     description: A prompty that extract users query intent based on the current_query and chat_history of the conversation
     model:
         api: chat
         configuration:
             type: azure_openai
     inputs:
         query:
           type: string
         chat_history:
             type: list
             is_chat_history: true
             default: []
     
     ---
     system:
     - You are an AI assistant reading a current user query and chat_history.
     - Given the chat_history, and current user's query, infer the user's intent expressed in the current user query.
     - Once you infer the intent, respond with a search query that can be used to retrieve relevant documents for the current user's query based on the intent
     - Be specific in what the user is asking about, but disregard parts of the chat history that are not relevant to the user's intent.
     
     Example 1:
     With a chat_history like below:
     \```
     chat_history: [    {
           "role": "user",
           "content": "are the trailwalker shoes waterproof?"
         },
         {
           "role": "assistant",
           "content": "Yes, the TrailWalker Hiking Shoes are waterproof. They are designed with a durable and waterproof construction to withstand various terrains and weather conditions."
         }
     ]
     \```
     User query: "how much do they cost?"
     
     Intent: "The user wants to know how much the Trailwalker Hiking Shoes cost."
     Search query: "price of Trailwalker Hiking Shoes"
     
     
     Example 2:
     With a chat_history like below:
     \```
     chat_history: [    {
           "role": "user",
           "content": "are the trailwalker shoes waterproof?"
         },
         {
           "role": "assistant",
           "content": "Yes, the TrailWalker Hiking Shoes are waterproof. They are designed with a durable and waterproof construction to withstand various terrains and weather conditions."
         },
         {
           "role": "user",
           "content": "how much do they cost?"
         },
         {
           "role": "assistant",
           "content": "The TrailWalker Hiking Shoes are priced at $110."
         },
         {
           "role": "user",
           "content": "do you have waterproof tents?"
         },
         {
           "role": "assistant",
           "content": "Yes, we have waterproof tents available. Can you please provide more information about the type or size of tent you are looking for?"
         },
         {
           "role": "user",
           "content": "which is your most waterproof tent?"
         },
         {
           "role": "assistant",
           "content": "Our most waterproof tent is the Alpine Explorer Tent. It is designed with a waterproof material and has a rainfly with a waterproof rating of 3000mm. This tent provides reliable protection against rain and moisture."
         }
     ]
     \```
     User query: "how much does it cost?"
     
     Intent: "the user would like to know how much the Alpine Explorer Tent costs"
     Search query: "price of Alpine Explorer Tent"
     
     {% for item in chat_history %}
     {{item.role}}
     {{item.content}}
     {% endfor %}
     
     Current user query:
     {{query}}
     
     Search query:
    

Die einfache Systemnachricht in der Datei queryIntent.prompty erfüllt die Mindestanforderungen, damit die RAG-Lösung mit dem Chatverlauf arbeiten kann.

Konfigurieren erforderlicher Pakete

Erstellen Sie die Datei requirements.txt im Ordner copilot_flow. Fügen Sie den folgenden Inhalt hinzu:

openai
azure-identity
azure-search-documents==11.4.0
promptflow[azure]==1.11.0
promptflow-tracing==1.11.0
promptflow-tools==1.4.0
promptflow-evals==0.3.0
jinja2
aiohttp
python-dotenv

Diese Pakete sind erforderlich, damit der Flow lokal und in einer bereitgestellten Umgebung ausgeführt werden kann.

Verwenden des Flex-Flows

Wie bereits erwähnt verwendet diese Implementierung den Flex-Flow von prompt flow. Hierbei handelt es sich um den Code-First-Ansatz für die Implementierung von Flows. Sie geben eine Eingabefunktion an (die in copilot.py definiert wird). Weitere Informationen finden Sie unter Entwickeln eines Flows.

Dieser YAML-Code gibt die Eingabefunktion (die in copilot.py definierte Funktion get_chat_response) an. Außerdem gibt er die Anforderungen für die Ausführung des Flows an.

Erstellen Sie die Datei flow.flex.yaml im Ordner copilot_flow. Fügen Sie den folgenden Inhalt hinzu:

entry: copilot:get_chat_response
environment:
  python_requirements_txt: requirements.txt

Testen Ihrer Chat-App mithilfe von Prompt Flow

Verwenden Sie die Testfunktion von Prompt Flow, um anhand von Beispieleingaben zu sehen, dass Ihre Chat-App wie erwartet funktioniert. Die Datei flow.flex.yaml ermöglicht die Verwendung von prompt flow, um Tests mit Ihren angegebenen Eingaben durchzuführen.

Führen Sie den Flow mithilfe des folgenden prompt flow-Befehls aus:

pf flow test --flow ./copilot_flow --inputs chat_input="how much do the Trailwalker shoes cost?"

Alternativ können Sie den Flow interaktiv mit dem Flag --ui ausführen.

pf flow test --flow ./copilot_flow --ui

Bei Verwendung von --ui öffnet die interaktive exemplarische Chatumgebung ein Fenster in Ihrem lokalen Browser.

  • Bei der ersten Ausführung mit dem Flag --ui müssen Sie Ihre Chateingaben und -ausgaben manuell aus den Optionen auswählen. Wählen Sie bei der erstmaligen Erstellung dieser Sitzung die Einstellungen unter Konfiguration der Felder für Chateingabe/-ausgabe aus, und beginnen Sie dann zu chatten.
  • Bei der nächsten Ausführung mit dem Flag --ui werden Ihre Einstellungen von der Sitzung abgerufen.

Screenshot: Exemplarische Chatumgebung

Wenn Sie mit Ihrer interaktiven Sitzung fertig sind, drücken Sie im Terminalfenster STRG+C, um den Server zu beenden.

Testen mit Chatverlauf

Im Allgemeinen wird der Chatverlauf von prompt flow und Prompty unterstützt. Wenn Sie mit dem Flag --ui im lokal bereitgestellten Front-End testen, wird Ihr Chatverlauf von prompt flow verwaltet. Bei Tests ohne --ui können Sie eine Eingabedatei angeben, die den Chatverlauf enthält.

Da diese Anwendung RAG implementiert, war zusätzliche Logik zur Behandlung des Chatverlaufs in der Datei queryIntent.prompty erforderlich.

Erstellen Sie zum Testen mit Chatverlauf eine Datei namens input_with_chat_history.json im Ordner copilot_flow, und fügen Sie den folgenden Inhalt ein:

{
    "chat_input": "how much does it cost?",
    "chat_history": [
        {
        "role": "user",
        "content": "are the trailwalker shoes waterproof?"
        },
        {
        "role": "assistant",
        "content": "Yes, the TrailWalker Hiking Shoes are waterproof. They are designed with a durable and waterproof construction to withstand various terrains and weather conditions."
        },
        {
        "role": "user",
        "content": "how much do they cost?"
        },
        {
        "role": "assistant",
        "content": "The TrailWalker Hiking Shoes are priced at $110."
        },
        {
        "role": "user",
        "content": "do you have waterproof tents?"
        },
        {
        "role": "assistant",
        "content": "Yes, we have waterproof tents available. Can you please provide more information about the type or size of tent you are looking for?"
        },
        {
        "role": "user",
        "content": "which is your most waterproof tent?"
        },
        {
        "role": "assistant",
        "content": "Our most waterproof tent is the Alpine Explorer Tent. It is designed with a waterproof material and has a rainfly with a waterproof rating of 3000mm. This tent provides reliable protection against rain and moisture."
        }
    ]
    }

Führen Sie zum Testen mit dieser Datei Folgendes aus:

pf flow test --flow ./copilot_flow --inputs ./copilot_flow/input_with_chat_history.json

Es wird eine Ausgabe wie die folgende erwartet: „Das Alpine Explorer-Zelt kostet 350 USD.“

Dieses System kann die Absicht der Abfrage „Wie viel kostet es?“ interpretieren und weiß dadurch, dass sich „es“ auf das Alpine Explorer-Zelt bezieht, da dies der neueste Kontext im Chatverlauf war. Anschließend erstellt das System eine Suchabfrage für den Preis des Alpine Explorer-Zelts, um die relevanten Dokumente für die Kosten des Alpine Explorer-Zelts abzurufen, und wir erhalten die Antwort.

Wenn Sie zur Ablaufverfolgung dieser Flowausführung navigieren, können Sie diese Konversation in Aktion sehen. Der Link für lokale Ablaufverfolgungen wird in der Konsolenausgabe vor dem Ergebnis der Testausführung des Flows angezeigt.

Screenshot der Konsolenausgabe für den Prompt Flow.

Bereinigen von Ressourcen

Um unnötige Azure-Kosten zu vermeiden, sollten Sie die in diesem Tutorial erstellten Ressourcen löschen, wenn sie nicht mehr benötigt werden. Zum Verwalten von Ressourcen können Sie das Azure-Portal verwenden.

Löschen Sie sie aber noch nicht, wenn Sie Ihre Chat-App im nächsten Teil dieser Tutorialreihe in Azure bereitstellen möchten.

Nächster Schritt