# 《WaLiSSH - AI Shell 智能终端》第2-11节:UI 对接&迭代功能

作者:小傅哥
博客:https://bugstack.cn (opens new window)
视频:https://t.zsxq.com/OXlKJ (opens new window)

沉淀、分享、成长,让自己和他人都能有所收获!😄

大家好,我是技术UP主小傅哥。

好嘞,到这可以开始对接UI了,让整个功能以产品的形态展示。对话过程中,让用户看到;

  1. Agent 当前处于分析、工具执行还是生成阶段;
  2. 文本如何逐步生成;
  3. 调用了什么工具,传入了什么参数,结果是成功还是失败;
  4. 当前执行到第几步,是否还会继续;
  5. 连接中断、用户停止或后端异常时,页面如何正常结束。

与此同时,再优化2个场景:

  1. 上下文污染:每轮工具执行后,环境信息、工具摘要都被追加到用户消息尾部。下次打开会话,模型看到的"用户消息"其实是"用户原文 + 上次的环境快照 + 上次的工具输出",又长又乱还浪费 token。
  2. 意图标签太粗糙:早期实现只把一个枚举名(如 DIAGNOSE)塞进 Prompt,低置信度时反而误导模型。

这一节的视频会先演示使用效果。

# 一、本章诉求

在本分支 2-11-ai-case-ReAct-ui 的开发中,我们解决了以下核心问题:

问题 现象 解法
子 Agent 事件不可见 dispatchSubAgents 派发的子 Runner 事件不进入父事件流 AgentEventPublisher 三级路由 + 子工具合成事件
SSH 工具事件丢失 executeCommand 的 FunctionResponse 不一定以标准形式进入父事件流 SshExecuteAdkTool 合成 tool_call / tool_result 事件
同一工具事件重复 ADK 可能对同一 FunctionCall / Response 重复投递 Controller 端按 toolCallId 去重
上下文膨胀 动态 Prompt 后缀原样写入 Session,跨轮重复累积 PromptEnvelope 定界用户原文,Session 只保存原文
Prompt 前缀不稳定 所有动态上下文堆在用户消息后,缓存命中率低 ContextPlacement 分层:稳定前缀 / 动态尾部
意图标签误导 低置信度枚举名照样渲染,模型被误导 结构化意图提示:置信度 + 候选 + 实体 + 使用原则
用户消息含 --- 被误切 旧实现用 \n---\n 分隔动态后缀,用户 Markdown 内容被切断 PromptEnvelope 用 XML 风格标签定界,不依赖内容特征

没有一次或者一直完美的东西,只有不断优化的目标和诉求。

# 二、总体架构

先从全局视角看这一节做了什么:

用户发送消息 + terminalSessionId
         │
         ▼
┌─────────────────────────────────────────────────────┐
│ Controller.chatStream()                             │
│                                                     │
│  1. 创建 SseEmitter + 心跳                           │
│  2. 注册 session / terminal 监听器                    │
│  3. 订阅 chatService.handleMessageStream()          │
│  4. 逐事件转换 → JSON SSE                            │
│  5. 收到嵌套事件 → 同一转换逻辑处理                     │
│  6. finally: 注销监听器 + 清理 ThreadLocal           │
└────────────────────┬────────────────────────────────┘
                     │
         ┌───────────┼───────────────┐
         ▼           ▼               ▼
   主 Runner     子 Agent Runner    SSH 工具
   Event 流      (独立 Runner)      executeCommand
         │           │               │
         │           ▼               ▼
         │   AgentEventPublisher(三级路由)
         │   invocation → session → terminal
         │           │               │
         └───────────┴───────┬───────┘
                             ▼
                    Controller 事件桥接层
                             │
                             ▼
                      JSON SSE → 前端 UI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29