Come compilare e utilizzare un indice usando il codice

Importante

Gli elementi contrassegnati (anteprima) in questo articolo sono attualmente disponibili in anteprima pubblica. Questa anteprima viene fornita senza un contratto di servizio e non è consigliabile per i carichi di lavoro di produzione. Alcune funzionalità potrebbero non essere supportate o potrebbero presentare funzionalità limitate. Per altre informazioni, vedere le Condizioni supplementari per l'uso delle anteprime di Microsoft Azure.

Questo articolo illustra come creare un indice e usarlo dal codice. Per creare un indice in locale, viene usato il pacchetto promptflow-rag. Per creare un indice remoto nel cloud, viene usato il pacchetto azure-ai-ml. Gli indici vengono usati tramite langchain.

Prerequisiti

Devi avere:

  • Hub e progetto di Studio AI.

  • Una connessione al servizio Azure AI Search per indicizzare i dati del prodotto e del cliente di esempio. Se non si dispone di un servizio di Azure AI Search, è possibile crearne uno dal portale di Azure o vedere le istruzioni qui.

  • Modelli per l'incorporamento:

    • È possibile usare un modello di incorporamento ada-002 dal Servizio OpenAI di Azure. Le istruzioni per la distribuzione sono disponibili qui.
    • OPPURE è possibile usare qualsiasi altro modello di incorporamento distribuito nel progetto di Studio AI. In questo esempio viene usato l'incorporamento multilingue Cohere. Le istruzioni per la distribuzione di questo modello sono disponibili qui.

Compilare e usare un indice in locale

È possibile compilare e utilizzare un indice in locale.

Pacchetti necessari per le operazioni sugli indici locali

Installare i pacchetti seguenti necessari per la creazione dell'indice locale.

pip install promptflow-rag langchain langchain-openai

Configurare AI Search per l'uso locale

Azure AI Search viene usata come archivio di indici. Per iniziare, è possibile configurare il servizio Azure AI Search usando il codice seguente:

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"

Creare un indice in locale usando gli incorporamenti di OpenAI di Azure

Per creare un indice che usa incorporamenti OpenAI di Azure, si configurano le variabili di ambiente per la connessione al modello.

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/"

A questo punto è possibile compilare l'indice usando la funzione 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
)

Il codice precedente compila un indice in locale. Usa le variabili di ambiente per ottenere il servizio AI Search e anche per connettersi al modello di incorporamento di OpenAI di Azure.

Compilare un indice in locale usando altri modelli di incorporamento distribuiti nel progetto di Studio AI

Per creare un indice che usa un modello di incorporamento distribuito nel progetto di Studio AI, viene configurata la connessione al modello usando ConnectionConfig come illustrato di seguito. subscription, resource_group e workspace fanno riferimento al progetto in cui è installato il modello di incorporamento. connection_name fa riferimento al nome della connessione per il modello, disponibile nella pagina delle impostazioni del progetto di Studio AI.

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>"
    )

A questo punto è possibile compilare l'indice usando la funzione 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
)

Il codice precedente compila un indice in locale. Usa le variabili di ambiente per ottenere il servizio AI Search e la configurazione della connessione per connettersi al modello di incorporamento.

Utilizzo di un indice locale

L'indice locale creato può essere usato come retriever langchain per le query di ricerca.

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>")

Registrazione dell'indice nel progetto di Studio AI (facoltativo)

In modo facoltativo, è possibile registrare l'indice nel progetto di Studio AI in modo che l'utente o altri utenti autorizzati ad accedere al progetto possano usarlo dal cloud. Prima di procedere installare i pacchetti necessari per le operazioni remote.

Connettersi al progetto

# connect to the AI Studio 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>"
    )

subscription, resource_group e workspace nel codice precedente fanno riferimento al progetto a cui si vuole connettersi.

Registrare l'indice

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")
          )

Nota

Le variabili di ambiente sono destinate per praticità a un ambiente locale. Tuttavia, se si registra un indice locale creato usando variabili di ambiente, l'indice potrebbe non funzionare come previsto perché i segreti delle variabili di ambiente non verranno trasferiti all'indice cloud. Per risolvere questo problema, è possibile usare ConnectionConfig o connection_id per creare un indice locale prima della registrazione.

Compilare un indice (in remoto) nel progetto di Studio AI

Viene creato un indice nel cloud nel progetto di Studio AI.

Pacchetti necessari per le operazioni sugli indici remoti

Installare i pacchetti seguenti necessari per la creazione dell'indice remoto.

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

Connettersi al progetto di Studio AI

Per iniziare, ci si connette al progetto. subscription, resource_group e workspace nel codice seguente fanno riferimento al progetto a cui si vuole connettersi.

# connect to the AI Studio 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>"
    )

Ottenere la connessione al servizio AI Search

Questo progetto deve avere una connessione al servizio di ricerca di intelligenza artificiale. I dettagli vengono recuperati dal progetto.

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

Connettersi ai modelli di incorporamento

È possibile connettersi a OpenAI di Azure usando connessioni Microsoft Entra ID o connessioni basate su chiavi 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")

È possibile connettersi al modello di incorporamento distribuito nel progetto di Studio AI (modelli diversi da OpenAI di Azure) usando la connessione 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)

Selezionare i dati di input per compilare l'indice

È possibile compilare l'indice dai tipi di input seguenti:

  • File e cartelle locali
  • Repository GitHub
  • Archiviazione di Azure

È possibile usare l'esempio di codice seguente per usare una di queste origini e configurare 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}"

Compilare l'indice nel cloud

È ora possibile compilare l'indice usando ai_search_connection, embeddings_model_config e input_source. Usiamo la funzione build_index. Se si usa un URL di Archiviazione di Azure come origine di input, è anche necessario fornire un 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
)

A seconda delle dimensioni dei dati dell'origine di input, il completamento dei passaggi precedenti potrebbe richiedere del tempo. Al termine del processo, è possibile recuperare l'oggetto indice.

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

Utilizzo di un indice registrato dal progetto

Per utilizzare un indice registrato dal progetto, è necessario connettersi al progetto e recuperare l'indice. L'indice recuperato può essere usato come retriever langchain per utilizzarlo. È possibile connettersi al progetto con un client come illustrato di seguito.

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>")

Funzione Domande e risposte per l'uso dell'indice

È stato illustrato come creare un indice in locale o nel cloud. Usando questo indice, viene compilata una funzione di domande e risposte che accetta una domanda utente e fornisce una risposta dai dati dell'indice. Prima di tutto, si ottiene l'indice come langchain_retriever come illustrato qui. Questo retriever viene ora usato nella funzione. Questa funzione usa l'LLM come definito nel costruttore AzureChatOpenAI. Usa l'indice come langchain_retriever per eseguire query sui dati. Viene creato un modello di richiesta che accetta un contesto e una domanda. Usiamo il valore RetrievalQA.from_chain_type di langchain per mettere insieme tutti questi elementi e ottenere le risposte.

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"]]),
    }

Facciamo una domanda per assicurarci di ottenere una risposta.

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