AI-персона в Discourse: поддержка загрузки

Теперь вы можете включать большие объемы текста в свои AI-персоны!

Это дает несколько преимуществ:

  1. Вы можете добавлять большие объемы текста в свои пользовательские AI-боты, которых нет в обучающих данных моделей (например, внутренние обучающие документы, внутренние отчеты).

  2. Вы можете лучше обосновать персону конкретными данными (даже если они есть в обучающем наборе модели), что поможет модели правильно цитировать конкретную информацию и повысить качество результатов.

Чтобы добавить загрузки:

  1. Создайте новую персону через интерфейс /admin/plugins/discourse-ai/ai-personas/.

  2. Загрузите текстовые файлы, которые вы хотите включить в свою персону.

:information_source: Перед загрузкой файлов добавьте соответствующие расширения (.md и .txt) в настройках сайта authorized extensions, чтобы они могли использоваться персоной.

  1. Настройте параметры индексации по своему усмотрению.

Предварительные требования

Для работы этой опции необходимо включить ai_embeddings_enabled и настроить модель ai_embeddings_model.

Discourse AI поддерживает огромное количество моделей эмбеддингов.

Наши размещенные клиенты получают бесплатный доступ к передовой модели bge-large-en.

Пользователи с самостоятельным размещением или те, кто хочет больше выбора, могут самостоятельно разместить модель эмбеддингов или использовать модели от OpenAI, Google (Gemini) и других.

Является ли это RAG?

Реализация нашей поддержки загрузки действительно основана на Retrieval-Augmented Generation (генерация с усилением извлечения).

На высоком уровне каждый раз, когда мы собираемся попросить LLM ответить на вопрос пользователя, мы ищем высоко релевантную информацию на основе введенного вами текста и внедряем её в системный промпт.

Объяснение различных параметров индексации

Что такое токен? Токены — это примитивы, используемые большими языковыми моделями для разделения текста. Отличное визуальное объяснение доступно по адресу: https://platform.openai.com/tokenizer

Реализация загрузки в Discourse AI включает следующие переключатели:

Upload Chunk Tokens (Токены чанка загрузки): после загрузки файлов они разбиваются на части. Это позволяет вам контролировать размер этих частей. Если часть слишком велика для вашей модели эмбеддингов, то эмбеддинг будет обрезан (будет обработана только часть токенов).

Upload Chunk Overlap Tokens (Токены перекрытия чанка загрузки): это количество токенов из предыдущего чанка, включаемых в текущий. Чем больше это число, тем больше дублирующейся информации будет сохранено в вашем индексе.

Search Conversation Chunks (Чанки поиска в диалоге): этот параметр контролирует количество «чанков» токенов, которые будут безусловно включены в промпт завершения на основе релевантности. Чем больше число, тем больше контекста будет предоставлено LLM (и тем дороже будут вызовы). Например: если это значение установлено на 10, а Upload Chunk Tokens — на 200, то каждое завершение будет иметь дополнительную нагрузку в 2000 токенов.

Как Discourse AI разбивает большие объемы текста?

Discourse использует рекурсивный разделитель текстов по символам (Recursive Character Text Splitter), который пытается сохранять вместе абзацы, затем строки и, наконец, слова при разделении.

Кроме того, Discourse предоставляет вам дополнительный контроль над тем, как будет разбиваться ваш текст.

Разделитель [[metadata ВАШИ МЕТАДАННЫЕ ЗДЕСЬ]] можно использовать для разделения больших объемов текста и правильного выделения того, что охватывает каждый раздел.

Например:

[[metadata о кошках]]
длинная история о кошках
[[metadata о собаках]]
длинная история о собаках

Это позволяет одному текстовому документу охватывать широкий спектр контента и защищает вас от «загрязнения чанков». Гарантируется, что в чанки о кошках будет включена только информация о кошках, а в чанки о собаках — только информация о собаках.

Звучит сложно, как мне это отладить?

Discourse AI поставляется с настройкой сайта ai bot debugging enabled groups. Пользователи в этой группе имеют доступ к отладке AI:

Экраны отладки AI помогут вам получить представление о том, какую информацию мы отправляем AI.

:warning: Мусор на входе — мусор на выходе Если вы предоставите LLM бесполезную или неясную информацию, она не сможет волшебным образом преобразовать её в полезную.

Этот экран поможет вам лучше решить, каким должен быть размер ваших чанков или включаете ли вы слишком много или слишком мало чанков.

Это вообще работает?

Реальный пример — разделение документации HAProxy и её загрузка в персону:

Системный промпт:

Вы — бот, специализирующийся на ответах на вопросы о HAProxy.

Вы живете на форуме Discourse и рендерите markdown Discourse.

При предоставлении ответов всегда старайтесь включать ссылки обратно на документацию HAProxy.

Например, вот как вы будете ссылаться на раздел 10.1.1. Имейте в виду, что вы можете ссылаться на раздел или на опцию внутри него.

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

Не скупитесь на ссылки, они очень полезны.

Содержимое загрузки:
processed-haproxy-2.txt (1.2 MB)

Которое было сгенерировано с помощью следующего скрипта:

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 = +""
  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

И Claude Opus, и GPT-4 могут довольно неудачно справляться со сложными вопросами. Это понятно, так как они питаются всеми токенами из интернета, поэтому 50 разных версий документации HAProxy и все обсуждения в мире о ней попадают в «мозг», что может сильно запутать модель:

Примеры запутанных ответов GPT-4 и Claude 3 Opus

Оба варианта объективно намного хуже точно настроенного ответа, который предоставляет Discourse RAG:

Примеры менее запутанных ответов GPT-4 и Claude Opus

Будущее

Мы с нетерпением ждем ваших отзывов. Некоторые идеи на будущее:

  • Поддержка PDF/DOCX/XLS и других форматов, чтобы вам не нужно было конвертировать их в текст.
  • Умное разбиение на чанки для исходного кода / HTML.
  • Умные преобразования входящих данных перед индексацией.

Дайте нам знать, что вы думаете!

Огромная благодарность @Roman за внедрение этой функции :hugs:

24 лайка

Возможно ли, помимо вручную загружаемого текста, включить сообщения форума, соответствующие выбранным критериям?

Например:

  • в заданной категории
  • с определённым тегом (или без него)
  • входящие в тему, помеченную как решённая (или являющиеся конкретно ответом-решением)
  • являющиеся первым сообщением в теме (OP), а не ответом
  • опубликованные пользователем из заданной группы
  • опубликованные до или после определённой даты

Или, возможно, вместо флажков с этими параметрами использовать опцию «является одним из топ-N тем по заданному поиску на форуме»?

1 лайк

Всё это можно реализовать уже сегодня с помощью пользовательской команды поиска:

  • Можно выбирать заданную категорию в фильтре
  • тег
  • решённые
  • только операторы (думаю, это возможно)
  • заданная группа
  • до и после указанной даты

:hugs:

5 лайков

Хм, возможно, я что-то неправильно понимаю. Делает ли предоставление этой возможности персоне то же самое?

Я пробовал, и в основном я просто получаю от Mistral выдуманные названия тем и ссылки на совершенно случайные номера постов. :slight_smile:

1 лайк

Действительно ли Mistral достаточно хорош для этих задач? Мне кажется, это может вызывать галлюцинации. Сэм прав: изменив базовый запрос, можно выполнить все, что вы указали в исходном сообщении.

1 лайк

И ещё: я отправил сообщение, не закончив свои мысли. Вопрос был в следующем: действительно ли предоставление команды поиска и параметров даёт тот же эффект, что и загрузка файлов?

Впрочем, да, Mistral может оказаться недостаточно хорошим.

1 лайк

Просто хочу немного дополнить:

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

Mistral существует в разных версиях: есть Mistral 7b, Mixtral 8x7b (та, что у вас), и совершенно новая mistralai/Mixtral-8x22B-Instruct-v0.1 · Hugging Face — эта и ещё 5–6 моделей, которые они выпускают, включая некоторые закрытые.

Нужно быть осторожным с утверждением «Mistral недостаточно хорош» и всегда уточнять детали.

Я бы сказал, что Mixtral-8x7b просто не очень подходит для поддержки работы с инструментами — она слишком часто уходит в сторону.

Моя оценка:

  1. Довольно хороша для поддержки «загрузки» (upload)
  2. Очень хороша для поддержки пользовательских персонажей
  3. Слаба в поддержке инструментов

Мы пытаемся понять, можно ли перейти на 8x22b (она изначально хорошо поддерживает инструменты), но проблема в том, что требования к памяти довольно высоки, и нам придётся квантовать модель, чтобы она поместилась на наших серверах.

Но если у вас есть соглашение о защите данных с Amazon, я настоятельно рекомендую Bedrock — он даст доступ к Claude 3 Opus и Haiku.

Я понимаю напряжение между открытыми и закрытыми моделями. Сложно, что закрытые модели пока значительно опережают открытые.

2 лайка

Вы правы, мне следовало сформулировать это лучше. Я действительно имел в виду, что проприетарные модели в целом лучше.

2 лайка

Загрузка нескольких .txt файлов одновременно вызывает сбой: они быстро появляются, но затем отображается только один, после чего кнопка «Добавить файл» перестает реагировать.

Также я думаю, что поддержка .md файлов была бы отличным дополнением.

1 лайк

Ой, ой… Хорошее замечание, @Roman, посмотрю.

Это должно работать нормально, это уже поддерживается, вам просто нужно включить расширение.

3 лайка

Я исправил ошибку, связанную с несколькими файлами:

4 лайка

2 сообщения были перенесены в новую тему: Улучшение качества фильтров поиска в Discourse AI

Привет, Сэм, я wondering, как именно это работает. Это сообщит ИИ, что это данные о кошках или собаках, но как это повлияет на чанки, если они уже установлены на определенное количество токенов (например, 2000)? Будет ли чанк разорван, когда он увидит строку вроде [[metadata о собаках]], и начнется новый чанк?

1 лайк

Да, оно прервется раньше

2 лайка

Ой, я использовал формат <meta>content</meta>, который работает для большинства LLM-моделей. Есть ли причина, по которой вы выбрали способ с [[скобками]]? Работают ли <теги> всё ещё, или в Discourse лучше использовать метод со скобками?

1 лайк

Это вообще не потребляется LLM (мы парсим и потребляем метаданные). Хотелся разделитель, который крайне маловероятно встретится в индексированных данных.

2 лайка

Добавил этот фрагмент в текст

1 лайк

Создаются ли эти эмбеддинги для AI Personas в одной и той же векторной базе данных? И, кстати, все ли эмбеддинги, сгенерированные для Discourse, хранятся в одной и той же векторной базе данных?

1 лайк

Всё в Postgres с использованием той же БД

2 лайка

Может ли кто-нибудь подсказать, что происходит с загруженными текстовыми файлами в персонажах, если их удалить из списка загруженных файлов? Я понимаю, что они используются для RAG, но если я удалю файл, будет ли он удалён из того, что было проиндексировано? Мне интересно, можно ли отредактировать то, что проиндексировано, удалив текстовый файл, внеся необходимые изменения и загрузив его снова?

1 лайк