Nesta aplicação, a ingestão de todos os documentos de exemplo é acionada com o comando flask create-index . A implementação deste comando está no arquivo app.py no diretório api e simplesmente importa o módulo index_data.py do diretório data e chama sua função main() , que realiza uma importação completa de todos os documentos armazenados no arquivo data.json .
Estrutura do documento
A estrutura de cada documento é a seguinte:
name: o título do documentourl: um URL para o documento hospedado em um site externosummary: um breve resumo do conteúdo do documentocontent: o corpo do documentocreated_on: data de criaçãoupdated_atData de atualização (pode estar ausente se o documento nunca foi atualizado)category: a categoria do documento, que pode sergithub,sharepointouteamsrolePermissions: uma lista de permissões de função
A partir destes, este exemplo de aplicação usa o campo content como o texto a ser indexado e adiciona name, summary, url, category e updated_at como metadados associados.
O seguinte trecho de código Python mostra como os documentos são importados:
Aqui, o módulo json da biblioteca padrão do Python é usado para ler o arquivo de dados e, em seguida, para cada documento incluído, um objeto Document do Langchain é criado. Os documentos têm um atributo page_content que define o conteúdo a ser convertido em vetores e pesquisado, além de vários campos adicionais que são armazenados como metadados. O metadata_keys determina quais campos do conteúdo de origem devem ser armazenados como metadados do documento.
Dependendo das suas necessidades de ingestão, o método pode ser refinado ou alterado. O projeto Langchain oferece uma ampla seleção de carregadores de documentos que podem ser usados dependendo do formato do conteúdo de origem.
O modelo Elastic Learned Sparse EncodeR (ELSER)
O índice Elasticsearch usado nesta aplicação está configurado para criar automaticamente representações vetoriais esparsas para todos os documentos inseridos. A função install_elser() em index_data.py garante que o modelo ELSER esteja instalado e implantado na instância do Elasticsearch que você está usando.
Divisão de texto
O campo content nesses documentos é longo, o que significa que uma única incorporação não será capaz de representá-lo completamente. A solução padrão ao trabalhar com grandes quantidades de texto é dividir o texto em trechos menores e, em seguida, obter representações vetoriais (embeddings) para cada trecho individual, que são então armazenadas e indexadas.
Nesta aplicação, é utilizada a classe RecursiveCharacterTextSplitter da biblioteca Langchain , em conjunto com o codificador tiktoken da OpenAI, que conta o comprimento das passagens em tokens, as mesmas unidades utilizadas pelos LLMs.
Considere o seguinte exemplo, que demonstra como a divisão de texto funciona no aplicativo:
Ao definir o argumento chunk_size do divisor de texto, é possível controlar o comprimento das passagens resultantes. O chunk_overlap permite alguma sobreposição entre as passagens, o que muitas vezes ajuda a obter melhores incorporações.
Na aplicação em si, o divisor é inicializado com os seguintes argumentos:
Você pode alterar esses valores e ver como as mudanças afetam a qualidade do chatbot. Cada vez que você alterar a configuração do divisor, você deve regenerar o índice executando o comando flask create-index .
Note que existem outras considerações sobre a divisão de texto em combinação com o modelo ELSER que você deve levar em conta. Para casos de uso em produção, talvez seja necessário escolher um método de tokenização diferente do apresentado neste tutorial.
Loja de Documentos
Os documentos são armazenados em um índice do Elasticsearch. O nome do índice é controlado pela variável de ambiente ES_INDEX , que é definida no arquivo .env. arquivo. Por padrão, o nome deste índice é workplace-app-docs.
O aplicativo usa a classe ElasticsearchStore , que faz parte da integração do Elasticsearch no Langchain, e usa a biblioteca cliente oficial do Elasticsearch para Python.
A lógica completa que lida com o índice do Elasticsearch é mostrada abaixo:
O método ElasticsearchStore.from_documents() importa todas as instâncias Document armazenadas em workplace_docs, escrevendo-as no índice fornecido no argumento index_name . Todas as operações são realizadas através do cliente fornecido no argumento es_connection .
O argumento strategy define a forma como este índice será utilizado. Para esta aplicação, a classe SparseVectorRetrievalStrategy indica que devem ser mantidas incorporações de vetores esparsos para cada documento. Isso adicionará um pipeline ao índice que gerará embeddings por meio do modelo solicitado (ELSER versão 2 neste caso).
A integração do Elasticsearch com o Langchain oferece outras estratégias que podem ser utilizadas dependendo do caso de uso. Em particular, a estratégia ApproxRetrievalStrategy pode ser usada quando são utilizadas incorporações vetoriais densas.
Anteriormente
ImplementaçãoPróximo
Ponto final do chatbot