轻量级:非Store模式设计与实现
在不落库的前提下,完整复用 Run/Tool/State/Context 执行栈与流式协议,通过线程本地内存态 Repo 提供“即开即用、请求内可观测 ”的轻量体验。
设计目标
- 零持久:请求内不向数据库写入对话、Run、Step、工具记录。
- 端到端流式:支持 SSE 流、并在阻塞模式下返回完整聚合结果。
- 最小逻辑入侵:仅在 Repo 层切换到内存实现;执行主干保持一致。
- 可并发:保留多线程执行、工具并行与输出串行化能力。
- 安全边界:禁止与历史依赖耦合的能力(如 previous_response_id、conversation)。
开启与生命周期
-
入口开关:
ResponseController.createResponses()
中,当request.store == false
时调用RepoContext.activate()
启用非Store模式。- 代码:
api/src/main/java/com/ke/assistant/controller/ResponseController.java
- 关键逻辑:
boolean nonStore = Boolean.FALSE.equals(request.getStore());
if (nonStore) RepoContext.activate();
- 在
finally
中RepoContext.detach();
- 代码:
-
跨线程传播:
TaskExecutor
提交任务时捕获线程本地的RepoContext.State
快照,并在执行线程attach/detach
,保证 runner/executor/caller 三个线程池的一致上下文。- 代码:
api/src/main/java/com/ke/assistant/core/TaskExecutor.java
- 方法:
addRunner/addExecutor/addToolSender/supplyCaller
→wrapWithRepoContext(...)
- 代码:
-
生命周期:
RepoContext
为 ThreadLocal 容器;在请求发起线程激活,提交到执行线程后携带快照;当所有执行线程结束时自动detach
,内存数据随之释放。- 非Store模式下的实体仅在本次执行的相关线程内可见,不对后续请求可见。
数据平面:内存态 RepoContext
-
存储结构:
RepoContext.Store
提供内存 Map 作为“轻量数据库”。- 代码:
api/src/main/java/com/ke/assistant/db/context/RepoContext.java
- 维护实体:
threads/messages/runs/runSteps/runTools/responseIdMappings/threadFiles
。 - 提供轻量查询:按时间排序、游标分页、范围筛选等常用方法。
- 代码:
-
Repo 选择逻辑:各 Repo 通过
BaseRepo.isNoStoreMode()
判定是否走内存态。- 代码:
api/src/main/java/com/ke/assistant/db/repo/BaseRepo.java
- 示例:
MessageRepo.findById(...)
在非Store时调用getContextStore().findMessageById(...)
;ResponseIdMappingRepo.findByResponseId(...)
、findByPreviousResponseId(...)
同理。
- 代码: