作者:来自 Elastic Aurélien Foucret
发现如何使用 ES|QL COMPLETION 命令,通过一个 LLM 在几行代码中将你的 Elasticsearch 数据转化为创意输出。
Elasticsearch 有对行业领先的 Gen AI 工具和服务商的原生集成。查看我们的网络研讨会,了解如何超越 RAG 基础,或使用 Elastic Vector Database 构建生产级应用。
为了为你的用例构建最佳搜索解决方案,可以立即开始免费的 cloud 试用,或者在本地机器上尝试 Elastic。
如果你能只用几行代码,就把 Elasticsearch 数据转化为创意输出,会怎么样?借助 ES|QL 中的新 COMPLETION 命令,现在你可以做到。
我们来构建一个有趣的东西来展示它:Chuck Norris 事实生成器。我们会结合电影描述和 GPT 模型来生成连 Rambo 都会惊叹的传奇事实。
你需要准备什么
-
一个 LLM(比如我们下面示例中的 OpenAI 的 GPT-4o)
-
一份电影描述的数据集
你可以从 Kaggle 下载一个示例数据集,并使用 Kibana 中的 Data Visualizer 或 _bulk API上传到你的 Elasticsearch 集群。
设置 inference endpoint
在你能运行 COMPLETION 命令之前,你需要通过 _inference API 为你要用的模型创建一个 inference endpoint。
以下是如何用 OpenAI 设置 GPT-4o 的方法:
PUT _inference/completion/my-gpt-4o-endpoint
{
"service": "openai",
"service_settings": {
"api_key": "<your_api_key>",
"model_id": "gpt-4o-2024-11-20"
}
}
一旦完成这些,你就可以在查询中直接引用 my-gpt-4o-endpoint
。
查询
神奇的地方就在这里。这个单一的 ES|QL 查询处理了整个工作流:它会根据你的输入找到一部电影,从它的描述中构建提示词,然后调用 LLM 生成一个传奇的 Chuck Norris 笑话。下面是支持我们 Chuck Norris 笑话生成器的完整 ES|QL 查询。它接受一个电影查询,检索最相关的描述,把它转化为提示词,并在一个管道式的查询中发送给 LLM。
POST _query
{
"query": """
FROM movies METADATA _score
| WHERE MATCH(title, ?query) OR MATCH(overview, ?query)
| SORT _score DESC
| LIMIT 1
| EVAL prompt=CONCAT(?instruction, overview)
| COMPLETION chuck_norris_fact = prompt WITH { "inference_id": "my-gpt-4o-endpoint" }
| KEEP title, overview, chuck_norris_fact
""",
"params": [
{ "instruction": "Generate a Chuck Norris Fact from the following description:\\\n" },
{ "query": "rambo III" }
]
}
返回的结果如下:
{
"took": 1626,
"is_partial": false,
"documents_found": 1,
"values_loaded": 2,
"columns": [
{
"name": "title",
"type": "text"
},
{
"name": "overview",
"type": "text"
},
{
"name": "chuck_norris_fact",
"type": "keyword"
}
],
"values": [
"Rambo III",
"Combat has taken its toll on Rambo, but he's finally begun to find inner peace in a monastery. When Rambo's friend and mentor Col. Trautman asks for his help on a top secret mission to Afghanistan, Rambo declines but must reconsider when Trautman is captured.",
"Chuck Norris once entered a monastery to find inner peace—five minutes later, he left because the monks couldn't handle his level of enlightenment. When Chuck heard Rambo needed help in Afghanistan, Chuck rescued Trautman, won the war, and trained a goat to ride a helicopter, all before Rambo finished tying his bandana."
]
}
是的,模型真的这么说了。💪🐐🚁
解析查询
让我们逐步解析查询并拆解发生的事情。
步骤 1:检索相关的电影数据
我们从为用户查询搜索最相关的电影开始。
我们使用 MATCH 函数在 title 和 overview 字段中搜索由查询参数提供的文本,只保留第一个结果,并使用 metadata _score 字段按相关性排序:
FROM movies METADATA _score
| WHERE MATCH(title, ?query) OR MATCH(overview, ?query)
| SORT _score DESC
| LIMIT 1
这将把我们的数据集缩小到最佳匹配,得到电影的标题和描述,这些将成为 LLM 的上下文。
步骤 2:从上下文构建提示
现在我们通过把作为查询参数提供的静态指令(用 ?instruction 表示)与电影的 overview 拼接起来,为 LLM 创建输入提示:
| EVAL prompt = CONCAT(?instruction, overview)
这会创建一个新的 prompt 列,将提供的指令与返回文档的 overview 字段结合起来,对于我们的请求看起来大致如下:
Generate a Chuck Norris Fact from the following description:
Combat has taken its toll on Rambo, but he's finally begun to find inner peace in a monastery. When Rambo's friend and mentor Col. Trautman asks for his help on a top secret mission to Afghanistan, Rambo declines but must reconsider when Trautman is captured.
你可以轻松更换不同的指令,通过调整 instruction 参数来改变 LLM 生成内容的语气或风格。而且因为 prompt 只是另一个 ES|QL 表达式,你可以用任何生成字符串的函数来组合它——无论是简单拼接、条件逻辑,还是根据文档内容进行格式化。
步骤 3:使用 LLM 生成文本
最后,我们使用新的 COMPLETION 命令,将 prompt 传给连接到模型的 inference endpoint,并选择要返回的字段:
| COMPLETION chuck_norris_fact = prompt WITH { "inference_id": "my-gpt-4o-endpoint" }
| KEEP title, overview, chuck_norris_fact
结果?一个 Chuck Norris 事实,基于你的电影数据生成,无需额外工具。
这个示例也展示了 ES|QL 管道结构的全部威力。每一步自然衔接到下一步,让你可以在一个声明式查询中表达完整的检索增强生成(retrieval augmented generation - RAG)流程。它干净、可组合,并且完全在 Elasticsearch 内部运行。
接下来做什么?
虽然 COMPLETION 命令仍处于技术预览阶段,这个新功能开启了全新的可能性 —— 从摘要和内容生成,到丰富信息和讲故事。自己试试吧!指向你最喜欢的电影,调整 prompt,或者随心所欲地从 SQL 错误生成俳句。力量掌握在你手中。
告诉我们你构建了什么!💬