AI 与向量

为文档添加生成式问答功能

学习如何使用我们的无头搜索工具包构建类似ChatGPT的文档搜索系统


Supabase 提供了一个无头搜索工具包,用于为您的文档添加"生成式问答"功能。该工具包是"无头"(headless)的,因此您可以将其集成到现有网站中,并按照网站主题进行样式匹配。

您可以在 Supabase 文档中看到实际效果。只需按下 cmd+k 并"询问"类似"Supabase 有哪些功能?"的问题。您将看到响应信息会实时流式返回,这些信息都来自文档提供的内容:

无头搜索

技术栈

  • Supabase:数据库和边缘函数
  • OpenAI:嵌入向量和补全功能
  • GitHub Actions:用于导入您的 Markdown 文档

工具包组成

该工具包包含两部分:

  1. 无头向量搜索模板,您可以在自己的组织中部署
  2. GitHub Action,用于导入您的 Markdown 文件,将其转换为嵌入向量并存储到数据库中

使用步骤

在文档中构建相似性搜索需要三个步骤:

  1. 准备数据库
  2. 导入文档
  3. 添加搜索界面

准备数据库

准备工作包括创建一个新的Supabase项目并保存数据库和API凭证,这些信息可以在项目设置中找到。

现在我们可以按照无头向量搜索的说明来设置数据库:

  1. 将仓库克隆到本地机器:git clone git@github.com:supabase/headless-vector-search.git
  2. 将仓库链接到远程项目:supabase link --project-ref XXX
  3. 应用数据库迁移:supabase db push
  4. 设置OpenAI密钥为机密:supabase secrets set OPENAI_API_KEY=sk-xxx
  5. 部署边缘函数:supabase functions deploy --no-verify-jwt
  6. 在Supabase仪表板的设置 > API设置 > 公开的schema中暴露docs schema

导入您的文档

现在我们需要将您的文档作为嵌入向量推送到数据库中。您可以手动完成此操作,但为了简化流程,我们创建了一个 GitHub Action,可以在每次有 Pull Request 时自动更新您的数据库。

在您的知识库仓库中,创建一个名为 .github/workflows/generate_embeddings.yml 的新工作流,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
name: 'generate_embeddings'on: # 在 main 分支变更时运行 push: branches: - mainjobs: generate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: supabase/embeddings-generator@v0.0.x # 请更新至最新版本 with: supabase-url: 'https://your-project-ref.supabase.co' # 更新为您的项目URL supabase-service-role-key: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }} openai-key: ${{ secrets.OPENAI_API_KEY }} docs-root-path: 'docs' # 您的md(x)文件根目录路径

请确保选择最新版本,并在您的仓库设置中(settings > secrets > actions)将 SUPABASE_SERVICE_ROLE_KEYOPENAI_API_KEY 设置为仓库机密。

添加搜索界面

现在您需要在文档中创建一个搜索界面。由于这是一个无头(headless)界面,您可以使用任何语言实现。唯一的要求是将用户查询发送到query边缘函数,该函数将从OpenAI流式返回答案。实现可能如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const onSubmit = (e: Event) => { e.preventDefault() answer.value = "" isLoading.value = true const query = new URLSearchParams({ query: inputRef.current!.value }) const projectUrl = `https://your-project-ref.supabase.co/functions/v1` const queryURL = `${projectURL}/${query}` const eventSource = new EventSource(queryURL) eventSource.addEventListener("error", (err) => { isLoading.value = false console.error(err) }) eventSource.addEventListener("message", (e: MessageEvent) => { isLoading.value = false if (e.data === "[DONE]") { eventSource.close() return } const completionResponse: CreateCompletionResponse = JSON.parse(e.data) const text = completionResponse.choices[0].text answer.value += text }); isLoading.value = true}

相关资源