版本:v1.1 日期:2026-08-02 状态:待用户确认 范围:智能操作节点、Agent/Skill 节点、技能生成(待用户确认是否纳入)
v1.1 变更:用户确定 Q1=同步阻塞方案;新增"无超时 Askfor"要求(用户可能几小时后才回来);调研发现 S1 拉长超时方案在网络中断时无法恢复,确定采用 S2 持久化 + 重连 子方案。
用户希望把 Hermes agent 执行时的思考过程展示从单一的"追加型思考"扩展为 5 个区域:
| 序号 | 区域 | 数据特征 | 更新模式 |
|---|---|---|---|
| ① | 追加型思考过程 | 模型流式输出的完整文本(已存在) | 增量累加 |
| ② | 实时型思考过程 | "正在进行 XXX"、"下一步:XXX" 等当前状态文案 | 覆盖式(同一条目被新文案替换) |
| ③ | 工具调用 | 上方:当前调用中的工具;下方:历史调用列表 | 上方覆盖、下方追加 |
| ④ | TODO List | agent 规划的待办,含已完成/未完成 | 增删改(item 状态切换) |
| ⑤ | Askfor | 模型抛出的"需用户确认"问题,含选项按钮组;最后一项固定为"自定义输入" | 阻塞式(等待用户作答后消失) |
| 能力 | Python 侧位置 | Bridge 是否透传 | Java 是否接收 | 前端是否展示 |
|---|---|---|---|---|
| 流式文本(text) | conversation_loop.py:461 |
✅ hermes_bridge.py:287 |
✅ HermesBridgeClient.java:293 |
✅ 追加思考 |
| 工具开始/结束 | tool_executor.py:431 |
✅ hermes_bridge.py:294-297 |
✅ HermesBridgeClient.java:269, 283 |
❌ useWorkflowRunner.js:184 主动忽略 |
| TODO 工具 | tools/todo_tool.py:240 |
⚠️ 仅作普通 tool_end | ⚠️ 仅作 TOOL_RESULT | ❌ |
| Askfor(clarify) | run_agent.py:378 |
❌ | ❌ | ❌ |
| 实时进度(step) | run_agent.py:380 |
❌ | ❌ | ❌ |
| 状态通知(status) | run_agent.py:384 |
❌ | ❌ | ❌ |
| 思考 spinner(thinking) | run_agent.py:376 |
❌ | ❌ | ❌ |
| 工具细分进度(tool_progress) | agent_init.py:184 |
❌ | ❌ | ❌ |
核心结论:Hermes 的能力池是充足的,瓶颈在 Bridge 透传层只接了 3 个回调(stream_callback / tool_start_callback / tool_complete_callback),其余 5+ 类回调全部沉默执行。
[Python AIAgent]
↓ (callback)
[hermes_bridge.py / FastAPI:18731] ← 仅透传 text/tool_start/tool_end
↓ (SSE)
[HermesBridgeClient.java] ← switch 仅识别 5 类 ExecutionLog
↓ (NodeStreamSink)
[WorkflowLevelExecutor.java:196] ← 包装为 node_stream 事件
↓ (SseEmitter)
[useWorkflowRunner.js:130] ← handleSSEEvent 仅处理 thinking 累加
↓
[WorkflowEditor.vue:2293] ← <pre> 纯文本追加
两个关键事实:
hermes_bridge.py:211-223 创建 AIAgent 时未传 clarify_callback,导致 agent.clarify_callback is None。agent 调用 clarify 工具时直接返回 "Clarify tool is not available in this execution context."(tools/clarify_tool.py:57-61),不阻塞、自主决策。hermes_cli/callbacks.py:42)/ Gateway 默认 600s(tools/clarify_gateway.py:245)HermesBridgeClient.java:198)WorkflowController.java:203)WorkflowLevelExecutor.java:56)核心难点:用户希望 Askfor 无超时(可能几小时后才回来)。但单纯拉长超时(S1 方案)在网络中断场景下不可行——用户笔记本合盖 8 小时后 TCP 连接已死,前端 reader.read() 抛 network error(useWorkflowRunner.js:123-127 当前只显示"工作流执行失败"),用户回来后无法重连,工作流会在 24h 兜底 abort 后变成 FAILED。
Hermes 已有的同步阻塞参考实现:tools/clarify_gateway.py 的 wait_for_response(clarify_gateway.py:103-143)用 1 秒切片 Event.wait 轮询 + touch_activity_if_due 防 watchdog,配合 resolve_gateway_clarify(clarify_gateway.py:150-162)唤醒。Gateway 模式在用,可直接照搬。
项目已具备的关键基础设施(决定方案走向):
external/SseEventBus.java:32-141 已实现按 runId 缓存最近 1000 条事件 + Last-Event-ID 头断线重连 + 完成后缓存保留 1 小时ExternalApiController.java:227 的外部 API 入口已支持断线重连model/entity/WorkflowRun.java / WorkflowRunNode.java 已有完整的运行/节点状态字段NoopSseEmitter.java:16 已用 Long.MAX_VALUE 实现"永不超时"(外部 API 现有实践)结论:采用 S2 持久化 + 重连 方案——clarify 触发时把问题写入 DB + 透传到前端 SSE,前端连接断开后通过 Last-Event-ID 重新订阅 SseEventBus 续接;用户答题后调 POST /runs/{runId}/resume 把答案送回 Bridge 唤醒阻塞线程。
以下问题不同选择会导致改造范围差异巨大,实施前必须确认:
用户决定:采用同步阻塞方案。Askfor 必须无超时(用户可能几小时后才回来)。
最终方案:同步阻塞 + S2 持久化 + 重连 组合(详见 §4.7 Askfor 子方案专章)。
关键决策:
tools/clarify_gateway.pyclarifyWaitExecutor 池与 nodeExecutor 解耦WorkflowPause 表,前端连接断开后可重连续接POST /runs/{runId}/resume 把答案送回 Bridge 唤醒阻塞线程| 方案 | 数据源 | 描述 |
|---|---|---|
| A. 复用 step_callback | 每轮 LLM 调用前的进度 | 颗粒度粗(一轮一次) |
| B. 复用 tool_progress_callback | tool.started / reasoning.available | 颗粒度细,但语义偏工具 |
| C. 复用 thinking_callback | TUI spinner 文案 | 接近用户期望,但当前触发位置较少 |
| D. 全部都接 | 前端按优先级合并展示 | 最完整,但事件流复杂 |
推荐:方案 D,前端按 tool.started > status > step > thinking_spinner 优先级合并到同一"当前状态"槽位。
| 方案 | 描述 |
|---|---|
| A. 解析 todo 工具调用结果 | Bridge 识别 tool_name='todo' 时,把 tool_end 的 result_summary(截断后的 JSON)解析为 TODO 列表 |
| B. 改 todo 工具不被截断 | 给 Bridge 加白名单,todo 工具的 result 不做 500 字截断,原样转发 |
推荐:方案 B。方案 A 会因为 500 字截断丢失数据。
HermesSmartActionExecutor)HermesAgentExecutor)SkillGenerationServiceImpl)推荐:三个全部支持。前两个走同一 HermesBridgeClient 通道,零额外成本;技能生成也调用同一 Bridge,只需在 SkillGenerationController 的 SSE 转发处补几个事件类型。
| 方案 | 描述 |
|---|---|
A. 改造 WorkflowEditor.vue 的 node-result-card |
在现有卡片内增加 4 个折叠区 |
B. 抽出 AgentThinkingPanel.vue 公共组件 |
三处入口(WorkflowEditor/SkillGeneration/RunHistory)共用 |
推荐:方案 B。三处现有实现高度重复,借这次重构统一收口。
RunHistory.vue 从持久化 ExecutionLog 回放。新增 4 类信息若也要在历史中回看,需要扩展 ExecutionLog.Type 枚举并持久化。
推荐:扩展枚举,支持回放。代价小(加几个枚举值),价值大(用户体验一致)。
方案前提:Q1=同步阻塞(S2 持久化+重连)、Q2=D 全部都接、Q3=B 不截断、Q4=全部入口、Q5=B 抽公共组件、Q6=扩展枚举支持回放。
目标:把 Hermes 已有的 6 类回调全部接出来,作为新 SSE 事件转发;同时挂载同步阻塞的 clarify_callback。
改动文件:
backend/hermes-bridge/hermes_bridge.py改动点:
回调注册(hermes_bridge.py:332-340 附近):
step_callback → 发 step 事件,含 {iteration, prev_tools}status_callback → 发 status 事件,含 {category, message}thinking_callback → 发 thinking_status 事件(注意与现有 text 区分),含 {content}tool_progress_callback → 发 tool_progress 事件,含 {event_name, ...detail}clarify_callback → 调用 wait_for_response,发 clarify_request 事件,含 {clarify_id, question, choices};阻塞等待 /clarify/{clarify_id}/answer POSTtool_complete_callback 增强:识别 tool=='todo' 时发独立 todo_update 事件,content 为完整 TODO JSONtodo 工具白名单(hermes_bridge.py:297 附近):截断逻辑前加判断 if tool == 'todo': result_summary = json.dumps(result),跳过 500 字截断
新增端点:POST /clarify/{clarify_id}/answer
{answer: <string>}tools.clarify_gateway.resolve_gateway_clarify(clarify_id, answer) 唤醒阻塞线程wait_for_response 无超时改造(tools/clarify_gateway.py:103-143):增加 timeout is None 分支,跳过 deadline 检查,仅靠 Event.wait 切片轮询维持 watchdog 心跳
验证:
curl POST /run 发起请求,断言 SSE 流中能看到所有新事件类型目标:HermesBridgeClient 能解析新 SSE 事件,并通过 sink 推给工作流引擎。
改动文件:
backend/src/main/java/com/agent/management/engine/hermes/HermesBridgeClient.javabackend/src/main/java/com/agent/management/engine/WorkflowRunEvent.javabackend/src/main/java/com/agent/management/engine/ExecutionLog.javabackend/src/main/java/com/agent/management/engine/NodeStreamSink.java改动点:
WorkflowRunEvent.nodeStream 的 kind 枚举扩展:
thinking | tool_call | tool_resultstatus | step | tool_progress | todo_update | clarify_requestExecutionLog.Type 枚举扩展:
STATUS | STEP | TOOL_PROGRESS | TODO_UPDATE | CLARIFY_REQUESTHermesBridgeClient.parseSseResponse 的 switch 增加新分支:
step → sink.emit(nodeId, "step", json, null) + 写入 logs(STEP)status → 同上 kind=statustool_progress → 同上 kind=tool_progresstodo_update → 同上 kind=todo_update,content 为完整 TODO JSONclarify_request → 特殊处理(见阶段 4):解析 {clarify_id, question, choices} → sink.emit(nodeId, "clarify_request", json, null) + 不结束 SSE 读取循环,继续 readLine 等待后续事件HermesBridgeClient.run 增加超时配置:
conn.setReadTimeout(86_400_000) — 24h(兜底,正常情况靠重连机制)新增方法:HermesBridgeClient.submitClarifyAnswer(runId, clarifyId, answer)
http://127.0.0.1:18731/clarify/{clarifyId}/answer验证:
目标:WorkflowLevelExecutor 把新 kind 通过 SSE 推给前端;引入独立的 clarify 等待池与暂停持久化。
改动文件:
backend/src/main/java/com/agent/management/engine/WorkflowLevelExecutor.javabackend/src/main/java/com/agent/management/engine/WorkflowEngine.javabackend/src/main/java/com/agent/management/controller/WorkflowController.javabackend/src/main/java/com/agent/management/external/SseEventBus.javabackend/src/main/java/com/agent/management/model/entity/WorkflowRun.javabackend/src/main/java/com/agent/management/model/entity/WorkflowPause.java (新增)backend/src/main/java/com/agent/management/engine/repository/WorkflowPauseRepository.java (新增)改动点:
node_stream 事件透传(WorkflowLevelExecutor.java:196 附近):现有 sink lambda 已能包装任意 kind,无需特殊处理
独立 clarify 等待池(WorkflowLevelExecutor.java 顶部新增字段):
private static final ExecutorService clarifyWaitExecutor =
Executors.newCachedThreadPool(r -> {
Thread t = new Thread(r, "clarify-wait");
t.setDaemon(true);
return t;
});
HermesAgentExecutor 接收到 clarify_request 事件后,把当前线程的等待动作 CompletableFuture.supplyAsync(..., clarifyWaitExecutor).join() 转移线程,让 nodeExecutor 池立即释放槽位持久化暂停点:WorkflowPause 实体字段:
id / run_id / node_id / clarify_id / question / choices(JSON) /
created_at / answered_at / answer / status(UNANSWERED/ANSWERED)
HermesAgentExecutor 收到 clarify_request 时 INSERT 一条主超时延长:EXECUTION_TIMEOUT_MINUTES = 1440L(24h 兜底)
SseEmitter 超时延长:WorkflowController.java:203 改为 new SseEmitter(86_400_000L),与 SseEventBus.SSE_TIMEOUT_MS 同步
新增 Controller 端点:
POST /api/workflows/runs/{runId}/resume:接收 {clarifyId, answer} → 调 HermesBridgeClient.submitClarifyAnswer → 更新 WorkflowPause 状态GET /api/workflows/runs/{runId}/stream:关键新增——按 runId 重订阅 SseEventBus(复用外部 API 已有的 Last-Event-ID 机制),断线重连入口GET /api/workflows/runs/{runId}/state:返回 {status, currentPause: {clarifyId, question, choices} | null},供前端轮询恢复SseEventBus 调优:
MAX_EVENTS_PER_RUN 调大到 5000(clarify 期间累积事件可能超 1000)TTL_AFTER_COMPLETION_MS 改为 25 小时(确保用户回来后还能看到完整重放)SSE 心跳:在 WorkflowController.run() 启动后,并发启动一个 ScheduledExecutorService,每 30 秒向 SseEmitter 发送 event().comment(":keep-alive"),防止 NAT/防火墙清连接
验证:
目标:useWorkflowRunner.js 能接收新事件、维护对应状态、支持断线重连。
改动文件:
frontend/src/composables/useWorkflowRunner.jsfrontend/src/api/workflow.js改动点:
解除 useWorkflowRunner.js:184 对 tool_call/tool_result 的忽略
扩展 nodeResults[i] 字段:
{
streamingThinking: '', // ① 已有
currentStatus: '', // ② 实时型,覆盖式
currentTool: null, // ③ 当前调用中的工具
toolHistory: [], // ③ 历史工具调用
todos: [], // ④ TODO 列表
pendingAsk: null, // ⑤ Askfor 问题
}
handleSSEEvent 增加分支:
kind=status|step|tool_progress → 更新 currentStatus(优先级:tool_progress > status > step)kind=tool_call → 推入 currentTool,unshift 到 toolHistorykind=tool_result → 清空 currentTool,更新 toolHistory[0].resultkind=todo_update → 解析 JSON 覆盖 todoskind=clarify_request → 解析 {clarifyId, question, choices} → 设置 pendingAsk新增 submitClarify(clarifyId, answer) 方法:
/api/workflows/runs/{runId}/resumependingAsk关键:断线重连逻辑:
useWorkflowRunner.js:100-122 的 reader.read() 抛错时不再立即报失败lastEventId(从 SSE 响应头或事件 id 字段提取)→ 5 秒后调用 GET /api/workflows/runs/{runId}/stream?lastEventId=N 重连GET /api/workflows/runs/{runId}/state 轮询(每 30 秒),发现 PAUSED 则渲染 Askfor UI验证:
目标:新建 AgentThinkingPanel.vue,三处入口共用。
新建文件:
frontend/src/components/agent/AgentThinkingPanel.vue 主容器frontend/src/components/agent/AskforBlock.vuefrontend/src/components/agent/StatusBlock.vuefrontend/src/components/agent/CurrentToolBlock.vuefrontend/src/components/agent/ThinkingFoldBlock.vuefrontend/src/components/agent/TodoFoldBlock.vuefrontend/src/components/agent/ToolHistoryFoldBlock.vue改动文件:
frontend/src/views/workflow/WorkflowEditor.vue:替换 2293-2304 的 <pre> 区为 <AgentThinkingPanel :node-result="r" ... />frontend/src/views/skill/SkillGeneration.vue:替换 437-494 的 log-section 为 <AgentThinkingPanel :agent-state="..." />frontend/src/views/workflow/RunHistory.vue:替换 300-308 为 <AgentThinkingPanel mode="replay" :logs="..." />AgentThinkingPanel.vue 设计:
<template>
<div class="agent-thinking-panel">
<!-- ⑤ Askfor(最上方,最显眼,仅在 pendingAsk 时出现) -->
<AskforBlock v-if="state.pendingAsk" :ask="state.pendingAsk" @answer="onAnswer" />
<!-- ② 实时型思考(覆盖式,带脉冲动画) -->
<StatusBlock v-if="state.currentStatus" :text="state.currentStatus" live />
<!-- ③ 工具调用:当前进行中(覆盖式) -->
<CurrentToolBlock v-if="state.currentTool" :tool="state.currentTool" />
<!-- ① 追加型思考(折叠,自动滚到底) -->
<ThinkingFoldBlock :text="state.streamingThinking" :expanded="expandedThinking" />
<!-- ④ TODO List(折叠) -->
<TodoFoldBlock v-if="state.todos.length" :todos="state.todos" :expanded="expandedTodo" />
<!-- ③ 工具调用历史(折叠) -->
<ToolHistoryFoldBlock :tools="state.toolHistory" :expanded="expandedHistory" />
</div>
</template>
AskforBlock.vue 关键设计:
emit('answer', value),由父组件调 submitClarify(clarifyId, value)state.currentStatus = '等待用户回答' 的视觉提示,让用户感受到"系统正在等"子组件复用清单:
StatusBlock:复用 nrc-thinking-live 脉冲动画(WorkflowEditor.vue:2991-2995, 3027-3037)CurrentToolBlock:单卡片 + spinnerThinkingFoldBlock:复用 .nrc-thinking 样式 + 自动滚动(借鉴 SkillGeneration.vue:259-264)TodoFoldBlock:复用 RagChatPanel.vue:22-29 的 .step 样式ToolHistoryFoldBlock:复用 SkillGeneration.vue:446-463 的 tool-item 样式验证:
验证清单:
/state 接口恢复 Askfor UI → 提交答案 → 工作流继续Hermes agent Bridge(daemon) Bridge(主) Java Executor SseEmitter 前端
│ │ │ │ │ │
│ clarify_tool │ │ │ │ │
│─────────────>│ │ │ │ │
│ │ Event.wait │ │ │ │
│ │ +queue.put │ │ │ │
│ │ (clarify_req) │ │ │ │
│ │───────────────>│ yield SSE │ │ │
│ │ │────────────>│ emit sink │ │
│ │ │ │────────────>│ event │
│ │ │ │ │──────────>│
│ │ │ │ INSERT pause │ │
│ │ │ │ │ │ 渲染 Askfor UI
│ │ │ │ │ │
│ │ ...用户离开 8 小时... │ │ │
│ │ │ │ │ TCP 断 │ reader.read()抛错
│ │ │ │ │ │
│ │ │ │ │ │ 5秒后重连
│ │ │ │ │<──────────│ GET /stream
│ │ │ │ │ │ ?lastEventId=N
│ │ │ │ │──────────>│ 续接 SSE
│ │ │ │ │ │
│ │ │ │ │ │ 用户答题
│ │ │ │ POST /resume │ │
│ │ │ │<─────────────│<──────────│
│ │ │ │ POST /answer │ │
│ │ │ │─────────────>│ │
│ │ resolve │ │ │ │
│ │ Event.set() │ │ │ │
│ │<───────────────│ │ │ │
│ │ │ │ │ │
│ │ 继续执行 │ │ │ │
│<─────────────│ │ │ │ │
│ 后续节点... │ │ │ │ │
| 层 | 配置 | 数值 | 说明 |
|---|---|---|---|
| clarify_callback | wait_for_response 的 timeout 参数 |
None(无限) |
改造 clarify_gateway.py 支持 None 分支 |
| HttpURLConnection readTimeout | HermesBridgeClient.java:198 |
86_400_000 ms(24h) |
仅兜底,正常情况由 SSE 心跳维持 |
| SseEmitter | WorkflowController.java:203 |
86_400_000 ms(24h) |
仅兜底 |
| SseEventBus SSE_TIMEOUT_MS | SseEventBus.java:41 |
86_400_000 ms(24h) |
仅兜底 |
| WorkflowLevelExecutor 主超时 | WorkflowLevelExecutor.java:56 |
1440L 分钟(24h) |
仅兜底,防止永久死锁 |
| SseEventBus 完成后 TTL | SseEventBus.java:38 |
90_000_000 ms(25h) |
完成后保留 1h+ 以便用户回看 |
| WorkflowPause DB 记录保留 | 定时清理任务 | 30 天 | 超过 30 天未回答视为放弃 |
重要说明:所有"24h"超时都是兜底——正常情况下用户答题几秒内完成,靠 SSE 心跳 + 重连机制保证体验上的"无超时"。24h 是为了防止用户彻底失联时占用资源。
位置:WorkflowController.java 新增 SseEmitter 后立即启动心跳任务。
实现:
ScheduledFuture<?> heartbeat = heartbeatScheduler.scheduleAtFixedRate(() -> {
try {
emitter.send(SseEmitter.event().comment(":keep-alive"));
} catch (IOException e) {
// 连接已断,停止心跳
}
}, 30, 30, TimeUnit.SECONDS);
心跳周期 30 秒:
关键改进:独立 clarifyWaitExecutor 池
对比 S1 vs S2(含独立池):
| 维度 | S1(拉长超时) | S2(持久化+重连+独立池) |
|---|---|---|
| 用户离开 8h 时节点 worker 池占用 | 占满 8h | 0(已转移 clarifyWaitExecutor) |
| 用户离开 8h 时 clarifyWaitExecutor 池占用 | N/A | 每个阻塞 clarify 占 1 个(CachedThreadPool 无上限,但有 24h 兜底) |
| TCP 断开后服务端行为 | 24h 后才 abort | 用户答题前一直等(合理),24h 兜底 |
| 用户回来后体验 | 工作流已 FAILED,需重跑 | 自动重连续接,答题后继续 |
SseEventBus.java:32 加优先级逻辑| 风险 | 等级 | 缓解 |
|---|---|---|
| Bridge 透传层改动可能影响既有 thinking 流(高流量场景) | 高 | 加 feature flag(环境变量 HERMES_BRIDGE_EXPOSE_ALL_CALLBACKS=true),新回调可灰度开关;保留旧逻辑作 fallback |
| Askfor 同步阻塞方案复杂(持久化 + 重连 + 心跳 + 独立池) | 高 | 分阶段交付:先实现 ①~④(无 Askfor)+ Askfor UI 骨架;Askfor 全链路作为最后阶段,独立可关闭 |
| Hermes 各 callback 的实际触发频率/数据量未充分压测 | 中 | 阶段 1 完成后做一轮压测,前端可加节流(如 tool_progress 每 200ms 合并) |
| 三处入口(WorkflowEditor/SkillGeneration/RunHistory)样式差异大,公共组件抽取后可能风格不一致 | 中 | 阶段 5 完成后逐一人工对比,必要时加 prop 暴露主题差异 |
| clarifyWaitExecutor 无界可能被恶意工作流耗尽 | 中 | 单工作流同时 pending clarify 上限 8 个;超过则拒绝新 clarify,触发 failStrategy |
| SseEventBus 容量超限丢事件导致重连后丢数据 | 中 | 加优先级标记,clarify_request 永不丢弃 |
| todo 工具结果不截断可能导致 SSE 单条过大 | 低 | 单条 TODO 列表通常 <2KB,可接受;如需可加 50KB 上限保护 |
| RunHistory 持久化字段扩展需要数据库迁移 | 低 | ExecutionLog 是 JSON 字段,加枚举值不需要 DDL;WorkflowPause 是新表,需要 Flyway 迁移 |
| 24h 兜底超时仍可能让用户失联 | 低 | 监控指标:当前 pending clarify 数;超过阈值告警 |
| 阶段 | 后端工时 | 前端工时 | 测试工时 | 合计 |
|---|---|---|---|---|
| 1. Bridge 透传(含 clarify_callback) | 8h | - | 2h | 10h |
| 2. Java 接收(含 clarify_request 处理) | 5h | - | 1h | 6h |
| 3. 引擎推送 + 持久化 + 重连端点 + 心跳 + 独立池 | 10h | - | 3h | 13h |
| 4. 前端 composable(含断线重连) | - | 6h | 2h | 8h |
| 5. 前端公共组件(7 个子组件) | - | 14h | 3h | 17h |
| 6. 端到端测试(含 8h 长等待模拟) | - | - | 6h | 6h |
| 合计 | 23h | 20h | 17h | 60h(约 7.5 人日) |
比 v1.0 多 23h,主要来自 Askfor S2 方案的持久化、重连、心跳、独立池。
| 版本 | 日期 | 变更 |
|---|---|---|
| v1.0 | 2026-08-02 | 初稿,待用户确认 Q1~Q6 |
| v1.1 | 2026-08-02 | Q1 已确认=同步阻塞方案;新增"无超时"要求;调研 S1/S2/S3 三方案后确定采用 S2 持久化+重连;新增 §4.7 Askfor 子方案专章;工时从 37h 上调至 60h |