统一 Elastic 向量数据库与 LLM 功能,实现智能查询

发布于:2025-03-18 ⋅ 阅读:(13) ⋅ 点赞:(0)

作者:来自 Elastic Sunile Manjee

利用 LLM 功能进行查询解析,并使用 Elasticsearch 搜索模板,将复杂的用户请求转换为结构化的、基于模式的搜索,从而实现高精度查询结果。

想象一下,你在搜索“距离 Belongil Beach 250 米内、最近翻新、至少 4 星级、配有游泳池和健身房的住宿”,而搜索引擎精准地返回了符合你需求的结果。智能搜索能够理解查询意图并进行推理,仅靠启发式方法难以实现这种能力。这正是大型语言模型(LLM)功能与 Elasticsearch 搜索模板结合,打造真正智能搜索体验的关键所在。

亲自体验

如果你对此存疑,不必担心。完整的端到端示例已在 Python notebook 中提供,包含数据、索引映射、推理端点、搜索模板和 LLM 功能。你需要一个 Elastic Cloud 实例、Azure OpenAI 实例和 Google Maps API 密钥。

问题:处理复杂约束

传统的搜索方法,如基于关键词或向量的检索,在面对包含多重细节的复杂查询时往往难以提供理想结果。例如,在酒店搜索场景中,用户可能希望:

  • 位置:距离 Belongil Beach 250 米以内
  • 评分:至少 4 星级
  • 设施:包括游泳池和健身房
  • 状态:最近翻新

使用简单的关键词匹配或相似度评分可能会导致搜索结果不完整或不相关,影响用户体验和信任度。

LLMs + Elasticsearch:基于模式的搜索

Elasticsearch 采用索引模式架构,在索引数据时定义了诸如 “rating - 评分”“ geopoint - 地理位置 ” “amenities - 设施” 等字段,使得搜索结果的筛选和排名更加精准。然而,这也要求查询语句具备相应的结构化格式。

这正是 LLM(如 GPT 系列或生成式模型)发挥作用的关键。LLM 可以解析用户的自然语言查询,提取关键信息(例如 “distance = 250m” “rating >= 4” “amenities = pool, gym”, “靠近 Belongil Beach” 等),并在检测到地理信息时调用地理编码服务。然后,LLM 生成一个 JSON 负载,将其插入 Elasticsearch 搜索模板 —— 这是一个参数化查询,将查询逻辑与动态值分离。

这种方法结合了 LLMs 的语义理解能力和 Elasticsearch 的基于模式的筛选与分面搜索能力,实现真正智能的搜索体验。

示例实际应用

假设用户的查询是:

“recently renovated accommodations 250m from Belongil Beach with at least 4 stars and with a pool and gym.”

  1. LLM 处理: LLM 分析文本,识别出需要一个基于距离的筛选(250 米)、最低评分(rating - 4 星)、相关设施(ameniteis - 游泳池、健身房),以及 “recently renovated - 最近翻新” 的上下文提示。它还调用地理编码服务获取 “Belongil Beach” 的精确纬度和经度坐标。
  2. 搜索模板: 你可以创建一个 Elasticsearch 搜索模板,该模板接受 rating、distance、latitude、longitude 以及可能的自由文本查询作为参数。一旦 LLM 提供这些参数,你的应用程序就可以填充占位符并调用 Elasticsearch。在这里,不仅可以利用过滤,还可以结合向量搜索、ELSER 和词法搜索进行混合查询。
  3. 搜索结果: 返回的响应精确匹配了符合以下条件的住宿:距离 Belongil Beach 250 米内、至少 4 星级、标记为最近翻新,并且配有游泳池和健身房。例如:
    • Hotel name: Belongil Beach Apartment
    • Rating: 4 星
    • City: Byron Bay,新南威尔士州
    • Country: 澳大利亚

相比单纯依赖向量空间或混合搜索,你可以输入精确的过滤条件,从而提高召回的全面性和精确度。

为什么这种方法有效

  • 精准度和召回率: 通过按照索引模式结构化查询,可以消除歧义,确保不会错过有效结果(高召回率),同时排除无关结果(高精准度)。相比之下,仅依赖向量空间可能缺乏自然的筛选功能。

  • 可扩展性: Elasticsearch 设计用于处理海量数据。一旦提取出查询参数,即使在超大索引上,查询依然保持极高的执行速度。

  • 灵活性: 如果出现新的属性(例如 “EV charging station”),LLM 仍能识别该属性作为酒店设施,并将其注入 Elasticsearch 搜索模板。

  • 复杂查询的适应性: 无论用户查询多么复杂,LLM 的语义解析都能确保捕捉所有相关细节,包括距离限制、星级评分、基于位置的条件等。

为什么使用搜索模板

Elasticsearch 搜索模板支持创建参数化查询,将查询逻辑与动态值分离。这在根据用户输入或其他可变数据构建动态查询时尤为重要。

例如,假设酒店索引包含以下字段:

  • Description
  • Attractions
  • Rating
  • Facilities
  • Location
    • Latitude
    • Longitude

用户可能在搜索查询中包含这些属性的任意组合。随着字段数量的增加,手动为每种可能的输入组合构建查询变得不可行。搜索模板通过根据用户输入动态生成适当的查询,解决了这一问题。例如:

  • 如果用户指定了 rating 和 attractions,则会生成相应的查询。
  • 如果用户提供了 location 和 rating,则搜索模板会生成匹配这些输入的查询。

搜索模板采用 JSON 格式定义,并包含用于动态值的占位符。在执行搜索模板时,Elasticsearch 会用实际值替换占位符并执行查询。

搜索模板可用于执行多种任务,例如:

  • 根据用户输入筛选结果
  • 提升特定结果的相关性
  • 添加自定义评分函数
  • 进行结果聚合

下面是一个示例搜索模板,它会根据输入参数动态创建查询。

{
    "script": {
        "lang": "mustache",
        "source": """{
            "_source": false,
            "fields": [
                "HotelName",
                "HotelRating",
                "countryName",
                "cityName",
                "countryCode",
                "Attractions"
            ],
            "retriever": {
                "standard": {
                    "query": {
                        "semantic": {
                            "field": "semantic_description_elser",
                            "query": "{{query}}"
                        }
                    },
                    "filter": {
                        "bool": {
                            "must": [
                                {{#distance}}
                                {
                                    "geo_distance": {
                                        "distance": "{{distance}}",
                                        "location": {
                                            "lat": {{latitude}},
                                            "lon": {{longitude}}
                                        }
                                    }
                                }
                                {{/distance}}

                                {{#rating}}{{#distance}},{{/distance}}
                                {
                                    "range": {
                                        "HotelRating": {
                                            "gte": {{rating}}
                                        }
                                    }
                                }
                                {{/rating}}

                                {{#countryName}}{{#distance}}{{^rating}},{{/rating}}{{/distance}}{{#rating}},{{/rating}}
                                {
                                    "term": {
                                        "countryName": "{{countryName}}"
                                    }
                                }
                                {{/countryName}}

                                {{#city}}{{#distance}}{{^rating}},{{/rating}}{{/distance}}{{#rating}},{{/rating}}
                                {
                                    "match": {
                                        "cityName": "{{city}}"
                                    }
                                }
                                {{/city}}

                                {{#countryCode}}{{#distance}}{{^rating}},{{/rating}}{{/distance}}{{#rating}},{{/rating}}
                                {
                                    "term": {
                                        "countryCode": "{{countryCode}}"
                                    }
                                }
                                {{/countryCode}}

                                {{#distance}}{{^rating}}{{/rating}}{{/distance}}{{#rating}}{{/rating}}
                            ],
                            "should": [
                                {{#attraction}}
                                {
                                    "wildcard": {
                                        "Attractions": {
                                            "value": "*{{attraction}}*",
                                            "case_insensitive": true
                                        }
                                    }
                                }
                                {{/attraction}}
                            ]
                        }
                    }
                }
            }
        }"""
    }
}

如果你想对 search template 有更深入的了解,请参考文章 “Elasticsearch:search template”。

LLM 功能

大型语言模型(LLM)具备强大的推理能力,可用于解析数据、调用 API 或请求额外信息,以确定最佳的下一步操作。当 LLM 与搜索模板结合时,它能够判断用户查询是否包含搜索模板支持的属性。如果识别出受支持的属性,LLM 将执行相应的用户定义方法调用。

Notebook 中,包含了一些 LLM 功能。每个功能都在工具列表(tools list)中进行了定义。

  tools = [
        {
            "type": "function",
            "function": { ...

让我们简要回顾每个功能。extract_hotel_search_parameters LLM 函数的作用是从用户查询中提取搜索模板支持的参数。

"type": "function",
            "function": {
                "name": "extract_hotel_search_parameters",
                "description": "Extract search parameters for finding hotels (excluding the query itself).  the parameters are extracted from the input query",

geocode_location LLM 函数将在识别出位置属性(例如 “500 meters from Belongil Beach”)时被调用。

{
    "type": "function",
    "function": {
        "name": "geocode_location",
        "description": "Resolve a location to its latitude and longitude.",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The name of the location, e.g., Belongil Beach."
                }
            },
            "required": ["location"]
        }
    }
}

LLM 函数 query_elasticsearch 将使用 geocode_location(如果在用户查询中找到)和 extract_hotel_search_parameters 提取的参数进行调用。

"type": "function",
            "function": {
                "name": "extract_hotel_search_parameters",
                "description": "Extract search parameters for finding hotels (excluding the query itself).  the parameters are extracted from the input query",

Completions API 将每个 LLM 函数注册为一个工具。本文前面已详细介绍了这些工具列表。

   while True:
        # Call the LLM with tools
        response = client.chat.completions.create(
            model=deployment_name,
            messages=messages,
            tools=tools,
            tool_choice="auto",
        )

Azure OpenAI

Notebook 使用 Azure OpenAI completions 模型运行。要运行它,你需要 Azure OpenAI 密钥(Key 1 或 Key 2)、端点(Endpoint)、部署名称(Deployment Name)和版本号(Version number)。所有这些信息都可以在 Azure OpenAI → Keys and Endpoint 下找到。

部署一个 completions 模型,该部署名称将在 Notebook 中使用。

在 Chat Playground 中,点击 View code 以查找 API 版本。

Google Maps API

该 Notebook 使用 Google Maps API 对用户查询中识别的位置进行地理编码。此功能需要一个 Google 账户和 API 密钥,可在此处生成。

将 LLM 功能与搜索模板付诸实践

LLM 通过推理确定所需的功能及其执行顺序,基于给定查询进行处理。例如,当执行查询 recently renovated accommodations 250m from Belongil Beach with at least 4 stars and with a pool and gym 时,LLM 的推理层被激活:

提取参数

初始 LLM 函数调用旨在从查询中提取参数。

Role: assistant
Tool Calls:
  Tool Call ID: call_VHhjy0TMxPnefibSssrTa5r0
  Function Name: extract_hotel_search_parameters
  Arguments: {"query":"recently renovated accommodations 250m from Belongil Beach with at least 4 stars and with a pool and gym","distance":"250m","rating":4,"location":"Belongil Beach","attraction":"recently renovated, pool, gym"}

地理编码

LLM 随后判断查询包含 “from” 位置,并确定应调用地理编码函数。

--------------------------------------------------
Updated parameters after geocode_location:
{'query': 'recently renovated accommodations 250m from Belongil Beach with at least 4 stars and with a pool and gym', 'distance': '250m', 'rating': 4, 'location': 'Belongil Beach', 'attraction': 'recently renovated, pool, gym', 'latitude': -28.6337328, 'longitude': 153.6003455}

Formatted Messages:
Message 1:
Role: assistant
Tool Calls:
  Tool Call ID: call_jr4jJ04lW0y0E2AKnVmNumyh
  Function Name: query_elasticsearch
  Arguments: {"query":"recently renovated accommodations 250m from Belongil Beach with at least 4 stars and with a pool and gym","latitude":-28.6337328,"longitude":153.6003455,"distance":"250m","rating":4,"attraction":"recently renovated, pool, gym"}

--------------------------------------------------

智能查询

LLM 的推理层利用先前函数调用提取的参数,结合搜索模板执行 Elasticsearch 查询。

--------------------------------------------------
Function Arguments for query_elasticsearch:
{'query': 'recently renovated accommodations 250m from Belongil Beach with at least 4 stars and with a pool and gym', 'latitude': -28.6337328, 'longitude': 153.6003455, 'distance': '250m', 'rating': 4, 'attraction': 'recently renovated, pool, gym'}
Parameters for Elasticsearch:
{'query': 'recently renovated accommodations 250m from Belongil Beach with at least 4 stars and with a pool and gym', 'latitude': -28.6337328, 'longitude': 153.6003455, 'distance': '250m', 'rating': 4, 'attraction': 'recently renovated, pool, gym'}
Elasticsearch Query:
{
  "id": "hotel_search_template",
  "params": {
    "query": "recently renovated accommodations 250m from Belongil Beach with at least 4 stars and with a pool and gym",
    "latitude": -28.6337328,
    "longitude": 153.6003455,
    "distance": "250m",
    "rating": 4,
    "attraction": "recently renovated, pool, gym"
  }
}
Elasticsearch query successful.

精准结果

通过 LLM 功能与搜索模板执行智能查询,成功找到完美匹配的结果。

Number of results found: 1

Formatted Messages:
Message 1:
Role: assistant
Content: I found one recently renovated accommodation within 250 meters of Belongil Beach that has at least 4 stars and offers both a pool and gym:

- **Hotel Name:** Belongil Beach Apartment
- **Rating:** 4 stars
- **Location:** Byron Bay, New South Wales, Australia

If you need more information or assistance with booking, please let me know!

结论

将大型语言模型(LLM)功能与 Elasticsearch 搜索模板相结合,实现了对查询意图的理解和推理能力。与其将查询视为一段无结构的文本,我们通过系统性拆解,将其匹配到已知的模式,并让 Elasticsearch 负责搜索、筛选和评分的核心工作。最终,用户获得了一种高度精准且友好的搜索体验 —— 他们只需输入需求,系统便能准确理解其意图。

立即体验向量搜索!你可以通过 Search AI自学实践课程进行操作,也可以选择启动免费的云试用,或在本地机器上尝试 Elastic。

原文:Unifying Elastic vector database and LLM functions for intelligent query - Elasticsearch Labs