Partilhar via


Ferramenta de pesquisa de ficheiros do Azure OpenAI Assistants (Pré-visualização)

A Pesquisa de Arquivos aumenta o Assistente com conhecimento externo ao seu modelo, como informações proprietárias do produto ou documentos fornecidos por seus usuários. O OpenAI analisa e fragmenta automaticamente seus documentos, cria e armazena as incorporações e usa a pesquisa vetorial e de palavras-chave para recuperar conteúdo relevante para responder às consultas do usuário.

Nota

A pesquisa de arquivos não é cobrada no momento.

Nota

  • A pesquisa de arquivos pode ingerir até 10.000 arquivos por assistente - 500 vezes mais do que antes. É rápido, suporta consultas paralelas através de pesquisas multi-threaded e apresenta reclassificação e reescrita de consultas melhoradas.
    • O repositório vetorial é um novo objeto na API. Depois que um arquivo é adicionado a um repositório vetorial, ele é automaticamente analisado, fragmentado e incorporado, pronto para ser pesquisado. Os repositórios vetoriais podem ser usados entre assistentes e threads, simplificando o gerenciamento de arquivos e o faturamento.
  • Adicionamos suporte para o tool_choice parâmetro que pode ser usado para forçar o uso de uma ferramenta específica (como pesquisa de arquivos, interpretador de código ou uma função) em uma execução específica.

Suporte à pesquisa de ficheiros

Regiões suportadas

A pesquisa de ficheiros está disponível em regiões que suportam Assistentes.

Versão da API

  • 2024-05-01-pré-visualização

Tipos de ficheiro suportados

Nota

Para tipos de texto/MIME, a codificação deve ser utf-8, utf-16 ou ASCII.

File format Tipo de MIME
c. texto/x-c
.cs texto/x-csharp
.cpp texto/x-c++
.doc aplicação/msword
.docx aplicativo/vnd.openxmlformats-officedocument.wordprocessingml.document
.html text/html
.java texto/x-java
.json application/json
.md texto/marcação
.pdf aplicação/pdf
.php texto/x-php
.pptx application/vnd.openxmlformats-officedocument.presentationml.presentation
.py texto/x-python
.py texto/x-script.python
.rb texto/x-rubi
.tex texto/x-tex
.txt text/plain
.css texto/css
.js texto/javascript
.sh aplicação/x-sh
.ts aplicação/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"}],
)

Para acessar seus arquivos, a ferramenta de pesquisa de arquivos usa o objeto de armazenamento vetorial. Carregue seus arquivos e crie um repositório vetorial para contê-los. Depois que o repositório vetorial for criado, você deve pesquisar seu status até que todos os arquivos estejam fora do estado para garantir que todo o conteúdo tenha terminado o in_progress processamento. O SDK fornece auxiliares para upload e sondagem.

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)

Atualizar o assistente para usar o novo repositório de vetores

Para tornar os ficheiros acessíveis ao seu assistente, atualize os do tool_resources assistente com o novo vector_store ID.

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

Criar um thread

Você também pode anexar arquivos como anexos de mensagem no seu thread. Isso criará outro vector_store associado ao thread ou, se já houver um repositório vetorial anexado a esse thread, anexará os novos arquivos ao repositório vetorial de thread existente. Quando você cria um Executar neste thread, a ferramenta de pesquisa de arquivos consultará o vector_store do seu assistente e o vector_store no 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)

Os repositórios de vetores são criados usando anexos de mensagens que têm uma política de expiração padrão de sete dias após terem sido ativos pela última vez (definidos como a última vez que o repositório de vetores fez parte de uma execução). Esse padrão existe para ajudá-lo a gerenciar seus custos de armazenamento vetorial. Você pode substituir essas políticas de expiração a qualquer momento.

Crie uma execução e verifique a saída

Crie uma Execução e observe que o modelo usa a ferramenta de pesquisa de arquivos para fornecer uma resposta à pergunta do usuário.

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

Como funciona

A ferramenta de pesquisa de arquivos implementa várias práticas recomendadas de recuperação prontas para uso para ajudá-lo a extrair os dados certos de seus arquivos e aumentar as respostas do modelo. A ferramenta file_search:

  • Reescreve as consultas do usuário para otimizá-las para pesquisa.
  • Divide consultas complexas de usuários em várias pesquisas que podem ser executadas em paralelo.
  • Executa pesquisas semânticas e de palavras-chave em repositórios de vetores de assistente e thread.
  • Reclassifica os resultados da pesquisa para escolher os mais relevantes antes de gerar a resposta final.
  • Por padrão, a ferramenta de pesquisa de arquivos usa as seguintes configurações:
    • Tamanho do bloco: 800 tokens
    • Sobreposição de blocos: 400 tokens
    • Modelo de incorporação: text-embedding-3-large em 256 dimensões
    • Número máximo de partes adicionadas ao contexto: 20

Repositórios vetoriais

Os objetos de armazenamento vetorial dão à ferramenta de pesquisa de arquivos a capacidade de pesquisar seus arquivos. Adicionar um arquivo a um repositório vetorial analisa, fragmenta, incorpora e armazena automaticamente o arquivo em um banco de dados vetorial capaz de pesquisa semântica e de palavras-chave. Cada armazenamento vetorial pode armazenar até 10.000 arquivos. Os armazenamentos vetoriais podem ser anexados a Assistentes e Threads. Atualmente, você pode anexar no máximo um repositório de vetores a um assistente e, no máximo, um armazenamento de vetores a um thread.

Criação de repositórios vetoriais e adição de arquivos

Você pode criar um repositório vetorial e adicionar arquivos a ele em uma única chamada de API:

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

Adicionar arquivos a repositórios vetoriais é uma operação assíncrona. Para garantir que a operação seja concluída, recomendamos que você use os auxiliares de 'criar e pesquisar' em nossos SDKs oficiais. Se você não estiver usando os SDKs, poderá recuperar o vector_store objeto e monitorar sua file_counts propriedade para ver o resultado da operação de ingestão de arquivos.

Os arquivos também podem ser adicionados a um repositório vetorial depois que ele é criado criando arquivos de armazenamento vetorial.

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

Como alternativa, você pode adicionar vários arquivos a um repositório vetorial criando lotes de até 500 arquivos.

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']
)

Da mesma forma, esses arquivos podem ser removidos de um armazenamento vetorial por:

  • Excluindo o objeto de arquivo de armazenamento vetorial ou,
  • Excluindo o objeto de arquivo subjacente (que remove o arquivo de todas as configurações de vetor_store e code_interpreter em todos os assistentes e threads em sua organização)

O tamanho máximo do ficheiro é de 512 MB. Cada arquivo não deve conter mais de 5.000.000 tokens por arquivo (calculados automaticamente quando você anexa um arquivo).

Anexando repositórios vetoriais

Você pode anexar armazenamentos de vetores ao seu Assistente ou Thread usando o parâmetro 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"]
    }
  }
)

Você também pode anexar um repositório de vetores a Threads ou Assistentes depois que eles forem criados, atualizando-os com o direito tool_resources.

Garantindo a prontidão do armazenamento vetorial antes de criar execuções

É altamente recomendável que você garanta que todos os arquivos em um vetor_store sejam totalmente processados antes de criar uma execução. Isso garantirá que todos os dados em seu armazenamento vetorial sejam pesquisáveis. Você pode verificar a prontidão do armazenamento de vetores usando os auxiliares de sondagem nos SDKs ou sondando manualmente o vector_store objeto para garantir que o status seja concluído.

Como fallback, há uma espera máxima de 60 segundos no objeto Run quando o armazenamento vetorial do thread contém arquivos que ainda estão sendo processados. Isso é para garantir que todos os arquivos que seus usuários carregam em um thread sejam totalmente pesquisáveis antes que a execução prossiga. Essa espera de fallback não se aplica ao armazenamento de vetores do assistente.

Gerenciando custos com políticas de expiração

A file_search ferramenta usa o vector_stores objeto como seu recurso e você será cobrado com base no tamanho dos vetor_store objetos criados. O tamanho do objeto de armazenamento de vetor é a soma de todos os blocos analisados de seus arquivos e suas incorporações correspondentes.

Para ajudá-lo a gerenciar os custos associados a esses objetos vetor_store, adicionamos suporte para políticas de expiração no vector_store objeto. Você pode definir essas políticas ao criar ou atualizar o vector_store objeto.

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

Os repositórios de vetores de thread têm políticas de expiração padrão

Os repositórios de vetores criados usando auxiliares de thread (como tool_resources.file_search.vector_stores em Threads ou message.attachments em Mensagens) têm uma política de expiração padrão de sete dias após terem sido ativos pela última vez (definidos como a última vez que o repositório de vetores fez parte de uma execução).

Quando um repositório vetorial expira, as execuções nesse thread falharão. Para corrigir isso, você pode recriar um novo vetor_store com os mesmos arquivos e reanexá-lo ao 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]
    )