Partager via


Comment générer et consommer un index à l’aide du code

Important

Les éléments marqués (préversion) dans cet article sont actuellement en préversion publique. Cette préversion est fournie sans contrat de niveau de service, nous la déconseillons dans des charges de travail de production. Certaines fonctionnalités peuvent être limitées ou non prises en charge. Pour plus d’informations, consultez Conditions d’Utilisation Supplémentaires relatives aux Évaluations Microsoft Azure.

Dans cet article, vous allez apprendre à créer un index et à l’utiliser à partir du code. Pour créer un index localement, nous utilisons le package promptflow-rag. Pour créer un index distant sur le cloud, nous utilisons le package azure-ai-ml. Nous utilisons les index à l’aide de langchain.

Prérequis

Vous devez avoir :

  • Un hub et un projet Azure AI Foundry.

  • Une connexion de service Recherche Azure AI pour indexer l’exemple de produit et les données client. Si vous n’avez pas de service Recherche Azure AI, vous pouvez en créer un à partir du Portail Azure ou consulter les instructions fournies ici.

  • Modèles pour l’incorporation :

    • Vous pouvez utiliser un modèle d’incorporation ada-002 à partir d’Azure OpenAI. Les instructions de déploiement sont disponibles ici.
    • Vous pouvez aussi utiliser n’importe quel autre modèle d’incorporation déployé dans votre projet Azure AI Foundry. Dans cet exemple, nous utilisons l’incorporation multilingue Cohere. Les instructions pour déployer ce modèle sont disponibles ici.

Générer et consommer un index localement

Nous pouvons générer et consommer un index localement.

Packages requis pour les opérations d’index local

Installez les packages suivants requis pour la création d’index local.

pip install promptflow-rag langchain langchain-openai

Configurer la recherche IA pour une utilisation locale

Nous utilisons Azure AI Search comme magasin d’index. Pour commencer, nous pouvons configurer le service Azure AI Search à l’aide du code suivant :

import os
# set credentials to your Azure AI Search instance
os.environ["AZURE_AI_SEARCH_KEY"] = "<your-ai-search-key>"
os.environ["AZURE_AI_SEARCH_ENDPOINT"] = "https://<your-ai-search-service>.search.windows.net"

Créer un index localement à l’aide d’incorporations Azure OpenAI

Pour créer un index qui utilise des incorporations Azure OpenAI, nous configurons des variables d’environnement pour nous connecter au modèle.

import os
# set credentials to your Azure OpenAI instance
os.environ["OPENAI_API_VERSION"] = "2023-07-01-preview"
os.environ["AZURE_OPENAI_API_KEY"] = "<your-azure-openai-api-key>"
os.environ["AZURE_OPENAI_ENDPOINT"] = "https://<your-azure-openai-service>.openai.azure.com/"

Nous allons maintenant générer l’index à l’aide de la fonction build_index.

from promptflow.rag.config import LocalSource, AzureAISearchConfig, EmbeddingsModelConfig
from promptflow.rag import build_index

local_index_aoai=build_index(
    name="<your-index-name>" + "aoai",  # name of your index
    vector_store="azure_ai_search",  # the type of vector store
    embeddings_model_config=EmbeddingsModelConfig(
        model_name="text-embedding-ada-002",
        deployment_name="text-embedding-ada-002", # verify if your deployment name is same as model name
    ),
    input_source=LocalSource(input_data="<path-to-your-local-files>"),  # the location of your file/folders
    index_config=AzureAISearchConfig(
        ai_search_index_name="<your-index-name>" + "-aoai-store", # the name of the index store inside the azure ai search service
    ),
    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
)

Le code ci-dessus génère un index localement. Il utilise des variables d'environnement pour obtenir le service AI Search et également pour se connecter au modèle d'intégration Azure OpenAI.

Créer un index localement en utilisant d’autres modèles d’incorporation déployés dans votre projet Azure AI Foundry

Pour créer un index qui utilise un modèle d’incorporation déployé dans votre projet Azure AI Foundry, nous configurons la connexion au modèle en utilisant ConnectionConfig, comme indiqué ci-dessous. Le subscription, resource_group et workspace fait référence au projet où le modèle d’incorporation est installé. connection_name fait référence au nom de connexion du modèle, qui se trouve dans la page des paramètres du projet Azure AI Foundry.

from promptflow.rag.config import ConnectionConfig

my_connection_config=ConnectionConfig(
    subscription_id="<subscription_id>",
    resource_group_name="<resource_group_name>",
    workspace_name="<ai_studio_project_name>",
    connection_name="<serverless_connection_name>"
    )

Nous allons maintenant générer l’index à l’aide de la fonction build_index.

from promptflow.rag.config import LocalSource, AzureAISearchConfig, EmbeddingsModelConfig
from promptflow.rag import build_index

local_index_cohere=build_index(
    name="<your-index-name>" + "cohere",  # name of your index
    vector_store="azure_ai_search",  # the type of vector store
    embeddings_model_config=EmbeddingsModelConfig(
        model_name="cohere-embed-v3-multilingual", # in this example we use cohere multi lingual embedding
        connection_config=my_connection_config # created in previous step
    ),
    input_source=LocalSource(input_data="<path-to-your-local-files>"),  # the location of your file/folders
    index_config=AzureAISearchConfig(
        ai_search_index_name="<your-index-name>" + "cohere-store", # the name of the index store inside the azure ai search service
    ),
    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
)

Le code ci-dessus génère un index localement. Il utilise des variables d'environnement pour obtenir le service AI Search et la configuration de connexion pour se connecter au modèle d'intégration.

Consommation d’un index local

L'index local créé peut être utilisé comme récupérateur de langchain pour le consommer pour les requêtes de recherche.

from promptflow.rag import get_langchain_retriever_from_index

# Get the OpenAI embedded Index
retriever=get_langchain_retriever_from_index(local_index_aoai)
retriever.get_relevant_documents("<your search query>")

# Get the Cohere embedded Index
retriever=get_langchain_retriever_from_index(local_index_cohere)
retriever.get_relevant_documents("<your search query>")

Inscription de l’index dans votre projet Azure AI Foundry (facultatif)

Si vous le souhaitez, vous pouvez inscrire l’index dans votre projet Azure AI Foundry afin que vous ou d’autres personnes ayant accès à votre projet puissiez l’utiliser depuis le cloud. Avant de continuer installer les packages requis pour les opérations à distance.

Se connecter au projet

# connect to the Azure AI Foundry project
from azure.identity import DefaultAzureCredential
from azure.ai.ml import MLClient

client=MLClient(
    DefaultAzureCredential(), 
    subscription_id="<subscription_id>",
    resource_group_name="<resource_group_name>",
    workspace_name="<ai_studio_project_name>"
    )

Le subscription, resource_group et workspace dans le code ci-dessus fait référence au projet auquel vous souhaitez vous connecter.

Inscrire l’index

from azure.ai.ml.entities import Index

# register the index with Azure OpenAI embeddings
client.indexes.create_or_update(
    Index(name="<your-index-name>" + "aoai", 
          path=local_index_aoai, 
          version="1")
          )

# register the index with cohere embeddings
client.indexes.create_or_update(
    Index(name="<your-index-name>" + "cohere", 
          path=local_index_cohere, 
          version="1")
          )

Remarque

Les variables d’environnement sont destinées à des raisons pratiques dans un environnement local. Toutefois, si vous inscrivez un index local créé à l’aide de variables d’environnement, l’index peut ne pas fonctionner comme prévu, car les secrets des variables d’environnement ne seront pas transférés vers l’index cloud. Pour résoudre ce problème, vous pouvez utiliser ConnectionConfig ou connection_id pour créer un index local avant l’inscription.

Générer un index (à distance) dans votre projet Azure AI Foundry

Nous créons un index dans le cloud dans votre projet Azure AI Foundry.

Packages requis pour les opérations d’index distant

Installez les packages suivants requis pour la création d’index distant.

pip install azure-ai-ml promptflow-rag langchain langchain-openai

Se connecter au projet Azure AI Foundry

Pour commencer, nous nous connectons au projet. Le subscription, resource_group et workspace dans le code ci-dessous fait référence au projet auquel vous souhaitez vous connecter.

# connect to the Azure AI Foundry project
from azure.identity import DefaultAzureCredential
from azure.ai.ml import MLClient

client=MLClient(
    DefaultAzureCredential(), 
    subscription_id="<subscription_id>",
    resource_group_name="<resource_group_name>",
    workspace_name="<ai_studio_project_name>"
    )

Obtenez la connexion au service AI Search

Ce projet doit avoir une connexion au service AI Search. Nous récupérons les détails du projet.

ai_search_connection = client.connections.get("<ai_search_connection>")

Se connecter aux modèles d’incorporation

Vous pouvez vous connecter à Azure OpenAI à l’aide de connexions Microsoft Entra ID ou de connexions basées sur une clé API.

from azure.ai.ml.entities import IndexModelConfiguration
## aoai connections - entra id
aoai_connection = client.connections.get("<your_aoai_entra_id_connection>")
embeddings_model_config = IndexModelConfiguration.from_connection(
    aoai_connection, 
    model_name="text-embedding-ada-002",
    deployment_name="text-embedding-ada-002") # verify if your deployment name is same as model name

## OR you can connect using API Key based connections 
from azure.ai.ml.entities import IndexModelConfiguration
## aoai connections - API Key
aoai_connection = client.connections.get("<your_aoai_connection>", populate_secrets=True)
embeddings_model_config = IndexModelConfiguration.from_connection(
    aoai_connection, 
    model_name="text-embedding-ada-002",
    deployment_name="text-embedding-ada-002")

Vous pouvez vous connecter au modèle d’incorporation déployé dans votre projet Azure AI Foundry (modèles OpenAI non-Azure) en utilisant la connexion serverless.

from azure.ai.ml.entities import IndexModelConfiguration
serverless_connection = client.connections.get("<my_embedding_model_severless_connection_name>")
embeddings_model_config = IndexModelConfiguration.from_connection(cohere_serverless_connection)

Sélectionner les données d’entrée pour générer l’index

Vous pouvez générer un index à partir des types d’entrées suivants :

  • Fichiers et dossiers locaux
  • Dépôts GitHub
  • Stockage Azure

Nous pouvons utiliser l’exemple de code suivant pour utiliser l’une de ces sources et configurer notre input_source:

# Local source
from azure.ai.ml.entities import LocalSource

input_source=LocalSource(input_data="<path-to-your-local-files>")

# GitHub repository
from azure.ai.ml.entities import GitSource

input_source=GitSource(
    git_url="https://github.com/rust-lang/book.git", # connecting to the RUST repo as an example
    git_branch_name="main", 
    git_connection_id="")

# Azure Storage
input_source_subscription = "<subscription>"
input_source_resource_group = "<resource_group>"
input_source_workspace = "<workspace>"
input_source_datastore = "<datastore_name>"
input_source_path = "path"

input_source = f"azureml://subscriptions/{input_source_subscription}/resourcegroups/{input_source_resource_group}/workspaces/{input_source_workspace}/datastores/{input_source_datastore}/paths/{input_source_path}"

Générer l’index sur le cloud

Nous pouvons maintenant générer l’index à l’aide du ai_search_connection, embeddings_model_config et input_source. Nous utilisons la fonction build_index. Si vous utilisez une URL de stockage Azure comme source d’entrée, vous devez également fournir une UserIdentityConfiguration.

# from azure.ai.ml.entities.credentials import UserIdentityConfiguration # user specified identity used to access the data. Required when using an azure storage URL
from azure.ai.ml.entities import AzureAISearchConfig

client.indexes.build_index(
    name="<index_name>", # name of your index
    embeddings_model_config=embeddings_model_config, 
    input_source=input_source, 
    # input_source_credential=UserIdentityConfiguration(), # user specified identity used to access the data. Required when using an azure storage URL
    index_config=AzureAISearchConfig(
        ai_search_index_name="<index_name>",  # the name of the index store in AI search service
        ai_search_connection_id=ai_search_connection.id, 
    ),
    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
)

En fonction de la taille de vos données sources d’entrée, les étapes ci-dessus peuvent prendre un certain temps. Une fois le travail terminé, vous pouvez récupérer l’objet d’index.

my_index=client.indexes.get(name="<index_name>", label="latest")

Consommation d’un index inscrit à partir de votre projet

Pour utiliser un index inscrit à partir de votre projet, vous devez vous connecter au projet et récupérer l’index. L'index récupéré peut être utilisé comme récupérateur de langhcain pour le consommer. Vous pouvez vous connecter au projet avec un client comme indiqué ici.

from promptflow.rag import get_langchain_retriever_from_index

my_index=client.indexes.get(
    name="<registered_index_name>", 
    label="latest")

index_langchain_retriever=get_langchain_retriever_from_index(my_index.path)
index_langchain_retriever.get_relevant_documents("<your search query>")

Une fonction question et réponse pour utiliser l’index

Nous avons vu comment créer un index localement ou dans le cloud. À l’aide de cet index, nous créons une fonction QnA qui accepte une question utilisateur et fournit une réponse à partir des données d’index. Commençons par obtenir l’index en tant que langchain_retriever comme indiqué ici. Nous utilisons maintenant cette retriever dans notre fonction. Cette fonction utilise le LLM tel que défini dans le constructeur AzureChatOpenAI. Il utilise l’index comme langchain_retriever pour interroger les données. Nous créons un modèle d’invite qui accepte un contexte et une question. Nous utilisons la RetrievalQA.from_chain_type de langchain pour rassembler tous ces éléments et nous obtenir les réponses.

def qna(question: str, temperature: float = 0.0, prompt_template: object = None) -> str:
    from langchain import PromptTemplate
    from langchain.chains import RetrievalQA
    from langchain_openai import AzureChatOpenAI

    llm = AzureChatOpenAI(
        openai_api_version="2023-06-01-preview",
        api_key="<your-azure-openai-api-key>",
        azure_endpoint="https://<your-azure-openai-service>.openai.azure.com/",
        azure_deployment="<your-chat-model-deployment>", # verify the model name and deployment name
        temperature=temperature,
    )

    template = """
    System:
    You are an AI assistant helping users answer questions given a specific context.
    Use the following pieces of context to answer the questions as completely, 
    correctly, and concisely as possible.
    Your answer should only come from the context. Don't try to make up an answer.
    Do not add documentation reference in the response.

    {context}

    ---

    Question: {question}

    Answer:"
    """
    prompt_template = PromptTemplate(template=template, input_variables=["context", "question"])

    qa = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=index_langchain_retriever,
        return_source_documents=True,
        chain_type_kwargs={
            "prompt": prompt_template,
        },
    )

    response = qa(question)

    return {
        "question": response["query"],
        "answer": response["result"],
        "context": "\n\n".join([doc.page_content for doc in response["source_documents"]]),
    }

Posons une question pour nous assurer que nous obtenons une réponse.

result = qna("<your question>")
print(result["answer"])