Soporte para carga de Persona AI en Discourse

Ahora puedes incluir grandes cantidades de texto en tus personas de IA.

Esto ofrece múltiples beneficios:

  1. Puedes introducir grandes cantidades de texto en tus bots de IA personalizados que no están presentes en el entrenamiento de los modelos. (por ejemplo: documentos de capacitación internos, informes internos)

  2. Puedes anclar mejor una persona con datos concretos (incluso si existen en el conjunto de entrenamiento del modelo), lo que puede ayudar al modelo a citar información específica correctamente y aumentar la calidad de los resultados.

Para agregar cargas:

  1. Crea una nueva persona usando la interfaz /admin/plugins/discourse-ai/ai-personas/.

  2. Carga los archivos de texto que deseas incluir en tu persona

:information_source: Antes de cargar archivos, agrega las extensiones relevantes (.md y .txt) a través de la configuración del sitio authorized extensions para que pueda ser utilizada por la persona.

  1. Ajusta las opciones de indexación como consideres oportuno.

Prerrequisitos

Para que la opción funcione, deberás tener configurados ai_embeddings_enabled y un ai_embeddings_model.

Discourse AI admite una gran cantidad de modelos de incrustación.

Nuestros clientes alojados obtienen acceso gratuito al modelo de última generación bge-large-en.

Los autoalojadores o las personas que deseen más opciones pueden autoalojar un modelo de incrustación o utilizar modelos de Open AI, Google (Gemini) y más.

¿Es esto un RAG?

La implementación de nuestro soporte de carga es, de hecho, Generación Aumentada por Recuperación.

A un alto nivel, cada vez que estamos a punto de pedirle a un LLM que responda a la pregunta de un usuario, buscamos información muy relevante basada en el texto que ingresaste y la inyectamos en el prompt del sistema.

Explicando las diversas opciones de indexación

¿Qué es un token? Los tokens son primitivas utilizadas por los modelos de lenguaje grandes para dividir el texto. Una excelente explicación visual se encuentra en: https://platform.openai.com/tokenizer

La implementación de carga de Discourse AI viene con los siguientes interruptores:

Upload Chunk Tokens: después de cargar los archivos, los dividimos en partes. Esto te permite controlar el tamaño de las partes. Si una parte es demasiado grande para tu modelo de incrustación, la incrustación se truncará (solo se procesará parte de los tokens).

Upload Chunk Overlap Tokens: este es el número de tokens incluidos del chunk anterior en el actual. Cuanto mayor sea este número, más información duplicada se almacenará en tu índice.

Search Conversation Chunks: esto controla cuántos “chunks” de tokens se incluirán incondicionalmente según la relevancia en el prompt de finalización. Cuanto mayor sea el número, más contexto se proporcionará al LLM (y más caras serán las llamadas). Por ejemplo: Si esto se establece en 10 y Upload Chunk Tokens se establece en 200, cada finalización tendrá una sobrecarga adicional de 2000 tokens.

¿Cómo divide Discourse AI los cuerpos de texto?

Discourse utiliza un Divisor de Texto Recursivo por Caracteres, que intenta mantener juntos párrafos, luego líneas y finalmente palabras al dividir.

Además, Discourse te da control adicional sobre cómo se dividirá tu texto.

El separador [[metadata YOUR METADATA HERE]] se puede usar para dividir grandes cuerpos de texto y resaltar adecuadamente lo que cubre cada sección.

Por ejemplo:

[[metadata about cats]]
a long story about cats
[[metadata about dogs]]
a long story about dogs

Esto permite que un solo documento de texto cubra una gran variedad de contenido y te protege de la “contaminación de chunks”. Tienes la garantía de que solo se incluirán datos sobre gatos en los chunks de gatos y sobre perros en los chunks de perros.

Suena complicado, ¿cómo depuro esto?

Discourse AI viene con la configuración del sitio ai bot debugging enabled groups, los usuarios de este grupo tienen acceso a la depuración de IA:

Las pantallas de depuración de IA pueden ayudarte a obtener una visión de la información que enviamos a la IA.

:warning: Basura entra - Basura sale Si proporcionas información inútil o vaga a un LLM, este no puede convertirla mágicamente en información útil.

Esta pantalla puede ayudarte a decidir mejor cuán grandes deben ser tus chunks o si estás incluyendo demasiados o muy pocos chunks.

¿Esto funciona?

Un ejemplo del mundo real es dividir la documentación de HAProxy y alimentarla a una persona:

System Prompt:

Eres un bot especializado en responder preguntas sobre HAProxy.

Vives en un foro de Discourse y renderizas markdown de Discourse.

Al proporcionar respuestas, intenta siempre incluir enlaces a la documentación de HAProxy.

Por ejemplo, así es como enlazarías a la sección 10.1.1. Ten en cuenta que puedes enlazar a una sección o a una opción dentro de ella.

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

Sé liberal con los enlaces, son muy útiles.

Contenido de la carga:
processed-haproxy-2.txt (1.2 MB)

Lo que se generó usando el siguiente 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 Claude Opus como GPT-4 pueden fallar estrepitosamente con preguntas complejas. Esto es comprensible ya que se alimentan de todos los tokens de Internet, por lo que 50 versiones diferentes de la documentación de HAProxy y toda la discusión del mundo sobre ella entran en el cerebro, lo que puede confundirlo mucho:

Ejemplos de GPT-4 y Claude 3 Opus confundidos

Ambos son objetivamente no tan buenos como la respuesta ajustada que proporciona el RAG de Discourse:

Ejemplos de GPT-4 y Claude Opus menos confundidos

El futuro

Esperamos sus comentarios. Algunas ideas para el futuro podrían ser:

  • Soporte para PDF/DOCX/XLS, etc., para que no necesites convertir a texto.
  • División de código fuente/html más inteligente.
  • Transformaciones inteligentes de los datos entrantes antes de la indexación.

¡Háganos saber lo que piensa!

Muchas gracias a @Roman por implementar esta función :hugs:

24 Me gusta

¿Sería posible, además del texto cargado manualmente, incluir publicaciones de foros que coincidan con criterios seleccionados?

Como:

  • en una categoría determinada
  • tiene una etiqueta determinada (o, no la tiene)
  • es parte de un tema marcado como resuelto (alternativamente, es específicamente una publicación de solución)
  • es el OP del tema, no una respuesta
  • es publicado por un usuario de un grupo determinado
  • es antes o después de una fecha determinada

¿O tal vez en lugar de casillas de verificación con estas cosas, simplemente “es uno de los N temas principales para una búsqueda dada en el foro”?

1 me gusta

Todo esto es factible hoy en día con un comando de búsqueda personalizado:

  • Se puede seleccionar la categoría dada en el filtro
  • etiqueta
  • resuelto
  • solo op (creo que es factible)
  • grupo dado
  • antes y después de la fecha

:hugs:

5 Me gusta

Hmmm, ¿tal vez estoy entendiendo mal? ¿Hace lo mismo hacerlo disponible para la persona?

Lo he intentado y, en su mayor parte, solo consigo que Mistral invente títulos de temas y enlace a números de publicaciones totalmente aleatorios. :slight_smile:

1 me gusta

¿Es Mistral realmente lo suficientemente bueno para estas tareas? Creo que eso podría causar las alucinaciones. Sam tiene razón, al cambiar la consulta base puedes hacer todo lo que dijiste en el OP.

1 me gusta

Y, publiqué antes de terminar mis pensamientos. La pregunta era: ¿proporcionar el comando de búsqueda y los parámetros hace efectivamente lo mismo que proporcionar archivos cargados?

Pero sí, Mistral puede que no sea lo suficientemente bueno.

1 me gusta

Solo para ampliar un poco aquí:

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

Mistral viene en muchos sabores… está Mistral 7b, Mixtral 8x7b (el que tienes), y el flamante mistralai/Mixtral-8x22B-Instruct-v0.1 · Hugging Face - este y otros 5/6 modelos que lanzan, incluyendo algunos de código cerrado.

Hay que tener cuidado con un “Mistral no es lo suficientemente bueno” y siempre aclarar.

Diría que Mixtral-8x7b simplemente no es una buena opción para el soporte de herramientas, se desvía demasiado.

Diría que es:

  1. Bastante bueno para el soporte de “carga”
  2. Muy bueno en el soporte de personalidades personalizadas
  3. Débil en el soporte de herramientas

Estamos intentando ver si podemos actualizar a 8x22b (viene con buen soporte de herramientas), el problema es que los requisitos de memoria son bastante altos y necesitaríamos cuantizar el modelo para que encaje bien en nuestros servidores.

Pero realmente… si tienes un acuerdo de privacidad de datos con Amazon, te recomendaría encarecidamente Bedrock, que te daría acceso a Claude 3 Opus y Haiku.

Entiendo la tensión entre los modelos de código abierto y los de código cerrado. Es difícil, los de código cerrado están bastante por delante en este momento.

2 Me gusta

Tienes razón, debería haberme expresado mejor. De hecho, estaba insinuando que los modelos de código cerrado son mejores en general.

2 Me gusta

Subir varios archivos .txt a la vez está dando errores: aparecen rápidamente, pero luego solo se muestra uno y, después de eso, el botón “Añadir archivo” ya no responde.

Además, creo que el soporte para archivos .md sería una gran adición.

1 me gusta

oh yikes … buena observación @Roman lo revisará.

Esto debería funcionar bien, ya está soportado, solo necesitas habilitar la extensión.

3 Me gusta

Empujé una corrección para el error de múltiples archivos:

4 Me gusta

2 publicaciones se dividieron en un nuevo tema: Mejorando la calidad de los filtros de búsqueda en Discourse AI

Hola Sam, me pregunto cómo funciona esto exactamente. Le dirá a la IA que estos son datos sobre gatos o perros, pero ¿cómo afectará a los fragmentos si ya están configurados en un número determinado de tokens (digamos 2000)? ¿Cortará un fragmento cuando vea una línea como [[metadata about dogs]] y comenzará un nuevo fragmento?

1 me gusta

Sí, se cortará pronto

2 Me gusta

Oh, vaya, estaba usando el formato <meta content="TU METADATO AQUÍ">, que funciona para la mayoría de los modelos de LLM. ¿Hay alguna razón por la que elegiste la forma [[corchetes]]? ¿Siguen funcionando las <etiquetas> o es mejor usar el método de corchetes en Discourse?

1 me gusta

Esto no es consumido en absoluto por el LLM (analizamos y consumimos metadatos) quería un separador que fuera muy poco probable que apareciera en los datos indexados.

2 Me gusta

Añadido esto a la copia

1 me gusta

¿Estas incrustaciones creadas para Personas de IA se encuentran en la misma base de datos vectorial? Y, de hecho, ¿todas las incrustaciones generadas para Discourse se almacenan en la misma base de datos vectorial?

1 me gusta

Todo en Postgres usando la misma base de datos

2 Me gusta

¿Alguien puede decirme qué sucede con los archivos de texto cargados en las personas si se eliminan de la lista de archivos cargados? Entiendo que se utilizan para RAG, pero si elimino el archivo, ¿se eliminará de lo que se ha indexado? Me pregunto si es posible editar lo que se ha indexado eliminando un archivo de texto, haciendo el ajuste y volviéndolo a cargar.

1 me gusta