作者:来自 Elastic Lionel Palacin
在此博客中,我们将探讨如何通过利用大型语言模型 (LLM) 和检索增强生成 (RAG) 等技术实施对话式搜索来增强你的客户成功应用程序。
你将了解对话式搜索在客户成功应用程序环境中的优势,以及如何使用 Elasticsearch 有效地实施它。
简介
什么是客户成功应用程序
客户成功应用程序是一种允许客户自助查找支持信息的工具,这样他们就可以在需要时获得答案,并可以最大限度地提高他们使用的产品或服务的价值,并帮助他们最大限度地提高产品或服务的价值。想象一下,你正在预订网站上计划一次旅行,有一个专门的部分可以帮助你解决有关你计划的旅行的任何问题或疑问,以及联系支持人员以获得进一步帮助的选项。这就是客户成功应用程序的作用 —— 它让客户满意并确保他们对你的服务有成功的体验。
什么是 AI 对话式搜索
AI 对话式搜索允许用户使用自然语言与你的应用程序进行交互,就像与人交谈一样。该技术可以理解用户查询、检索相关信息并实时提供准确的上下文感知响应,使搜索体验更加直观和高效。
从技术角度来看,AI 对话式搜索结合了大型语言模型 (LLMs) 和检索增强生成 (RAG) 的强大功能。LLMs 能够根据大量训练数据理解和生成类似人类的文本。RAG 通过集成检索系统来增强此功能,该系统从预定义、实时和特定领域的数据集中提取相关信息,确保响应既准确又与上下文相关。
AI 对话式搜索对客户成功应用程序的好处
与传统的搜索栏体验相比,AI 对话式搜索使客户成功应用程序更加用户友好且更有帮助。它允许客户自然地提出问题并获得快速、个性化的答案,从而节省他们的时间和挫败感。此外,如果第一个答案不令人满意或他们需要更多解释,他们可以提出后续问题。
总体而言,AI 对话式搜索为客户创造了更好的体验,让他们感到被重视,并根据他们的需求为他们提供规范指导。
AI 对话式搜索的实现
在下一部分中,我们将介绍从头开始构建 AI 对话式搜索应用程序的不同步骤。
高层架构
从高级架构的角度来看,AI 对话式搜索体验的核心是 RAG 应用程序,它具有先进的检索系统(在我们的例子中是 Elasticsearch)和对话式界面。
数据收集和预处理
根据定义,客户成功应用程序环境中的 AI 对话式搜索体验需要访问专有数据。这些数据代表了你所提供的服务所特有的知识。
首先,你需要确定数据的来源,例如内部知识库、常见问题解答和文档。接下来,你需要构建一个数据管道,将这些数据带入检索系统,并准备将其用于 RAG 应用程序。
使用 Elasticsearch,你可以从任何地方提取任何类型的数据,无论是非结构化数据还是非结构化数据。查看此博客,其中解释了根据你使用 Elasticsearch 的情况使用哪种提取方法。
此外,数据需要进行转换才能在我们的 AI 对话式搜索应用中有效使用。我们希望用户使用自然语言提问,因此检索系统需要支持高级搜索技术,例如语义和混合搜索,以检索最相关的信息。这需要在段落中分块长文本并生成密集或稀疏的向量嵌入,然后再将它们索引到 Elasticsearch 中。这一切都可以在 Elasticsearch 中作为数据管道的一部分完成。查看此博客,其中介绍了如何利用 Elasticsearch 中的索引映射自动转换数据。
设置 Elasticsearch
开始使用 Elasticsearch 的最简单方法是创建一个 serverless 项目。按照此处描述的步骤,在几秒钟内即可完成 Elasticsearch 部署。
在接下来的步骤中,你将需要 Elasticsearch API 密钥和 Elasticsearch URL 端点。因此请确保检索它们。
设置数据管道
在此博客中,我们将使用示例数据集来实现我们的 AI 对话式搜索示例,并使用 Python 代码将其提取到索引 search-faq 中。
我们还想准备数据以支持语义搜索。为此,我们将利用 Elasticsearch serverless 开箱即用的 E5 多语言模型来生成向量嵌入。
第一步是准备索引映射以存储我们将提取的数据。请注意,名为 semantic 且类型为 semantic_text 的字段是将从 content 字段的内容自动生成嵌入的字段(请注意 copy_to 选项)。
让我们看看这个的 Python 代码。
from elasticsearch_serverless import Elasticsearch
import json
import os
client = Elasticsearch(
os.getenv("ELASTICSEARCH_URL"),
api_key=os.getenv("ES_API_KEY"),
request_timeout=600
)
mappings={"properties":{"semantic":{"type":"semantic_text","inference_id":"e5-small"},"content":{"type":"text","copy_to":"semantic"}}}
# Create index
client.indices.create(index="search-faq", mappings=mappings)
接下来,我们需要创建一个 inference service 来操作 E5 多语言 ML 模型。
inference_config={"service":"elasticsearch","service_settings":{"num_allocations":1,"num_threads":1,"model_id":".multilingual-e5-small"}}
# Create inference
client.inference.put(inference_id="e5-small", task_type="text_embedding", inference_config=inference_config)
现在数据管道已准备就绪。它将在摄取时自动为每个文档生成向量嵌入。
with open("faq.json") as f:
documents = json.load(f)
def generate_docs():
index_name = "search-faq"
for row in documents:
yield { "index" : { "_index" : index_name } }
yield row
client.bulk(operations=generate_docs())
使用 Next.Js 创建应用程序
现在我们的检索系统已经准备就绪,我们将构建一个简单的聊天界面供用户交互。
此应用程序的灵感来自此处记录的 Vercel RAG 示例。
首先,初始化 Next.JS 应用程序。
pnpm create next-app@latest chat-example --ts --tailwind --app --no-eslint --no-src-dir --no-import-alias
然后导航到应用程序文件夹 chat-example。
cd chat-example
让我们添加一个 API 路由来实现 RAG 应用程序的逻辑。聊天前端将使用用户问题调用此 API。接下来,使用语义搜索从 Elasticsearch 检索相关文档。从返回的文档生成上下文窗口,OpenAI 使用该窗口向用户提供有意义的答案。
创建一个新文件 app/api/chat/route.ts 并开始编辑它。
首先让我们添加导入并初始化 Elasticsearch 客户端连接
import { openai } from '@ai-sdk/openai';
import { convertToCoreMessages, streamText, tool } from 'ai';
const { Client } = require('@elastic/elasticsearch-serverless')
import { z } from 'zod';
const client = new Client({
node: process.env.ELASTICSEARCH_URL, // serverless project URL
auth: { apiKey: process.env.ES_API_KEY }, // project API key
})
然后我们声明一个使用语义搜索查询 Elasticsearch 的函数。
// Retrieve relevant content from the knowledge base
async function findRelevantContent(question: string) {
// Semantic search query
const body = await client.search({
size: 3,
index: 'search-faq',
body: {
query: {
semantic: {
field: "semantic",
query: question
}
}
}
});
return body.hits.hits.map((hit: any) => ({
content: hit._source.content
}));
}
最后,我们声明处理路由 POST 调用的主函数。此函数检索用户问题,使用 findRelevantContent 函数从 Elasticsearch 检索文档,然后构建上下文窗口,将其传递给 LLM,然后将答案流回客户端。
export async function POST(req: Request) {
const { messages } = await req.json();
const result = await streamText({
model: openai('gpt-4-turbo'),
system: `You are a customer service assistant, please be concise in your answer. Check your knowledge base before answering any questions.
Only respond to questions using information from tool calls.
if no relevant information is found in the tool calls, respond, "Sorry, I don't know."`,
messages: convertToCoreMessages(messages),
tools: {
getInformation: tool({
description: `get information from your knowledge base to answer questions.`,
parameters: z.object({
question: z.string().describe('the users question'),
}),
execute: async ({ question }: { question: string }) => findRelevantContent(question),
}),
},
});
// Respond with the stream
return result.toAIStreamResponse();
}
现在让我们编辑前端以显示一个简单的聊天界面。打开文件 app/page.tsx 并将现有内容替换为以下内容:
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
maxToolRoundtrips: 2,
});
return (
<div className="flex flex-col w-full max-w-md py-24 mx-auto stretch">
<div className="space-y-4">
{messages.map(m => (
<div key={m.id} className="whitespace-pre-wrap">
<div>
<div className="font-bold">{m.role}</div>
<p>
{m.content.length > 0 ? (
m.content
) : (
<span className="italic font-light">
{'calling tool: ' + m?.toolInvocations?.[0].toolName}
</span>
)}
</p>
</div>
</div>
))}
</div>
<form onSubmit={handleSubmit}>
<input
className="fixed bottom-0 w-full max-w-md p-2 mb-8 border border-gray-300 rounded shadow-xl"
value={input}
placeholder="Ask your question..."
onChange={handleInputChange}
/>
</form>
</div>
);
}
默认情况下,项目使用深色主题创建。为了便于示例,我们来简化一下,打开文件 app/globals.css 并仅保留以下内容:
@tailwind base;
@tailwind components;
@tailwind utilities;
让我们测试一下我们的应用程序。在运行应用程序之前,导出以下环境变量:
# Export the URL of your Elasticsearch deployment
export ELASTICSEARCH_URL=<es_url>
# Export your Elasticsearch API Key
export ES_API_KEY=<es_api_key>
# Export your OpenAI API Key
export OPENAI_API_KEY=<openai_api_key>
安装项目依赖项:
pnpm install ai @ai-sdk/openai zod @elastic/elasticsearch-serverless
最后,在本地运行该应用程序:
yarn dev
就这样,你构建了第一个 AI 对话搜索!
该示例的工作代码可以在 Github 中找到。
结论
在本文中,你了解了在构建客户成功应用程序时使用 AI 对话式搜索相对于传统搜索体验的优势。然后,你看到了有关如何使用 Elasticsearch、OpenAI 和 Next.JS 构建 AI 对话式搜索的端到端指南。使用本教程开始使用生成式 AI 和 Elasticsearch 增强客户体验。你还可以查看 Kibana 中的 Playground 以快速开始对话式搜索。
准备好自己尝试了吗?开始免费试用。
希望将 RAG 构建到你的应用程序中?想要尝试使用矢量数据库的不同 LLM?
在 Github 上查看我们针对 LangChain、Cohere 等的示例笔记本,并立即加入 Elasticsearch Relevance Engine 培训。
原文:Build a Conversational Search for your Customer Success Application with Elasticsearch and OpenAI — Search Labs