dot Redis 8 来了,而且它是开源的

了解更多

使用 Kernel Memory 和 Redis 构建 LLM 应用

Redis 现已集成 Kernel Memory,使任何开发人员都能使用 Semantic Kernel 构建高性能 AI 应用。

Semantic Kernel 是 Microsoft 的开发者工具包,用于将 LLM 集成到你的应用中。你可以将 Semantic Kernel 视为一种操作系统,其中 LLM 是 CPU,LLM 的上下文窗口是 L1 缓存,而你的向量存储是 RAM 中的内容。Kernel Memory 是 Semantic Kernel 的一个组件项目,充当内存控制器,而这正是 Redis 发挥作用的地方,它充当物理内存。

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

在本文中,我们将看到使用 Semantic Kernel 和 Redis 构建 AI 聊天应用是多么容易。

操作模式

你可以通过两种方式运行 Kernel Memory

  1. 直接在你的应用内部运行
  2. 作为独立服务运行

如果你在应用内部直接运行 Kernel Memory,你会局限于 .NET 生态系统(这对这个 .NET 开发人员来说不是什么大问题),但将 Kernel Memory 作为独立服务运行的好处是它可以被任何能够发出 HTTP 请求的语言调用。

运行示例

为了说明 Kernel Memory 的平台中立性,我们提供了两个示例,一个用 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 Stack
  4. Kernel Memory 作为其自身的独立服务
OpenAIApiKey=<YOUR_OPENAI_API_KEY> docker compose up

向 Kernel Memory 添加数据

我们有一个预构建的啤酒信息数据集,可以将其添加到 Kernel Memory(并向其询问推荐)。要添加该数据集,只需运行

./common/scripts/setup_beers.sh

访问前端

要访问前端,请导航到 http://localhost:3000. 从那里,你可以向机器人询问推荐

这都如何工作?

此演示包含几个部分

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

Redis 已启用向量数据库,这是 Redis、Redis CloudAzure Cache for Redis(企业层)提供的一项功能。这些选项中的任何一个都可以工作。我们的前端是一个简单的 React 应用。Kernel Memory 需要一些配置,我们将在下面介绍。插件和 HTTP 调用驱动我们的后端,所以我们也将介绍这一点。 

配置 Kernel Memory

要让 Kernel Memory 使用 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 对象列出了 Kernel Memory 中 Redis 连接器的重要配置参数

  • ConnectionString 是一个 StackExchange.Redis 连接字符串,它告诉如何连接到 Redis。
  • Tags 告诉 Kernel Memory 你可能希望根据哪些可能的标签进行过滤,并提供可选的分隔符,以便你遵循 Redis 标签语义
  • AppPrefix 允许你为 Kernel Memory 提供一个应用前缀,这样你就可以让多个 Kernel Memory 应用使用同一个 Redis 数据库。

与 Kernel Memory 交互

与 Kernel Memory 打交道,主要有两件事要完成

  1. 添加数据
  2. 查询数据

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

要与 Kernel Memory 交互,使用 HTTP 接口。此接口有几种前端方式

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

向 Kernel Memory 添加文档

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

[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 中,目前还没有 Kernel Memory 客户端(尚未提供),但你可以直接使用 Upload endpoint

@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}

查询 Kernel Memory

要查询 Kernel Memory,可以使用 Search 或 Ask endpoint。Search endpoint 会对索引进行搜索,并返回最相关的文档给你,而 Ask endpoint 会执行搜索并将结果导入 LLM。

从提示词调用

Kernel Memory 的 .NET 客户端带有自己的插件,允许你从提示词中调用它

{{$systemPrompt}}


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


Result:{{memory.ask $intent}}

上述提示词将根据提供的系统提示词(以及管道早期从聊天历史记录和最新消息生成的意图)总结对 Kernel Memory 的 Ask endpoint 的响应。要让插件本身工作,你需要将 Memory Plugin 添加到 kernel 中。以下是 .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");

这将 Kernel Memory 注入 DI container,然后添加 Semantic Kernel,最后将来自 Kernel Memory Client 的 MemoryPlugin 添加到 Semantic Kernel。

从 HTTP 端点调用

自然地,你也可以从 HTTP 端点调用这些查询函数。在 Python 示例中,我们只是调用 Search endpoint(然后格式化结果)

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 提供了一种直接的方式来管理语义计算的构建模块,Kernel Memory 提供了一种直观且灵活的方式来与 Semantic Kernel 的内存层交互。正如我们在此观察到的,将 Kernel Memory 与 Redis 集成就像在配置文件中添加几行代码一样简单。