free-code-dotnet/docs/服务子系统设计/服务子系统设计-会话记忆与上下文.md
应文浩wenhao.ying@xiaobao100.com e25ac591a7 init easy-code
2026-04-06 07:24:24 +08:00

171 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 服务子系统设计 — 会话记忆与上下文
## 元数据
- 项目名称: free-code
- 文档类型: 服务子系统设计
- 原始代码来源: `../../src/utils/memory/`
- 关联总览: [服务子系统设计总览](服务子系统设计.md)
- 原始映射: [原始代码映射](reference/原始代码映射-服务子系统.md)
- 相关模块: [核心模块设计 — 查询引擎](../核心模块设计/核心模块设计-查询引擎-QueryEngine.md)
- 相关模块: [基础设施设计 — 后台任务管理](../基础设施设计/基础设施设计-后台任务管理.md)
- 相关模块: [基础设施设计 — 特性开关](../UI与扩展设计/UI与扩展设计-特性开关系统.md)
## 1. 设计目标
会话记忆与上下文子系统负责把长会话中的关键内容压缩、沉淀、同步,并在需要时为查询引擎提供可控、低成本的上下文补充。该子系统强调阈值触发、轻量模型处理、以及在写入团队知识库前的安全校验。
## 2. 核心数据结构
```csharp
public enum MemoryType
{
Session,
Dream,
Team
}
public sealed record MemoryEntry(
string Id,
MemoryType Type,
string SessionId,
string Content,
DateTimeOffset CreatedAt,
IReadOnlyList<string> Tags);
```
`MemoryType` 用于区分会话记忆、自动梦境摘要与团队共享记忆。`MemoryEntry` 记录统一承载记忆内容、来源会话、创建时间和标签,便于检索与同步。
## 3. 会话记忆服务
```csharp
public interface ISessionMemoryService
{
Task<MemoryEntry?> ExtractAsync(
string sessionId,
int tokenCount,
int toolCallCount,
CancellationToken cancellationToken = default);
Task SaveAsync(MemoryEntry entry, CancellationToken cancellationToken = default);
Task<IReadOnlyList<MemoryEntry>> GetRecentAsync(
string sessionId,
CancellationToken cancellationToken = default);
}
```
`ISessionMemoryService` 使用阈值触发提取:当 token 数或 tool call 数超过阈值时,触发一次记忆抽取,生成摘要型 `MemoryEntry`
```csharp
public sealed class SessionMemoryService : ISessionMemoryService
{
private readonly int _tokenThreshold = 12000;
private readonly int _toolCallThreshold = 24;
public async Task<MemoryEntry?> ExtractAsync(
string sessionId,
int tokenCount,
int toolCallCount,
CancellationToken cancellationToken = default)
{
var shouldExtract = tokenCount >= _tokenThreshold || toolCallCount >= _toolCallThreshold;
if (!shouldExtract)
{
return null;
}
return await Task.FromResult(new MemoryEntry(
Id: Guid.NewGuid().ToString("N"),
Type: MemoryType.Session,
SessionId: sessionId,
Content: "基于会话上下文生成的压缩记忆。",
CreatedAt: DateTimeOffset.UtcNow,
Tags: new[] { "session", "summary" }));
}
public Task SaveAsync(MemoryEntry entry, CancellationToken cancellationToken = default) => Task.CompletedTask;
public Task<IReadOnlyList<MemoryEntry>> GetRecentAsync(string sessionId, CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<MemoryEntry>>(Array.Empty<MemoryEntry>());
}
```
## 4. 自动梦境服务
```csharp
public interface IAutoDreamService
{
Task<MemoryEntry?> GenerateAsync(
string sessionId,
TimeSpan idleDuration,
int sessionCount,
CancellationToken cancellationToken = default);
}
```
`IAutoDreamService` 在两类条件触发:会话空闲超过 24 小时,或会话累计次数达到设定阈值。它用于生成更高层级的长期偏好、主题趋势和待办线索。
```csharp
public sealed class AutoDreamService : IAutoDreamService
{
private readonly TimeSpan _idleThreshold = TimeSpan.FromHours(24);
private readonly int _sessionCountThreshold = 10;
public async Task<MemoryEntry?> GenerateAsync(
string sessionId,
TimeSpan idleDuration,
int sessionCount,
CancellationToken cancellationToken = default)
{
if (idleDuration < _idleThreshold && sessionCount < _sessionCountThreshold)
{
return null;
}
return await Task.FromResult(new MemoryEntry(
Id: Guid.NewGuid().ToString("N"),
Type: MemoryType.Dream,
SessionId: sessionId,
Content: "基于空闲周期与会话积累生成的自动梦境摘要。",
CreatedAt: DateTimeOffset.UtcNow,
Tags: new[] { "dream", "long-term" }));
}
}
```
## 5. 团队记忆同步服务
```csharp
public interface ITeamMemorySyncService
{
Task PushAsync(MemoryEntry entry, CancellationToken cancellationToken = default);
Task<MemoryEntry?> PullAsync(string memoryId, CancellationToken cancellationToken = default);
}
```
`ITeamMemorySyncService` 支持推送与拉取团队记忆。推送前必须执行 secret scanning避免把敏感信息写入共享知识库。
```csharp
public sealed class TeamMemorySyncService : ITeamMemorySyncService
{
public Task PushAsync(MemoryEntry entry, CancellationToken cancellationToken = default)
{
var hasSecret = false;
if (hasSecret)
{
throw new InvalidOperationException("检测到敏感信息,禁止推送团队记忆。");
}
return Task.CompletedTask;
}
public Task<MemoryEntry?> PullAsync(string memoryId, CancellationToken cancellationToken = default)
=> Task.FromResult<MemoryEntry?>(null);
}
```
## 6. 设计说明
- 记忆相关操作使用轻量模型 `claude-haiku-4-5`,优先保证低延迟与低成本。
- 记忆抽取优先走阈值触发,避免每轮上下文都进行重处理。
- 团队记忆同步前必须进行 secret scanning防止把密钥、令牌或隐私数据外发。
- 该子系统与查询引擎联动,用于补充局部上下文,而不是替代主对话历史。