# 自然语言搜索

大型语言模型(LLMs)最强大的能力之一,就是能够将自然语言转化为结构化数据。在本指南中,我们将学习如何利用这一能力来理解用户的搜索查询,并将其转换为结构化的Typesense搜索查询。

# 使用场景

我们以一个公开的汽车数据集 (opens new window)为例。结合Google的Gemini (opens new window) LLM和Typesense,我们可以支持如下自然语言查询:

  • 一辆本田或宝马,至少200马力,后轮驱动,价格2万到5万美元,必须是2014年以后的车
  • 给我看看你们动力最强的车
  • 高性能意大利车,700马力以上
  • 我不会开手动挡

注意这些查询中有些包含多个条件,有些情况下关键词本身可能并不存在于数据集中。

以下是该数据集的一个示例记录供参考:

{
  "city_mpg": 13,
  "driven_wheels": "rear wheel drive",
  "engine_cylinders": 8,
  "engine_fuel_type": "premium unleaded (recommended)",
  "engine_hp": 707,
  "highway_mpg": 22,
  "id": "1480",
  "make": "Dodge",
  "market_category": ["Factory Tuner", "High-Performance"],
  "model": "Charger",
  "msrp": 65945,
  "number_of_doors": 4,
  "popularity": 1851,
  "transmission_type": "AUTOMATIC",
  "vehicle_size": "Large",
  "vehicle_style": "Sedan",
  "year": 2017
}

# 数据流程

核心思路如下:

  1. 获取用户输入的自然语言查询
  2. 将其发送给LLM(大语言模型),附带具体指令要求将其转换为包含 filter_bysort_byq 搜索参数的Typesense查询
  3. 使用LLM返回的搜索参数在Typesense中执行查询并返回结果

我们本质上是在实现类似于"文本转SQL"的功能,只不过这里实现的是"文本转Typesense查询",执行查询并返回结果。

这个看似简单的概念能帮助构建强大的自然语言搜索体验。关键在于如何优化提示词,使其能稳定地将自然语言准确转换为合法的Typesense语法。

# 实时演示

以下视频展示了本指南将构建的效果:

你也可以在这里体验实时演示:https://natural-language-search-cars-genkit.typesense.org/ (opens new window)

接下来让我们看看如何端到端地构建这个应用。

# 项目设置

我们将使用 Next.js (opens new window)Genkit (opens new window) 框架,后者能让我们在应用中轻松集成生成式 AI 功能。

请按照 Genkit 文档 (opens new window) 中的说明学习如何在 Next.js 应用中初始化 Genkit。

接下来,让我们安装 Typesense 客户端到应用中:

npm i typesense@next

我们将使用的数据集可以从 Github (opens new window) 下载。

# 初始化 Typesense 客户端

我们需要两个独立的 Typesense API 密钥:

  • 一个仅用于前端搜索的 API 密钥
  • 一个具有写入权限的后端 API 密钥

请参考 API 密钥 文档了解如何生成仅搜索 API 密钥。

如果您使用 Typesense Cloud,请在集群页面点击"Generate API key"按钮。这将为您提供一组可用的主机名和 API 密钥。

# 创建 Typesense 集合

我们将使用以下模式创建一个 Typesense Collection(集合),并将汽车数据集导入其中:

现在我们已经准备好将数据集索引到刚创建的集合中:

# 编写提示词

我们的目标是将自然语言查询(如'最新款福特车低于4万美元')转换为Typesense的查询格式:

{
  "filter_by": "make:Ford && msrp:<40000",
  "sort_by": "year:desc"
}

在Genkit中,模型输出模式使用Zod定义。

我们可以通过在generate()中指定TypesenseQuerySchema来使LLM输出符合我们的模式: