Udostępnij za pośrednictwem


Samouczek: część 2 — tworzenie niestandardowej aplikacji do czatu przy użyciu zestawu SDK przepływu monitów

W tym samouczku użyjesz zestawu SDK przepływu monitów (i innych bibliotek) do kompilowania, konfigurowania, oceniania i wdrażania aplikacji czatu dla firmy zajmującej się sprzedażą detaliczną o nazwie Contoso Trek. Twoja firma detaliczna specjalizuje się w sprzęcie kempingowym na świeżym powietrzu i odzieży. Aplikacja do czatu powinna odpowiadać na pytania dotyczące produktów i usług. Na przykład aplikacja do czatu może odpowiedzieć na pytania, takie jak "który namiot jest najbardziej wodoodporny?" lub "jaki jest najlepszy śpiwór do zimnej pogody?".

W tej części opisano, jak ulepszyć podstawową aplikację czatu przez dodanie rozszerzonej generacji rozszerzonej (RAG) pobierania w celu uziemienia odpowiedzi w danych niestandardowych. Pobieranie rozszerzonej generacji (RAG) to wzorzec, który używa danych z dużym modelem językowym (LLM) do generowania odpowiedzi specyficznych dla danych. Z tej części drugiej dowiesz się, jak wykonywać następujące działania:

  • Wdrażanie modeli sztucznej inteligencji w usłudze Azure AI Studio do użycia w aplikacji
  • Opracowywanie niestandardowego kodu RAG
  • Testowanie aplikacji czatu przy użyciu przepływu monitów

Ten samouczek jest drugą częścią trzyczęściowego samouczka.

Wymagania wstępne

Struktura kodu aplikacji

Utwórz folder o nazwie rag-tutorial na komputerze lokalnym. W tej serii samouczków opisano tworzenie zawartości każdego pliku. Po ukończeniu serii samouczków struktura folderów wygląda następująco:

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.]

Implementacja w tym samouczku korzysta z elastycznego przepływu przepływu monitów, który jest podejściem code-first do implementowania przepływów. Należy określić funkcję entry (która znajduje się w copilot.py), a następnie użyć funkcji testowania, oceny i śledzenia przepływu monitów dla przepływu. Ten przepływ jest w kodzie i nie ma języka DAG (skierowanego grafu Acyklicznego) ani innego składnika wizualizacji. Dowiedz się więcej o sposobie opracowywania przepływu elastycznego w dokumentacji przepływu monitów w usłudze GitHub.

Ustawianie początkowych zmiennych środowiskowych

Istnieje kolekcja zmiennych środowiskowych używanych w różnych fragmentach kodu. Dodaj je wszystkie do pliku env .

Ważne

Jeśli utworzysz to w repozytorium git, upewnij się, że .env znajduje się on w .gitignore pliku, aby nie przypadkowo zaewidencjonować go w repozytorium.

Zacznij od tych wartości. W miarę postępu pracy z samouczkiem dodasz jeszcze kilka wartości.

  1. Utwórz plik env w folderze rag-tutorial. Dodaj następujące zmienne:

    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>
    

Zastąp symbole zastępcze następującymi wartościami:

  • Znajdź element <your subscription id>, <your resource group>i <your project name> z widoku projektu w programie AI Studio:

    1. W programie AI Studio przejdź do projektu i wybierz pozycję Ustawienia w okienku po lewej stronie.
    2. W sekcji Właściwości projektu znajdź identyfikator subskrypcji i grupę zasobów. Pole Nazwa to <your project name>
  • Nadal w obszarze Ustawienia projektu w sekcji Połączone zasoby zobaczysz wpis dla usługi Azure AIServices lub Azure OpenAI. Wybierz nazwę, aby otworzyć szczegóły połączenia. Nazwa połączenia zostanie wyświetlona w górnej części strony Szczegóły połączenia. Skopiuj tę nazwę do użycia dla elementu <your AIServices or Azure OpenAI connection name>.

  • Wróć do strony Ustawienia projektu. W sekcji Połączone zasoby wybierz link dla usługi Azure AI Search.

    • Skopiuj docelowy adres URL dla elementu <your Azure Search endpoint>.
    • Skopiuj nazwę u góry elementu <your Azure Search connection name>.

    Zrzut ekranu przedstawia nazwy punktów końcowych i połączeń.

Wdrażanie modeli

Potrzebujesz dwóch modeli do utworzenia aplikacji czatu opartej na usłudze RAG: modelu czatu platformy Azure OpenAI (gpt-3.5-turbo) i modelu osadzania usługi Azure OpenAI (text-embedding-ada-002). Wdróż te modele w projekcie usługi Azure AI Studio, korzystając z tego zestawu kroków dla każdego modelu.

Te kroki umożliwiają wdrożenie modelu w punkcie końcowym w czasie rzeczywistym z katalogu modeli programu AI Studio:

  1. Zaloguj się do programu AI Studio i przejdź do strony głównej.

  2. Wybierz pozycję Katalog modeli na lewym pasku bocznym.

  3. W filtrze Kolekcje wybierz pozycję Azure OpenAI.

    Zrzut ekranu przedstawiający sposób filtrowania według modeli usługi Azure OpenAI w katalogu.

  4. Wybierz model z kolekcji Azure OpenAI. Po raz pierwszy wybierz gpt-3.5-turbo model. Po raz drugi wybierz text-embedding-ada-002 model.

  5. Wybierz pozycję Wdróż , aby otworzyć okno wdrażania.

  6. Wybierz koncentrator, do którego chcesz wdrożyć model. Użyj tego samego centrum co projekt.

  7. Określ nazwę wdrożenia i zmodyfikuj inne ustawienia domyślne w zależności od wymagań.

  8. Wybierz Wdróż.

  9. Zostanie wyświetlona strona szczegółów wdrożenia. Wybierz pozycję Otwórz na placu zabaw.

  10. Wybierz pozycję Wyświetl kod , aby uzyskać przykłady kodu, których można użyć do korzystania z wdrożonego modelu w aplikacji.

Podczas wdrażania gpt-3.5-turbo modelu znajdź następujące wartości w sekcji Wyświetl kod i dodaj je do pliku env :

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

Podczas wdrażania text-embedding-ada-002 modelu dodaj nazwę do pliku env :

AZURE_OPENAI_EMBEDDING_DEPLOYMENT=<embedding_model_deployment_name>

Instalowanie interfejsu wiersza polecenia platformy Azure i logowanie

Zainstaluj interfejs wiersza polecenia platformy Azure i zaloguj się z lokalnego środowiska deweloperskiego, aby można było wywołać usługę Azure OpenAI przy użyciu poświadczeń użytkownika.

W większości przypadków można zainstalować interfejs wiersza polecenia platformy Azure z poziomu terminalu przy użyciu następującego polecenia:

winget install -e --id Microsoft.AzureCLI

Możesz postępować zgodnie z instrukcjami Instalowanie interfejsu wiersza polecenia platformy Azure, jeśli te polecenia nie działają w konkretnym systemie operacyjnym lub konfiguracji.

Po zainstalowaniu interfejsu wiersza polecenia platformy Azure zaloguj się przy użyciu az login polecenia i zaloguj się przy użyciu przeglądarki:

az login

Teraz utworzymy naszą aplikację i wywołamy usługę Azure OpenAI Service z poziomu kodu.

Tworzenie nowego środowiska języka Python

Najpierw musimy utworzyć nowe środowisko języka Python, za pomocą których można zainstalować pakiety zestawu SDK przepływu monitu. Nie instaluj pakietów w globalnej instalacji języka Python. Zawsze należy używać środowiska wirtualnego lub conda podczas instalowania pakietów języka Python. W przeciwnym razie możesz przerwać globalną instalację języka Python.

W razie potrzeby zainstaluj język Python

Zalecamy używanie języka Python w wersji 3.10 lub nowszej, ale wymagana jest co najmniej wersja python 3.8. Jeśli nie masz zainstalowanej odpowiedniej wersji języka Python, możesz postępować zgodnie z instrukcjami w samouczku języka Python programu VS Code, aby uzyskać najprostszy sposób instalowania języka Python w systemie operacyjnym.

Utworzenie środowiska wirtualnego

Jeśli masz już zainstalowany język Python w wersji 3.10 lub nowszej, możesz utworzyć środowisko wirtualne przy użyciu następujących poleceń:

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

Aktywowanie środowiska języka Python oznacza, że po uruchomieniu python lub pip w wierszu polecenia należy użyć interpretera języka Python zawartego .venv w folderze aplikacji.

Uwaga

Możesz użyć deactivate polecenia , aby zamknąć środowisko wirtualne języka Python i później ponownie aktywować je w razie potrzeby.

Uaktualnianie narzędzia pip

Aby upewnić się, że masz najnowszą wersję narzędzia, uruchom następujące polecenie:

python -m pip install --upgrade pip

Instalowanie zestawu SDK przepływu monitów

Przepływ monitów to zestaw narzędzi programistycznych zaprojektowanych w celu usprawnienia kompleksowego cyklu tworzenia aplikacji sztucznej inteligencji opartych na usłudze LLM, od ideacji, tworzenia prototypów, testowania, oceny, wdrażania produkcyjnego i monitorowania.

Użyj narzędzia, aby zainstalować zestaw SDK przepływu monitów w utworzonym środowisku wirtualnym.

pip install promptflow
pip install azure-identity

Zestaw SDK przepływu monitów przyjmuje zależność od wielu pakietów, które można wybrać oddzielnie zainstalować, jeśli nie chcesz ich wszystkich:

  • promptflow-core: zawiera podstawowe środowisko uruchomieniowe przepływu monitów używane do wykonywania kodu LLM
  • promptflow-tracing: uproszczona biblioteka używana do emitowania śladów OpenTelemetry w standardach
  • promptflow-devkit: zawiera narzędzia do testowania przepływu monitów i przeglądarki śledzenia dla lokalnych środowisk deweloperskich
  • openai: biblioteki klienta do korzystania z usługi Azure OpenAI
  • python-dotenv: służy do ustawiania zmiennych środowiskowych przez odczytywanie ich z .env plików

Tworzenie indeksu usługi Azure AI Search

Celem tej aplikacji opartej na usłudze RAG jest uziemienie odpowiedzi modelu w danych niestandardowych. Używasz indeksu usługi Azure AI Search, który przechowuje wektoryzowane dane z modelu osadzania. Indeks wyszukiwania służy do pobierania odpowiednich dokumentów na podstawie pytania użytkownika.

Jeśli nie masz jeszcze utworzonego indeksu usługi Azure AI Search, omówimy sposób jej tworzenia. Jeśli masz już indeks do użycia, możesz przejść do sekcji ustawienia zmiennej środowiskowej wyszukiwania. Indeks wyszukiwania jest tworzony w usłudze Azure AI usługa wyszukiwania, do którego utworzono lub odwołuje się w poprzednim kroku.

  1. Użyj własnych danych lub pobierz przykładowe dane produktu firmy Contoso Trek w pliku ZIP na komputerze lokalnym. Rozpakuj plik do folderu rag-tutorial/data . Te dane są kolekcją plików markdown reprezentujących informacje o produkcie. Dane są ustrukturyzowane w sposób łatwy do pozyskiwania do indeksu wyszukiwania. Utworzysz indeks wyszukiwania na podstawie tych danych.

  2. Pakiet RAG przepływu monitu umożliwia pozyskiwanie plików markdown, lokalne tworzenie indeksu wyszukiwania i rejestrowanie go w projekcie w chmurze. Zainstaluj pakiet RAG przepływu monitu:

    pip install promptflow-rag
    
  3. Utwórz plik build_index.py w folderze rag-tutorial.

  4. Skopiuj i wklej następujący kod do pliku build_index.py .

    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))
    
    • Ustaw zmienną index_name na nazwę żądanego indeksu.
    • W razie potrzeby możesz zaktualizować zmienną path_to_data do ścieżki, w której są przechowywane pliki danych.

    Ważne

    Domyślnie przykładowy kod oczekuje struktury kodu aplikacji zgodnie z opisem wcześniej w tym samouczku. Folder data powinien być na tym samym poziomie co build_index.py i pobrany product-info folder z plikami md w nim.

  5. W konsoli uruchom kod, aby utworzyć indeks lokalnie i zarejestrować go w projekcie chmury:

    python build_index.py
    
  6. Po uruchomieniu skryptu możesz wyświetlić nowo utworzony indeks na stronie Indeksy projektu usługi Azure AI Studio. Aby uzyskać więcej informacji, zobacz How to build and consume vector indexes in Azure AI Studio (Jak tworzyć i wykorzystywać indeksy wektorów w usłudze Azure AI Studio).

  7. Jeśli ponownie uruchomisz skrypt o tej samej nazwie indeksu, zostanie utworzona nowa wersja tego samego indeksu.

Ustawianie zmiennej środowiskowej indeksu wyszukiwania

Gdy masz nazwę indeksu, której chcesz użyć (tworząc nowy lub odwołując się do istniejącego), dodaj ją do pliku env w następujący sposób:

AZUREAI_SEARCH_INDEX_NAME=<index-name>

Opracowywanie niestandardowego kodu RAG

Następnie utworzysz kod niestandardowy, aby dodać możliwości rozszerzonej generacji (RAG) pobierania do podstawowej aplikacji czatu. W przewodniku Szybki start utworzono pliki chat.py i chat.prompty . W tym miejscu rozszerzysz ten kod, aby uwzględnić możliwości RAG.

Aplikacja do czatu z narzędziem RAG implementuje następującą ogólną logikę:

  1. Generowanie zapytania wyszukiwania na podstawie intencji zapytania użytkownika i historii czatów
  2. Osadzanie zapytania przy użyciu modelu osadzania
  3. Pobieranie odpowiednich dokumentów z indeksu wyszukiwania, biorąc pod uwagę zapytanie
  4. Przekazywanie odpowiedniego kontekstu do modelu uzupełniania czatu usługi Azure OpenAI
  5. Zwraca odpowiedź z modelu Azure OpenAI

Logika implementacji aplikacji czatu

Logika implementacji aplikacji czatu znajduje się w pliku copilot.py . Ten plik zawiera podstawową logikę aplikacji czatu opartej na programie RAG.

  1. Utwórz folder o nazwie copilot_flow w folderze rag-tutorial .

  2. Następnie utwórz plik o nazwie copilot.py w folderze copilot_flow .

  3. Dodaj następujący kod do pliku copilot.py :

    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)
    

Plik copilot.py zawiera dwie kluczowe funkcje: get_documents() i get_chat_response().

Zwróć uwagę, że te dwie funkcje mają @trace dekorator, który umożliwia wyświetlenie dzienników śledzenia przepływu monitów poszczególnych danych wejściowych i wyjściowych wywołań funkcji. @trace jest alternatywnym i rozszerzonym podejściem do sposobu, w jaki przewodnik Szybki start przedstawia możliwości śledzenia.

Funkcja get_documents() jest rdzeniem logiki RAG.

  1. Pobiera zapytanie wyszukiwania i liczbę dokumentów do pobrania.
  2. Osadza zapytanie wyszukiwania przy użyciu modelu osadzania.
  3. Wysyła zapytanie do indeksu usługi Azure Search, aby pobrać dokumenty istotne dla zapytania.
  4. Zwraca kontekst dokumentów.

Funkcja get_chat_response() kompiluje się z poprzedniej logiki w pliku chat.py :

  1. Przyjmuje element i chat_input dowolny chat_historyelement .
  2. Tworzy zapytanie wyszukiwania na chat_input podstawie intencji i chat_history.
  3. Wywołuje metodę get_documents() pobierania odpowiednich dokumentów.
  4. Wywołuje model uzupełniania czatu z kontekstem, aby uzyskać uziemiony odpowiedź na zapytanie.
  5. Zwraca odpowiedź i kontekst. Ustawiamy słownik wpisany jako obiekt zwracany dla naszej get_chat_response() funkcji. Możesz wybrać sposób, w jaki kod zwraca odpowiedź, aby najlepiej dopasować swój przypadek użycia.

Funkcja get_chat_response() używa dwóch Prompty plików, aby wykonać niezbędne wywołania modelu dużego języka (LLM), które omówimy w następnej kolejności.

Monituj o szablon czatu

Plik chat.prompty jest prosty i podobny do chat.prompty w przewodniku Szybki start. Monit systemowy jest aktualizowany w celu odzwierciedlenia naszego produktu, a szablony monitów zawierają kontekst dokumentu.

  1. Dodaj plik chat.prompty w katalogu copilot_flow . Plik reprezentuje wywołanie modelu uzupełniania czatu z podanym monitem systemowym, historią czatu i kontekstem dokumentu.

  2. Dodaj ten kod do pliku chat.prompty :

    ---
    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}}
    

Monituj szablon historii czatów

Ponieważ wdrażamy aplikację opartą na programie RAG, istnieje dodatkowa logika wymagana do pobierania odpowiednich dokumentów nie tylko dla bieżącego zapytania użytkownika, ale także z uwzględnieniem historii czatów. Bez tej dodatkowej logiki połączenie LLM będzie uwzględniać historię czatów. Ale nie pobrano odpowiednich dokumentów dla tego kontekstu, więc nie otrzymasz oczekiwanej odpowiedzi.

Jeśli na przykład użytkownik zadaje pytanie "czy jest wodoodporny?", potrzebujemy systemu, aby przyjrzeć się historii czatów, aby określić, do czego odnosi się słowo "it" i uwzględnić ten kontekst w zapytaniu wyszukiwania do osadzenia. W ten sposób pobieramy odpowiednie dokumenty dla "go" (być może namiot Alpine Explorer) i jego "koszt".

Zamiast przekazywać tylko zapytanie użytkownika do osadzenia, musimy wygenerować nowe zapytanie wyszukiwania, które uwzględnia dowolną historię czatów. Używamy innego Prompty (czyli innego wywołania LLM) z określonym monitem o interpretację intencji zapytania użytkownika danej historii czatu i konstruowania zapytania wyszukiwania, które ma wymagany kontekst.

  1. Utwórz plik queryIntent.prompty w folderze copilot_flow .

  2. Wprowadź ten kod, aby uzyskać szczegółowe informacje o formacie monitu i przykładach z kilkoma zrzutami.

    ---
     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:
    

Prosty komunikat systemowy w naszym pliku queryIntent.prompty osiąga minimum wymagane przez rozwiązanie RAG do pracy z historią czatów.

Konfigurowanie wymaganych pakietów

Utwórz requirements.txt pliku w folderze copilot_flow. Dodaj tę zawartość:

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

Te pakiety są wymagane, aby przepływ był uruchamiany lokalnie i w wdrożonym środowisku.

Korzystanie z przepływu flex

Jak wspomniano wcześniej, ta implementacja korzysta z elastycznego przepływu przepływu monitów, czyli podejścia opartego na kodzie do implementowania przepływów. Należy określić funkcję entry (zdefiniowaną w copilot.py). Dowiedz się więcej na temat opracowywania elastycznego przepływu.

Ten plik yaml określa funkcję entry, która jest funkcją zdefiniowaną get_chat_response w pliku copilot.py. Określa również wymagania, które należy uruchomić przepływ.

Utwórz plik flow.flex.yaml w folderze copilot_flow . Dodaj tę zawartość:

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

Testowanie aplikacji czatu przy użyciu przepływu monitów

Użyj możliwości testowania przepływu monitów, aby zobaczyć, jak aplikacja czatu działa zgodnie z oczekiwaniami w przykładowych danych wejściowych. Korzystając z pliku flow.flex.yaml , możesz użyć przepływu monitów do przetestowania przy użyciu określonych danych wejściowych.

Uruchom przepływ przy użyciu tego polecenia przepływu wiersza polecenia:

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

Alternatywnie możesz uruchomić przepływ interaktywnie z flagą --ui .

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

W przypadku korzystania z usługi --uiśrodowisko interaktywnego przykładowego czatu otwiera okno w przeglądarce lokalnej.

  • Przy pierwszym uruchomieniu z flagą --ui należy ręcznie wybrać dane wejściowe i wyjściowe czatu z opcji. Po pierwszym utworzeniu tej sesji wybierz ustawienia konfiguracji pola Dane wejściowe/wyjściowe czatu, a następnie rozpocznij rozmowę.
  • Przy następnym uruchomieniu z flagą --ui sesja zapamięta ustawienia.

Zrzut ekranu przedstawiający przykładowe środowisko czatu.

Po zakończeniu sesji interakcyjnej wprowadź Ctrl + C w oknie terminalu, aby zatrzymać serwer.

Testowanie za pomocą historii czatów

Ogólnie rzecz biorąc, przepływ monitów i Prompty historia czatów pomocy technicznej. Jeśli testujesz z flagą --ui w lokalnym obsługiwanym frontonie, przepływ monitu zarządza historią czatu. Jeśli testujesz bez --uielementu , możesz określić plik wejściowy zawierający historię czatów.

Ponieważ nasza aplikacja implementuje aplikację RAG, musieliśmy dodać dodatkową logikę do obsługi historii czatów w pliku queryIntent.prompty .

Aby przetestować historię czatów, utwórz plik o nazwie input_with_chat_history.json w folderze copilot_flow i wklej następującą zawartość:

{
    "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."
        }
    ]
    }

Aby przetestować ten plik, uruchom polecenie:

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

Oczekiwane dane wyjściowe są podobne do: "Namiot Alpine Explorer jest wyceniany na 350 dolarów."

Ten system jest w stanie interpretować intencję zapytania "ile kosztuje?", aby wiedzieć, że "on" odnosi się do namiotu Alpine Explorer, który był najnowszym kontekstem w historii czatów. Następnie system tworzy zapytanie wyszukiwania dla ceny namiotu Alpine Explorer, aby pobrać odpowiednie dokumenty dla kosztu namiotu Alpine Explorer i otrzymamy odpowiedź.

Jeśli przejdziesz do śledzenia z tego przebiegu przepływu, zobaczysz konwersację w akcji. Link śledzenia lokalnego jest wyświetlany w danych wyjściowych konsoli przed wynikiem przebiegu testu przepływu.

Zrzut ekranu przedstawia dane wyjściowe konsoli dla przepływu monitu.

Czyszczenie zasobów

Aby uniknąć niepotrzebnych kosztów platformy Azure, usuń zasoby utworzone w tym samouczku, jeśli nie są już potrzebne. Aby zarządzać zasobami, możesz użyć witryny Azure Portal.

Ale nie usuwaj ich jeszcze, jeśli chcesz wdrożyć aplikację czatu na platformie Azure w następnej części tej serii samouczków.

Następny krok