Persona do Discourse AI, suporte para upload

Agora você pode incluir grandes blocos de texto em seus personas de IA!

Isso oferece vários benefícios:

  1. Você pode introduzir grandes blocos de texto em seus bots de IA personalizados que estão ausentes do treinamento dos modelos. (por exemplo: documentos de treinamento internos, relatórios internos)

  2. Você pode fundamentar melhor um persona com dados concretos (mesmo que existam no conjunto de treinamento do modelo), o que pode ajudar o modelo a citar corretamente informações específicas e aumentar a qualidade dos resultados.

Para adicionar uploads:

  1. Crie um novo persona usando a interface /admin/plugins/discourse-ai/ai-personas/.

  2. Faça o upload dos arquivos de texto que você deseja incluir em seu persona

:information_source: Antes de fazer o upload dos arquivos, adicione as extensões relevantes (.md e .txt) através da configuração do site authorized extensions para que ele possa ser usado pelo persona

  1. Ajuste as opções de indexação conforme achar adequado

Pré-requisitos

Para que a opção funcione, você precisará ter ai_embeddings_enabled e um ai_embeddings_model configurados.

O Discourse AI suporta uma grande quantidade de modelos de embedding.

Nossos clientes hospedados têm acesso gratuito ao modelo de ponta bge-large-en.

Autohospedadores ou pessoas que desejam mais opções podem auto-hospedar um modelo de embedding ou usar modelos da OpenAI, Google (Gemini) e outros.

Isso é um RAG?

A implementação do nosso suporte a upload é de fato Retrieval-Augmented Generation.

Em um nível geral, cada vez que estamos prestes a pedir a um LLM para responder a uma pergunta do usuário, procuramos informações altamente relevantes com base no texto que você inseriu e a injetamos no prompt do sistema.

Explicando as várias opções de indexação

O que é um token? Tokens são primitivas usadas por modelos de linguagem grandes para dividir texto. Uma ótima explicação visual está em: https://platform.openai.com/tokenizer

A implementação de upload do Discourse AI vem com as seguintes opções:

Upload Chunk Tokens: após os arquivos serem carregados, nós os dividimos em pedaços. Isso permite que você controle o tamanho dos pedaços. Se um pedaço for muito grande para o seu modelo de embedding, o embedding será truncado (apenas parte dos tokens será processada).

Upload Chunk Overlap Tokens: Este é o número de tokens incluídos do chunk anterior no atual. Quanto maior esse número, mais informações duplicadas serão armazenadas em seu índice.

Search Conversation Chunks: Isso controla quantos “chunks” de tokens serão incluídos incondicionalmente com base na relevância no prompt de conclusão. Quanto maior o número, mais contexto o LLM receberá (e mais caras serão as chamadas). Por exemplo: Se isso estiver definido como 10 e Upload Chunk Tokens estiver definido como 200, cada conclusão terá um overhead extra de 2000 tokens.

Como o Discourse AI divide grandes blocos de texto?

O Discourse usa um Divisor de Texto Recursivo por Caracteres, que tenta manter parágrafos, depois linhas e, finalmente, palavras juntas ao dividir.

Além disso, o Discourse oferece controle extra sobre como seu texto será dividido.

O separador [[metadata YOUR METADATA HERE]] pode ser usado para dividir grandes blocos de texto e destacar adequadamente o que cada seção cobre.

Por exemplo:

[[metadata sobre gatos]]
uma longa história sobre gatos
[[metadata sobre cachorros]]
uma longa história sobre cachorros

Isso permite que um único documento de texto cubra uma grande variedade de conteúdo e protege você contra “contaminação de chunks”. Você tem a garantia de que apenas dados sobre gatos serão incluídos em chunks de gatos e cachorros em chunks de cachorros.

Parece complicado, como depuro isso?

O Discourse AI vem com a configuração do site ai bot debugging enabled groups, usuários neste grupo têm acesso à depuração de IA:

As telas de depuração de IA podem ajudá-lo a ter uma visão das informações que enviamos para a IA.

:warning: Lixo entra - Lixo sai Se você fornecer informações inúteis ou vagas para um LLM, ele não poderá convertê-las magicamente em informações úteis.

Esta tela pode ajudá-lo a decidir melhor o tamanho de seus chunks ou se você está incluindo muitos ou poucos chunks.

Isso funciona?

Um exemplo do mundo real é dividir a documentação do HAProxy e alimentá-la em um persona:

System Prompt:

Você é um bot especializado em responder perguntas sobre HAProxy.

Você vive em um fórum Discourse e renderiza markdown Discourse.

Ao fornecer respostas, sempre tente incluir links de volta para a documentação do HAProxy.

Por exemplo, é assim que você vincularia à seção 10.1.1. Lembre-se de que você pode vincular a uma seção ou a uma opção dentro dela.

[fcgi-app](https://www.haproxy.com/documentation/haproxy-configuration-manual/latest/#10.1.1-fcgi-app)

Seja liberal com os links, eles são muito úteis.

Conteúdo do upload:
processed-haproxy-2.txt (1,2 MB)

Que foi gerado usando o seguinte script:

file_content = File.read("configuration.txt")

title = nil
body = nil
last_line = nil

sections = []

file_content.each_line do |line|
  if line.strip.match?(/^[-]+$/)
    section_number, title = title.to_s.split(" ", 2)
    sections << {
      section_number: section_number,
      title: title,
      body: body.to_s.strip
    }

    title = last_line
    body = nil
    last_line = nil
  else
    body = body.to_s + last_line.to_s
    last_line = line
  end
end

section_number, title = title.to_s.split(" ", 2)
sections << { section_number: section_number, title: title, body: body }

section_names =
  sections.map { |section| [section[:section_number], section[:title]] }.to_h

sections[4..-1].each do |section|
  title = []
  current = +"".freeze
  section_number = section[:section_number]
  section_number
    .split(".")
    .each do |number|
      current << number
      current << "."
      title << section_names[current].to_s.strip
    end
  title = title.join(" - ")

  body = section[:body]

  next if body.strip.empty?
  puts "[[metadata section=\"#{section_number}\" title=\"#{title.strip}\"]]"
  puts body
end

Tanto o Claude Opus quanto o GPT-4 podem falhar miseravelmente com perguntas complexas. Isso é compreensível, pois eles se alimentam de todos os tokens da internet, então 50 versões diferentes da documentação do HAProxy e toda a discussão mundial sobre isso entram no cérebro, o que pode confundi-lo bastante:

Exemplos de GPT-4 e Claude 3 Opus confusos

Ambos são objetivamente muito inferiores à resposta ajustada que o Discourse RAG fornece:

Exemplos de GPT-4 e Claude Opus menos confusos

O futuro

Estamos ansiosos por feedback. Algumas ideias para o futuro podem ser:

  • Suporte a PDF/DOCX/XLS etc. para que você não precise converter para texto
  • Chunking mais inteligente para código fonte / html
  • Transformações inteligentes de dados de entrada antes da indexação

Deixe-nos saber o que você pensa!

Um grande agradecimento a @Roman por implementar este recurso :hugs:

24 curtidas

Seria possível, além de textos enviados manualmente, incluir posts de fóruns que correspondam a critérios selecionados?

Como:

  • em uma determinada categoria
  • tem uma certa tag (ou, não tem)
  • faz parte de um tópico marcado como resolvido (alternativamente, é especificamente uma postagem de solução)
  • é o OP do tópico, não uma resposta
  • é postado por um usuário em um determinado grupo
  • é antes ou depois de uma determinada data

Ou talvez, em vez de caixas de seleção com essas opções, simplesmente “é um dos N principais tópicos para uma determinada pesquisa de fórum”?

1 curtida

Tudo isso é realizável hoje com um comando de pesquisa personalizado:

  • Categoria dada pode ser selecionada no filtro
  • tag
  • resolvido
  • apenas op (acho que é realizável)
  • grupo dado
  • antes e depois da data

:hugs:

5 curtidas

Hmmm, talvez eu esteja entendendo mal. Tornar isso disponível para a persona faz o mesmo?

Eu tentei, e na maioria das vezes estou apenas fazendo o Mistral alucinar títulos de tópicos e vincular a números de postagem totalmente aleatórios. :slight_smile:

1 curtida

Mistral é realmente bom o suficiente para essas tarefas? Acho que isso pode causar as alucinações. Sam está certo, ao alterar a consulta base, você pode fazer tudo o que declarou no OP.

1 curtida

E, eu postei antes de terminar meus pensamentos. A pergunta foi: fornecer o comando de busca e os parâmetros faz efetivamente a mesma coisa que fornecer arquivos carregados?

Mas sim, o Mistral pode não ser bom o suficiente.

1 curtida

Só para expandir um pouco aqui:

https://chat.lmsys.org/?leaderboard

Mistral vem em muitos sabores… existe Mistral 7b, Mixtral 8x7b (o que você tem) e o novíssimo mistralai/Mixtral-8x22B-Instruct-v0.1 · Hugging Face - este e outros 5/6 modelos que eles lançam, incluindo alguns de código fechado.

É preciso ter cuidado com um “Mistral não é bom o suficiente” e sempre esclarecer.

Eu diria que o Mixtral-8x7b simplesmente não é uma boa opção para suporte a ferramentas, ele se desvia demais.

Eu diria que ele é

  1. Muito bom para suporte de “upload”
  2. Muito bom em suporte de persona personalizada
  3. Fraco em suporte a ferramentas

Estamos tentando ver se podemos atualizar para o 8x22b (ele vem com bom suporte a ferramentas), o problema é que os requisitos de memória são bem altos e precisaríamos quantizar o modelo para que ele caiba bem em nossos servidores.

Mas realmente… se você tem um acordo de privacidade de dados com a Amazon, eu recomendaria fortemente o Bedrock, que lhe daria acesso ao Claude 3 Opus e Haiku.

Eu entendo a tensão entre modelos de código aberto vs. modelos de código fechado. É difícil, os modelos de código fechado estão um pouco à frente no momento.

2 curtidas

Você está certo, eu deveria ter me expressado melhor. Eu estava de fato insinuando que os modelos de código fechado são melhores em geral.

2 curtidas

O upload de vários arquivos .txt de uma vez está com problemas: eles aparecem rapidamente, mas depois apenas um é exibido, e o botão “adicionar arquivo” não responde mais.

Além disso, acho que o suporte a arquivos .md seria uma ótima adição.

1 curtida

oh yikes … nice catch @Roman will have a look.

This should work fine, it is already supported you just need to enable the extension.

3 curtidas

Enviei uma correção para o bug de vários arquivos:

4 curtidas

2 posts foram divididos em um novo tópico: Melhorando a qualidade dos filtros de pesquisa no Discourse AI

Olá Sam, eu me pergunto como isso funciona exatamente. Isso dirá à IA que são dados sobre gatos ou cães, mas como isso afetará os chunks se eles já estiverem definidos para um número fixo de tokens (digamos, 2000). Ele cortará um chunk quando vir uma linha como [[metadata about dogs]] e iniciará um novo chunk?

1 curtida

Sim, ele será cortado cedo

2 curtidas

Ah, que chato, eu estava usando o formato <meta content=...>, que funciona para a maioria dos modelos de LLM. Há alguma razão pela qual você escolheu a forma [[colchetes]]? As <tags> ainda funcionam ou é melhor usar o método de colchetes no Discourse?

1 curtida

Isso não é consumido pelo llm de forma alguma (analisamos e consumimos metadados) queria um separador que fosse muito improvável de aparecer em dados indexados

2 curtidas

Adicionado este trecho à cópia

1 curtida

Esses embeddings criados para Personas de IA estão no mesmo banco de dados vetorial? E, na verdade, todos os embeddings gerados para Discourse são armazenados no mesmo banco de dados vetorial?

1 curtida

Tudo no Postgres usando o mesmo banco de dados

2 curtidas

Alguém pode me dizer o que acontece com os arquivos de texto carregados nas personas se eles forem excluídos da lista de arquivos carregados? Eu entendo que eles são usados para RAG, mas se eu excluir o arquivo, isso o excluirá do que foi indexado? Estou me perguntando se é possível editar o que foi indexado excluindo um arquivo de texto, fazendo seu ajuste e reenviando?

1 curtida