状态:设计初稿,2026-10-24。需求见 requirements.md,FWH 业务工具见 agent-mcp.md。AgentServer 接口与事件以其仓库
docs/design/04-api.md和后台“API 协议”页为准,第三方 MCP 接入见其 ADR-0021。
新助手是 ToolBox 中独立的新模块:独立的入口、前后端代码、数据集合和 MCP 服务;旧 Kiro 助手(legacy-kiro-assistant.md)原样保留,两者互不调用、互不共享数据。
浏览器(ToolBox)
├─ 旧:顶栏 AiChat → /ai/*(不改动)
└─ 新:菜单「AI 助手」页面(/ai-assistant)→ 会话栏 + <AgentChat> + 文件栏
│ @agent-server/client:baseUrl = <ToolBox API>/agent,Authorization = ToolBox 登录令牌
▼
ToolBox Go 后端(新模块 agent)
├─ /agent/sessions/*:会话列表、创建、改名、删除(AgentSessions)
└─ /agent/v1/*:AgentServer 代理(鉴权 → 归属校验 → 换 API Key → 转发,SSE 透传)
▼
AgentServer /v1
Profile fwh-assistant(或按角色的其他 Profile):Claude、技能、资料库、MCP 服务
MCP Gateway ── Bearer AGENT_MCP_TOKEN(固定请求头,无会话信息)──┐
▼
ToolBox fwh-agent-mcp(新服务,无用户状态,只读工具集)
▼
FWH 云 API / PostgreSQL / MongoDB / Redis / Plane / SIM 平台
职责划分:
| 组件 | 负责 |
|---|---|
| ToolBox 前端(新模块) | 独立页面:会话栏、<AgentChat>、文件栏、主题适配(ui-design.md) |
| ToolBox 后端(新模块) | 用户鉴权、按角色选择 Profile、会话归属、AgentServer 代理 |
| AgentServer | Agent 运行、事件落库与续传、工作区与文件、审批、沙箱、技能、资料库、MCP Gateway 与审计 |
| fwh-agent-mcp | 业务数据查询(无用户)、PII 脱敏、业务凭证 |
| 编号 | 决策 | 理由 |
|---|---|---|
| D-01 | 新助手与旧助手完全分开:新路由前缀 /agent、新集合、新前端目录、新 MCP 服务 |
旧助手可以继续使用到新助手验收完成,下线时直接删除整块旧代码,没有交叉依赖 |
| D-02 | 业务工具用无用户状态的新 MCP(agent-mcp.md) | AgentServer Gateway 以固定请求头连接 MCP、多会话共用连接,不传会话信息;身份由上层控制更简单可靠 |
| D-03 | 用户隔离在 ToolBox 后端实现:浏览器只持有 ToolBox 登录令牌,所有 AgentServer 请求经代理并校验会话归属 | AgentServer 不区分使用者,同一 API Key 下的会话彼此可见;API Key 不出后端 |
| D-04 | 用户能力差异通过 Profile 表达:ToolBox 创建会话时按用户角色选择 Profile,Profile 决定技能、资料库和勾选的 MCP 服务 | MCP 无用户后,权限边界上移到“会话用哪个 Profile” |
| D-05 | 前端使用 @agent-server/chat-ui 的 <AgentChat> |
流式、工具卡片、审批/提问、附件、产出文件、中断、断线续传都已具备 |
| 文件 | 内容 |
|---|---|
service/config/config.go |
新增 Agent 段 |
service/utils/agentserver/client.go |
AgentServer HTTP 客户端(会话创建、改名、删除、子资源反查) |
service/utils/agentserver/proxy.go |
/agent/v1/* 代理:白名单、转发、SSE 透传、事件解析 |
service/services/agentServices.go |
会话与归属、Profile 选择 |
service/repositories/mongo/agentSessionRepo.go |
AgentSessions、AgentResources |
service/controllers/agentControllers.go |
HTTP 处理 |
service/routes/agentRoutes.go |
路由注册(routes.go 中调用 AgentSetup) |
不引用 utils/acp、services/aiChatServices.go、utils/filestore 等旧助手代码。
AGENT_ENABLED=true
AGENT_SERVER_URL=http://127.0.0.1:8787
AGENT_SERVER_API_KEY=ask_xxx # 只在后端
AGENT_PROFILE_DEFAULT=prf_xxx # 默认 Profile(fwh-assistant)
AGENT_PROFILE_BY_ROLE=ops:prf_yyy,admin:prf_zzz # 可选:角色 → Profile,按顺序取第一个命中的
AGENT_ALLOWED_ROLES= # 可选:为空表示所有登录用户可用
API Key 在 AgentServer 后台签发时,勾选上述全部 Profile 为可用。
AgentSessions(新集合,不复用 AiChatSessions):
| 字段 | 说明 |
|---|---|
sessionId |
AgentServer 会话 ID(ses_…),唯一索引 |
userId |
ToolBox 用户名(AuthGetUserName) |
profileId |
创建时选用的 Profile |
title、createdAt、lastActive |
|
deletedAt |
软删除 |
索引:{ userId, deletedAt, lastActive }。
AgentResources(代理校验不带会话 ID 的请求用):resourceId(run_ / itx_ / file_,唯一)、sessionId、createdAt(TTL 与会话保留期一致)。
| 接口 | 行为 |
|---|---|
GET /agent/sessions |
本人未删除的会话,按 lastActive 倒序,上限 50 |
POST /agent/sessions |
按角色选 Profile → POST /v1/sessions { profileId } → 写 AgentSessions → 返回 { sessionId, title } |
PATCH /agent/sessions/:id |
校验归属 → PATCH /v1/sessions/:id { title } → 更新 |
DELETE /agent/sessions/:id |
校验归属 → DELETE /v1/sessions/:id → 软删除 |
用户角色变化后,已有会话继续使用创建时的 Profile;新建会话使用新角色对应的 Profile。
路由 ALL /agent/v1/*,先经 ToolBox 鉴权中间件,然后:
| 方法 | 路径 | 归属校验 |
| --- | --- | --- |
| GET | /v1/sessions/:id、/events、/files、/stream(SSE) | 路径中的会话 |
| POST | /v1/sessions/:id/messages、/v1/sessions/:id/files | 路径中的会话 |
| PATCH | /v1/sessions/:id(只保留 title、model) | 路径中的会话 |
| GET、POST | /v1/runs/:id、/v1/runs/:id/interrupt | AgentResources |
| GET | /v1/interactions?sessionId= | 查询参数中的会话 |
| POST | /v1/interactions/:id | AgentResources |
| GET | /v1/files/:fileId | AgentResources |
| GET | /v1/profiles、/v1/providers | 无(只读元数据) |
不放行 GET /v1/sessions(会列出所有用户的会话)、POST /v1/sessions、DELETE、/v1/usage、/v1/browser-tokens。
归属校验:会话属于当前用户且未删除;子资源先查 AgentResources,查不到时反查 AgentServer(GET /v1/runs/:id 与文件列表都带 sessionId;交互在本人最近活跃的会话中用 GET /v1/interactions?sessionId= 查找),确认后补写。不符统一返回 404。
转发:Authorization 换成 API Key,去掉 Cookie 与 ToolBox 专有头,保留 Last-Event-ID;multipart 原样转发(Fiber BodyLimit 按 AgentServer 上传上限调整)。
记录子资源:POST /messages 响应中的 runId、POST /files 响应中的文件 ID;SSE 与 /events 透传时解析 run.started、interaction.required、file.changed,异步批量写入,不阻塞转发;发消息时刷新 lastActive。
SSE:逐块写出并立即 Flush,客户端断开时取消上游请求,加 X-Accel-Buffering: no;Caddy/nginx 对 /agent/v1/sessions/*/stream 关闭缓冲。断线续传由 SDK 的 Last-Event-ID 完成,代理不重试。
新助手是菜单路由 /ai-assistant 下的独立大页面(左侧会话栏、中间对话、右侧文件栏),不放在顶栏。路由、布局、交互与代码结构见 ui-design.md;代码在 src/views/ai-assistant/ 与 src/service/agent/。
不修改顶栏的 Actions/AiChat/ 和 src/service/aiChat/,旧助手入口保持不变。
const client = new AgentClient({
baseUrl: `${getBaseUrl()}/agent`, // SDK 请求 /agent/v1/...
getToken: async () => getToolBoxToken(), // 与 serverReq.ts 相同的登录令牌
})
依赖按 AgentServer docs/integration.md 安装三个 SDK 包(URL tgz,锁定版本),main.ts 引入 @agent-server/chat-ui/style.css。同源请求 ToolBox 后端,不需要 AgentServer 的 CORS 与浏览器令牌。
主题:ToolBox 切换明暗时同步设置 data-theme(若组件只认 <html> 上的属性,需确认不影响 NaiveUI);必要时覆盖 --app-* 变量对齐 ToolBox 主色。
均在 AgentServer 后台完成,不改 AgentServer 代码(agent-mcp.md 5.2 的结果处理改动除外)。
| 项 | 配置 |
|---|---|
| MCP 服务 | fwh:远程 HTTP,http://127.0.0.1:8091/mcp,请求头 Authorization: Bearer <AGENT_MCP_TOKEN>;二期 fwhops |
| 技能 | 新写 fwh-assistant(第 6 节),源码在 ToolBox deploy/agent-assistant/skills/fwh-assistant/。AgentServer 暂无自定义技能入口,需求见 AgentServer 仓库 docs/design/12-custom-skills.md;实现后作为技能源导入 |
| 资料库 | fwh-wiki:/srv/agent-server/knowledge/fwh-wiki(手动运行同步脚本从 FranklinWH-Wiki client/docs 拷贝,排除 .vitepress、public、casdoor;home 下的路径受 ProtectHome 限制,不能直接引用);fwh-data-knowledge:同样方式同步 docs/knowledge |
Profile fwh-assistant |
引擎 Claude;权限模式“需审批”;技能 report-conventions、custom-skills:fwh-assistant(AgentServer 支持后);资料库 fwh-wiki、fwh-data-knowledge(有内容后);MCP 服务 fwh;文件访问 restricted;按需开放 WebSearch / WebFetch |
Profile fwh-assistant-ops(二期) |
在上一个基础上加勾 fwhops |
| API Key | 平台 fwh-toolbox,可用 Profile 为上述全部,默认 fwh-assistant |
fwh-assistant从头编写,旧的 deploy/kiro/skills/、deploy/kiro/steering/ 只作为素材,不迁移、不改动。内容:
site_get → alarm_events → mqtt_log_search → fault_record_list”);何时用 *_export 并在工作区用 pandas 分析;mcp-data-guard.md 的规则,改写为面向新工具);工具不足时说明缺口,不用其他方式拼凑;templates/company-template.pptx(随技能分发);产出写入 outputs/;工具名在技能中写引擎侧可见的名称(mcp__gateway__fwh__site_get 等)。
| 阶段 | 内容 | 依赖 | 完成标志 |
|---|---|---|---|
| S1 | Agent MCP 框架(kit、HTTP、约束测试)+ 站点、告警两个领域 |
— | go test ./agentmcp/... 通过;AgentServer 后台“测试连接”能列出工具 |
| S2 | Agent MCP 其余领域工具与导出工具 | S1 | 单测通过 |
| S3 | AgentServer:resource 结果落盘(agent-mcp.md 5.2) |
— | AgentServer 测试通过 |
| S4 | 技能 fwh-assistant、资料库同步、Profile、API Key;在 Playground 回归第 8 节业务用例 |
S1、S2 | Playground 通过 |
| S5 | ToolBox 后端新模块:配置、集合、会话接口、代理 | — | 接口与代理单测通过 |
| S6 | ToolBox 前端新页面(ui-design.md) | S5 | 本地联调通过 |
| S7 | 测试环境上线,新页面与旧助手并存,用户验收第 8 节用例 | S4~S6 | 验收通过 |
| S8 | 决定旧助手下线时间;下线时删除旧助手全部代码、cmd/mcp、deploy/kiro/、Kiro 配置与部署脚本 |
S7 | 单独评审 |
S1~S4(MCP 与 AgentServer 侧)和 S5~S6(ToolBox 前后端)可以并行。
| 编号 | 用例 | 覆盖 |
|---|---|---|
| T-01 | 问“站点 XXXX 的概况和最近 7 天告警”,回答含表格;工具卡片显示中文标题,没有弹审批 | 只读工具直接调用 |
| T-02 | 分析某站点 30 天功率流:Agent 调用导出工具,数据落在工作区文件,用 Python 统计并出图;上下文中没有明细 | 导出与落盘 |
| T-03 | 问一个 Wiki 中的产品问题(如某告警码含义),回答引用文档路径 | 资料库 |
| T-04 | 粘贴截图 + 上传 xlsx,生成带中文图表的 Word 报告和公司模版 PPT,文件卡片可下载、PDF 可预览 | 上传与产出 |
| T-05 | 运行中刷新页面,回到同一会话且输出继续;运行中切换到其他标签页再回来,输出未中断;运行中点击中断 | 续传与中断 |
| T-11 | 宽屏三栏、1024~1279px 文件栏收起、< 1024px 两侧都收起为抽屉,均可正常使用 | 页面布局 |
| T-06 | 用户 A 用自己的令牌请求用户 B 的会话(stream / events / files / messages)及 B 的 runId / interactionId / fileId,全部 404;GET /agent/v1/sessions 返回 403 |
用户隔离 |
| T-07 | 配置了角色映射时,不同角色的用户新建会话使用不同 Profile;无权使用的用户看不到“AI 助手”菜单、接口返回 403 | Profile 选择 |
| T-08 | 让 Agent 读取 ToolBox service/.env、~/.ssh:被拦截并写入 AgentServer 审计 |
沙箱 |
| T-09 | 重启 ToolBox 后端、AgentServer、fwh-agent-mcp 后,历史会话时间线完整且可继续对话;fwh-agent-mcp 停止时,工具返回“暂不可用”而不是挂起 | 可恢复 |
| T-10 | 旧 AI 助手在新模块上线后功能不受影响 | 相互独立 |