AI-бот — пользовательские инструменты

:bookmark: Это руководство объясняет, как создавать, настраивать и интегрировать пользовательские инструменты ИИ в плагине Discourse AI, позволяя администраторам расширять возможности бота с помощью определенных пользователем функций JavaScript.

:person_raising_hand: Требуемый уровень доступа пользователя: Администратор

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

Краткое содержание

В этой документации рассматриваются следующие темы:

  • Создание нового пользовательского инструмента ИИ
  • Настройка параметров и скриптов инструмента
  • Доступные API для скриптов инструментов
  • Интеграция пользовательских инструментов с персонажами ИИ
  • Тестирование и устранение неполадок пользовательских инструментов

Создание нового пользовательского инструмента ИИ

Чтобы создать новый инструмент ИИ:

  1. Перейдите в Панель администратора > Плагины > Discourse AI > Инструменты
  2. Нажмите «Новый инструмент» (вы можете использовать существующие предустановки, чтобы ознакомиться с возможностями)
  3. Заполните следующие поля:
    • Имя: Название инструмента, отображаемое для LLM
    • Описание: Описание инструмента, отображаемое для LLM
    • Краткое описание: Краткое описание того, что делает инструмент для помощи пользователям (отображается в деталях)
    • Параметры: Определите входные данные, необходимые вашему инструменту, как они будут представлены LLM
    • Скрипт: Код JavaScript, обеспечивающий работу вашего инструмента
  4. Нажмите «Сохранить»

Настройка скриптов инструментов

Доступные API

Ваши скрипты инструментов имеют доступ к следующим API:

  1. HTTP-запросы:

    http.get(url, options)
    http.post(url, options)
    http.put(url, options)
    http.patch(url, options)
    http.delete(url, options)
    

    Используйте их для взаимодействия со внешними сервисами. Вы можете использовать options для указания заголовков и тела HTTP-запроса:

    http.get(url, { headers: { "Authorization": "Bearer key" } })
    http.post(url, { headers: { "Content-Type": "application/json" }, body: { key: "value" } })
    http.patch(url, { headers: { "Authorization": "Bearer key" }, body: "some body" })
    http.delete(url, { headers: { "Authorization": "Bearer key" } })
    http.put(url, { headers: { "Authorization": "Bearer key" }, body: "some body" })
    

    Все методы HTTP возвращают объект { status: number, body: string }.

  2. Интеграция с LLM (языковой моделью):

    llm.truncate(text, length)
    

    Обрезает текст до указанной длины в токенах на основе токенизатора настроенной LLM.

    llm.generate(prompt, options)
    

    Генерирует текст с использованием настроенной LLM. Промпт может быть простой строкой или структурированным объектом, например { messages: [{ type: "system", content: "..." }, { type: "user", content: "..." }] }. Опции включают json: true для запроса и автоматического парсинга вывода в формате JSON, а также temperature, top_p, max_tokens и stop_sequences.

  3. Интеграция пользовательских загрузок (RAG)

    index.search(query, { filenames: ["file.pdf"], limit: 10 })
    

    Ищет фрагменты документов RAG, индексированных и прикрепленных к этому инструменту. Возвращает Array<{ fragment: string, metadata: string | null }>, отсортированный по релевантности. Ограничение по умолчанию — 10, максимум — 200.

    index.getFile(filename)
    

    Извлекает полное содержимое загруженного файла RAG по его точному имени файла. Возвращает полный текст или null, если файл не найден.

  4. Поддержка загрузок

    upload.create(filename, base_64_content)
    

    Создает новую загрузку. Возвращает { id: number, url: string, short_url: string }.

    upload.getUrl(shortUrl)
    

    По короткому URL (например, upload://12345) возвращает полный URL, совместимый с CDN.

    upload.getBase64(uploadIdOrShortUrl, maxPixels)
    

    Получает содержимое существующей загрузки в кодировке base64. Принимает ID загрузки (число) или короткий URL (строку). Необязательный параметр maxPixels для автоматического изменения размера изображения (по умолчанию: 10 000 000).

  5. Контроль цепочки выполнения

    chain.setCustomRaw(raw)
    

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

  6. Управление секретами

    secrets.get(alias)
    

    Возвращает значение учетных данных, связанное с указанным псевдонимом. Псевдонимы определяются в конфигурации контрактов секретов инструмента и привязываются к секретам ИИ в панели администратора. Выбрасывает ошибку, если псевдоним не объявлен, не привязан или отсутствуют учетные данные.

    const apiKey = secrets.get("my_api_key");
    
  7. Интеграция с Discourse

    Инструменты могут напрямую взаимодействовать с данными Discourse:

    discourse.baseUrl              // Базовый URL сайта
    discourse.search(params)       // Выполнить поиск в Discourse
    discourse.getPost(post_id)     // Получить детали поста (включая необработанное содержимое)
    discourse.getTopic(topic_id)   // Получить детали темы (теги, категория и т. д.)
    discourse.getUser(id_or_username)  // Получить детали пользователя
    discourse.createTopic(params)  // Создать новую тему
    discourse.createPost(params)   // Создать новый пост/ответ
    discourse.editPost(post_id, raw, options)    // Изменить содержимое поста
    discourse.editTopic(topic_id, updates, options) // Изменить свойства темы (теги, категория, видимость)
    discourse.createChatMessage(params) // Отправить сообщение в чате
    discourse.createStagedUser(params)  // Создать подготовленного пользователя
    discourse.getAgent(name)       // Получить другого агента ИИ (с методом respondTo)
    discourse.updateAgent(name, updates) // Обновить конфигурацию агента ИИ
    discourse.getCustomField(type, id, key)      // Читать пользовательское поле в посте/теме/пользователе
    discourse.setCustomField(type, id, key, value) // Устанавливать пользовательское поле в посте/теме/пользователе
    
  8. Объект контекста

    Объект context предоставляет информацию о том, где выполняется инструмент:

    • Контекст разговора бота: context.post_id, context.topic_id, context.private_message, context.participants, context.username, context.user_id
    • Контекст чата: context.message_id, context.channel_id, context.username
    • Контекст автоматизации: context.post_id, context.topic_id, context.username, context.user_id, context.feature_name, context.feature_context
    • Общие свойства: context.site_url, context.site_title, context.site_description

Обязательные функции

Ваш скрипт должен реализовывать:

  • invoke(params): Основная функция, которая выполняется при вызове инструмента

Он также может опционально реализовывать:

  • details(): Возвращает строку (может включать базовый HTML), описывающую выполнение инструмента, отображаемую в интерфейсе чата
  • customSystemMessage(): Вызывается во время сборки промпта (не во время вызова инструмента). Возвращает строку, добавляемую к системному промпту, или null/undefined для пропуска. Имеет доступ к объектам context, discourse и index.

Пример скрипта:

function invoke(params) {
  let result = http.get("https://api.example.com/data?query=" + params.query);
  return JSON.parse(result.body);
}

function details() {
  return "Получены данные из Example API";
}

Ограничения и безопасность

  • Тайм-аут выполнения: Тайм-аут по умолчанию составляет 2000 мс времени обработки скрипта. Таймер приостанавливается во время внешних HTTP-запросов (http.*) и вызовов LLM (llm.generate), поэтому учитывается только время обработки самого скрипта.
  • Память: Максимальный лимит кучи V8 — 10 МБ
  • HTTP-запросы: Максимум 20 запросов за одно выполнение инструмента
  • Песочница: Скрипты выполняются в ограниченной среде JavaScript V8 (через MiniRacer). Нет доступа к глобальным объектам браузера, файловой системе хоста или серверным библиотекам. Сетевые запросы проксируются через бэкенд Discourse.

Тестирование вашего инструмента

Вам следует тестировать любой созданный инструмент, чтобы убедиться, что результаты, предоставляемые LLM, соответствуют вашим ожиданиям.

Интеграция инструментов с персонажами ИИ

Чтобы добавить свой пользовательский инструмент к персонажу ИИ:

  1. Перейдите в Панель администратора > Плагины > Discourse AI > Персонажи
  2. Отредактируйте существующий персонаж или создайте новый
  3. В разделе «Инструменты» вы увидите свои пользовательские инструменты в списке наряду со встроенными
  4. Выберите свой пользовательский инструмент, чтобы добавить его к персонажу

Пользовательские инструменты в действии

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

Устранение неполадок

Если ваш инструмент работает не так, как ожидалось:

  1. Используйте интерфейс Тестирования, чтобы убедиться, что он ведет себя ожидаемым образом для ваших входных данных.
  2. Убедитесь, что ваша группа включена в ai_bot_debugging_allowed_groups. Участники этой группы имеют полный доступ к транскриптам бота; вы можете просмотреть логи ИИ там.
  3. Если происходит что-то неожиданное, перейдите на https://SITENAME/logs, чтобы проверить наличие ошибок.

Дополнительные ресурсы

14 лайков

I’m just getting into building tools for AI personas in Discourse, in part so I can really focus on it; this seems like it’s very useful given how many useful and public APIs there are!

For instance, I’m getting results such as:

Understanding Decision-Making Through Poker Strategies AI

maiki:

Create an infocard for Breath of the Wild.

gpt-4o:

Here is an information card for “The Legend of Zelda: Breath of the Wild”:


Title: The Legend of Zelda: Breath of the Wild
Developer: Nintendo
Publisher: Nintendo
Release Date: March 3, 2017
Platforms: Nintendo Switch, Wii U
Genre: Action-adventure
Mode: Single-player

Synopsis:
Set in a vast open world, players control Link, who awakens from a deep slumber to defeat Calamity Ganon and save the kingdom of Hyrule. The game is praised for its immersive environment, allowing players to explore and interact freely with the world and its systems.

Awards:
The game has won numerous awards, including several Game of the Year accolades, for its innovative design, expansive world, and enchanting gameplay.

More information: Wikidata Entry


“Breath of the Wild” is renowned for redefining open-world games and delivering a captivating experience that encourages exploration and discovery.

maiki:

The same for Animal Crossing: New Horizons.

gpt-4o:

Here is an information card for “Animal Crossing: New Horizons”:


Title: Animal Crossing: New Horizons
Developer: Nintendo
Publisher: Nintendo
Release Date: March 20, 2020
Platform: Nintendo Switch
Genre: Social simulation
Mode: Single-player, Multiplayer

Synopsis:
In this charming social simulation game, players assume the role of a customizable character who relocates to a deserted island after purchasing a package from Tom Nook. The game allows for real-time exploration, resource gathering, crafting, and customization, fostering a communal and relaxing gameplay experience.

Awards:
The game was acclaimed for its creative freedom and timing of release, receiving accolades for Game of the Year and its contributions to social gaming during the global pandemic.

More information: Wikidata Entry


“Animal Crossing: New Horizons” became a cultural phenomenon, celebrated for its engaging social features and stress-relieving gameplay during challenging times.

maiki:

A long way from Chicago

gpt-4o:

Here is an information card for the book “A Long Way from Chicago”:


Title: A Long Way from Chicago
Author: Richard Peck
Publication Year: 1998
Genre: Historical Fiction, Young Adult
ISBN: 978-0141303529

Synopsis:
This Newbery Honor-winning novel is a series of short stories chronicling the annual summer trips of Joey and his sister Mary Alice from Chicago to a rural Illinois town to visit their larger-than-life Grandma Dowdel during the late 1920s and 1930s. Each chapter presents an amusing and poignant episode that imparts life lessons amidst the backdrop of the Great Depression.

Awards:
The book was awarded a Newbery Honor in 1999 and is celebrated for its humor, depth, and portrayal of rural American life during the early 20th century.

More information: Wikidata Entry


This book is appreciated for its nostalgic and heartwarming storytelling, capturing the essence of familial bonds and simpler times.

maiki:

Thinking in Bets

gpt-4o:

I previously found the Wikidata entry for “Thinking in Bets,” but I’m unable to retrieve further specific details directly from Wikidata at the moment. However, here is a brief card based on available information:


Title: Thinking in Bets: Making Smarter Decisions When You Don’t Have All the Facts
Author: Annie Duke
Publication Year: 2018
Genre: Non-fiction, Decision Making, Psychology
ISBN: 978-0735216358

Synopsis:
The book leverages insights from poker to help readers understand decision-making under uncertainty. Annie Duke, blending her experiences as a professional poker player and cognitive psychologist, offers a framework for making smarter decisions, evaluating outcomes, and adopting a probabilistic mindset.

More information: Wikidata Entry


For detailed insights, you might consider checking additional resources or databases pertaining to book publications.


Okay, so that’s fine, but I noticed this description…

…and wonder: should I be building my prompts referring directly to those tools, for efficient use?

My general approach to prompt-writing is to refine over time and then lock onto a pattern of behavior I wish for the AI tooling to adopt. However, if I could add specific instructions on, for instance, when to lookup a Wikidata entity, and when to list all claims of a particular entity (two different APIs), then I feel I could refine the entire workflow to flow as I intend… :star_struck:

4 лайка

Indeed clearly explaining the tool and providing examples in the system prompt is beneficial.

2 лайка

Is it possible in a custom tool to insert the API key and OpenAI project from the admin settings?

1 лайк

You can make rest calls from a custom tool and specify all headers

2 лайка

just realized that lol… sorry for the brainfart

1 лайк

I have uploaded some documents to a persona, it generated the embeddings and now can do semantic search over them. But in some cases, semantic search is not ideal, so I’d like to enhance it and have hybrid search e.g. keep what’s already there and add keyword search. At the moment if I want to do that I should write a custom tool , right?
I know I could simply publish the docs as topics and then it’ll work out of the box with the native Discourse search, but it’s not an option currently.

I’m seeing a tool schema error when adding a custom tool with an array parameter. Error on conversation start:

{
“error”: {
“code”: 400,
“message”: “* GenerateContentRequest.tools[0].function_declarations[3].parameters.properties[properties].items: missing field.\n”,
“status”: “INVALID_ARGUMENT”
}
}

What I tried:

  • Created a custom tool with a parameter named properties of type array.
  • The parameter list UI doesn’t allow specifying items.
  • Exported/imported a full tool JSON that includes items: { type: “string” } for properties.
  • After importing, the error persists as soon as the tool is enabled for a persona. If I remove the tool, the bot works.

Expected:

Either the parameter list UI should allow defining array item types, or the import should honor items so the schema validates.

Has anyone seen this? Is there a known limitation or a required UI path for defining array params?

1 лайк