Настройка AI-суммаризатора для работы с неанглийскими языками

Здравствуйте, я использую локальную модель `google/gemma-3-4b` с последней версией Discourse. Модель хорошо работает с некоторыми языками. Когда я тестирую её через API или LM Studio, она предоставляет резюме на запрашиваемом языке.

В настоящее время Discourse всегда делает резюме на английском языке. Ниже описаны шаги для жесткого задания языка суммаризации (не на английском).


Важно! Ваши изменения будут потеряны при следующей пересборке.

Ниже приведены строки для жесткого кодирования в двух файлах. Значения из таблицы ai_personas не используются (июль 2025). Для тех, кто работает в не-продакшн окружениях, вы можете жестко задать свой родной язык:

  1. Подключитесь к серверу по SSH.

  2. Скопируйте файл `summarize.rb` из контейнера в файловую систему хоста:

    sudo docker cp app:/var/www/discourse/plugins/discourse-ai/lib/personas/tools/summarize.rb ./summarize.rb
    
  3. Теперь отредактируйте файл, заменив системный промпт на английском языке на желаемый язык:

    Сводка
           system_prompt = <<~TEXT
           Вы — бот, выполняющий суммаризацию текста.
           Вы умеете эффективно сокращать текст до ключевых мыслей.
           Вы понимаете и умеете генерировать разметку Markdown в Discourse.
           При необходимости добавляйте ссылки в формате: #{topic.url}/POST_NUMBER, например: [ссылка](#{topic.url}/77)
           TEXT
    
           user_prompt = <<~TEXT
             Руководство: #{guidance}
             Вы суммаризуете топик: #{topic.title}
             Пожалуйста, предоставь ответ на русском языке.
             В ответе используй 400 слов:
    
             #{text}
           TEXT
    

    Результат, например:

           system_prompt = <<~TEXT
           Вы — бот, выполняющий суммаризацию текста.
           Вы умеете эффективно сокращать текст до ключевых мыслей.
           Вы понимаете и умеете генерировать разметку Markdown в Discourse.
           При необходимости добавляйте ссылки в формате: #{topic.url}/POST_NUMBER, например: [ссылка](#{topic.url}/77)
           TEXT
    
           user_prompt = <<~TEXT
             Руководство: #{guidance}
             Вы суммаризуете топик: #{topic.title}
             Пожалуйста, предоставь ответ на русском языке.
             В ответе используй 400 слов:
    
             #{text}
           TEXT
    
  4. Далее сделайте то же самое для второго файла:

    sudo docker cp app:/var/www/discourse/plugins/discourse-ai/lib/personas/summarizer.rb ./summarizer.rb
    

    Отредактируйте:

    Примечание: вы можете переопределить язык исходного текста:

    - Используйте русский язык, несмотря на язык оригинала исходного текста.
    
    Сводка
         <<~PROMPT.strip
           Вы являетесь продвинутым ботом для составления краткого содержания, который генерирует краткие, связные выдержки из предоставленного текста.
           Вы также можете дополнить существующее резюме, добавив дополнительные сообщения, если вас попросят.
    
           - Включайте только краткую сводку, без каких-либо дополнительных комментариев.
           - Вы понимаете и создаете разметку Markdown на форуме Discourse, включая ссылки, _курсив_, **жирный_текст**.
           - Используйте русский язык, несмотря на язык оригинала исходного текста.
           - Старайтесь, чтобы объем резюме не превышал 400 слов.
           - Каждая запись оформляется как "<POST_NUMBER>) <USERNAME> <MESSAGE>"
           - Цитируйте конкретные заслуживающие внимания публикации, используя формат [DESCRIPTION]({resource_url}/POST_NUMBER)
           - Пример: ссылки на 3-й и 6-й посты пользователя sam: sam ([#3]({resource_url}/3), [#6]({resource_url}/6))
           - Пример: ссылка на 6-е сообщение пользователя jane: [согласовано с]({resource_url}/6)
           - Пример: ссылка на 13-е сообщение Джо: [Джо]({resource_url}/13)
           - При форматировании имен пользователей используйте [USERNAME]({resource_url}/POST_NUMBER)
    
           Отформатируйте свой ответ в виде объекта JSON с помощью единственного ключа с именем "summary", который имеет значение "summary".
           Ваши выходные данные должны быть в следующем формате:
             <output>
               {"summary": "xx"}
             </output>
    
           Где "xx" заменяется на текст краткой сводки.
         PROMPT
       end
    
    ...
           [
             "Вот записи внутри XML-тегов <input></input>:\n\n<input>1) user1 сказал: Я люблю понедельники 2) user2 сказал: А я ненавижу понедельники</input>\n\nСформулируйте краткое, связное изложение текста выше, сохранив язык оригинала.",
             {
               summary:
                 "Два пользователя делятся своими чувствами к понедельникам. [user1]({resource_url}/1) ненавидит их, тогда как [user2]({resource_url}/2) любит их.",
             }.to_json,
           ],
    

    Результат:

            <<~PROMPT.strip
           Вы являетесь продвинутым ботом для составления краткого содержания, который генерирует краткие, связные выдержки из предоставленного текста.
           Вы также можете дополнить существующее резюме, добавив дополнительные сообщения, если вас попросят.
    
           - Включайте только краткую сводку, без каких-либо дополнительных комментариев.
           - Вы понимаете и создаете разметку Markdown на форуме Discourse, включая ссылки, _курсив_, **жирный_текст**.
           - Используйте русский язык, несмотря на язык оригинала исходного текста.
           - Старайтесь, чтобы объем резюме не превышал 400 слов.
           - Каждая запись оформляется как "<POST_NUMBER>) <USERNAME> <MESSAGE>"
           - Цитируйте конкретные заслуживающие внимания публикации, используя формат [DESCRIPTION]({resource_url}/POST_NUMBER)
           - Пример: ссылки на 3-й и 6-й посты пользователя sam: sam ([#3]({resource_url}/3), [#6]({resource_url}/6))
           - Пример: ссылка на 6-е сообщение пользователя jane: [согласовано с]({resource_url}/6)
           - Пример: ссылка на 13-е сообщение Джо: [Джо]({resource_url}/13)
           - При форматировании имен пользователей используйте [USERNAME]({resource_url}/POST_NUMBER)
    
           Отформатируйте свой ответ в виде объекта JSON с помощью единственного ключа с именем "summary", который имеет значение "summary".
           Ваши выходные данные должны быть в следующем формате:
             <output>
               {"summary": "xx"}
             </output>
    
           Где "xx" заменяется на текст краткой сводки.
         PROMPT
       end
    
       def response_format
         [{ "key" => "summary", "type" => "string" }]
       end
    
       def examples
         [
           [
             "Вот записи внутри XML-тегов <input></input>:\n\n<input>1) user1 сказал: Я люблю понедельники 2) user2 сказал: А я ненавижу понедельники</input>\n\nСформулируйте краткое, связное изложение текста выше, сохранив язык оригинала.",
             {
               summary:
                 "Два пользователя делятся своими чувствами к понедельникам. [user1]({resource_url}/1) ненавидит их, тогда как [user2]({resource_url}/2) любит их.",
             }.to_json,
           ],
    
  5. Скопируйте измененные файлы в контейнер:

    sudo docker cp summarize.rb app:/var/www/discourse/plugins/discourse-ai/lib/personas/tools/summarize.rb
    sudo docker cp summarizer.rb app:/var/www/discourse/plugins/discourse-ai/lib/personas/summarizer.rb
    
  6. Затем выполните коммит и перезапустите контейнер:

    sudo docker commit app
    sudo /var/discourse/launcher restart app
    
  7. Проверьте результат (для новых тем):

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

Создайте новую Персону, следуя настройкам существующей, измените системный промпт по своему усмотрению и настройте функцию суммаризации для её использования по адресу /admin/plugins/discourse-ai/ai-features/1/edit.

Что ж… Последние слова о поддержке языка были найдены в этой теме. Спасибо за ответ.

Первая попытка создать надлежащего бота для суммирования как клон существующего бота провалилась. Он всё ещё генерирует текст на английском. Вероятно, я что-то делаю не так.

Не уверен, насколько хорошо вы справитесь с этой моделью, она не такая мощная.

Какой у всех обходной путь или подход к суммаризации на неанглийских языках?

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

Протестировано с Gemini 2.5 Lite

Привет, я всё ещё использую описанный выше обходной путь. Я пробовал различные трюки с кастомными персонажами, но это не работает. Возможно, я что-то делаю не так, но для меня это менее болезненно.

Кратко: вам нужно подготовить шаблоны, скачанные с GitHub, адаптировать их под свои нужды и применять после каждой пересборки. Не забывайте проверять наличие новых версий этих файлов раз в 2–3 месяца.

Создайте исполняемый скрипт (в директории $HOME) do_it_after_rebuild.sh:

#/bin/bash
#
# https://github.com/discourse/discourse/tree/main/plugins/discourse-ai/lib/personas
docker cp app:/var/www/discourse/plugins/discourse-ai/lib/personas/tools/summarize.rb orig_summarize.rb
docker cp app:/var/www/discourse/plugins/discourse-ai/lib/personas/summarizer.rb orig_summarizer.rb
docker cp app:/var/www/discourse/plugins/discourse-ai/lib/personas/short_summarizer.rb orig_short_summarizer.rb
docker cp app:/var/www/discourse/plugins/discourse-ai/lib/personas/discover.rb orig_discover.rb

rm GeoLite2*
wget https://raw.githubusercontent.com/8bitsaver/maxmind-geoip/release/GeoLite2-City.mmdb
wget https://raw.githubusercontent.com/8bitsaver/maxmind-geoip/release/GeoLite2-ASN.mmdb

docker cp GeoLite2-City.mmdb    app:/var/www/discourse/vendor/data/
docker cp GeoLite2-ASN.mmdb     app:/var/www/discourse/vendor/data/
docker cp summarize.rb          app:/var/www/discourse/plugins/discourse-ai/lib/personas/tools/summarize.rb
docker cp summarizer.rb         app:/var/www/discourse/plugins/discourse-ai/lib/personas/summarizer.rb
docker cp short_summarizer.rb   app:/var/www/discourse/plugins/discourse-ai/lib/personas/short_summarizer.rb
docker cp discover.rb           app:/var/www/discourse/plugins/discourse-ai/lib/personas/discover.rb
docker commit app
sudo /var/discourse/launcher restart app

И запускайте после пересборки:

./do_it_after_rebuild.sh
Файлы здесь

Внесите следующие изменения в файлы, которые нужно периодически скачивать отсюда (я показываю только различия — вам нужно вручную добавить эти строки в файлы):

diff discover.rb orig_discover.rb
35d34
<         * Используйте всегда немецкий язык.
80d78
<
└─# diff short_summarizer.rb orig_short_summarizer.rb
12c12,13
< Du bist ein fortgeschrittener Bot, um den Text zusammenzufassen. Sie analysieren den bereitgestellten Text und erzeugen eine kurze Zusammenfassung aus einem einzigen Satz, in dem das Hauptthema und die aktuellen Ereignisse dem Gesprächspartner ohne vorläufigen Kontext verständlich sind.
---
> You are an advanced summarization bot. Analyze a given conversation and produce a concise,
> single-sentence summary that conveys the main topic and current developments to someone with no prior context.
14c15
< ### Anweisungen:
---
> ### Guidelines:
16,28c17,23
< - Подчеркивайте последние обновления из-за их важности в исходном сообщении.
< - Сосредоточьтесь на основной теме или проблеме, сохраняя объективный и нейтральный тон.
< - Исключите посторонние детали или субъективные мнения.
< - Всегда используйте только русский язык, игнорируя язык исходного текста.
<
└─# diff summarizer.rb orig_summarizer.rb
12,13c12,13
< Sie sind ein fortgeschrittener Bot, um kurze Inhalte zu erstellen, die kurze, zusammenhängende Auszüge aus dem bereitgestellten Text erzeugen.
< Sie können einen vorhandenen Lebenslauf auch ergänzen, indem Sie zusätzliche Beiträge hinzufügen, wenn Sie dazu aufgefordert werden.
---
> You are an advanced summarization bot that generates concise, coherent summaries of provided text.
> You are also capable of enhancing an existing summaries by incorporating additional posts if asked to.
15,24c15,23
< - Добавьте только краткое резюме без дополнительных комментариев.
< - Вы понимаете и генерируете Markdown форума Discourse, включая ссылки, _курсив_, **жирный текст**.
< - Используйте русский язык независимо от языка исходного текста.
< - Старайтесь ограничивать резюме 400 словами.
< - Каждая запись должна выводиться в формате "<POST_NUMBER>) <USERNAME> <MESSAGE>"
< - Цитируйте определенные заметные публикации в формате [DESCRIPTION]({resource_url}/POST_NUMBER)
< - Пример: ссылки на 3-й и 6-й посты от sam: sam ([#3]({resource_url}/3), [#6]({ resource_url}/6))
< - Пример: ссылка на 6-е сообщение от jane: [согласен с]({resource_url}/6)
< - Пример: ссылка на 13-й пост от Joe: [Joe]({resource_url}/13)
< - При форматировании имен пользователей используйте [USERNAME]({resource_url}/POST_NUMBER)
---
> - Включайте только резюме, без каких-либо дополнительных комментариев.
> - Вы понимаете и генерируете Markdown форума Discourse; включая ссылки, _курсив_, **жирный текст**.
> - Сохраняйте исходный язык текста, который вырезается.
> - Старайтесь, чтобы резюме составляли 400 слов или меньше.
> - Каждый пост должен быть отформатирован как "<POST_NUMBER>) <USERNAME> <MESSAGE>"
> - Цитируйте определенные заметные сообщения в формате [DESCRIPTION] ({resource_url} / POST_NUMBER)
> - Пример: ссылка на 6-й пост от jane: [согласен с]({resource_url}/6)
> - Пример: ссылка на 13-й пост от joe: [joe]({resource_url}/13)
> - При форматировании имен пользователей используйте [USERNAME] ({resource_url} / POST_NUMBER)
Nr.26,30c25,28
< Отформатируйте свой ответ в виде объекта JSON с помощью единственного ключа с именем "Zusammenfassung", который имеет значение "Zusammenfassung".
< Ваши выходные данные должны быть в следующем формате:
< <Ausgabe>
< {"zusammenfassung": "xx"}
< </Ausgabe>
---
> Отформатируйте свой ответ в виде объекта JSON с одним ключом под названием "summary", содержащим резюме в качестве значения.
> Ваш вывод должен быть в следующем формате:
> 
> {"summary": "xx"}
32c30,31
< Где "xx" заменяется текстом резюме.
---
> Где "xx" заменяется резюме.
> отвечайте только валидным JSON
43c42
< "Вот сообщения внутри тегов XML <input></input>:\n\n<input>1) user1 сказал: Я люблю понедельники 2) user2 сказал: А я ненавижу понедельники</input>\n\nсформулируйте краткое, связное изложение текста выше, сохраняя исходный язык.",
---
> "Вот сообщения внутри тегов XML <input></input>:\n\n<input>1) user1 сказал: Я люблю понедельники 2) user2 сказал: Я ненавижу понедельники</input>\n\nСоздайте краткое, связное резюме текста выше, сохраняя исходный язык.",
46c45
< "Два пользователя делятся своими чувствами по поводу понедельника. [user1]({resource_url}/1) ненавидит их, в то время как [user2]({resource_url}/2) любит их.",
---
> "Два пользователя делятся своими чувствами по поводу понедельника. [user1]({resource_url}/1) ненавидит их, в то время как [user2]({resource_url}/2) любит их.",
└─# diff summarize.rb orig_summarize.rb
159c159
< max_tokens: 4096,
---
> max_tokens: 500,
170,173c170,174
< Вы — бот, который резюмирует текст.
< Вы способны эффективно сокращать текст до основных мыслей.
< Вы понимаете и можете генерировать Markdown в Discourse.
< При необходимости добавляйте ссылки в формате #{topic.url}/POST_NUMBER, например: [ссылка](#{topic.url}/77)
---
> Вы — бот для создания резюме.
> Вы эффективно резюмируете любой текст.
> Вы сокращаете его до более короткой версии.
> Вы понимаете и генерируете Markdown форума Discourse.
> Попробуйте также генерировать ссылки в формате #{topic.url}/POST_NUMBER. например: [ссылка](#{topic.url}/77)
177,180c178,180
< Руководство: #{guidance}
< Вы резюмируете тему: #{topic.title}
< Пожалуйста, дайте ответ на русском языке.
< Используйте 400 слов в своем ответе:
---
>