Strumento di ricerca file di Azure OpenAI Assistants (anteprima)

Ricerca file aumenta l'Assistant con informazioni dall'esterno del modello, ad esempio informazioni sui prodotti proprietari o documenti forniti dagli utenti. OpenAI analizza e blocca automaticamente i documenti, crea e archivia gli incorporamenti e usa sia la ricerca vettoriale che la ricerca di parole chiave per recuperare il contenuto pertinente per rispondere alle query degli utenti.

Importante

  • La ricerca di file prevede addebiti aggiuntivi oltre i costi basati su token per l'utilizzo di Azure OpenAI.

Nota

  • Ricerca file può inserire fino a 10.000 file per assistente, 500 volte più di prima. È veloce, supporta query parallele tramite ricerche multithread e include la riclassificazione avanzata e la riscrittura di query.
    • L’archivio di vettori è un nuovo oggetto nell’API. Dopo l’aggiunta a un archivio di vettori, un file viene analizzato, suddiviso in blocchi, incorporato e preparato per essere sottoposto a ricerca. Gli archivi di vettori possono essere usati in diversi assistenti e thread, semplificando quindi la gestione dei file e la fatturazione.
  • È stato aggiunto il supporto per il parametro tool_choice, che può essere usato per imporre l’uso di uno strumento specifico, ad esempio ricerca file, interprete di codice o una funzione, in una determinata esecuzione.

Supporto per la ricerca di file

Aree geografiche supportate

La ricerca di file è disponibile nelle aree che supportano Assistants.

Versione dell'API

  • 2024-05-01-preview

Tipi di file supportati

Nota

Per i tipi text/MIME, la codifica deve essere utf-8, utf-16 o ASCII.

File format Tipo MIME
c. text/x-c
.cs text/x-csharp
.cpp text/x-c++
doc application/msword
DOCX application/vnd.openxmlformats-officedocument.wordprocessingml.document
.html text/html
java. text/x-java
.json application/json
.md text/markdown
PDF applicazione/PDF
.php text/x-php
PPTX application/vnd.openxmlformats-officedocument.presentationml.presentation
.py text/x-python
.py text/x-script.python
.rb text/x-ruby
.tex text/x-tex
.txt text/plain
.css text/css
js text/javascript
.sh application/x-sh
.ts application/typescript
from openai import AzureOpenAI
    
client = AzureOpenAI(
    api_key=os.getenv("AZURE_OPENAI_API_KEY"),  
    api_version="2024-05-01-preview",
    azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
    )

assistant = client.beta.assistants.create(
  name="Financial Analyst Assistant",
  instructions="You are an expert financial analyst. Use your knowledge base to answer questions about audited financial statements.",
  model="gpt-4-turbo",
  tools=[{"type": "file_search"}],
)

Per accedere ai file, lo strumento di ricerca file usa l'oggetto dell'archivio vettoriale. Caricare i file e creare un archivio vettoriale per contenere i file. Dopo aver creato l'archivio vettoriale, è necessario eseguire il polling dello stato fino a quando tutti i file non sono al di fuori dello stato in_progress per assicurarsi che tutto il contenuto abbia terminato l'elaborazione. L'SDK fornisce helper per il caricamento e il polling.

from openai import AzureOpenAI
    
client = AzureOpenAI(
    api_key=os.getenv("AZURE_OPENAI_API_KEY"),  
    api_version="2024-05-01-preview",
    azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
    )

# Create a vector store called "Financial Statements"
vector_store = client.beta.vector_stores.create(name="Financial Statements")
 
# Ready the files for upload to OpenAI
file_paths = ["mydirectory/myfile1.pdf", "mydirectory/myfile2.txt"]
file_streams = [open(path, "rb") for path in file_paths]
 
# Use the upload and poll SDK helper to upload the files, add them to the vector store,
# and poll the status of the file batch for completion.
file_batch = client.beta.vector_stores.file_batches.upload_and_poll(
  vector_store_id=vector_store.id, files=file_streams
)
 
# You can print the status and the file counts of the batch to see the result of this operation.
print(file_batch.status)
print(file_batch.file_counts)

Aggiornare l'assistente per usare il nuovo archivio vettoriale

Per rendere i file accessibili all'assistente, aggiornare il tool_resources dell'assistente con il nuovo ID vector_store.

assistant = client.beta.assistants.update(
  assistant_id=assistant.id,
  tool_resources={"file_search": {"vector_store_ids": [vector_store.id]}},
)

Creare un thread

È anche possibile allegare file come allegati di messaggi nel thread. In questo modo verrà creato un altro vector_store associato al thread oppure, se è già presente un archivio vettoriale collegato a questo thread, allegare i nuovi file all'archivio del vettore di thread esistente. Quando si crea un'istruzione Esegui in questo thread, lo strumento di ricerca file eseguirà una query sia di vector_store dall'assistente che di vector_store nel thread.

# Upload the user provided file to OpenAI
message_file = client.files.create(
  file=open("mydirectory/myfile.pdf", "rb"), purpose="assistants"
)
 
# Create a thread and attach the file to the message
thread = client.beta.threads.create(
  messages=[
    {
      "role": "user",
      "content": "How many company shares were outstanding last quarter?",
      # Attach the new file to the message.
      "attachments": [
        { "file_id": message_file.id, "tools": [{"type": "file_search"}] }
      ],
    }
  ]
)
 
# The thread now has a vector store with that file in its tool resources.
print(thread.tool_resources.file_search)

Gli archivi vettoriali vengono creati usando allegati di messaggi con un criterio di scadenza predefinito di sette giorni dopo l'ultimo aggiornamento attivo (definito come l'ultima volta che l'archivio vettoriale faceva parte di un'esecuzione). Questa impostazione predefinita consente di gestire i costi di archiviazione vettoriali. È possibile eseguire l'override di questi criteri di scadenza in qualsiasi momento.

Creare un'esecuzione e controllare l'output

Creare un'istruzione Esegui e osservare che il modello usa lo strumento di ricerca file per fornire una risposta alla domanda dell'utente.

from typing_extensions import override
from openai import AssistantEventHandler, OpenAI
 
client = OpenAI()
 
class EventHandler(AssistantEventHandler):
    @override
    def on_text_created(self, text) -> None:
        print(f"\nassistant > ", end="", flush=True)

    @override
    def on_tool_call_created(self, tool_call):
        print(f"\nassistant > {tool_call.type}\n", flush=True)

    @override
    def on_message_done(self, message) -> None:
        # print a citation to the file searched
        message_content = message.content[0].text
        annotations = message_content.annotations
        citations = []
        for index, annotation in enumerate(annotations):
            message_content.value = message_content.value.replace(
                annotation.text, f"[{index}]"
            )
            if file_citation := getattr(annotation, "file_citation", None):
                cited_file = client.files.retrieve(file_citation.file_id)
                citations.append(f"[{index}] {cited_file.filename}")

        print(message_content.value)
        print("\n".join(citations))


# Then, we use the stream SDK helper
# with the EventHandler class to create the Run
# and stream the response.

with client.beta.threads.runs.stream(
    thread_id=thread.id,
    assistant_id=assistant.id,
    instructions="Please address the user as Jane Doe. The user has a premium account.",
    event_handler=EventHandler(),
) as stream:
    stream.until_done()

Funzionamento

Lo strumento di ricerca file implementa diverse procedure consigliate di recupero predefinite per consentire l'estrazione dei dati corretti dai file e l'aumento delle risposte del modello. Lo strumento file_search:

  • Riscrive le query utente per ottimizzarle per la ricerca.
  • Suddivide le query utente complesse in più ricerche che può essere eseguita in parallelo.
  • Esegue sia ricerche semantiche di parole chiave sia in archivi di assistente che in archivi vettoriali di thread.
  • Classifica i risultati della ricerca per selezionare quelli più rilevanti prima di generare la risposta finale.
  • Per impostazione predefinita, lo strumento di ricerca file usa le impostazioni seguenti:
    • Dimensioni blocco: 800 token
    • Sovrapposizione blocchi: 400 token
    • Modello di incorporamento: text-embedding-3-large a 256 dimensioni
    • Numero massimo di blocchi aggiunti al contesto: 20

Archivi di vettori

Gli oggetti dell'archivio vettoriale offrono allo strumento di ricerca file la possibilità di eseguire ricerche nei file. L'aggiunta di un file a un archivio vettoriale analizza automaticamente, blocchi, incorporamenti e archivia il file in un database vettoriale in grado di eseguire ricerche semantiche e parole chiave. Ogni archivio vettoriale può contenere fino a 10.000 file. Gli archivi vettoriali possono essere collegati sia a Assistenti che a Thread. Attualmente è possibile collegare al massimo un archivio vettoriale a un assistente e al massimo un archivio vettoriale a un thread.

Creazione di archivi vettoriali e aggiunta di file

È possibile creare un archivio vettoriale e aggiungervi file in una singola chiamata API:

vector_store = client.beta.vector_stores.create(
  name="Product Documentation",
  file_ids=['file_1', 'file_2', 'file_3', 'file_4', 'file_5']
)

L'aggiunta di file agli archivi vettoriali è un'operazione asincrona. Per assicurarsi che l'operazione sia completata, è consigliabile usare gli helper "create and poll" negli SDK ufficiali. Se non si usano gli SDK, è possibile recuperare l'oggetto vector_store e monitorarne la proprietà file_counts per visualizzare il risultato dell'operazione di inserimento file.

I file possono anche essere aggiunti a un archivio vettoriale dopo che è stato creato creando file dell'archivio vettoriale.

file = client.beta.vector_stores.files.create_and_poll(
  vector_store_id="vs_abc123",
  file_id="file-abc123"
)

In alternativa, è possibile aggiungere più file a un archivio vettoriale creando batch di un massimo di 500 file.

batch = client.beta.vector_stores.file_batches.create_and_poll(
  vector_store_id="vs_abc123",
  file_ids=['file_1', 'file_2', 'file_3', 'file_4', 'file_5']
)

Analogamente, questi file possono essere rimossi da un archivio vettoriale tramite:

  • Eliminazione dell'oggetto file dell'archivio di vettori o
  • Eliminando l'oggetto file sottostante (che rimuove il file da tutte le configurazioni di vector_store e code_interpreter in tutti gli assistenti e i thread dell'organizzazione)

La dimensione massima del file è 512 MB. Ogni file deve contenere non più di 5.000.000 token per ogni file (calcolato automaticamente quando si allega un file).

Collegamento di archivi vettoriali

È possibile collegare archivi vettoriali all'Assistant o al thread usando il parametro tool_resources.

assistant = client.beta.assistants.create(
  instructions="You are a helpful product support assistant and you answer questions based on the files provided to you.",
  model="gpt-4-turbo",
  tools=[{"type": "file_search"}],
  tool_resources={
    "file_search": {
      "vector_store_ids": ["vs_1"]
    }
  }
)

thread = client.beta.threads.create(
  messages=[ { "role": "user", "content": "How do I cancel my subscription?"} ],
  tool_resources={
    "file_search": {
      "vector_store_ids": ["vs_2"]
    }
  }
)

È anche possibile collegare un archivio vettoriale ai thread o agli Assistant dopo che sono stati creati aggiornandoli con il tool_resourcescorretto.

Verifica dell'idoneità dell'archivio vettoriale prima della creazione delle esecuzioni

È consigliabile assicurarsi che tutti i file in un vector_store siano completamente elaborati prima di creare un'esecuzione. In questo modo tutti i dati nell'archivio vettoriale sono ricercabili. È possibile verificare l'idoneità dell'archivio vettoriale usando gli helper di polling negli SDK o eseguendo manualmente il polling dell'oggetto vector_store per assicurarsi che lo stato sia completato.

Come fallback, è previsto un'attesa massima di 60 secondi nell'oggetto run quando l'archivio vettoriale del thread contiene file ancora in fase di elaborazione. Ciò consente di assicurarsi che tutti i file caricati dagli utenti in un thread siano completamente ricercabili prima che l'esecuzione proceda. Questa attesa di fallback non si applica all'archivio vettoriale dell'assistente.

Gestione dei costi con i criteri di scadenza

Lo strumento file_search usa l'oggetto vector_stores come risorsa e verrà addebitato in base alle dimensioni degli oggetti vector_store creati. La dimensione dell'oggetto archivio vettoriale è la somma di tutti i blocchi analizzati dai file e degli incorporamenti corrispondenti.

Per semplificare la gestione dei costi associati a questi oggetti vector_store, è stato aggiunto il supporto per i criteri di scadenza nell'oggetto vector_store. È possibile impostare questi criteri durante la creazione o l'aggiornamento dell'oggetto vector_store.

vector_store = client.beta.vector_stores.create_and_poll(
  name="Product Documentation",
  file_ids=['file_1', 'file_2', 'file_3', 'file_4', 'file_5'],
  expires_after={
	  "anchor": "last_active_at",
	  "days": 7
  }
)

Gli archivi vettoriali di thread hanno criteri di scadenza predefiniti

Gli archivi vettoriali creati usando gli helper thread (ad esempio tool_resources.file_search.vector_stores in Thread o message.attachments in Messaggi) hanno un criterio di scadenza predefinito di sette giorni dopo l'ultimo attivo (definito come l'ultima volta che l'archivio vettoriale faceva parte di un'esecuzione).

Quando un archivio vettoriale scade, l'esecuzione su tale thread avrà esito negativo. Per risolvere questo problema, è possibile ricreare un nuovo vector_store con gli stessi file e ricollegarlo al thread.

all_files = list(client.beta.vector_stores.files.list("vs_expired"))

vector_store = client.beta.vector_stores.create(name="rag-store")
client.beta.threads.update(
    "thread_abc123",
    tool_resources={"file_search": {"vector_store_ids": [vector_store.id]}},
)

for file_batch in chunked(all_files, 100):
    client.beta.vector_stores.file_batches.create_and_poll(
        vector_store_id=vector_store.id, file_ids=[file.id for file in file_batch]
    )