技术速递|利用 Redis 使 AI 驱动的 .NET 应用程序更加一致和智能

news2024/10/7 18:25:08

作者:Catherine Wang
排版:Alan Wang

Redis 是一种流行的内存数据存储,可用于解决构建和扩展智能应用程序的关键挑战。在本文中,你将了解如何使用 Redis 的 Azure 缓存来提高使用 Azure OpenAI 的应用程序的效率。

Redis 的 Azure 缓存不受最近的 Redis 许可证更新的影响:

“我们将持续的合作以确保 Azure 客户能够无缝地利用 Azure Cache for Redis 的所有层级。Azure Cache
for Redis、Azure Cache for Redis Enterprise 和 Enterprise Flash
服务不会中断,客户将收到及时的更新和错误修复,以保持最佳性能。” – Julia Liuson,开发部总裁

本博客包括两个示例应用程序:

第一个是基于 .NET 揭秘检索增强生成的演示聊天 Semantic Kernel 应用程序。我添加了使用 Redis 保存额外知识并启用聊天历史记录的功能。完整示例位于 Chat App with Redis。
第二个是一个演示应用程序,它在 .NET 8 中使用 Redis OM dotnet 进行 Redis 输出缓存,以提高生成式 AI 的一致性和弹性。完整示例位于 OpenAI 的输出缓存中。

Redis 为 OpenAI 模型提供了额外的知识

像 GPT 这样的 OpenAI 模型在大多数情况下都经过训练且知识渊博,但它们无法了解您公司的内部文档或最近的博客文章。这就是为什么您需要 Redis 作为附加知识的语义内存存储。

语义内存存储有两个基本要求:

  1. 智能应用程序无法直接读取文本 blob、图像、视频等非结构化数据。语义内存存储需要支持向量嵌入的有效保存。
  2. 智能应用程序需要执行总结、比较、异常检测等任务。语义内存存储需要支持搜索功能。这意味着用于查找相关数据的索引、距离算法和搜索查询。

Redis Enterprise 提供了 RediSearch 模块来满足这些需求。您可以使用内置的 FLAT 和 HNSW 索引算法、余弦等距离算法以及 KNN 搜索查询在 Redis 中保存向量嵌入。

Semantic Kernel 为 Redis 语义内存存储提供了一个 连接器。在语义内核中使用 Redis 作为语义内存存储的代码可能如下所示(来自 ChatAppRedis):

//初始化Redis连接
ConnectionMultiplexer connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(redisConnection);
IDatabase database = connectionMultiplexer.GetDatabase();

//创建和使用Redis语义内存存储
RedisMemoryStore memoryStore = new RedisMemoryStore(database, vectorSize: 1536);
var memory = new SemanticTextMemory(
    memoryStore,
    new AzureOpenAITextEmbeddingGenerationService(aoaiEmbeddingModel, aoaiEndpoint, aoaiApiKey)
    );

//将文本字符串保存到 Redis 语义存储中的代码
await memory.SaveInformationAsync(collectionName, $"{your_text_blob}", $"{an_arbitrary_key}");

Redis 保留聊天记录以启用 AI 记忆

像 GPT 这样的 OpenAI 模型不会记住聊天记录。Semantic Kernel 提供聊天记录,以回答基于先前上下文的问题。例如,您可以要求聊天应用程序讲一个笑话。然后问为什么这个笑话好笑。第二个问题的答案将与第一个问题相关,这就是聊天记录所启用的功能。

Chat History 对象存储在内存中。客户要求将其保存到外部存储,以获得以下好处:

  • 资源效率——内存是应用服务器中的稀缺资源。
  • 应用程序弹性——在服务器故障转移期间,我们希望避免内存中的数据丢失和出现故障。

Redis 是保存聊天记录的理想选择,因为:

  • 数据过期支持 - 应用程序可以设置聊天记录的过期时间,以保持其记忆犹新。
  • 数据结构——Redis 支持 Hash 等内置数据结构,可以轻松查询相关消息。
  • 弹性 – 如果会话由于服务器故障转移而中断,聊天可以继续。

下面是一个对话示例。如果没有在 Redis 中保留聊天记录,我就无法根据之前的上下文提出问题。
在这里插入图片描述
借助 Redis 中的聊天记录,我可以在开始新会话时继续之前的对话。
在这里插入图片描述
从 Redis 获取用户消息并转到 ChatHistory 对象的代码可能如下所示:

RedisValue[] userMsgList = await _redisConnection.BasicRetryAsync(
    async(db) =>(await db.HashValuesAsync(_userName + ":" + userMessageSet)));

if (userMsgList.Any()) {
  foreach (var userMsg in userMsgList) {
    chat.AddUserMessage(userMsg.ToString());
  }
}

将用户消息保存到 Redis 的代码可能如下所示:

chat.AddUserMessage(question);

await _redisConnection.BasicRetryAsync(
    async(_db) => _db.HashSetAsync($"{_userName}:{userMessageSet}", [
      new HashEntry(new RedisValue(Utility.GetTimestamp()), question)
    ]));

Redis Hash 用于每个用户的用户消息和辅助消息。Redis Insight 提供 UI 来查看和管理保存的聊天记录数据。
在这里插入图片描述
我们可以进一步利用这种聊天记录体验,将其转换为向量嵌入,以提高回答类似问题的一致性和相关性。好处是:

  • 对略有不同的问题给出一致的答案
  • 通过减少对 OpenAI 的 API 调用来节省成本

把带有 Redis 的聊天应用程序作为参考,将以前的聊天记录保存在 Redis 语义内存存储中的代码可能如下所示:

//将用户和助理消息作为向量嵌入存储在 Redis 中。 仅保存前一个会话。
if (_historyContent.Length > 0)
{
    await memory.SaveInformationAsync(_userName+"_chathistory", _historyContent, "lastsession");
}

用于搜索以前的聊天记录的代码可能如下所示:

await foreach (var result in memory.SearchAsync(_userName+"_chathistory", question, limit: 1))
        stbuilder.Append(result.Metadata.Text);

我收到了关于类似问题的一致答复。即“法国首都在哪里?” 和“哪里是法国首都?”
在这里插入图片描述
我的实验代码有局限性:

  • 它只保存最后一次聊天会话的历史记录
  • 它不会根据逻辑分组将大型历史对象划分为块
  • 代码很乱

这就是我们在语义内核中添加对此体验的官方支持的原因,请参阅 microsoft/semantic-kernel #5436。请分享您对此问题的反馈,以帮助我们设计出色的体验。

Redis 提高 Web 应用程序性能

.NET 提供了多种缓存抽象来提高 Web 应用程序性能。这些仍然适用于您的整体智能应用。 此外,缓存抽象与语义缓存相辅相成,以提供高性能且一致的 Web 响应。

网页输出缓存

使用相同参数的重复 Web 请求会引入不必要的服务器利用率和依赖项调用。在 .NET 8 中,我们引入了 Redis 输出缓存来改进以下领域的 Web 应用程序:

  • 一致性——输出缓存确保相同的请求得到一致的响应。
  • 性能 – 输出缓存避免了对数据存储或 API 的重复依赖调用,从而加快了整体 Web 响应时间。
  • 资源效率 – 输出缓存可降低渲染网页时的 CPU 利用率。

下面是前面提到的示例应用程序,它使用 Redis 输出缓存来提高调用 DALL-E 以根据提示生成图像的性能。使用 OpenAI 图像生成进行输出缓存。使用输出缓存所需最少的编码。

使用 .NET 8 Redis 输出缓存的代码片段可能如下所示:

app.MapGet("/cached/{prompt}", async (HttpContext context, string prompt, IConfiguration config) => 
    { await GenerateImage.GenerateImageAsync(context, prompt, config); 
    }).CacheOutput();

添加语义缓存以确保类似的提示收到一致的响应

Redis OM for dotnet 刚刚发布了语义缓存功能。它支持使用 Azure OpenAI 嵌入来生成向量。 以下代码片段显示了示例用法。完整的代码示例可以在 OutputCacheOpenAI 存储库中的 GenerateImageSC.cs 中找到。

使用 Redis 作为语义缓存的代码片段可能如下所示:

_provider = new RedisConnectionProvider(_config["SemanticCacheAzureProvider"]);
var cache = _provider.AzureOpenAISemanticCache(
    _config["apiKey"], _config["AOAIResourceName"],
    _config["AOAIEmbeddingDeploymentName"], 1536);

if (cache.GetSimilar(_prompt).Length > 0) {
  imageURL = cache.GetSimilar(_prompt)[0];
  await context.Response.WriteAsync(
      "<!DOCTYPE html><html><body> " +
      $"<img src=\"{imageURL}\" alt=\"AI Generated Picture {_prompt}\" width=\"460\" height=\"345\">" +
      " </body> </html>");
}

这样,我就可以确保来自不同用户的类似提示会产生相同的图像,从而提高一致性并减少 API 调用,从而减少对 DALL-E 的调用并提高性能。下面的屏幕截图演示了类似提示重复使用的相同图片。

这是从提示“a french garden in monet style””返回的图像。
在这里插入图片描述
这是从提示“a monet style french garden”返回的图像。它与上面相同,因为先前的条目已被语义缓存:
在这里插入图片描述
这是 Redis 语义缓存中的条目:
在这里插入图片描述
Redis 语义缓存是 Redis 输出缓存的补充,因为:

  • 语义缓存进一步减少了 API 依赖调用,从而提高性能和降低成本。
  • 输出缓存可降低渲染网页时的 CPU 利用率。

总之,Redis 可以成为高性能、一致且低成本的智能 Web 应用程序解决方案和设计的关键部分。

下一步计划

最近发布的 Enterprise E5 SKU 对于试验 RediSearch 模块来说具有成本效益。请查看用于 Redis 的 Azure 缓存。

今天就可以在您的智能应用程序中试用 Redis!通过在博文中发表评论,分享您对这些场景的想法和反馈 - 我们很乐意听取您的意见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1630179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

聚观早报 | 生数科技推出Vidu;2024款欧拉好猫正式上市

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 4月28日消息 生数科技推出Vidu 2024款欧拉好猫正式上市 雷诺与小米汽车洽谈技术合作 微软张祺谈未来AI如何发展 …

机器学习/算法工程师面试题目与答案-数学基础部分

机器学习/算法工程师面试题目--数学基础部分 一、数学基础1、微积分SGD,Momentum,Adagard,Adam原理L1不可导的时候该怎么办sigmoid函数特性 2、统计学&#xff0c;概率论求 Max(a, b) 期望拿更长的玫瑰花的最好策略最大化工作天数的员工数切比雪夫不等式随机截成三段组成三角形…

基于MSP430F249的电子钟仿真(源码+仿真)

目录 1、前言 2、仿真 3、程序 资料下载地址&#xff1a;基于MSP430F249的电子钟仿真(源码仿真&#xff09; 1、前言 基于MSP430F249的电子钟仿真&#xff0c;数码管显示时分秒&#xff0c;并可以通过按键调节时间。 2、仿真 3、程序 #include <MSP430x24x.h> #def…

Jenkins集成Terraform实现阿里云CDN自动刷新

在互联网业务中&#xff0c;CDN的应用已经成了普遍&#xff0c;SRE的日常需求中&#xff0c;CDN的刷新在前端需求逐渐中占了很大比例&#xff0c;并且比较琐碎。做为合格的SRE&#xff0c;把一切自动化是终极使命&#xff0c;而今天就分享通过JenkinsTerraform实现阿里云的CDN自…

java-动态代理

为什么需要代理&#xff1f; 如何创建代理 注意&#xff1a;实现类和代理需要实现同一个接口 接口 public interface Star {String sing(String song);void dance(); }实现类 public class BigStar implements Star {private String name;public BigStar(String name) {this.…

2024Mac系统热门游戏排行榜 Mac支持的网络游戏有哪些?mac能玩哪些大型网游 苹果电脑Mac游戏资源推荐 Mac玩Windows游戏

“游戏是这个世界上唯一能和女性争夺男朋友的东西&#xff08;/滑稽&#xff0c;有不少女生也喜欢玩游戏&#xff09;。” 虽然只是一句玩笑话&#xff0c;不过也可以看出游戏对大多数男生来说是必不可少的一项娱乐活动了。而网络游戏是游戏中的一大分支&#xff0c;能让玩家们…

uniapp问题归类

最近使用uniapp中&#xff0c;遇到了一些问题&#xff0c;这边mark下。 1. 启动页变形 设置启动页的时候发现在部分android手机上启动页被拉伸了&#xff0c;最后看了下官方建议使用9.png图 生成9.png地址&#xff0c;推荐图片大小为1080x2340 uniapp推荐官方地址传送门 我…

Thread类的基本用法

1.线程创建 这里介绍线程创建常用的五种方法 1.继承Thread&#xff0c;重写run class MyThread extends Thread{public void run(){//这里写的代码就是线程要完成的任务while (true){System.out.println("hello thread");try {Thread.sleep(1000);//线程会休眠一秒…

Springboot+Vue项目-基于Java+MySQL的家政服务平台系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

FreeRTOS:3.信号量

FreeRTOS信号量 参考链接&#xff1a;FreeRTOS-信号量详解_freertos信号量-CSDN博客 目录 FreeRTOS信号量一、信号量是什么二、 FreeRTOS信号量1、二值信号量1、获取信号量2、释放信号量 2、计数信号量3、互斥信号量1、优先级反转2、优先级继承3、源码解析1、互斥量创建2、获取…

[蓝桥杯2024]-PWN:fd解析(命令符转义,标准输出重定向)

查看保护 查看ida 这里有一次栈溢出&#xff0c;并且题目给了我们system函数。 这里的知识点没有那么复杂 完整exp&#xff1a; from pwn import* pprocess(./pwn) pop_rdi0x400933 info0x601090 system0x400778payloadb"ca\\t flag 1>&2" print(len(paylo…

2024.04.28 Typecho管理视频文件,出现预览功能

需求原因原版的Typecho不支持在线视频预览,只有一个图片预览功能, 所以为了实现可以在线预览视频功能, 修改 typecho/admin/media.php 在大概19行的时候,追加如下内容 <?php if ($attachment->attachment->isImage): ?><p><img src"<?php $att…

装饰器模式【结构型模式C++】

1.概述 装饰器模式是一种结构型设计模式&#xff0c; 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。 2.结构 抽象构件&#xff08;Component&#xff09;角色&#xff1a;定义一个抽象接口以规范准备接收附加责任的对象。具体构件&#xff08;Concre…

关于文档中心的英文快捷替换方案

背景&#xff1a;文档中心需要接入国际化&#xff0c;想节省时间做统一英文方案处理&#xff1b; 文档中心是基于vuepress框架编写的&#xff1b; 1、利用百度翻译 API 的接口去做底层翻译处理&#xff0c;https://api.fanyi.baidu.com/需要在该平台上注册账号&#xff0c;个人…

决策树学习笔记

一、衡量标准——熵 随机变量不确定性的度量 信息增益&#xff1a;表示特征X使得类Y的不确定性减少的程度。 二、数据集 14天的打球情况 特征&#xff1a;4种环境变化&#xff08;天气、温度等等&#xff09; 在上述数据种&#xff0c;14天中打球的天数为9天&#xff1b;不…

docker部署的nacos2.2x开启鉴权功能

注意在2.2.0版本之后如果不开启鉴权&#xff0c;那么默认不需要登录就可以访问 所以我们需要手动开启鉴权&#xff0c;nacos启动好以后来到容器内部修改 docker exec -it nacos /bin/shvim conf/application.properties在第34行下面添加 nacos.core.auth.enabledtrue nacos.cor…

编译GTSAM库时报错undefined reference to `_dl_vsym@GLIBC_PRIVATE‘

/home/alex/miniforge3/envs/ros_py39_env/bin/ld: /home/alex/miniforge3/envs/ros_py39_env/bin/../x86_64-conda-linux-gnu/sysroot/lib64/libdl.so.2: undefined reference to _dl_vsymGLIBC_PRIVATE SOLUTION&#xff1a;在CMakeLists.txt里加入&#xff1a; set (CMAKE…

信号分解 | RLMD(鲁棒性局部均值分解)-Matlab

分解效果 RLMD(鲁棒性局部均值分解) RLMD(鲁棒性局部均值分解)-Matlab 代码实现 % %% 清除所有变量 关闭窗口 clc clear all close all%% 导入数据 % data = xlsread(Data.xlsx);%% 输入信号%% RLMD分解 %参数进行设置 % options.display =

OPPO Reno10Pro/Reno11/K10手机强解BL刷root权限KSU内核抓包刷机救砖

OPPO Reno10Pro/Reno11/K10手机虽然发布时间并不久&#xff0c;但由于天玑处理器的体质&#xff0c;已经支持强制解锁BL了&#xff0c;该漏洞来自第三方工具适配&#xff0c;支持OPPO天机8100/8200刷机救砖解锁BL不需要等待官方深度测试直接实现。解锁BL后的OPPO Reno10Pro/Ren…

会声会影2024Win版64位电脑下载及系统配置要求

会声会影是一款专业的视频编辑软件&#xff0c;至今也推出了多版软件&#xff0c;深受用户的喜爱&#xff0c;这不&#xff0c;最近会声会影又要出2024版了&#xff0c;相信有很多用户都想知道新版本有哪些变化&#xff0c;新增了什么功能。下面我就为大家带来会声会影2024美颜…