调研日期:2026-08-18 背景:对话页多会话并发场景调研结论。当前主流程(对话页多会话并发)链路安全, 以下缺陷暂不触发或影响面有限,记录备查。
| 层 | 隔离机制 | 位置 |
|---|---|---|
| Java 执行层 | ChatRunService 固定线程池 max(8, cpu×2),每 run 独立线程;SseEventBus 按 runId 隔离 |
backend/src/main/java/com/agent/management/service/ChatRunService.java:110 |
| Bridge 线程层 | 每个 /run 请求创建独立 daemon 线程,事件经 run 级 queue(局部变量)隔离 |
backend/hermes-bridge/hermes_bridge.py:541 |
| Agent 实例层 | LRU 池按 session_id::hermes_home::model_id 键控;每会话有独立 hermesSession |
hermes_bridge.py:202、ChatSessionService.java:51 |
| 工作目录(主要路径) | _SESSION_CWD 为 contextvars,线程内 set/reset 配对,hermes-agent 工具优先读取 |
hermes_bridge.py:489-525 |
| Clarify | 按 clarify_id 注册/唤醒,run 级孤儿清理配对 |
hermes_bridge.py:411-447 |
os.chdir 进程级竞态(优先级:中)位置:backend/hermes-bridge/hermes_bridge.py:474-479
现象:working_dir 除设置 contextvar 外,还会切换进程 cwd(os.chdir(wd))
并覆盖进程级环境变量 TERMINAL_CWD。多个 run 并发时:
chdir 的 run 主导,先启动的 run 拿到错误目录;original_cwd,会破坏仍在运行的 run 的进程 cwd。影响面:仅限直接调用 os.getcwd() 的工具;走 _SESSION_CWD(contextvar,
线程隔离)的工具不受影响。
触发场景:工作流 DAG 同层多个 Hermes 节点并发执行(多个 /run 请求同时
携带不同 working_dir)。对话页多会话场景因 Agent 隔离 + 工具走 contextvar
基本无感。
修复建议:将 os.chdir / TERMINAL_CWD 下沉为按 task_id 的隔离机制
(与 register_task_env_overrides 同思路),运行线程内不再触碰进程全局状态。
位置:backend/hermes-bridge/hermes_bridge.py:494-500、:202-207
现象:同一 session_id::hermes_home::model_id 的两个并发 run 会从 LRU 池
拿到同一个 Agent 实例:
_run 内直接给实例属性赋回调(agent.tool_start_callback = ... 等),
后启动的 run 覆盖先启动 run 的全部回调 → 事件流向错乱;run_conversation 历史)交叉污染。当前防线:仅前端"同会话运行中禁发"(useChat.js 的 sending computed)。
双浏览器窗口打开同一会话、或直接调 API 可绕过。
修复建议(低成本方案):Java 层 ChatRunService.startRun 增加校验——
同会话存在 RUNNING 状态消息时拒绝新 run(返回业务错误)。Bridge 层可选
加固:/run 检测 cache_key 已有活跃 run 时强制 force_new 并发运行。
HERMES_HOME 环境变量进程全局覆盖(优先级:低)位置:backend/hermes-bridge/hermes_bridge.py:210-212
现象:带 hermes_home 的请求直接 os.environ["HERMES_HOME"] = ...,
并发请求互相覆盖,技能目录加载可能错乱。
当前防线:对话页与工作流节点均传 hermes_home=null(Java 侧
HermesAgentExecutor.java:98),回落固定 HERMES_HOME,暂不触发。
修复建议:仅在 Agent 构造期间临时设置并立即恢复(临界区内),或改为 显式传参注入而非环境变量。
缺陷 2(Java 层会话级 run 互斥校验,成本低、封堵面大)> 缺陷 1(工作目录 隔离机制重构)> 缺陷 3(当前不触发,可延后)。