dot 未来将以超快速度降临您所在的城市。

加入我们参加 Redis 发布会

使用内核内存和 Redis 构建 LLM 应用程序

Redis 现在与内核内存集成,允许任何开发人员使用 Semantic Kernel 构建高性能 AI 应用程序。

Semantic Kernel 是微软的开发者工具包,用于将 LLM 集成到您的应用程序中。您可以将 Semantic Kernel 视为一种操作系统,其中 LLM 是 CPU,LLM 的上下文窗口是 L1 缓存,您的向量存储是 RAM 中的内容。 内核内存 是 Semantic Kernel 的一个组件项目,充当内存控制器,而 Redis 在此处发挥作用,充当物理内存。

作为一项 AI 服务,内核内存允许您索引和检索非结构化的多模态数据。您可以使用 KM 轻松实现常见的 LLM 设计模式,例如检索增强生成 (RAG)。当您的应用程序需要高性能和可靠性时,Redis 是内核内存后端的自然选择。

在这篇文章中,我们将了解如何使用 Semantic Kernel 和 Redis 轻松构建 AI 聊天应用程序。

操作模式

您可以通过两种方式运行内核内存

  1. 直接在您的应用程序中
  2. 作为独立服务

如果您直接在应用程序中运行内核内存,您将被限制在 .NET 生态系统中(对于 .NET 开发人员来说这不是什么大问题),但将内核内存作为独立服务运行的优势在于,任何能够发出 HTTP 请求的语言都可以访问它。

运行示例

为了说明内核内存的平台中立性,我们提供了两个示例,一个是用 Python 编写的,另一个是用 .NET 编写的。在实践中,任何可以运行 HTTP 服务器的语言都可以轻松地替换为运行此示例。

克隆示例

要克隆 .NET 示例,请运行以下命令

git clone --recurse-submodules https://github.com/redis-developer/redis-rag-chat-dotnet

要克隆 python 示例,请运行

git clone --recurse-submodules https://github.com/redis-developer/redis-rag-chat-python

运行示例

这些示例应用程序依赖于 OpenAI 的完成和嵌入 API。首先,获取 OpenAI API 密钥。然后将 API 密钥传递给 docker-compose。这将启动

  1. 前端服务(用 react 编写的)
  2. 后端 Web 服务(用 .NET 或 Python 编写的,取决于您使用的存储库)
  3. Redis 堆栈
  4. 内核内存作为独立服务
OpenAIApiKey=<YOUR_OPENAI_API_KEY> docker compose up

向内核内存添加数据

我们有一个预构建的啤酒信息数据集,我们可以将其添加到内核内存中(并要求其提供推荐)。要添加该数据集,只需运行

./common/scripts/setup_beers.sh

访问前端

要访问前端,请导航到 https://#:3000。从那里,您可以向机器人请求推荐

这一切是如何运作的?

此演示包含几个部分

  1. Redis
  2. 我们的 React 前端,提供了一个简单的聊天界面
  3. 内核内存
  4. 后端,维护聊天会话,搜索内核内存,并为 LLM 构建提示

Redis 启用了向量数据库,这是 Redis、Redis 云Azure 缓存 for Redis(企业版) 提供的功能。这些选项中的任何一个都可以使用。我们的前端是一个简单的 React 应用程序。内核内存需要一些配置,我们将在下面介绍。插件和 HTTP 调用驱动我们的后端,因此我们也将介绍它们。

配置内核内存

要使用 Redis 启动并运行内核内存,您需要对以下内容进行一些小的更新

common/kernel-memory/appsettings.json file. Start with the template 
common/kernel-memory/appsettings.json. 
Rename this file to appsettings.json. 

请注意,在此文件中有一个 Retrieval 对象

"Retrieval": {
 "MemoryDbType": "Redis",
 "EmbeddingGeneratorType": "OpenAI",
 "SearchClient": {
   "MaxAskPromptSize": -1,
   "MaxMatchesCount": 100,
   "AnswerTokens": 300,
   "EmptyAnswer": "INFO NOT FOUND"
 }
}

这会告诉检索器使用哪个 Embedding Generator(OpenAI)以及使用哪个 MemoryDbType(Redis)。

还有一个 Redis 对象:

"Redis": {
 "Tags": {
   "user": ",",
   "email": "|"
 },
 "ConnectionString": "redis-km:6379",
 "AppPrefix":"redis-rag-chat-"
}

此 Redis 对象映射出内核内存中 Redis 连接器的重要配置参数

  • ConnectionString 是一个 StackExchange.Redis 连接字符串,它告诉它如何连接到 Redis。
  • Tags 告诉内核内存您可能想要过滤的哪些可能的标签,并提供可选的分隔符,以便您能够遵循 Redis 标签语义
  • AppPrefix 允许您为内核内存提供应用程序前缀,这样您就可以让多个内核内存应用程序使用同一个 Redis 数据库。

与内核内存交互

我们基本上想对内核内存做两件事

  1. 添加记忆
  2. 查询记忆

当然,内核内存还有更多功能,包括信息提取、分区、管道、嵌入生成、摘要等等,但我们已经配置了所有这些功能,并且它们都用于这两个目标。

要与内核内存交互,您可以使用 HTTP 接口。该接口有几个前端

  1. 在 Semantic Kernel 插件中
  2. 使用 IKernelMemory 接口(在 .NET 中)
  3. 直接使用 Http 端点

将文档添加到内核内存

要上传文档,请调用 IKernelMemory 的一个 Import 函数。在 .NET 示例中,我们使用了一个简单的文档导入,使用文件流,但您也可以导入网页和文本

[HttpPost("upload")]
public async Task<IActionResult> AddDocument(IFormFile file)
{
   await using var fileStream = file.OpenReadStream();
   var document = new Document().AddStream(file.FileName, fileStream);
   var res = await _kernelMemory.ImportDocumentAsync(document);
   return Ok(res);
}

在 Python 中,还没有内核内存客户端,但您可以简单地使用 Upload 端点

@app.post("/documents/upload")
async def upload_document(file: UploadFile = File(...)):
   file_content = await file.read()


   data = {
       "index": "km-py",
       "id": str(uuid.uuid4())
   }
   files = {'file': (file.filename, file_content, file.content_type)}


   response = requests.post(f"{kernel_memory_url}/upload", files=files, data=data)
   response.raise_for_status()
   return {"status": response.status_code, "response_data": response.text}

查询内核内存

要查询内核内存,您可以使用 Search 或 Ask 端点。Search 端点会对索引进行搜索,并返回与您最相关的文档,而 Ask 端点会执行搜索,然后将结果传递到 LLM。

从提示调用

内核内存 .NET 客户端带有它自己的插件,允许您从提示调用它

{{$systemPrompt}}


The following is the answer generated by kernel memory, put it into your own words:


Result:{{memory.ask $intent}}

上面的提示将总结对内核内存 Ask 端点的响应,该响应基于提供的系统提示(以及从聊天历史记录和管道中更早的最新消息生成的意图)。要使该插件本身正常工作,您需要将 Memory Plugin 添加到内核。以下是 .NET 项目的 Program.cs 中的一些摘录

var kmEndpoint = builder.Configuration["KernelMemoryEndpoint"];  
var kernelMemory = new MemoryWebClient(kmEndpoint);
builder.Services.AddSingleton(kernelMemory);
var kernelBuilder = builder.Services.AddKernel();
kernelBuilder.AddOpenAIChatCompletion(builder.Configuration["OpenAICompletionModelId"]!, builder.Configuration["OpenAIApiKey"]!);
kernelBuilder.Plugins.AddFromObject(new MemoryPlugin(kernelMemory), "memory");

这会将内核内存注入 DI 容器,然后添加 Semantic Kernel,最后将 MemoryPlugin 从内核内存客户端添加到 Semantic Kernel。

从 HTTP 端点调用

当然,您也可以从 HTTP 端点调用这些查询函数。在 Python 示例中,我们只调用了 search 端点(然后格式化结果)

def get_memories(question: str) -> str:
   data = {
       "index": "km-py",
       "query": question,
       "limit": 5
   }


   response = requests.post(f"{kernel_memory_url}/search", json=data)


   if response.status_code == 200:
       response_json = response.json()
       memories = response_json.get('results',[])
   res = ""
       for memory in memories:
           res += "memory:"
           for partition in memory['partitions']:
               res += partition['text']
           res += '\n'
       print(res)
       return res


   raise Exception(response.text)

然后可以将这些记忆馈送到我们的 LLM,以便在回答问题时提供更多上下文。

总结

Semantic Kernel 提供了一种简单的方法来管理语义计算机的构建块,而内核内存提供了一种直观且灵活的方式来与 Semantic Kernel 的内存层交互。正如我们在这里所观察到的,将内核内存与 Redis 集成就像在配置文件中添加几行代码一样简单。