AI 机器人 - 自定义工具

:bookmark: 本指南说明了如何在 Discourse AI 插件中创建、配置和集成自定义 AI 工具,使管理员能够通过用户定义的 JavaScript 函数来扩展机器人的功能。

:person_raising_hand: 所需用户级别:管理员

工具是可编程的功能,AI 机器人可以使用它们来执行特定任务或检索信息,而不仅仅是基于文本的响应。这些工具是脚本或集成,允许机器人与外部 API 交互、操作数据或执行附加功能以扩展其能力。

摘要

本文档涵盖:

  • 创建新的自定义 AI 工具
  • 配置工具参数和脚本
  • 工具脚本可用的 API
  • 将自定义工具与 AI 角色集成
  • 测试和故障排除自定义工具

创建新的自定义 AI 工具

要创建新的 AI 工具:

  1. 导航至管理面板 (Admin Panel) > 插件 (Plugins) > Discourse AI > 工具 (Tools)
  2. 点击“新建工具”(New Tool)(您可以使用现有预设来了解各种选项)
  3. 填写以下字段:
    • 名称 (Name):向 LLM (大型语言模型) 展示的工具名称
    • 描述 (Description):向 LLM 展示的工具描述
    • 摘要 (Summary):工具为协助用户所做工作的简要说明(显示在详细信息中)
    • 参数 (Parameters):定义工具作为向 LLM 展示时所需的输入
    • 脚本 (Script):为您的工具提供动力的 JavaScript 代码
  4. 点击“保存”(Save)

配置工具脚本

可用 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 标头和主体 (body):

    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 的分词器,将文本截断到指定的 token 长度。

    llm.generate(prompt, options)
    

    使用配置的 LLM 生成文本。提示 (prompt) 可以是简单的字符串,也可以是结构化对象,例如 { messages: [{ type: "system", content: "..." }, { type: "user", content: "..." }] }。选项包括 json: true 以请求并自动解析 JSON 输出,以及 temperaturetop_pmax_tokensstop_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),返回完整的 CDN 友好 URL。

    upload.getBase64(uploadIdOrShortUrl, maxPixels)
    

    获取现有上传项的 base64 编码内容。接受上传 ID(数字)或短 URL(字符串)。可选的 maxPixels 参数用于自动图像大小调整(默认值:10,000,000)。

  5. 执行链控制

    chain.setCustomRaw(raw)
    

    设置机器人帖子的最终原始内容并停止工具执行链。这对于直接生成完整响应的工具(例如图像生成工具)非常有用。

  6. Secrets 管理

    secrets.get(alias)
    

    返回绑定到给定别名的凭据值。别名在工具的 Secret 契约配置中定义,并在管理面板中绑定到 AI 密钥 (AI Secrets)。如果别名未声明、未绑定或凭据缺失,则会抛出错误。

    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)       // 获取另一个 AI 代理(具有 respondTo 方法)
    discourse.updateAgent(name, updates) // 更新 AI 代理的配置
    discourse.getCustomField(type, id, key)      // 读取帖子/主题/用户上的自定义字段
    discourse.setCustomField(type, id, key, value) // 在帖子/主题/用户上设置自定义字段
    
  8. Context 对象

    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 以跳过。可以访问 contextdiscourseindex 对象。

示例脚本:

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

function details() {
  return "Fetched data from Example API";
}

限制和安全

  • 执行超时: 默认超时时间为 2000 毫秒的脚本处理时间。计时器在外部 HTTP 请求 (http.*) 和 LLM 调用 (llm.generate) 期间暂停,因此只有脚本自身的处理时间才会计入。
  • 内存: 最大 10MB V8 堆限制
  • HTTP 请求: 每个工具执行最多 20 个请求
  • 沙箱环境: 脚本在受限的 V8 JavaScript 环境中运行(通过 MiniRacer)。无法访问浏览器全局变量、宿主文件系统或服务器端库。网络请求通过 Discourse 后端代理。

测试您的工具

您应该测试构建的任何工具,以确保提供给 LLM 的结果符合您的预期。

将工具与 AI 角色集成

要将您的自定义工具添加到 AI 角色:

  1. 进入管理面板 (Admin Panel) > 插件 (Plugins) > Discourse AI > 角色 (Personas)
  2. 编辑现有角色或创建新角色
  3. 在“工具”(Tools) 部分,您将看到您的自定义工具与内置工具一起列出
  4. 选择您的自定义工具以将其添加到角色中

启用自定义工具

一旦您将自定义工具提供给 LLM,它就可以使用它来增强对话。

故障排除

如果您的工具没有按预期工作:

  1. 使用测试界面确保它对您的输入表现符合预期。
  2. 确保您的用户组在 ai_bot_debugging_allowed_groups 中。该组的成员可以完全访问机器人转录记录;您可以在那里查看 AI 日志。
  3. 如果发生任何意外情况,请访问 https://SITENAME/logs 检查错误。

附加资源

Discourse AI - AI bot

AI bot - Agents

14 个赞

我刚开始为 Discourse 中的 AI 角色构建工具,部分原因是为了能够真正专注于此;鉴于存在如此多有用且公开的 API,这似乎非常有益!

例如,我得到的结果包括:

通过扑克策略理解决策制定 AI

maiki:

创建一个《塞尔达传说:旷野之息》的信息卡。

gpt-4o:

这是《塞尔达传说:旷野之息》的信息卡:


标题: 《塞尔达传说:旷野之息》
开发商: 任天堂
发行商: 任天堂
发布日期: 2017 年 3 月 3 日
平台: Nintendo Switch、Wii U
类型: 动作冒险
模式: 单人

剧情简介:
游戏设定在一个广阔的开放世界中,玩家扮演林克,他从沉睡中醒来,以击败灾厄盖侬并拯救海拉鲁王国。游戏因其沉浸式环境而受到赞誉,玩家可以自由地探索和与世界及其系统互动。

奖项:
该游戏因其创新的设计、广阔的世界和迷人的玩法赢得了众多奖项,包括多个年度游戏奖项。

更多信息: Wikidata 条目


《旷野之息》以重新定义开放世界游戏并提供鼓励探索和发现的迷人体验而闻名。

maiki:

为《集合啦!动物森友会》也做同样的事情。

gpt-4o:

这是《集合啦!动物森友会》的信息卡:


标题: 《集合啦!动物森友会》
开发商: 任天堂
发行商: 任天堂
发布日期: 2020 年 3 月 20 日
平台: Nintendo Switch
类型: 社交模拟
模式: 单人、多人

剧情简介:
在这款迷人的社交模拟游戏中,玩家扮演一个可定制的角色,在购买了 Nook 先生的一揽子计划后,搬迁到一个荒岛上。游戏允许实时探索、资源收集、制作和定制,营造出一种社区感和轻松的游戏体验。

奖项:
该游戏因其创意自由和发布时机而广受好评,并因其在疫情期间对年度游戏和社交游戏的贡献而获奖。

更多信息: Wikidata 条目


《集合啦!动物森友会》成为一种文化现象,因其引人入胜的社交功能和在充满挑战的时期缓解压力的游戏玩法而受到赞誉。

maiki:

远离芝加哥

gpt-4o:

这是关于书籍《远离芝加哥》的信息卡:


标题: 《远离芝加哥》
作者: Richard Peck
出版年份: 1998
类型: 历史小说、青少年文学
ISBN: 978-0141303529

剧情简介:
这部纽伯瑞荣誉奖小说是一系列短篇故事,讲述了乔伊和他的妹妹玛丽·爱丽丝在 20 世纪 20 年代末和 30 年代每年夏天从芝加哥前往伊利诺伊州的一个乡村小镇拜访他们极富传奇色彩的奶奶 Dowdel 的经历。每一章都呈现了一个有趣而感人的插曲,在经济大萧条的背景下传达了生活课程。

奖项:
这本书于 1999 年获得纽伯瑞荣誉奖,并因其幽默、深度以及对 20 世纪早期美国乡村生活的描绘而受到赞誉。

更多信息: Wikidata 条目


这本书因其怀旧而温馨的故事而受到赞赏,捕捉了家庭纽带和简单时光的精髓。

maiki:

思考的赌注

gpt-4o:

我之前找到了“思考的赌注”的 Wikidata 条目,但目前无法直接从 Wikidata 获取更多具体细节。不过,这是基于现有信息的一个简短卡片:


标题: 《思考的赌注:在信息不全时做出更明智的决定》
作者: Annie Duke
出版年份: 2018
类型: 非虚构、决策、心理学
ISBN: 978-0735216358

剧情简介:
这本书借鉴了扑克的经验,帮助读者理解不确定情况下的决策制定。Annie Duke 结合了她作为职业扑克玩家和认知心理学家的经验,提供了一个做出更明智决策、评估结果和采用概率思维的框架。

更多信息: Wikidata 条目


如需详细见解,您可以考虑查阅有关书籍出版物的其他资源或数据库。


好的,这没问题,但我注意到这个描述……

……我想知道:我是否应该直接参考这些工具来构建我的提示,以便高效使用?

我编写提示的一般方法是随着时间的推移进行完善,然后锁定我希望 AI 工具采用的行为模式。但是,如果我能够添加具体的说明,例如何时查找 Wikidata 条目,以及何时列出特定条目的所有声明(两个不同的 API),那么我觉得我可以将整个工作流程精炼成我想要的样子…… :star_struck:

4 个赞

在系统提示中清楚地解释工具并提供示例确实是有益的。

2 个赞

在自定义工具中是否可以从管理员设置中插入 API 密钥和 OpenAI 项目?

1 个赞

您可以从自定义工具发出 REST 调用并指定所有标头

2 个赞

刚意识到,哈哈……抱歉,我脑子短路了。

1 个赞

我已经将一些文档上传到一个 Persona,它生成了嵌入,现在可以对其进行语义搜索。但在某些情况下,语义搜索并非理想选择,因此我想对其进行增强,实现混合搜索,例如保留现有功能并添加关键字搜索。目前,如果我想这样做,我应该编写一个自定义工具,对吗?
我知道我可以简单地将文档发布为主题,然后它就可以与原生的 Discourse 搜索配合使用,但这目前不是一个选项。

当我添加一个带有数组参数的自定义工具时,我看到了一个工具架构错误。错误在对话开始时出现:

{
“error”: {
“code”: 400,
“message”: “* GenerateContentRequest.tools[0].function_declarations[3].parameters.properties[properties].items: 缺少字段。\\n”,
“status”: “INVALID_ARGUMENT”
}
}

我尝试了什么:

  • 创建了一个名为 properties、类型为数组的自定义工具参数。
  • 参数列表 UI 不允许指定 items
  • 导出了/导入了一个完整的工具 JSON,其中包含 items: { type: “string” } 用于 properties
  • 导入后,只要工具对某个角色启用,错误就会持续存在。如果我删除该工具,机器人就能正常工作。

预期:

参数列表 UI 应该允许定义数组项类型,或者导入应该遵守 items 使得架构验证通过。

有人遇到过这个问题吗?是否存在已知的限制或定义数组参数所需的 UI 路径?

1 个赞