Skip to content

上下文记忆与会话状态 ​

Agent 的“记忆”有四个不同层次:会话业务状态、LLM canonical messages、执行摘要/工具结果、JSONL/checkpoint 持久化。把它们都称为 history 会导致恢复、压缩和分支实现出错。

1. ChatSession:业务会话容器 ​

ChatSession 固定以下身份和生命周期字段:

字段说明
sessionId、agentId、tenantId、userId访问隔离和路由键
roomId、sandboxWorkspace文件房间及当前相对工作目录
currentBranchId、currentLeafEntryIdJSONL 事件树分支和叶子
statusACTIVE、PAUSED、ENDED、EXPIRED
messages、context页面/历史投影和业务上下文,不等同于 LoopRuntime 消息
loopCount、maxLoops会话级轮数保护
datasetList、datasetsLoadedDataset 缓存
lastActiveTime、expireMinutes过期判断

isActive() 同时检查状态为 ACTIVE 和时间未过期。暂停的 session 不能被普通用户输入直接当作新一轮运行;应通过 resume 或明确结束后新建分支。

2. TaskExecutionState:图状态边界 ​

子图可序列化字段按四组理解:

组关键字段写入节点
输入agentConfig、llmModelConfig、datasetList、userInput、userIntent主图桥接/init
计划taskPlanText、taskTodoList、currentTaskplanning/acting
循环iterationCount、finishReason、loopSignal、lastIterationResultreasoning/refining
保护consecutiveFailures、replanCount、contextCompressionCount、hitl*、errorrefining/memory/acting
上下文executionHistoryText、toolResultStore、messages、runtimeMessagesacting/refining/checkpoint

其中 executionHistoryText、toolResultStore、messages 使用 appender reducer,节点返回增量会追加;runtimeMessages 是恢复时可重新构造 LangChain4j 消息的 canonical DTO 列表。新增字段要同步 SCHEMA、serializer、CheckpointStateCodec、恢复校验和测试。

3. LoopRuntime:不可直接持久化的运行对象 ​

LoopInitNode 为当前 session 创建 LoopRuntime,包含 ChatModel、工具规格、List<ChatMessage>、TodoManager、ToolResultStore、VFS/Sandbox 句柄、active Skill 和 StreamHandler。模型实例、线程、网络连接和 provider client 不写入 checkpoint。

恢复过程先从 runtimeMessages 反序列化 User/System/AI/Tool 消息,再按配置重新创建 ChatModel、工具和 workspace。只恢复 executionHistoryText 会让模型缺少工具调用配对消息;只恢复内存对象又无法跨进程。

4. 多层持久化 ​

ChatSessionManager 读取顺序受 agent.session.persistence.mode 影响:

模式语义
MIRROR传统 DB/缓存为常规来源,同时镜像 JSONL
PRIMARY优先从 JSONL 恢复,传统存储作为回退/投影
JSONL_ONLY不依赖传统会话表作为来源

L1 是 JVM 内存,L2 通常是 Redis,L3 是数据库或 JSONL 恢复。容器重建时必须挂载 agent.session.persistence.base-dir,否则会话、checkpoint、blob 和轨迹会丢失。

JSONL 事件包含 session header、用户 turn、节点/工具/模型事件、运行控制、分支、压缩和 Sandbox 生命周期。大 payload 按 inlinePayloadMaxBytes 等阈值写入 blob,事件只保存引用。

5. 检查点恢复 ​

checkpoint 文档至少包含 schemaVersion、checkpointId、session/branch/turn/run、graphVersion、current/next node、TaskState snapshot、runtime snapshot 和配置摘要。恢复顺序:

text
读取 session header
 -> SessionLease(当前实现为 JVM 内存租约)
 -> 校验租户/Agent/branch/schema/graph
 -> restore TaskExecutionState
 -> 校验 runtime surface digest 和 toolset hash
 -> restore canonical messages
 -> 重建 LoopRuntime/Sandbox
 -> 从 nextNode 继续 graph

工具配置、权限、消息投影或图版本变化时进入 RECOVERY_BLOCKED,不能静默清空状态重跑。AgentCheckpointStore 按 session/run 目录写入,保留数量由 checkpoint keepLast 控制。

6. 上下文压缩 ​

LoopReasoningNode 会使用真实 input token 预判压缩,LoopMemoryNode 也处理 FinishReason.LENGTH。策略分档:

使用率处理
<50%不压缩
50%-80%保留最近三个工具全文,旧结果变指针+预览
80%-95%仅保留最近一个工具全文,其余占位
>=95%LLM 硬压缩历史消息

硬压缩最多两次;耗尽后尝试重规划,仍失败则 FAILED。完整工具结果通过 READ_TOOL_RESULT(toolCallId, offset, limit) 延迟读取,而不是重新把全文塞回 prompt。压缩事件会记录原消息数、新消息数、摘要和被归档的工具调用 ID。

7. ChatMemory 与分支 ​

页面对话历史由 AiChatHistoryChatMemoryStore、MySQL/MapDB 实现和 JSONL projection 协作;它解决的是多轮展示和下一轮输入,不等于 Agentic Loop 的工具消息列表。分支通过 JSONL entry tree 的 branchId/currentLeafEntryId 管理,创建分支只改变后续历史投影,不应修改原分支已经完成的工具结果。

8. 恢复排障 ​

现象首先检查
session 找不到L1/L2/L3 读取顺序、tenant/user、JSONL header
模型看到上下文不完整runtimeMessages、surface digest、压缩事件
工具重复执行ToolExecutionJournal、toolCallId、runId
恢复被阻止schema/graph/toolset hash、分支和权限
文件结果消失Sandbox checkpoint、workspace binding、blob 卷
同一 session 并发恢复SessionLease;多实例需共享租约实现