您现在可以在 AI 角色中包含大段文本了!
这提供了多项优势:
-
您可以将大段文本引入到自定义 AI 机器人中,而这些文本在模型的训练数据中是缺失的(例如:内部培训文档、内部报告)。
-
您可以使用具体数据更好地固定角色的基础(即使这些数据存在于模型的训练集中),这有助于模型正确引用特定信息并提高结果的质量。
要添加上传内容:
-
使用
/admin/plugins/discourse-ai/ai-personas/界面创建新角色。 -
上传您希望包含在角色中的文本文件。
上传文件之前,请通过站点设置
authorized extensions添加相关扩展名(.md和.txt),以便角色可以使用。
- 根据需要调整索引选项。
先决条件
要使该选项运行,您需要配置 ai_embeddings_enabled 和 ai_embeddings_model。
Discourse AI 支持大量的嵌入模型。
我们的托管客户可以免费使用最先进的 bge-large-en 模型。
自托管者或希望有更多选择的人可以自托管嵌入模型,或使用 OpenAI、Google (Gemini) 等的模型。
这是 RAG 吗?
我们的上传支持的实现确实是 检索增强生成。
从高层次来看,每次我们要让 LLM 回答用户的问题时,我们都会根据您输入的文本查找高度相关的信息,并将其注入系统提示。
解释各种索引选项
什么是 token?token 是大型语言模型用来分割文本的基本单位。一个很好的可视化解释可以在这里找到:https://platform.openai.com/tokenizer
Discourse AI 上传实现附带以下切换:
Upload Chunk Tokens:文件上传后,我们会将其分割成小块。这允许您控制小块的大小。如果小块对于您的嵌入模型来说太大了,嵌入就会被截断(只有部分 token 会被处理)。
Upload Chunk Overlap Tokens:这是当前小块中包含的上一个块的 token 数量。这个数字越大,您的索引中存储的重复信息就越多。
Search Conversation Chunks:这控制着根据相关性无条件包含在完成提示中的“块”的数量。数字越大,LLM 获得的上下文就越多(并且调用成本就越高)。例如:如果设置为 10,而 Upload Chunk Tokens 设置为 200,那么每次完成都会有额外的 2000 个 token 开销。
Discourse AI 如何分割大段文本?
Discourse 使用递归字符文本分割器,它在分割时会尝试将段落、然后是行、最后是单词保留在一起。
此外,Discourse 还为您提供了对文本分割方式的额外控制。
[[metadata YOUR METADATA HERE]] 分隔符可用于分割大段文本并正确突出显示每个部分的内容。
例如:
[[metadata about cats]]
a long story about cats
[[metadata about dogs]]
a long story about dogs
这使得单个文本文档可以涵盖各种内容,并保护您免受“块污染”。您可以确保只有关于猫的数据包含在猫的块中,狗的数据包含在狗的块中。
听起来很复杂,我该如何调试?
Discourse AI 附带站点设置 ai bot debugging enabled groups,该组中的用户可以访问 AI 调试:
AI 调试屏幕可以帮助您了解我们发送给 AI 的信息。
垃圾进 - 垃圾出 如果您向 LLM 提供无用或模糊的信息,它无法神奇地将其转换为有用信息。
此屏幕可以帮助您更好地决定块的大小,或者您包含的块是太多还是太少。
这真的有用吗?
一个实际的例子是将 HAProxy 文档分割并输入到角色中:
System Prompt:
您是一个专门回答有关 HAProxy 问题 的机器人。
您生活在一个 Discourse 论坛上,并且渲染 Discourse markdown。
在提供答案时,请始终尝试包含指向 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 在处理复杂问题时都可能表现不佳。这是可以理解的,因为它们依赖于互联网上的所有 token,所以 50 个不同版本的 HAProxy 文档以及关于它的所有讨论都会进入它们的大脑,这可能会让它们非常困惑:
GPT-4 和 Claude 3 Opus 混淆的例子
两者客观上都不如 Discourse RAG 提供的精调答案:
GPT-4 和 Claude Opus 混淆较少的例子
未来
我们期待您的反馈,未来的一些想法可能是:
- 支持 PDF/DOCX/XLS 等格式,这样您就不需要转换为文本了
- 对源代码/HTML 进行更智能的块分割
- 在索引前对传入数据进行智能转换
请告诉我们您的想法!
非常感谢 @Roman 实现了这个功能 ![]()



