Compartir a través de


Tutorial: Parte 2: creación de una aplicación de chat personalizada con el SDK de flujo de avisos

En este tutorial, usará el SDK de flujo de avisos (y otras bibliotecas) para compilar, configurar, evaluar e implementar una aplicación de chat para su empresa minorista denominada Contoso Trek. Su empresa minorista se especializa en ropa y equipo de camping al aire libre. La aplicación de chat debe responder a preguntas sobre sus productos y servicios. Por ejemplo, la aplicación de chat puede responder a preguntas como "¿Qué tienda es la más impermeable?" o "¿cuál es la mejor bolsa de dormir para tiempo frío?".

En esta segunda parte se muestra cómo mejorar una aplicación de chat básica mediante la adición de la generación aumentada de recuperación (RAG) para fundamentar las respuestas en los datos personalizados. La generación aumentada de recuperación (RAG) es un patrón que usa los datos con un modelo de lenguaje grande (LLM) para generar respuestas específicas a los datos. En esta segunda parte, aprenderá a:

  • Implementación de modelos de IA en Estudio de IA de Azure para usarlos en la aplicación
  • Desarrollo de código de RAG personalizado
  • Uso del flujo de avisos para probar la aplicación de chat

Este tutorial es la segunda parte de un tutorial de tres partes.

Requisitos previos

Estructura del código de la aplicación

Cree una carpeta denominada rag-tutorial en el equipo local. En esta serie de tutoriales se explica la creación del contenido de cada archivo. Cuando complete la serie de tutoriales, la estructura de carpetas tendrá este aspecto:

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

La implementación de este tutorial usa el flujo flexible del flujo de avisos, que es el enfoque de código primero para implementar flujos. Especifique una función de entrada (que está en copilot.py) y, a continuación, use las funcionalidades de prueba, evaluación y seguimiento del flujo de avisos para el flujo. Este flujo está en el código y no tiene un DAG (Gráfico acíclico dirigido) u otro componente visual. Obtenga más información sobre cómo desarrollar un flujo flexible en la documentación del flujo de avisos en GitHub.

Establecimiento de variables de entorno iniciales

Hay una colección de variables de entorno que se usan en los distintos fragmentos de código. Agréguelos todos a un archivo .env .

Importante

Si crea esto en un repositorio git, asegúrese de que .env está en el archivo .gitignore para que no lo compruebe accidentalmente en el repositorio.

Comience con estos valores. Agregará algunos valores más a medida que avance en el tutorial.

  1. Cree un archivo .env en la carpeta rag-tutorial. Agregue estas variables:

    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>
    

Reemplace los marcadores de posición por los siguientes valores:

  • Busque la <your subscription id>, <your resource group> y <your project name> en la vista del proyecto en Estudio de IA:

    1. En AI Studio, vaya al proyecto y seleccione Configuración en el panel izquierdo.
    2. En la sección Propiedades del proyecto, encontrará el identificador de suscripción y el grupo de recursos. El campo Nombre es <your project name>
  • En la Configuración del proyecto, en la sección Recursos conectados, verá una entrada para Azure AIServices o Azure OpenAI. Seleccione el nombre para abrir los Detalles de la conexión. El nombre de la conexión aparece en la parte superior de la página Detalles de la conexión. Copie este nombre para usarlo para <your AIServices or Azure OpenAI connection name>.

  • Vuelva a la página Configuración del proyecto. En la sección Recursos conectados, seleccione el vínculo para Búsqueda de Azure AI.

    • Copie la dirección URL de destino para <your Azure Search endpoint>.
    • Copie el nombre en la parte superior de <your Azure Search connection name>.

    Recorte de pantalla que muestra los nombres de punto de conexión y conexión.

Implementación de modelos

Necesita dos modelos para crear una aplicación de chat basada en RAG: un modelo de chat de Azure OpenAI (gpt-3.5-turbo) y un modelo de inserción de Azure OpenAI (text-embedding-ada-002). Implemente estos modelos en el proyecto de Estudio de IA de Azure mediante este conjunto de pasos para cada modelo.

Estos pasos implementan un modelo en un punto de conexión en tiempo real desde el catálogo de modelos de Estudio de IA:

  1. Inicie sesión en Inteligencia artificial de Azure Studio y vaya a la página Inicio.

  2. Seleccione Catálogo de modelos en la barra lateral izquierda.

  3. En el filtro Colecciones, seleccione Azure OpenAI.

    Captura de pantalla que muestra cómo filtrar por modelos de Azure OpenAI en el catálogo.

  4. Seleccione el modelo de la colección Azure OpenAI. La primera vez, seleccione el modelo gpt-3.5-turbo. La segunda vez, seleccione el modelo text-embedding-ada-002.

  5. Seleccione Implementar para abrir la ventana de implementación.

  6. Seleccione el centro en el que desea implementar el modelo. Use el mismo centro que el proyecto.

  7. Especifique el nombre de la implementación y modifique otras opciones predeterminadas en función de sus requisitos.

  8. Seleccione Implementar.

  9. Llegará a la página de detalles de la implementación. Seleccione Abrir en el área de juegos.

  10. Seleccione Ver código para obtener ejemplos de código que se pueden usar para consumir el modelo implementado en la aplicación.

Al implementar el modelo gpt-3.5-turbo, busque los siguientes valores en la sección Ver código y agréguelos al archivo .env:

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

Al implementar el modelo text-embedding-ada-002, agregue el nombre al archivo .env:

AZURE_OPENAI_EMBEDDING_DEPLOYMENT=<embedding_model_deployment_name>

Instale la CLI de Azure e inicie sesión.

Instale la CLI de Azure e inicie sesión desde el entorno de desarrollo local, de modo que pueda usar las credenciales de usuario para llamar al servicio Azure OpenAI.

En la mayoría de los casos, puede instalar la CLI de Azure desde el terminal mediante el siguiente comando:

winget install -e --id Microsoft.AzureCLI

Puede seguir las instrucciones Cómo instalar la CLI de Azure si estos comandos no funcionan para su sistema operativo o configuración concretos.

Después de instalar la CLI de Azure, inicie sesión con el comando az login e inicie sesión con el explorador:

az login

Ahora creamos nuestra aplicación y llamamos a Azure OpenAI Service desde el código.

Creación de un entorno de Python

En primer lugar, es necesario crear un nuevo entorno de Python que podamos usar para instalar los paquetes del SDK de flujo de avisos. NO instale paquetes en la instalación global de Python. Siempre debe usar un entorno virtual o conda al instalar paquetes de Python; de lo contrario, puede interrumpir la instalación global de Python.

Si es necesario, instale Python.

Se recomienda usar Python 3.10 o posterior, pero se requiere al menos Python 3.8. Si no tiene instalada una versión adecuada de Python, puede seguir las instrucciones del Tutorial de Python de VS Code para la manera más fácil de instalar Python en el sistema operativo.

Creación de un entorno virtual

Si ya tiene Instalado Python 3.10 o superior, puede crear un entorno virtual con los siguientes comandos:

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

La activación del entorno de Python significa que, al ejecutar python o pip desde la línea de comandos, se usa el intérprete de Python incluido en la carpeta .venv de la aplicación.

Nota:

Puede usar el comando deactivate para salir del entorno virtual de Python y, posteriormente, volver a activarlo cuando sea necesario.

Actualización de PIP

Para asegurarse de que tiene la versión más reciente de pip, ejecute el siguiente comando:

python -m pip install --upgrade pip

Instalación del SDK de flujo de avisos

Flujo de avisos es un conjunto de herramientas de desarrollo diseñadas para simplificar el ciclo de desarrollo integral de aplicaciones de inteligencia artificial basadas en LLM, desde la ideación, la creación de prototipos, las pruebas, la evaluación hasta la implementación y supervisión de producción.

Use pip para instalar el SDK de flujo de avisos en el entorno virtual que ha creado.

pip install promptflow
pip install azure-identity

El SDK de flujo de avisos depende de varios paquetes, que puede optar por instalar por separado si no desea que todos ellos sean:

  • promptflow-core: contiene el tiempo de ejecución de flujo de avisos principal que se usa para ejecutar código LLM
  • promptflow-tracing: biblioteca ligera que se usa para emitir seguimientos de OpenTelemetry en estándares
  • promptflow-devkit: contiene las herramientas del visor de seguimiento y el generador de pruebas de flujo de avisos para entornos de desarrollo locales
  • openai: bibliotecas cliente para usar el servicio Azure OpenAI
  • python-dotenv: se usa para establecer variables de entorno leyéndolas de archivos .env

Creación de un índice de Búsqueda de Azure AI

El objetivo con esta aplicación basada en la RAG es fundamentar las respuestas del modelo en los datos personalizados. Use un índice de Búsqueda de Azure AI que almacene datos vectorizados del modelo de inserciones. El índice de búsqueda se usa para recuperar documentos relevantes en función de la pregunta del usuario.

Si aún no tiene un índice de Búsqueda de Azure AI creado, se explica cómo crear uno. Si ya tiene un índice que se va a usar, puede ir a la secciónEstablecer la variable de entorno de búsqueda. El índice de búsqueda se crea en el servicio de Búsqueda de Azure AI que se ha creado o al que se hace referencia en el paso anterior.

  1. Use sus propios datos o descargue los datos del ejemplo de productos minoristas de Contoso Trek de ejemplo en un archivo ZIP en la máquina local. Descomprima el archivo en la carpeta rag-tutorial/data. Estos datos son una colección de archivos de Markdown que representan información del producto. Los datos se estructuran de forma fácil de ingerir en un índice de búsqueda. Cree un índice de búsqueda a partir de estos datos.

  2. El paquete de RAG de flujo de avisos permite ingerir los archivos de Markdown, crear localmente un índice de búsqueda y registrarlo en el proyecto en la nube. Instale el paquete RAG del flujo de avisos:

    pip install promptflow-rag
    
  3. Cree el archivo build_index.py en la carpeta rag-tutorial.

  4. Copie y pegue el siguiente código en el archivo 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))
    
    • Establezca la variable index_name en el nombre del índice que desee.
    • Según sea necesario, puede actualizar la variable path_to_data a la ruta de acceso donde se almacenan los archivos de datos.

    Importante

    De forma predeterminada, el ejemplo de código espera la estructura de código de la aplicación como se describe anteriormente en este tutorial. La carpeta data debe estar en el mismo nivel que el build_index.py y la carpeta product-info descargada con archivos md dentro de ella.

  5. Desde la consola, ejecute el código para compilar el índice localmente y registrarlo en el proyecto en la nube:

    python build_index.py
    
  6. Una vez ejecutado el script, puede ver el índice recién creado en la página Índices del proyecto de Inteligencia artificial de Azure Studio. Para obtener más información, consulte Cómo compilar y consumir índices vectoriales en Inteligencia artificial de Azure Studio.

  7. Si vuelve a ejecutar el script con el mismo nombre de índice, crea una nueva versión del mismo índice.

Establecimiento de la variable de entorno de índice de búsqueda

Una vez que tenga el nombre de índice que desea usar (ya sea creando uno nuevo o haciendo referencia a uno existente), agréguelo al archivo .env, de la siguiente manera:

AZUREAI_SEARCH_INDEX_NAME=<index-name>

Desarrollo de código de RAG personalizado

A continuación, cree código personalizado para agregar funcionalidades de generación aumentada de recuperación (RAG) a una aplicación de chat básica. En el inicio rápido, creó los archivos chat.py y chat.prompty. Aquí expandirá ese código para incluir funcionalidades de RAG.

La aplicación de chat con la RAG implementa la siguiente lógica general:

  1. Genere una consulta de búsqueda basada en la intención de consulta de usuario y cualquier historial de chat
  2. Use un modelo de inserción para insertar la consulta
  3. Recupere documentos pertinentes del índice de búsqueda, dada la consulta
  4. Pase el contexto pertinente al modelo de finalización del chat de Azure OpenAI
  5. Devuelva la respuesta del modelo de Azure OpenAI

La lógica de implementación de la aplicación de chat

La lógica de implementación de la aplicación de chat está en el archivo copilot.py. Este archivo contiene la lógica principal de la aplicación de chat basada en la RAG.

  1. Cree una carpeta denominada copilot_flow en la carpeta rag-tutorial.

  2. A continuación, cree un archivo denominado copilot.py en la carpeta copilot_flow.

  3. Agregue el código siguiente al archivo 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)
    

El archivo copilot.py contiene dos funciones clave: get_documents() y get_chat_response().

Observe que estas dos funciones tienen el decorador @trace, lo que le permite ver los registros de seguimiento de flujo de avisos de cada entrada y salida de llamada de función. @trace es un enfoque alternativo y extendido de la forma en que el inicio rápido mostraba las funcionalidades de seguimiento.

La función get_documents() es el núcleo de la lógica de RAG.

  1. Toma la consulta de búsqueda y el número de documentos que se van a recuperar.
  2. Inserta la consulta de búsqueda mediante un modelo de inserción.
  3. Consulta el índice de Azure Search para recuperar los documentos pertinentes para la consulta.
  4. Devuelve el contexto de los documentos.

La función get_chat_response() se compila a partir de la lógica anterior en el archivo chat.py:

  1. Toma el chat_input y cualquier chat_history.
  2. Construye la consulta de búsqueda basada en intención chat_input y chat_history.
  3. Llama a get_documents() para recuperar los documentos pertinentes.
  4. Llama al modelo de finalización de chat con contexto para obtener una respuesta fundamentada a la consulta.
  5. Devuelve la respuesta y el contexto. Establecemos un diccionario tipado como objeto devuelto para nuestra función get_chat_response(). Puede elegir cómo el código devuelve la respuesta para adaptarse mejor a su caso de uso.

La función get_chat_response() usa dos archivos Prompty para realizar las llamadas necesarias al modelo de lenguaje grande (LLM), que veremos a continuación.

Solicitud de plantilla para chat

El archivo chat.prompty es sencillo y similar al chat.prompty en el inicio rápido. La solicitud del sistema se actualiza para reflejar nuestro producto y las plantillas de aviso incluyen el contexto del documento.

  1. Agregue el archivo chat.prompty en el directorio copilot_flow. El archivo representa la llamada al modelo de finalización del chat, con el símbolo del sistema, el historial de chat y el contexto del documento proporcionados.

  2. Agregue este código al archivo 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}}
    

Plantilla de solicitud para el historial de chats

Dado que estamos implementando una aplicación basada en la RAG, se requiere cierta lógica adicional para recuperar documentos relevantes no solo para la consulta actual del usuario, sino también teniendo en cuenta el historial de chat. Sin esta lógica adicional, la llamada al LLM tendría en cuenta el historial de chats. Pero no recuperaría los documentos adecuados para ese contexto, por lo que no obtendría la respuesta esperada.

Por ejemplo, si el usuario hace la pregunta "¿es impermeable?", necesitamos que el sistema examine el historial de chat para determinar a qué se refiere la palabra "es" e incluir ese contexto en la consulta de búsqueda que se va a insertar. De este modo, recuperamos los documentos adecuados para "es" (quizás la tienda de campaña Alpine Explorer) y su "costo".

En lugar de pasar solo la consulta del usuario para que se inserte, es necesario generar una nueva consulta de búsqueda que tenga en cuenta cualquier historial de chat. Usamos otro Prompty (que es otra llamada LLM) con una solicitud específica para interpretar la intención de consulta del usuario dado el historial de chat y construir una consulta de búsqueda que tenga el contexto necesario.

  1. Cree el archivo queryIntent.prompty en la carpeta copilot_flow.

  2. Escriba este código para obtener detalles específicos sobre el formato de la pregunta y ejemplos de pocas palabras.

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

El sencillo mensaje del sistema de nuestro archivo queryIntent.prompty logra el mínimo necesario para que la solución de RAG funcione con el historial de chat.

Configuración de paquetes necesarios

Cree el archivo requirements.txt en la carpeta copilot_flow. Agregue este contenido:

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

Estos paquetes son necesarios para que el flujo se ejecute localmente y en un entorno implementado.

Uso del flujo flexible

Como se mencionó anteriormente, esta implementación usa el flujo flexible del flujo de avisos, que es el enfoque primero en el código para implementar flujos. Especifique una función de entrada (que se define en copilot.py). Obtenga más información en Desarrollo de un flujo flexible.

Este YAML especifica la función de entrada, que es la función get_chat_response definida en copilot.py. También especifica los requisitos que debe ejecutar el flujo.

Cree el archivo flow.flex.yaml en la carpeta copilot_flow. Agregue este contenido:

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

Uso del flujo de avisos para probar la aplicación de chat

Use la funcionalidad de prueba del flujo de avisos para ver cómo funciona la aplicación de chat según lo previsto en las entradas de ejemplo. Con el archivo flow.flex.yaml, puede usar el flujo de avisos para probar con las entradas especificadas.

Ejecute el flujo mediante este comando de flujo de avisos:

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

Como alternativa, puede ejecutar el flujo de forma interactiva con la marca --ui.

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

Al usar --ui, la experiencia interactiva de chat de ejemplo abre una ventana en el explorador local.

  • La primera vez que se ejecuta con la marca --ui, es necesario seleccionar manualmente las entradas y salidas del chat en las opciones. La primera vez que cree esta sesión, seleccione Configuración del campo de entrada y salida del chat y, a continuación, comience a chatear.
  • La próxima vez que se ejecute con la marca --ui, la sesión recordará la configuración.

Recorte de pantalla que muestra la experiencia de chat de ejemplo.

Cuando haya terminado con la sesión interactiva, escriba Ctrl + C en la ventana del terminal para detener el servidor.

Prueba con historial de chat

En general, el flujo de avisos y los Prompty admiten el historial de chats. Si prueba con la marca --ui en el front-end servido localmente, el flujo de avisos administra el historial del chat. Si prueba sin el --ui, puede especificar un archivo de entradas que incluya el historial de chat.

Dado que nuestra aplicación implementa la RAG, teníamos que agregar lógica adicional para controlar el historial de chat en el archivo queryIntent.prompty.

Para probar con el historial de chat, cree un archivo denominado input_with_chat_history.json en la carpeta copilot_flow y pegue este contenido:

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

Para probar con este archivo, ejecute:

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

La salida esperada es similar a: "La tienda de campaña Alpine Explorer tiene un precio de 350 USD".

Este sistema puede interpretar la intención de la consulta "¿Cuánto cuesta esto?" para saber que "esto" hace referencia a la tienda de campaña Alpine Explorer, que era el contexto más reciente del historial de chat. A continuación, el sistema construye una consulta de búsqueda para el precio de la tienda de campaña Alpine Explorer para recuperar los documentos pertinentes para el costo de la tienda de campaña Alpine Explorer y obtenemos la respuesta.

Si navega al seguimiento desde esta ejecución de flujo, verá la conversación en acción. El vínculo de seguimientos locales muestra en la salida de la consola anterior el resultado de la ejecución de la prueba de flujo.

Recorte de pantalla que muestra la salida de la consola para el flujo de avisos.

Limpieza de recursos

Para evitar incurrir en costos innecesarios de Azure, debe eliminar los recursos que creó en este tutorial si ya no son necesarios. Para administrar recursos, puede usar Azure Portal.

Pero aún no los elimine, si quiere implementar su aplicación de chat en Azure en la siguiente parte de esta serie de tutoriales.

Paso siguiente