Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

创建标识:Senparc - 20240524

修改标识:Wang Qian - 20250728
修改描述:为长对话模式的支持新增了LastStoredMemory、LastStoredPrompt、UseLongChat属性

----------------------------------------------------------------*/

using Microsoft.Extensions.AI;
Expand Down Expand Up @@ -41,11 +44,27 @@ public class ChatStore
/// </summary>
public bool UseMarkdown { get; set; }

/// <summary>
/// 是否使用长对话模式
/// </summary>
public bool UseLongChat { get; set; }

/// <summary>
/// 上一次保存的记忆
/// </summary>
public string LastStoredMemory { get; set; }

/// <summary>
/// 上一次提问的prompt
/// </summary>
public string LastStoredPrompt { get; set; }

public ChatStore()
{
Status = ChatStatus.None;
MultimodelType = MultimodelType.None;
UseMarkdown = true;
UseLongChat = false;
}

public ChatHistory GetChatHistory()
Expand All @@ -60,7 +79,7 @@ public ChatHistory GetChatHistory()

public void SetChatHistory(ChatHistory chatHistory)
{
if (chatHistory==null)
if (chatHistory == null)
{
ClearHistory();
}
Expand Down Expand Up @@ -126,4 +145,5 @@ public enum MultimodelType
SimpleChat,
ChatAndImage
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@

创建标识:Senparc - 20240524

修改标识:Wang Qian - 20250728
修改描述:新增AI对话功能增强特性:
1. 新增"lc"命令:支持长对话模式,当对话达到10轮后自动整理记忆并清空历史
2. 新增记忆整理功能:在长对话模式下,AI会自动总结对话内容并保存为记忆
3. 优化欢迎消息:更新了功能说明,包含新增的命令使用说明

----------------------------------------------------------------*/

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

[结果由 AI 生成,仅供参考]";

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



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

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

Func<string, bool> longChatFunc = content => requestMessageText.Content.Equals(content, StringComparison.OrdinalIgnoreCase);

// 在对话、暂停状态下、可以切换长对话模式
if (chatStore.Status == oldChatStatus && longChatFunc("LC"))
{
chatStore.UseLongChat = chatStore.UseLongChat ? false : true;
await UpdateMessageContextAsync(currentMessageContext, chatStore);

var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = chatStore.UseLongChat ? "已开启长对话模式!AI将在对话每到达最大历史对话轮数(默认10轮)后,会自动整理对话记忆,并清空对话历史,再次输入lc以关闭" : "已关闭长对话模式!AI将不再自动整理对话记忆,并清空对话历史,再次输入lc以开启";
return responseMessage;
}

if (chatStore.Status == oldChatStatus && chatStore.MultimodelType == MultimodelType.SimpleChat)// 在文字对话的状态下,才能切换到多模态对话
{
if (requestMessageText.Content.Equals("M", StringComparison.OrdinalIgnoreCase))
Expand Down Expand Up @@ -421,8 +443,13 @@ private async Task TextChatAsync(string prompt, ChatStore chatStore, bool storeH
//最大保存 AI 对话记录数
var maxHistoryCount = 10;

//默认 SystemMessage(可根据自己需要修改)
var systemMessage = Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE;
//如果更新了记忆,把更新的记忆作为systemMessage
var memory = await ConsolidateMemoryAsync(chatStore, chatStore.LastStoredPrompt);

//更新上一次prompt
chatStore.LastStoredPrompt = prompt;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: AI Memory Bug: Prompt Mismatch & Compilation Error

The AI's long chat memory consolidation feature has two issues:

  1. Prompt Mismatch/Null: The ConsolidateMemoryAsync method uses the previous user prompt (chatStore.LastStoredPrompt) instead of the current one. This results in inaccurate memory summaries (e.g., "用户最近一次提问的内容是:[previous/null prompt]") and can lead to "null" being concatenated into the memory string if LastStoredPrompt is uninitialized. The current prompt is only updated after the consolidation call.
  2. Compilation Error: The conditional operator for systemMessage mixes await and non-async expressions, causing a type mismatch and a compilation error.
Locations (2)
Fix in Cursor Fix in Web


var systemMessage = memory == null ? Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE : memory;

var aiHandler = new SemanticAiHandler(setting);
var iWantToRun = aiHandler.ChatConfig(parameter,
Expand Down Expand Up @@ -505,5 +532,67 @@ public async Task<bool> JudgeMultimodel(RequestMessageText requestMessageText, C
}
return false;
}

/// <summary>
/// 整理记忆的方法
/// </summary>
/// <param name="chatStore"></param>
/// <returns></returns>
private async Task<string> ConsolidateMemoryAsync(ChatStore chatStore, string prompt)
{
var assistantMessageCount = chatStore.History.Count(h => h.Role == AuthorRole.Assistant);
if (chatStore.UseLongChat && assistantMessageCount >= 9)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Memory Consolidation Triggers Prematurely

The memory consolidation for long chat mode triggers one round too early. The condition assistantMessageCount >= 9 causes it to activate after 9 assistant messages, whereas documentation states it should occur after 10 rounds.

Locations (1)

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是因为SenParc.AI在处理最大对话轮数的逻辑稍微有一点问题,所以先暂时设置为9

{
var memoryPrompt = @"
请用简洁的语言总结:
1. 用户的主要需求或关注点
2. 重要的偏好或习惯
3. 关键的信息点
4. 之前聊天的内容
";
/* 模型配置
* 注意:需要在 appsettings.json 中的 <SenparcAiSetting> 节点配置 AI 模型参数,否则无法使用 AI 能力
*/
var setting = (SenparcAiSetting)Senparc.AI.Config.SenparcAiSetting;//也可以留空,将自动获取

//模型请求参数
var parameter = new PromptConfigParameter()
{
MaxTokens = 2000,
Temperature = 0.3,
TopP = 0.3,
};

//最大保存 AI 对话记录数
var maxHistoryCount = 10;

//使用上一轮的记忆作为SystemMessage
var systemMessage = chatStore.LastStoredMemory == null ? Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE : chatStore.LastStoredMemory;

var aiHandler = new SemanticAiHandler(setting);
var iWantToRun = aiHandler.ChatConfig(parameter,
userId: "Jeffrey",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Inconsistent User ID Handling Across Methods

The userId parameter is hardcoded as "Jeffrey" in the ConsolidateMemoryAsync method. This is inconsistent with other parts of the application (e.g., TextChatAsync) that correctly use the actual user's OpenId (requestMessage.FromUserName), potentially leading to incorrect user-specific memory management and conversation contexts.

Locations (1)

Fix in Cursor Fix in Web

maxHistoryStore: maxHistoryCount,
chatSystemMessage: systemMessage,
senparcAiSetting: setting);

//注入历史记录(也可以把 iWantToRun 对象缓存起来,其中会自动包含 history,不需要每次读取或者保存)
iWantToRun.StoredAiArguments.Context["history"] = chatStore.GetChatHistory();// AIKernl 的 history 为 ChatHistory 类型

var result = await aiHandler.ChatAsync(iWantToRun, memoryPrompt);

var memory = "用户之前的对话被概括为" + result.OutputString + "\n5.用户最近一次提问的内容是:" + prompt;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Memory Consolidation Issues

The ConsolidateMemoryAsync method has several issues:

  1. chatStore.LastStoredPrompt is passed as the prompt parameter before it's initialized, causing prompt to be null on the first call. This results in "用户最近一次提问的内容是:null" being included in the consolidated memory, which can confuse the AI.
  2. The consolidated memory string includes a hardcoded "5." for the user's last question, which is inconsistent with the 4-item summary template used for AI memory consolidation.
  3. The AI's result.OutputString is concatenated without null or empty checks, which can lead to a malformed memory string if the AI response is empty.
Locations (2)

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

只有在发送请求时才会调用这个方法,所以这个值不会为null


//更新chatStore中的上一轮记忆
chatStore.LastStoredMemory = memory;

//清空历史记录
chatStore.ClearHistory();
return memory;
}
else return null;


}
}
}
}