Skip to content

Commit 2caec68

Browse files
authored
Merge pull request #3162 from Q1an05/feature/完善微信公众号对话机器人服务
Feature/完善微信公众号对话机器人服务
2 parents 7d4bed1 + aa087f3 commit 2caec68

File tree

3 files changed

+121
-6
lines changed

3 files changed

+121
-6
lines changed

Samples/All/Senparc.Weixin.Sample.CommonService/AI/MessageHandlers/ChatStore.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
88
创建标识:Senparc - 20240524
99
10+
修改标识:Wang Qian - 20250728
11+
修改描述:为长对话模式的支持新增了LastStoredMemory、LastStoredPrompt、UseLongChat属性
12+
1013
----------------------------------------------------------------*/
1114

1215
using Microsoft.Extensions.AI;
@@ -41,11 +44,27 @@ public class ChatStore
4144
/// </summary>
4245
public bool UseMarkdown { get; set; }
4346

47+
/// <summary>
48+
/// 是否使用长对话模式
49+
/// </summary>
50+
public bool UseLongChat { get; set; }
51+
52+
/// <summary>
53+
/// 上一次保存的记忆
54+
/// </summary>
55+
public string LastStoredMemory { get; set; }
56+
57+
/// <summary>
58+
/// 上一次提问的prompt
59+
/// </summary>
60+
public string LastStoredPrompt { get; set; }
61+
4462
public ChatStore()
4563
{
4664
Status = ChatStatus.None;
4765
MultimodelType = MultimodelType.None;
4866
UseMarkdown = true;
67+
UseLongChat = false;
4968
}
5069

5170
public ChatHistory GetChatHistory()
@@ -60,7 +79,7 @@ public ChatHistory GetChatHistory()
6079

6180
public void SetChatHistory(ChatHistory chatHistory)
6281
{
63-
if (chatHistory==null)
82+
if (chatHistory == null)
6483
{
6584
ClearHistory();
6685
}
@@ -126,4 +145,5 @@ public enum MultimodelType
126145
SimpleChat,
127146
ChatAndImage
128147
}
148+
129149
}

Samples/All/Senparc.Weixin.Sample.CommonService/AI/MessageHandlers/CustomMessageHandler_AI.cs

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
88
创建标识:Senparc - 20240524
99
10+
修改标识:Wang Qian - 20250728
11+
修改描述:新增AI对话功能增强特性:
12+
1. 新增"lc"命令:支持长对话模式,当对话达到10轮后自动整理记忆并清空历史
13+
2. 新增记忆整理功能:在长对话模式下,AI会自动总结对话内容并保存为记忆
14+
3. 优化欢迎消息:更新了功能说明,包含新增的命令使用说明
15+
1016
----------------------------------------------------------------*/
1117

1218
using System;
@@ -45,6 +51,7 @@ public partial class CustomMessageHandler
4551
输入“t”可以从多模态进入纯文本对话模式
4652
输入“img 文字”可以强制生成图片,例如:img 一只猫
4753
输入“dm”可以关闭Markdown格式输出,使用纯文本回复
54+
输入“lc”可以开启长对话模式,开启后,对话每到达最大历史对话轮数(默认10轮)后,会自动整理对话记忆,并清空对话历史,以支持长对话
4855
4956
[结果由 AI 生成,仅供参考]";
5057

@@ -118,6 +125,8 @@ private async Task<IResponseMessageBase> AIChatAsync(RequestMessageBase requestM
118125
bool judgeMultimodel = true;
119126
var oldChatStatus = chatStore.Status;
120127

128+
129+
121130
if (requestMessageText.Content.Equals("E", StringComparison.OrdinalIgnoreCase))
122131
{
123132
prompt = $"我即将结束对话,请发送一段文字和我告别,并提醒我:输入“AI”可以再次启动对话。";
@@ -172,12 +181,25 @@ private async Task<IResponseMessageBase> AIChatAsync(RequestMessageBase requestM
172181

173182
//返回提示
174183
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
175-
responseMessage.Content = useMarkdown
184+
responseMessage.Content = useMarkdown
176185
? "已恢复Markdown格式输出,输入dm可关闭Markdown格式输出"
177186
: "已关闭Markdown格式输出,使用纯文本回复,输入md可恢复Markdown格式输出";
178187
return responseMessage;
179188
}
180189

190+
Func<string, bool> longChatFunc = content => requestMessageText.Content.Equals(content, StringComparison.OrdinalIgnoreCase);
191+
192+
// 在对话、暂停状态下、可以切换长对话模式
193+
if (chatStore.Status == oldChatStatus && longChatFunc("LC"))
194+
{
195+
chatStore.UseLongChat = chatStore.UseLongChat ? false : true;
196+
await UpdateMessageContextAsync(currentMessageContext, chatStore);
197+
198+
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
199+
responseMessage.Content = chatStore.UseLongChat ? "已开启长对话模式!AI将在对话每到达最大历史对话轮数(默认10轮)后,会自动整理对话记忆,并清空对话历史,再次输入lc以关闭" : "已关闭长对话模式!AI将不再自动整理对话记忆,并清空对话历史,再次输入lc以开启";
200+
return responseMessage;
201+
}
202+
181203
if (chatStore.Status == oldChatStatus && chatStore.MultimodelType == MultimodelType.SimpleChat)// 在文字对话的状态下,才能切换到多模态对话
182204
{
183205
if (requestMessageText.Content.Equals("M", StringComparison.OrdinalIgnoreCase))
@@ -421,8 +443,16 @@ private async Task TextChatAsync(string prompt, ChatStore chatStore, bool storeH
421443
//最大保存 AI 对话记录数
422444
var maxHistoryCount = 10;
423445

424-
//默认 SystemMessage(可根据自己需要修改)
425-
var systemMessage = Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE;
446+
//如果是长对话模式,那么调用整理记忆函数,如果整理了记忆,那么使用整理后的记忆,则否则使用默认系统消息
447+
//在长对话模式情况下,如果还没有整理过记忆,那么返回值会是null,此时会使用默认系统消息
448+
//默认系统消息可以自己设置,也可以使用Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE
449+
var systemMessage = chatStore.UseLongChat ?
450+
await ConsolidateMemoryAsync(chatStore, chatStore.LastStoredPrompt) ?? Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE
451+
:
452+
Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE;
453+
454+
//更新上一次prompt
455+
chatStore.LastStoredPrompt = prompt;
426456

427457
var aiHandler = new SemanticAiHandler(setting);
428458
var iWantToRun = aiHandler.ChatConfig(parameter,
@@ -505,5 +535,70 @@ public async Task<bool> JudgeMultimodel(RequestMessageText requestMessageText, C
505535
}
506536
return false;
507537
}
538+
539+
/// <summary>
540+
/// 整理记忆的方法
541+
/// </summary>
542+
/// <param name="chatStore"></param>
543+
/// <returns></returns>
544+
private async Task<string> ConsolidateMemoryAsync(ChatStore chatStore, string prompt)
545+
{
546+
var assistantMessageCount = chatStore.History.Count(h => h.Role == AuthorRole.Assistant);
547+
548+
//这里不进行是否使用长对话模式判断,因为判断是在TextChatAsync中进行的
549+
//如果AI消息条数大于等于9,则整理记忆,这里是9是因为Senparc.AI的消息最大条数处理逻辑稍有问题,所以暂时设置为9
550+
if (assistantMessageCount >= 9)
551+
{
552+
var memoryPrompt = @"
553+
请用简洁的语言总结:
554+
1. 用户的主要需求或关注点
555+
2. 重要的偏好或习惯
556+
3. 关键的信息点
557+
4. 之前聊天的内容
558+
";
559+
/* 模型配置
560+
* 注意:需要在 appsettings.json 中的 <SenparcAiSetting> 节点配置 AI 模型参数,否则无法使用 AI 能力
561+
*/
562+
var setting = (SenparcAiSetting)Senparc.AI.Config.SenparcAiSetting;//也可以留空,将自动获取
563+
564+
//模型请求参数
565+
var parameter = new PromptConfigParameter()
566+
{
567+
MaxTokens = 2000,
568+
Temperature = 0.3,
569+
TopP = 0.3,
570+
};
571+
572+
//最大保存 AI 对话记录数
573+
var maxHistoryCount = 10;
574+
575+
//使用上一轮的记忆作为SystemMessage
576+
var systemMessage = chatStore.LastStoredMemory == null ? Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE : chatStore.LastStoredMemory;
577+
578+
var aiHandler = new SemanticAiHandler(setting);
579+
var iWantToRun = aiHandler.ChatConfig(parameter,
580+
userId: "Jeffrey",
581+
maxHistoryStore: maxHistoryCount,
582+
chatSystemMessage: systemMessage,
583+
senparcAiSetting: setting);
584+
585+
//注入历史记录(也可以把 iWantToRun 对象缓存起来,其中会自动包含 history,不需要每次读取或者保存)
586+
iWantToRun.StoredAiArguments.Context["history"] = chatStore.GetChatHistory();// AIKernl 的 history 为 ChatHistory 类型
587+
588+
var result = await aiHandler.ChatAsync(iWantToRun, memoryPrompt);
589+
590+
var memory = "用户之前的对话被概括为" + result.OutputString + "\n5.用户最近一次提问的内容是:" + prompt;
591+
592+
//更新chatStore中的上一轮记忆
593+
chatStore.LastStoredMemory = memory;
594+
595+
//清空历史记录
596+
chatStore.ClearHistory();
597+
return memory;
598+
}
599+
else return chatStore.LastStoredMemory;
600+
601+
602+
}
508603
}
509-
}
604+
}

Samples/All/Senparc.Weixin.Sample.CommonService/MessageHandlers/CustomMessageHandler/CustomMessageHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ public override async Task<IResponseMessageBase> OnTextRequestAsync(RequestMessa
270270
* 这是一个特殊的过程,此请求通常来自于微微嗨(http://www.weiweihi.com)的“盛派网络小助手”应用请求(https://www.weiweihi.com/User/App/Detail/1),
271271
* 用于演示微微嗨应用商店的处理过程,由于微微嗨的应用内部可以单独设置对话过期时间,所以这里通常不需要考虑对话状态,只要做最简单的响应。
272272
*/
273-
if (defaultResponseMessage.Content == "测试")
273+
if (requestMessage.Content == "测试")
274274
{
275275
//进入APP测试
276276
defaultResponseMessage.Content = "您已经进入【盛派网络小助手】的测试程序,请发送任意信息进行测试。发送文字【退出】退出测试对话。10分钟内无任何交互将自动退出应用对话状态。";

0 commit comments

Comments
 (0)