为文档添加生成式问答功能
学习如何使用我们的无头搜索工具包构建类似ChatGPT的文档搜索系统
Supabase 提供了一个无头搜索工具包,用于为您的文档添加"生成式问答"功能。该工具包是"无头"(headless)的,因此您可以将其集成到现有网站中,并按照网站主题进行样式匹配。
您可以在 Supabase 文档中看到实际效果。只需按下 cmd+k
并"询问"类似"Supabase 有哪些功能?"的问题。您将看到响应信息会实时流式返回,这些信息都来自文档提供的内容:
技术栈
- Supabase:数据库和边缘函数
- OpenAI:嵌入向量和补全功能
- GitHub Actions:用于导入您的 Markdown 文档
工具包组成
该工具包包含两部分:
- 无头向量搜索模板,您可以在自己的组织中部署
- GitHub Action,用于导入您的 Markdown 文件,将其转换为嵌入向量并存储到数据库中
使用步骤
在文档中构建相似性搜索需要三个步骤:
- 准备数据库
- 导入文档
- 添加搜索界面
准备数据库
准备工作包括创建一个新的Supabase项目并保存数据库和API凭证,这些信息可以在项目设置中找到。
现在我们可以按照无头向量搜索的说明来设置数据库:
- 将仓库克隆到本地机器:
git clone git@github.com:supabase/headless-vector-search.git
- 将仓库链接到远程项目:
supabase link --project-ref XXX
- 应用数据库迁移:
supabase db push
- 设置OpenAI密钥为机密:
supabase secrets set OPENAI_API_KEY=sk-xxx
- 部署边缘函数:
supabase functions deploy --no-verify-jwt
- 在Supabase仪表板的设置 >
API设置
>公开的schema
中暴露docs
schema
导入您的文档
现在我们需要将您的文档作为嵌入向量推送到数据库中。您可以手动完成此操作,但为了简化流程,我们创建了一个 GitHub Action,可以在每次有 Pull Request 时自动更新您的数据库。
在您的知识库仓库中,创建一个名为 .github/workflows/generate_embeddings.yml
的新工作流,内容如下:
1234567891011121314151617name: '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_KEY
和 OPENAI_API_KEY
设置为仓库机密。
添加搜索界面
现在您需要在文档中创建一个搜索界面。由于这是一个无头(headless)界面,您可以使用任何语言实现。唯一的要求是将用户查询发送到query
边缘函数,该函数将从OpenAI流式返回答案。实现可能如下所示:
12345678910111213141516171819202122232425262728293031const 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}
相关资源
- 阅读我们如何为Supabase文档构建ChatGPT
- 查阅pgvector文档了解嵌入和向量相似度
- 了解如何使用Next.js从头开始构建类似功能