|
|
@@ -1,1226 +0,0 @@
|
|
|
-# FranklinWH-ToolBox AI 助手方案
|
|
|
-
|
|
|
-## 1. 协议栈说明
|
|
|
-
|
|
|
-| 协议 | 用途 | 状态 |
|
|
|
-| -------------------------------- | ---------------------- | ---------------------------------- |
|
|
|
-| **MCP** (Model Context Protocol) | AI Agent ↔ 工具/数据源 | Kiro CLI 原生支持,主力协议 |
|
|
|
-| **A2A** (Agent2Agent Protocol) | Agent ↔ Agent 协作 | Linux Foundation 维护,v1.0 已发布 |
|
|
|
-| ~~ACP~~ | ~~Agent 通信~~ | 2025.8 已合并入 A2A,不再独立存在 |
|
|
|
-
|
|
|
-**建议:** 项目内 AI 助手核心是 **Kiro CLI + 自定义 MCP Server**。如果后续需要多 Agent 协作再引入 A2A。
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-## 2. 现有系统架构
|
|
|
-
|
|
|
-### 2.1 前端(src/)
|
|
|
-
|
|
|
-| 项目 | 说明 |
|
|
|
-| ---------- | ------------------------------------------------ |
|
|
|
-| 框架 | Vue 3 + TypeScript + Vite |
|
|
|
-| UI 库 | Naive UI |
|
|
|
-| 状态管理 | Pinia(自定义 defineSetupStore 模板) |
|
|
|
-| 样式 | UnoCSS (Tailwind 兼容) |
|
|
|
-| 图表 | @antv/g2 |
|
|
|
-| HTTP | 自定义 FetchClient(支持拦截器、download、blob) |
|
|
|
-| 代码编辑器 | Monaco Editor |
|
|
|
-
|
|
|
-**前端目录结构:**
|
|
|
-
|
|
|
-```
|
|
|
-src/
|
|
|
-├── composable/ # 组合式函数
|
|
|
-├── components/ # 公共组件
|
|
|
-├── event/ # 事件系统
|
|
|
-├── injection/ # 依赖注入
|
|
|
-├── router/ # 路由配置
|
|
|
-├── service/ # API 层(按模块分目录:feedback/, siteInfoManage/, simCardManage/ 等)
|
|
|
-├── stores/ # Pinia Store(modules/data/, modules/views/)
|
|
|
-├── theme/ # 主题配置
|
|
|
-├── types/ # 全局类型
|
|
|
-├── utils/ # 工具函数
|
|
|
-└── views/ # 页面视图(按功能模块分目录)
|
|
|
- ├── feedback/
|
|
|
- ├── site-info-manage/
|
|
|
- ├── sites-monitor/
|
|
|
- ├── sim-card-manage/
|
|
|
- ├── batch-download/
|
|
|
- └── ...
|
|
|
-```
|
|
|
-
|
|
|
-### 2.2 后端(service/)
|
|
|
-
|
|
|
-| 项目 | 说明 |
|
|
|
-| -------- | ---------------------------------------------------------------------- |
|
|
|
-| 框架 | Go + Fiber v2 |
|
|
|
-| 数据库 | MongoDB + PostgreSQL + MySQL |
|
|
|
-| 缓存 | Redis(自定义 cache 层) |
|
|
|
-| 对象存储 | MinIO |
|
|
|
-| 任务队列 | Asynq (Redis-based) |
|
|
|
-| 外部 API | FranklinWH Energy API、Plane V2 Web API、Acceleronix API、SmartHub API |
|
|
|
-| 认证 | Casdoor JWT |
|
|
|
-| MQTT | FWH Pro MQTT |
|
|
|
-
|
|
|
-**后端目录结构:**
|
|
|
-
|
|
|
-```
|
|
|
-service/
|
|
|
-├── main.go # 入口(初始化所有依赖 + 启动 HTTP 服务)
|
|
|
-├── config/ # 配置加载(Viper,从 .env 读取)
|
|
|
-├── controllers/ # HTTP 路由处理器(Fiber Handler)
|
|
|
-├── services/ # 业务逻辑层
|
|
|
-├── repositories/ # 数据访问层
|
|
|
-│ ├── mongo/ # MongoDB 操作
|
|
|
-│ ├── redis/ # Redis 操作
|
|
|
-│ ├── pgsql/ # PostgreSQL 操作
|
|
|
-│ ├── mysql/ # MySQL 操作
|
|
|
-│ ├── api/ # 外部 API 客户端
|
|
|
-│ │ ├── fwh_pro/ # FranklinWH Energy/OSS API
|
|
|
-│ │ ├── plane_v1/ # Plane V1 API(API Key 认证)
|
|
|
-│ │ ├── plane_v2/ # Plane V2 Web API(Session 认证)
|
|
|
-│ │ ├── acceleronix/ # Acceleronix SIM 卡 API
|
|
|
-│ │ └── smartHub/ # SmartHub SIM 卡 API
|
|
|
-│ ├── mqtt/ # MQTT 通信
|
|
|
-│ └── events/ # 事件通信(xLog TCP)
|
|
|
-├── routes/ # 路由注册
|
|
|
-├── middleware/ # 中间件(认证等)
|
|
|
-├── domain/ # 领域模型
|
|
|
-├── dto/ # 数据传输对象
|
|
|
-├── database/ # 数据库连接初始化
|
|
|
-├── cache/ # Redis 缓存封装
|
|
|
-├── task/ # 任务队列(Asynq)
|
|
|
-├── scheduler/ # 定时任务
|
|
|
-├── jobs/ # 后台作业
|
|
|
-└── utils/ # 工具包
|
|
|
-```
|
|
|
-
|
|
|
-### 2.3 后端各层职责
|
|
|
-
|
|
|
-```
|
|
|
-HTTP Request
|
|
|
- │
|
|
|
- ▼
|
|
|
-┌──────────────┐
|
|
|
-│ controllers/ │ 解析参数、校验、调用 service、返回 JSON
|
|
|
-└──────┬───────┘
|
|
|
- │
|
|
|
- ▼
|
|
|
-┌──────────────┐
|
|
|
-│ services/ │ 业务逻辑编排、数据转换、调用多个 repository
|
|
|
-└──────┬───────┘
|
|
|
- │
|
|
|
- ▼
|
|
|
-┌──────────────┐
|
|
|
-│repositories/ │ 数据库 CRUD、外部 API 调用、缓存操作
|
|
|
-└──────────────┘
|
|
|
-```
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-## 3. 整体架构(AI 助手视角)
|
|
|
-
|
|
|
-```
|
|
|
-┌─────────────────────────────────────────────────────────────────┐
|
|
|
-│ 开发者终端 │
|
|
|
-│ Kiro CLI │
|
|
|
-│ (AI Agent / Host) │
|
|
|
-└────────────┬────────────────────────────────┬────────────────────┘
|
|
|
- │ MCP (stdio) │ MCP (stdio)
|
|
|
- ▼ ▼
|
|
|
-┌────────────────────────┐ ┌──────────────────────────────┐
|
|
|
-│ 内部工具 MCP Server │ │ 外部服务 MCP Server │
|
|
|
-│ (Go) │ │ (社区开源) │
|
|
|
-├────────────────────────┤ ├──────────────────────────────┤
|
|
|
-│• query_site_info │ │• AWS Docs 搜索 │
|
|
|
-│• search_sites │ │• Brave 网络搜索 │
|
|
|
-│• query_sim_card │ └──────────────────────────────┘
|
|
|
-│• query_power_flow │
|
|
|
-│• create_plane_issue │
|
|
|
-│• query_plane_issues │
|
|
|
-│• query_alarm_stats │
|
|
|
-└────────────┬───────────┘
|
|
|
- │ 直接 import 复用
|
|
|
- ▼
|
|
|
-┌────────────────────────────────────────────────────────────────┐
|
|
|
-│ 现有后端 service/ 代码 │
|
|
|
-├────────────────────────────────────────────────────────────────┤
|
|
|
-│ services/ │ repositories/ │ domain/dto │
|
|
|
-│ (业务逻辑) │ (数据访问+外部API) │ (数据模型) │
|
|
|
-└─────────┬───────────┴──────────┬─────────────┴─────────────────┘
|
|
|
- │ │
|
|
|
- ▼ ▼
|
|
|
-┌──────────────┐ ┌──────────────────────────────────────────────┐
|
|
|
-│ MongoDB │ │ 外部系统 │
|
|
|
-│ PostgreSQL │ │ • FranklinWH Energy API │
|
|
|
-│ Redis │ │ • Plane V2 Web API │
|
|
|
-│ MinIO │ │ • Acceleronix / SmartHub API │
|
|
|
-└──────────────┘ └──────────────────────────────────────────────┘
|
|
|
-```
|
|
|
-
|
|
|
-### 3.1 MCP Tools Server 与现有后端的关系
|
|
|
-
|
|
|
-**核心原则:MCP Tools Server 是现有后端 service 层的另一个入口,不是独立系统。**
|
|
|
-
|
|
|
-| 对比 | 现有 HTTP Server (`main.go`) | MCP Tools Server |
|
|
|
-| -------- | ------------------------------------- | ---------------------------------- |
|
|
|
-| 入口 | Fiber HTTP 路由 | stdio JSON-RPC |
|
|
|
-| 调用方 | 前端浏览器 | Kiro CLI (AI Agent) |
|
|
|
-| 认证 | Casdoor JWT | 无需(本地 stdio 进程) |
|
|
|
-| 复用层 | controllers → services → repositories | **直接调用 services/repositories** |
|
|
|
-| 输出格式 | JSON HTTP Response | MCP Tool Result (text/JSON) |
|
|
|
-
|
|
|
-**具体复用方式:**
|
|
|
-
|
|
|
-```go
|
|
|
-// MCP Tools Server 的 go.mod 中引用现有 service 模块
|
|
|
-// 方式一:同一 module,不同 main 入口
|
|
|
-// service/cmd/mcp/main.go (MCP Server 入口)
|
|
|
-// service/main.go (HTTP Server 入口)
|
|
|
-
|
|
|
-// 方式二:独立 module,replace 引用
|
|
|
-// mcp-servers/tools/go.mod:
|
|
|
-// require fwh-toolbox-server v0.0.0
|
|
|
-// replace fwh-toolbox-server => ../../service
|
|
|
-```
|
|
|
-
|
|
|
-**推荐方式一**(同一 module):在 `service/cmd/mcp/` 下创建 MCP Server 入口,共享整个 service 代码库。
|
|
|
-
|
|
|
-```
|
|
|
-service/
|
|
|
-├── main.go # 现有 HTTP Server 入口
|
|
|
-├── cmd/
|
|
|
-│ └── mcp/
|
|
|
-│ └── main.go # MCP Tools Server 入口
|
|
|
-├── services/ # 共享:业务逻辑
|
|
|
-├── repositories/ # 共享:数据访问
|
|
|
-├── domain/ # 共享:领域模型
|
|
|
-├── dto/ # 共享:DTO
|
|
|
-├── config/ # 共享:配置
|
|
|
-├── database/ # 共享:数据库连接
|
|
|
-└── cache/ # 共享:缓存
|
|
|
-```
|
|
|
-
|
|
|
-**MCP Server 入口初始化流程:**
|
|
|
-
|
|
|
-```go
|
|
|
-// service/cmd/mcp/main.go
|
|
|
-func main() {
|
|
|
- // 1. 加载配置(同 HTTP Server)
|
|
|
- cfg, _ := config.LoadConfig()
|
|
|
-
|
|
|
- // 2. 初始化数据库连接(同 HTTP Server)
|
|
|
- database.Init(&cfg.App)
|
|
|
- cache.Init(cfg.App.RedisAddr)
|
|
|
- repositories.PlaneWebHttpInit(&cfg.PlaneWebApi)
|
|
|
-
|
|
|
- // 3. 创建 MCP Server(替代 Fiber HTTP 路由)
|
|
|
- s := server.NewMCPServer("fwh-tools", "1.0.0",
|
|
|
- server.WithToolCapabilities(false),
|
|
|
- server.WithRecovery(),
|
|
|
- )
|
|
|
-
|
|
|
- // 4. 注册 Tools(调用 services/ 层函数)
|
|
|
- tools.RegisterSiteInfoTools(s)
|
|
|
- tools.RegisterSimCardTools(s)
|
|
|
- tools.RegisterPowerFlowTools(s)
|
|
|
- tools.RegisterAlarmTools(s)
|
|
|
- tools.RegisterShutdownTools(s)
|
|
|
- tools.RegisterPlaneTools(s)
|
|
|
-
|
|
|
- // 5. 启动 stdio 通信(替代 app.Listen)
|
|
|
- server.ServeStdio(s)
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-**不需要的部分:**
|
|
|
-
|
|
|
-- 不需要 Fiber 框架
|
|
|
-- 不需要 controllers/ 层(MCP handler 直接调用 services)
|
|
|
-- 不需要 middleware/(stdio 无需 HTTP 认证)
|
|
|
-- 不需要 routes/(MCP 用 tool 注册替代)
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-## 4. 知识库 MCP Server(独立 VitePress 项目)
|
|
|
-
|
|
|
-知识库是一个独立的 VitePress 文档项目,通过 `vitepress-plugin-mcp` 插件将文档暴露为 MCP Server。
|
|
|
-
|
|
|
-### 4.1 概述
|
|
|
-
|
|
|
-| 项目 | 说明 |
|
|
|
-| -------- | -------------------------------------------------- |
|
|
|
-| 位置 | 独立 Git 仓库(不在 FranklinWH-ToolBox 内) |
|
|
|
-| 框架 | VitePress(Markdown 文档站) |
|
|
|
-| 内容 | 团队知识:编码规范、架构模板、技术文档、最佳实践等 |
|
|
|
-| MCP 插件 | `vitepress-plugin-mcp`(npm 包) |
|
|
|
-| MCP 传输 | Streamable HTTP(远程 MCP Server) |
|
|
|
-| 配置层级 | `./.kiro/settings/mcp.json`(后端运行目录级别) |
|
|
|
-
|
|
|
-### 4.2 VitePress 知识库项目搭建
|
|
|
-
|
|
|
-**Step 1:创建 VitePress 项目**
|
|
|
-
|
|
|
-```bash
|
|
|
-mkdir team-knowledge && cd team-knowledge
|
|
|
-pnpm init
|
|
|
-pnpm add -D vitepress vitepress-plugin-mcp
|
|
|
-mkdir docs
|
|
|
-```
|
|
|
-
|
|
|
-**Step 2:编写文档内容**
|
|
|
-
|
|
|
-```
|
|
|
-team-knowledge/
|
|
|
-├── docs/
|
|
|
-│ ├── index.md # 首页
|
|
|
-│ ├── coding/
|
|
|
-│ │ ├── frontend.md # 前端编码规范
|
|
|
-│ │ ├── backend.md # 后端编码规范
|
|
|
-│ │ └── git.md # Git 提交规范
|
|
|
-│ ├── architecture/
|
|
|
-│ │ ├── vue-project.md # Vue 项目架构模板
|
|
|
-│ │ ├── go-service.md # Go 后端架构模板
|
|
|
-│ │ └── mcp-server.md # MCP Server 开发指南
|
|
|
-│ ├── devops/
|
|
|
-│ │ ├── deployment.md # 部署流程
|
|
|
-│ │ └── monitoring.md # 监控方案
|
|
|
-│ └── troubleshooting/
|
|
|
-│ ├── common-issues.md # 常见问题排查
|
|
|
-│ └── fwh-specific.md # FranklinWH 业务相关
|
|
|
-├── .vitepress/
|
|
|
-│ └── config.ts # VitePress + MCP 配置
|
|
|
-├── package.json
|
|
|
-└── pnpm-lock.yaml
|
|
|
-```
|
|
|
-
|
|
|
-**Step 3:配置 VitePress + MCP 插件**
|
|
|
-
|
|
|
-```ts
|
|
|
-// .vitepress/config.ts
|
|
|
-import { defineConfig } from 'vitepress'
|
|
|
-import { MCPPlugin } from 'vitepress-plugin-mcp'
|
|
|
-
|
|
|
-export default defineConfig({
|
|
|
- title: 'Team Knowledge Base',
|
|
|
- description: '团队知识库',
|
|
|
- themeConfig: {
|
|
|
- search: {
|
|
|
- provider: 'local', // 必须启用 local search(插件依赖它的索引)
|
|
|
- options: {},
|
|
|
- },
|
|
|
- sidebar: [
|
|
|
- {
|
|
|
- text: '编码规范',
|
|
|
- items: [
|
|
|
- { text: '前端', link: '/coding/frontend' },
|
|
|
- { text: '后端', link: '/coding/backend' },
|
|
|
- { text: 'Git', link: '/coding/git' },
|
|
|
- ],
|
|
|
- },
|
|
|
- {
|
|
|
- text: '架构模板',
|
|
|
- items: [
|
|
|
- { text: 'Vue 项目', link: '/architecture/vue-project' },
|
|
|
- { text: 'Go 后端', link: '/architecture/go-service' },
|
|
|
- ],
|
|
|
- },
|
|
|
- ],
|
|
|
- },
|
|
|
- vite: {
|
|
|
- plugins: [
|
|
|
- MCPPlugin({ port: 4100 }), // MCP Server 监听端口
|
|
|
- ],
|
|
|
- },
|
|
|
-})
|
|
|
-```
|
|
|
-
|
|
|
-**Step 4:启动**
|
|
|
-
|
|
|
-```bash
|
|
|
-# 开发模式(同时启动 VitePress + MCP Server)
|
|
|
-pnpm vitepress dev docs
|
|
|
-
|
|
|
-# MCP Server 自动在 http://localhost:4100 启动
|
|
|
-```
|
|
|
-
|
|
|
-**Step 5:验证 MCP Server**
|
|
|
-
|
|
|
-```bash
|
|
|
-# 测试 MCP Server 是否可用
|
|
|
-curl http://localhost:4100/mcp
|
|
|
-```
|
|
|
-
|
|
|
-### 4.3 插件暴露的 Tools
|
|
|
-
|
|
|
-`vitepress-plugin-mcp` 自动提供以下工具:
|
|
|
-
|
|
|
-| Tool 名称 | 描述 | 参数 |
|
|
|
-| ---------------------- | ---------------------------------------------------- | --------------- |
|
|
|
-| `search_documentation` | 全文搜索文档内容(基于 VitePress local search 索引) | `query: string` |
|
|
|
-| `get_page_content` | 获取指定页面的完整 Markdown 内容 | `path: string` |
|
|
|
-| `list_pages` | 列出所有文档页面 | 无 |
|
|
|
-
|
|
|
-### 4.4 在 Kiro 中配置连接
|
|
|
-
|
|
|
-知识库是**远程 MCP Server**(HTTP),在后端运行目录的 Kiro 配置中使用 `url` 字段连接:
|
|
|
-
|
|
|
-**`./.kiro/settings/mcp.json` 中添加:**
|
|
|
-
|
|
|
-```json
|
|
|
-{
|
|
|
- "mcpServers": {
|
|
|
- "team-knowledge": {
|
|
|
- "url": "http://lochost:4100/mcp"
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### 4.5 部署方案
|
|
|
-
|
|
|
-| 环境 | 方式 | 地址 |
|
|
|
-| -------- | ------------------------------------ | ------------------------------------ |
|
|
|
-| 本地开发 | `pnpm vitepress dev docs` | `http://localhost:4100/mcp` |
|
|
|
-| 团队共享 | 部署到内网服务器(PM2/systemd 常驻) | `http://knowledge.internal:4100/mcp` |
|
|
|
-| Docker | 容器化部署 | `http://knowledge:4100/mcp` |
|
|
|
-
|
|
|
-**PM2 部署示例:**
|
|
|
-
|
|
|
-```bash
|
|
|
-# ecosystem.config.js
|
|
|
-module.exports = {
|
|
|
- apps: [{
|
|
|
- name: 'knowledge-mcp',
|
|
|
- script: 'npx',
|
|
|
- args: 'vitepress dev docs --port 5173',
|
|
|
- cwd: '/opt/team-knowledge',
|
|
|
- env: { NODE_ENV: 'production' }
|
|
|
- }]
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-**注意:** `vitepress-plugin-mcp` 的 MCP Server 与 VitePress dev server 绑定运行。生产环境需要保持 `vitepress dev` 常驻运行(不是 `vitepress build`)。
|
|
|
-
|
|
|
-### 4.6 使用效果
|
|
|
-
|
|
|
-配置完成后,在 Kiro CLI 中可以直接使用知识库:
|
|
|
-
|
|
|
-```
|
|
|
-> 帮我查一下前端编码规范中关于组件命名的约定
|
|
|
-
|
|
|
-Kiro 会自动调用 team-knowledge MCP Server 的 search_documentation 工具,
|
|
|
-搜索知识库内容并返回相关文档片段。
|
|
|
-```
|
|
|
-
|
|
|
-### 4.7 添加新文档的流程
|
|
|
-
|
|
|
-```
|
|
|
-1. 在 team-knowledge 仓库中编写 Markdown 文件
|
|
|
-2. git commit && git push
|
|
|
-3. 服务器自动重启(PM2 watch 或 CI/CD)
|
|
|
-4. MCP Server 自动索引新内容
|
|
|
-5. Kiro 下次搜索即可获取新文档
|
|
|
-```
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-## 5. 内部工具 MCP Server 详细设计
|
|
|
-
|
|
|
-### 5.1 技术选型
|
|
|
-
|
|
|
-| 项目 | 选择 | 理由 |
|
|
|
-| --------- | ----------------------------- | -------------------------------------- |
|
|
|
-| 语言 | Go | 与后端一致,直接 import service 层代码 |
|
|
|
-| SDK | `github.com/mark3labs/mcp-go` | 社区最活跃的 Go MCP SDK |
|
|
|
-| Transport | stdio | Kiro CLI 本地调用,最简单 |
|
|
|
-| 构建产物 | 单二进制`fwh-mcp-server` | `go build -o fwh-mcp-server ./cmd/mcp` |
|
|
|
-
|
|
|
-### 5.2 暴露的 Tools 清单
|
|
|
-
|
|
|
-| Tool 名称 | 输入参数 | 描述 | 复用的 service 函数 |
|
|
|
-| --------------------------- | ------------------------------------- | ----------------------- | --------------------------------- |
|
|
|
-| `query_site_info` | `sn: string` | 查询站点设备详细信息 | `services.GetSiteInfoData` |
|
|
|
-| `search_sites` | `page, size: int, keyword?: string` | 搜索站点列表 | `services.QuerySiteInfoDataList` |
|
|
|
-| `query_sim_card` | `giccid: string` | 查询单张 SIM 卡状态 | `services.GetSimCardInfo` |
|
|
|
-| `search_sim_cards` | `page, size: int, status?, platform?` | 搜索 SIM 卡列表 | `services.GetSimCardBatchInfo` |
|
|
|
-| `query_power_flow` | `sn: string, date: string` | 查询站点功率流数据 | `services.QuerySitePowerFlow` |
|
|
|
-| `query_alarm_statistics` | `date?: string` | 查询告警统计 | `services.GetAlarmStatistics` |
|
|
|
-| `query_shutdown_statistics` | `date: string` | 查询停机统计 | `services.GetShutdownStatistics` |
|
|
|
-| `create_feedback` | `title, type, priority, description` | 创建 Plane Intake Issue | `services.SubmitFeedback` |
|
|
|
-| `query_feedback_history` | 无 | 查询 Feedback 提交历史 | `services.GetFeedbackHistory` |
|
|
|
-
|
|
|
-### 5.3 代码结构
|
|
|
-
|
|
|
-```
|
|
|
-service/
|
|
|
-├── cmd/
|
|
|
-│ └── mcp/
|
|
|
-│ ├── main.go # MCP Server 入口
|
|
|
-│ └── tools/
|
|
|
-│ ├── siteInfo.go # 站点信息相关 tools
|
|
|
-│ ├── simCard.go # SIM 卡相关 tools
|
|
|
-│ ├── powerFlow.go # 功率流相关 tools
|
|
|
-│ ├── alarm.go # 告警统计 tools
|
|
|
-│ ├── shutdown.go # 停机统计 tools
|
|
|
-│ └── plane.go # Plane/Feedback tools
|
|
|
-├── main.go # 现有 HTTP Server(不改动)
|
|
|
-├── services/ # 共享
|
|
|
-├── repositories/ # 共享
|
|
|
-└── ...
|
|
|
-```
|
|
|
-
|
|
|
-### 5.4 代码示例
|
|
|
-
|
|
|
-**入口 `service/cmd/mcp/main.go`:**
|
|
|
-
|
|
|
-```go
|
|
|
-package main
|
|
|
-
|
|
|
-import (
|
|
|
- "fmt"
|
|
|
- "log"
|
|
|
- "os"
|
|
|
-
|
|
|
- "github.com/mark3labs/mcp-go/server"
|
|
|
-
|
|
|
- "fwh-toolbox-server/cache"
|
|
|
- "fwh-toolbox-server/config"
|
|
|
- "fwh-toolbox-server/database"
|
|
|
- "fwh-toolbox-server/repositories"
|
|
|
-
|
|
|
- "fwh-toolbox-server/cmd/mcp/tools"
|
|
|
-)
|
|
|
-
|
|
|
-func main() {
|
|
|
- // 加载配置
|
|
|
- cfg, err := config.LoadConfig()
|
|
|
- if err != nil {
|
|
|
- log.Fatalf("加载配置失败: %v", err)
|
|
|
- }
|
|
|
-
|
|
|
- // 初始化基础设施(与 HTTP Server 相同)
|
|
|
- if err := database.Init(&cfg.App); err != nil {
|
|
|
- log.Fatalf("数据库初始化失败: %v", err)
|
|
|
- }
|
|
|
- cache.Init(cfg.App.RedisAddr)
|
|
|
- repositories.PlaneWebHttpInit(&cfg.PlaneWebApi)
|
|
|
-
|
|
|
- // 创建 MCP Server
|
|
|
- s := server.NewMCPServer(
|
|
|
- "fwh-tools",
|
|
|
- "1.0.0",
|
|
|
- server.WithToolCapabilities(false),
|
|
|
- server.WithRecovery(),
|
|
|
- )
|
|
|
-
|
|
|
- // 注册所有 Tools
|
|
|
- tools.RegisterSiteInfoTools(s)
|
|
|
- tools.RegisterSimCardTools(s)
|
|
|
- tools.RegisterPowerFlowTools(s)
|
|
|
- tools.RegisterAlarmTools(s)
|
|
|
- tools.RegisterShutdownTools(s)
|
|
|
- tools.RegisterPlaneTools(s)
|
|
|
-
|
|
|
- // 启动 stdio 通信
|
|
|
- fmt.Fprintln(os.Stderr, "[fwh-mcp-server] started (stdio)")
|
|
|
- if err := server.ServeStdio(s); err != nil {
|
|
|
- log.Fatalf("[fwh-mcp-server] error: %v", err)
|
|
|
- }
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-**工具示例 `service/cmd/mcp/tools/siteInfo.go`:**
|
|
|
-
|
|
|
-```go
|
|
|
-package tools
|
|
|
-
|
|
|
-import (
|
|
|
- "context"
|
|
|
- "encoding/json"
|
|
|
- "fmt"
|
|
|
-
|
|
|
- "github.com/mark3labs/mcp-go/mcp"
|
|
|
- "github.com/mark3labs/mcp-go/server"
|
|
|
-
|
|
|
- "fwh-toolbox-server/services"
|
|
|
-)
|
|
|
-
|
|
|
-func RegisterSiteInfoTools(s *server.MCPServer) {
|
|
|
- // Tool: 查询站点信息
|
|
|
- s.AddTool(
|
|
|
- mcp.NewTool("query_site_info",
|
|
|
- mcp.WithDescription("查询单个站点设备的详细信息,包括版本、网络状态、激活状态、SN、固件等"),
|
|
|
- mcp.WithString("sn", mcp.Required(), mcp.Description("站点 SN 序列号")),
|
|
|
- ),
|
|
|
- handleQuerySiteInfo,
|
|
|
- )
|
|
|
-
|
|
|
- // Tool: 搜索站点列表
|
|
|
- s.AddTool(
|
|
|
- mcp.NewTool("search_sites",
|
|
|
- mcp.WithDescription("搜索站点设备列表,支持分页"),
|
|
|
- mcp.WithNumber("page", mcp.Description("页码,从1开始,默认1")),
|
|
|
- mcp.WithNumber("size", mcp.Description("每页数量,默认10")),
|
|
|
- mcp.WithString("keyword", mcp.Description("搜索关键字(匹配 SN、设备名)")),
|
|
|
- ),
|
|
|
- handleSearchSites,
|
|
|
- )
|
|
|
-}
|
|
|
-
|
|
|
-func handleQuerySiteInfo(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
|
- sn, err := req.RequireString("sn")
|
|
|
- if err != nil {
|
|
|
- return mcp.NewToolResultError("参数 sn 必填"), nil
|
|
|
- }
|
|
|
-
|
|
|
- data, err := services.GetSiteInfoData(sn)
|
|
|
- if err != nil {
|
|
|
- return mcp.NewToolResultError(fmt.Sprintf("查询失败: %v", err)), nil
|
|
|
- }
|
|
|
-
|
|
|
- jsonBytes, _ := json.MarshalIndent(data, "", " ")
|
|
|
- return mcp.NewToolResultText(string(jsonBytes)), nil
|
|
|
-}
|
|
|
-
|
|
|
-func handleSearchSites(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
|
- page := int(req.GetFloat("page", 1))
|
|
|
- size := int(req.GetFloat("size", 10))
|
|
|
- keyword := req.GetString("keyword", "")
|
|
|
-
|
|
|
- data, err := services.QuerySiteInfoDataList(uint(page), uint(size), keyword, nil, nil, nil)
|
|
|
- if err != nil {
|
|
|
- return mcp.NewToolResultError(fmt.Sprintf("搜索失败: %v", err)), nil
|
|
|
- }
|
|
|
-
|
|
|
- jsonBytes, _ := json.MarshalIndent(data, "", " ")
|
|
|
- return mcp.NewToolResultText(string(jsonBytes)), nil
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-## 6. 外部服务 MCP Server
|
|
|
-
|
|
|
-直接使用社区开源 Server,不需要自己实现。**不使用 Git MCP Server。**
|
|
|
-
|
|
|
-| Server | 用途 | 包名 |
|
|
|
-| ----------------- | ------------------------ | ------------------------------------------ |
|
|
|
-| AWS Documentation | 搜索 AWS 文档、最佳实践 | `@aws/aws-documentation-mcp-server` |
|
|
|
-| Brave Search | 网络搜索(技术问题排查) | `@modelcontextprotocol/server-bravesearch` |
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-## 7. Kiro CLI 配置
|
|
|
-
|
|
|
-所有 Kiro 配置基于后端程序运行目录(`service/`)的相对路径 `./.kiro/`。
|
|
|
-
|
|
|
-### 7.1 工作区 MCP 配置
|
|
|
-
|
|
|
-**`service/.kiro/settings/mcp.json`:**
|
|
|
-
|
|
|
-```json
|
|
|
-{
|
|
|
- "mcpServers": {
|
|
|
- "fwh-tools": {
|
|
|
- "command": "./fwh-mcp-server",
|
|
|
- "args": [],
|
|
|
- "env": {
|
|
|
- "MONGO_DSN": "${MONGO_DSN}",
|
|
|
- "REDIS_ADDR": "${REDIS_ADDR}",
|
|
|
- "PLANE_WEB_HOST": "${PLANE_WEB_HOST}",
|
|
|
- "PLANE_WEB_EMAIL": "${PLANE_WEB_EMAIL}",
|
|
|
- "PLANE_WEB_PASSWORD": "${PLANE_WEB_PASSWORD}",
|
|
|
- "PLANE_WEB_WORKSPACE_SLUG": "${PLANE_WEB_WORKSPACE_SLUG}",
|
|
|
- "PLANE_WEB_PROJECT_ID": "${PLANE_WEB_PROJECT_ID}"
|
|
|
- }
|
|
|
- },
|
|
|
- "team-knowledge": {
|
|
|
- "url": "http://knowledge.internal:4100/mcp"
|
|
|
- },
|
|
|
- "aws-docs": {
|
|
|
- "command": "npx",
|
|
|
- "args": ["-y", "@aws/aws-documentation-mcp-server"]
|
|
|
- },
|
|
|
- "web-search": {
|
|
|
- "command": "npx",
|
|
|
- "args": ["-y", "@modelcontextprotocol/server-bravesearch"],
|
|
|
- "env": {
|
|
|
- "BRAVE_API_KEY": "${BRAVE_API_KEY}"
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### 7.2 Steering 文件
|
|
|
-
|
|
|
-**`service/.kiro/steering/project.md`:**
|
|
|
-
|
|
|
-```markdown
|
|
|
-# FranklinWH-ToolBox 项目上下文
|
|
|
-
|
|
|
-## 项目概述
|
|
|
-
|
|
|
-内部工具平台,前端 Vue3 + Naive UI,后端 Go Fiber + MongoDB。
|
|
|
-
|
|
|
-## 可用 MCP 工具
|
|
|
-
|
|
|
-- fwh-tools: 查询站点、SIM卡、功率流、告警、Plane Issue
|
|
|
-- team-knowledge: 搜索团队知识库文档
|
|
|
-- aws-docs: 搜索 AWS 文档
|
|
|
-- web-search: 网络搜索
|
|
|
-
|
|
|
-## 注意事项
|
|
|
-
|
|
|
-- 不要直接操作 Git
|
|
|
-- 修改代码后需 go build / npm run build 验证
|
|
|
-- 后端分层:controllers → services → repositories
|
|
|
-```
|
|
|
-
|
|
|
-### 7.3 部署目录结构
|
|
|
-
|
|
|
-```
|
|
|
-/var/www/fwh-toolbox/server/ # 后端运行目录(WorkingDirectory)
|
|
|
-├── fwh-toolbox-server # HTTP Server 二进制
|
|
|
-├── fwh-mcp-server # MCP Tools Server 二进制
|
|
|
-├── .kiro/
|
|
|
-│ ├── settings/
|
|
|
-│ │ └── mcp.json # MCP Server 配置(command: "./fwh-mcp-server")
|
|
|
-│ └── steering/
|
|
|
-│ └── project.md # Agent 指令文件
|
|
|
-└── .env # 环境变量配置
|
|
|
-```
|
|
|
-
|
|
|
-**源码目录结构:**
|
|
|
-
|
|
|
-```
|
|
|
-service/
|
|
|
-├── .kiro/ # Kiro 配置(开发环境 + 部署时拷贝)
|
|
|
-│ ├── settings/
|
|
|
-│ │ └── mcp.json
|
|
|
-│ └── steering/
|
|
|
-│ └── project.md
|
|
|
-├── cmd/
|
|
|
-│ └── mcp/
|
|
|
-│ ├── main.go # MCP Server 入口
|
|
|
-│ └── tools/ # 各工具实现
|
|
|
-│ ├── siteInfo.go
|
|
|
-│ ├── simCard.go
|
|
|
-│ ├── powerFlow.go
|
|
|
-│ ├── alarm.go
|
|
|
-│ ├── shutdown.go
|
|
|
-│ └── plane.go
|
|
|
-├── main.go # HTTP Server 入口
|
|
|
-└── ...
|
|
|
-```
|
|
|
-
|
|
|
-### 7.4 后端 ACP Client 引用
|
|
|
-
|
|
|
-ACP Client 启动 `kiro-cli acp` 时指定工作目录为后端运行目录,Kiro 自动从 `./.kiro/settings/mcp.json` 加载配置:
|
|
|
-
|
|
|
-```go
|
|
|
-cmd := exec.Command("kiro-cli", "acp")
|
|
|
-cmd.Dir = serviceDir // 后端运行目录(含 .kiro/ 和 fwh-mcp-server)
|
|
|
-```
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-## 8. 构建与运行
|
|
|
-
|
|
|
-### 8.1 构建 MCP Tools Server
|
|
|
-
|
|
|
-```bash
|
|
|
-cd service
|
|
|
-go build -o fwh-mcp-server ./cmd/mcp
|
|
|
-```
|
|
|
-
|
|
|
-### 8.2 本地测试
|
|
|
-
|
|
|
-```bash
|
|
|
-# 直接运行测试
|
|
|
-echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | ./fwh-mcp-server
|
|
|
-
|
|
|
-# 通过 Kiro CLI 测试(在 service/ 目录下)
|
|
|
-kiro chat # 然后在对话中使用工具
|
|
|
-```
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-## 9. 实现步骤
|
|
|
-
|
|
|
-| 阶段 | 内容 | 输出物 | 预估时间 |
|
|
|
-| ----------- | ------------------------------------- | ------------------------------ | -------- |
|
|
|
-| **Phase 1** | 创建`service/cmd/mcp/` 目录结构和入口 | main.go + go build 通过 | 0.5 天 |
|
|
|
-| **Phase 2** | 实现站点信息 Tools | tools/siteInfo.go | 1 天 |
|
|
|
-| **Phase 3** | 实现 SIM 卡 + 功率流 Tools | tools/simCard.go, powerFlow.go | 1 天 |
|
|
|
-| **Phase 4** | 实现告警 + Plane Tools | tools/alarm.go, plane.go | 1 天 |
|
|
|
-| **Phase 5** | 配置`.kiro/` + Steering + 联调 | 配置文件 + 端到端测试 | 0.5 天 |
|
|
|
-| **Phase 6** | 配置外部 MCP Server (AWS Docs, Brave) | npm 安装 + 环境变量配置 | 0.5 天 |
|
|
|
-
|
|
|
-**总计:约 4.5 天**
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-## 10. 前端 AI Chat 与后端通讯设计
|
|
|
-
|
|
|
-### 10.1 架构概览
|
|
|
-
|
|
|
-```
|
|
|
-┌────────────────────────────────┐
|
|
|
-│ 前端 (Vue 3) │
|
|
|
-│ src/views/ai-chat/ │
|
|
|
-│ ┌──────────────────────────┐ │
|
|
|
-│ │ ChatPanel 组件 │ │
|
|
|
-│ │ • 消息列表 (Markdown) │ │
|
|
|
-│ │ • 输入框 │ │
|
|
|
-│ │ • 流式输出显示 │ │
|
|
|
-│ └────────────┬─────────────┘ │
|
|
|
-│ │ SSE / fetch │
|
|
|
-└───────────────┼────────────────┘
|
|
|
- │
|
|
|
- ▼
|
|
|
-┌────────────────────────────────┐
|
|
|
-│ 后端 (Go Fiber) │
|
|
|
-│ service/controllers/ │
|
|
|
-│ aiChatControllers.go │
|
|
|
-│ ┌──────────────────────────┐ │
|
|
|
-│ │ POST /ai/chat │ │
|
|
|
-│ │ • 接收用户消息 │ │
|
|
|
-│ │ • 调用 LLM API │ │
|
|
|
-│ │ • SSE 流式返回 │ │
|
|
|
-│ └────────────┬─────────────┘ │
|
|
|
-│ │ │
|
|
|
-│ ▼ │
|
|
|
-│ ┌──────────────────────────┐ │
|
|
|
-│ │ LLM Provider │ │
|
|
|
-│ │ • Claude API (Anthropic) │ │
|
|
|
-│ │ • 或 OpenAI API │ │
|
|
|
-│ │ • 或 AWS Bedrock │ │
|
|
|
-│ └──────────────────────────┘ │
|
|
|
-│ │ │
|
|
|
-│ ▼ │
|
|
|
-│ ┌──────────────────────────┐ │
|
|
|
-│ │ MCP Tools (可选) │ │
|
|
|
-│ │ • 复用 services 层 │ │
|
|
|
-│ │ • AI 可调用内部工具 │ │
|
|
|
-│ └──────────────────────────┘ │
|
|
|
-└────────────────────────────────┘
|
|
|
-```
|
|
|
-
|
|
|
-### 10.2 通讯协议:SSE(Server-Sent Events)
|
|
|
-
|
|
|
-选择 SSE 而非 WebSocket 的原因:
|
|
|
-
|
|
|
-- AI 对话是单向流(服务端推送 token 流给前端)
|
|
|
-- SSE 基于 HTTP,天然支持认证 header
|
|
|
-- 无需额外的连接管理
|
|
|
-- 断线自动重连
|
|
|
-
|
|
|
-### 10.3 后端引擎:Kiro ACP Client
|
|
|
-
|
|
|
-后端实现 ACP (Agent Client Protocol) Client,通过 JSON-RPC 2.0 与 `kiro-cli acp` 子进程结构化通讯。
|
|
|
-
|
|
|
-**为什么选 ACP 而非直接 exec Kiro CLI:**
|
|
|
-
|
|
|
-| 对比项 | exec kiro chat | ACP Client |
|
|
|
-| -------------- | --------------------- | ------------------------------------------ |
|
|
|
-| 通讯格式 | 非结构化文本输出 | JSON-RPC 2.0 结构化 |
|
|
|
-| 会话管理 | 自己实现 | Kiro 原生支持(session/new, session/load) |
|
|
|
-| 工具调用可见性 | 无法感知 | ToolCall/ToolCallUpdate 实时事件 |
|
|
|
-| 取消操作 | kill 进程 | session/cancel 优雅取消 |
|
|
|
-| 会话持久化 | 自己实现 history.json | Kiro 自动持久化到 ~/.kiro/sessions/ |
|
|
|
-| 协议稳定性 | CLI 输出格式可能变 | ACP 是开放标准 |
|
|
|
-
|
|
|
-**架构:**
|
|
|
-
|
|
|
-```
|
|
|
-前端 SSE ←── 后端 (ACP Client) ←── JSON-RPC stdin/stdout ←── kiro-cli acp
|
|
|
- │
|
|
|
- ├── 自动调用 MCP Server
|
|
|
- ├── 自动管理会话上下文
|
|
|
- └── 自动持久化对话历史
|
|
|
-```
|
|
|
-
|
|
|
-### 10.4 后端接口设计
|
|
|
-
|
|
|
-**`POST /api/ai/chat`** — 发送消息
|
|
|
-
|
|
|
-请求:
|
|
|
-
|
|
|
-```json
|
|
|
-{
|
|
|
- "message": "帮我查一下 SN 为 ABC123 的站点信息",
|
|
|
- "sessionId": "sess_abc123" // 可选,不传则使用默认会话
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-响应(SSE 流,将 ACP 事件转发给前端):
|
|
|
-
|
|
|
-```
|
|
|
-Content-Type: text/event-stream
|
|
|
-
|
|
|
-event: message
|
|
|
-data: {"type":"text","content":"正在查询站点信息..."}
|
|
|
-
|
|
|
-event: tool_call
|
|
|
-data: {"type":"tool_call","name":"query_site_info","status":"running"}
|
|
|
-
|
|
|
-event: tool_update
|
|
|
-data: {"type":"tool_update","name":"query_site_info","status":"completed"}
|
|
|
-
|
|
|
-event: message
|
|
|
-data: {"type":"text","content":"该站点的固件版本是 v3.2.1..."}
|
|
|
-
|
|
|
-event: done
|
|
|
-data: {"type":"done","sessionId":"sess_abc123"}
|
|
|
-```
|
|
|
-
|
|
|
-**SSE 事件映射:**
|
|
|
-
|
|
|
-| SSE Event | ACP Update Type | 说明 |
|
|
|
-| ------------- | ------------------- | --------------------- |
|
|
|
-| `message` | `AgentMessageChunk` | AI 文本流(逐块推送) |
|
|
|
-| `tool_call` | `ToolCall` | Kiro 调用 MCP 工具 |
|
|
|
-| `tool_update` | `ToolCallUpdate` | 工具执行进度 |
|
|
|
-| `done` | `TurnEnd` | 本轮对话结束 |
|
|
|
-| `error` | - | 错误 |
|
|
|
-
|
|
|
-**其他接口:**
|
|
|
-
|
|
|
-| 接口 | 方法 | 描述 |
|
|
|
-| ------------------ | ------ | ---------------------- |
|
|
|
-| `/ai/chat` | POST | 发送消息,SSE 流式返回 |
|
|
|
-| `/ai/sessions` | GET | 获取当前用户会话列表 |
|
|
|
-| `/ai/sessions/new` | POST | 创建新会话 |
|
|
|
-| `/ai/sessions/:id` | DELETE | 删除会话 |
|
|
|
-| `/ai/cancel` | POST | 取消当前操作 |
|
|
|
-
|
|
|
-### 10.5 后端 ACP Client 实现
|
|
|
-
|
|
|
-**核心数据结构:**
|
|
|
-
|
|
|
-```go
|
|
|
-// ACPSession 单个用户的 ACP 连接
|
|
|
-type ACPSession struct {
|
|
|
- UserId string
|
|
|
- SessionId string // Kiro ACP session ID
|
|
|
- Process *exec.Cmd // kiro-cli acp 长驻进程
|
|
|
- Stdin io.WriteCloser // JSON-RPC 请求写入
|
|
|
- Stdout *bufio.Reader // JSON-RPC 响应/通知读取
|
|
|
- Mutex sync.Mutex // 同一用户串行对话
|
|
|
- LastActive time.Time
|
|
|
- RequestId int64 // JSON-RPC 请求 ID 自增
|
|
|
-}
|
|
|
-
|
|
|
-// ACPManager 管理所有用户的 ACP 会话
|
|
|
-type ACPManager struct {
|
|
|
- sessions map[string]*ACPSession // userId -> session
|
|
|
- mu sync.RWMutex
|
|
|
- maxIdle time.Duration // 空闲超时
|
|
|
- projectDir string // 项目目录
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-**完整通讯流程:**
|
|
|
-
|
|
|
-```go
|
|
|
-// 1. 启动 kiro-cli acp(每用户一个长驻进程)
|
|
|
-func (m *ACPManager) GetOrCreate(userId string) (*ACPSession, error) {
|
|
|
- if sess, exists := m.sessions[userId]; exists {
|
|
|
- sess.LastActive = time.Now()
|
|
|
- return sess, nil
|
|
|
- }
|
|
|
-
|
|
|
- cmd := exec.Command("kiro-cli", "acp")
|
|
|
- cmd.Dir = m.projectDir // 含 .kiro/settings/mcp.json
|
|
|
-
|
|
|
- stdin, _ := cmd.StdinPipe()
|
|
|
- stdout, _ := cmd.StdoutPipe()
|
|
|
- cmd.Start()
|
|
|
-
|
|
|
- sess := &ACPSession{
|
|
|
- UserId: userId,
|
|
|
- Process: cmd,
|
|
|
- Stdin: stdin,
|
|
|
- Stdout: bufio.NewReader(stdout),
|
|
|
- }
|
|
|
-
|
|
|
- // 2. initialize 握手
|
|
|
- sess.sendRPC("initialize", map[string]any{
|
|
|
- "protocolVersion": 1,
|
|
|
- "clientCapabilities": map[string]any{
|
|
|
- "fs": map[string]any{"readTextFile": true, "writeTextFile": true},
|
|
|
- },
|
|
|
- "clientInfo": map[string]any{"name": "fwh-toolbox", "version": "1.0.0"},
|
|
|
- })
|
|
|
-
|
|
|
- // 3. 创建会话
|
|
|
- result := sess.sendRPC("session/new", map[string]any{"cwd": m.projectDir})
|
|
|
- sess.SessionId = result.SessionId
|
|
|
-
|
|
|
- m.sessions[userId] = sess
|
|
|
- return sess, nil
|
|
|
-}
|
|
|
-
|
|
|
-// 4. 发送消息并流式读取
|
|
|
-func (sess *ACPSession) Prompt(message string, events chan<- SSEEvent) {
|
|
|
- sess.Mutex.Lock()
|
|
|
- defer sess.Mutex.Unlock()
|
|
|
-
|
|
|
- sess.sendRPC("session/prompt", map[string]any{
|
|
|
- "sessionId": sess.SessionId,
|
|
|
- "content": []map[string]any{{"type": "text", "text": message}},
|
|
|
- })
|
|
|
-
|
|
|
- // 持续读取 session/notification 直到 TurnEnd
|
|
|
- for {
|
|
|
- notif := sess.readNotification()
|
|
|
- switch notif.Params.UpdateType {
|
|
|
- case "AgentMessageChunk":
|
|
|
- events <- SSEEvent{Type: "message", Content: notif.Params.Text}
|
|
|
- case "ToolCall":
|
|
|
- events <- SSEEvent{Type: "tool_call", Name: notif.Params.ToolName}
|
|
|
- case "ToolCallUpdate":
|
|
|
- events <- SSEEvent{Type: "tool_update", Name: notif.Params.ToolName}
|
|
|
- case "TurnEnd":
|
|
|
- events <- SSEEvent{Type: "done", SessionId: sess.SessionId}
|
|
|
- close(events)
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 5. 取消操作
|
|
|
-func (sess *ACPSession) Cancel() {
|
|
|
- sess.sendRPC("session/cancel", map[string]any{"sessionId": sess.SessionId})
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-**Controller 层:**
|
|
|
-
|
|
|
-```go
|
|
|
-func AiChat(c *fiber.Ctx) error {
|
|
|
- userId := middleware.AuthGetUserName(c)
|
|
|
- var req struct {
|
|
|
- Message string `json:"message"`
|
|
|
- SessionId string `json:"sessionId"`
|
|
|
- }
|
|
|
- c.BodyParser(&req)
|
|
|
-
|
|
|
- sess, err := acpManager.GetOrCreate(userId)
|
|
|
- if err != nil {
|
|
|
- return Error(c, "AI 会话创建失败")
|
|
|
- }
|
|
|
-
|
|
|
- // SSE 流式响应
|
|
|
- c.Set("Content-Type", "text/event-stream")
|
|
|
- c.Set("Cache-Control", "no-cache")
|
|
|
-
|
|
|
- c.Context().SetBodyStreamWriter(func(w *bufio.Writer) {
|
|
|
- events := make(chan SSEEvent, 50)
|
|
|
- go sess.Prompt(req.Message, events)
|
|
|
-
|
|
|
- for event := range events {
|
|
|
- fmt.Fprintf(w, "event: %s\ndata: %s\n\n", event.Type, event.JSON())
|
|
|
- w.Flush()
|
|
|
- }
|
|
|
- })
|
|
|
- return nil
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### 10.6 多会话管理(ACP 原生能力)
|
|
|
-
|
|
|
-Kiro ACP 原生支持多会话,后端无需自己实现持久化。
|
|
|
-
|
|
|
-**ACP 会话方法:**
|
|
|
-
|
|
|
-| 方法 | 用途 |
|
|
|
-| ---------------- | -------------------------------------- |
|
|
|
-| `session/new` | 创建新会话(Kiro 分配 ID,自动持久化) |
|
|
|
-| `session/load` | 按 ID 恢复历史会话 |
|
|
|
-| `session/prompt` | 在指定会话中对话 |
|
|
|
-| `session/cancel` | 取消当前操作 |
|
|
|
-
|
|
|
-**会话生命周期:**
|
|
|
-
|
|
|
-```
|
|
|
-用户首次 → 启动 kiro-cli acp 进程 → initialize → session/new
|
|
|
- │
|
|
|
-用户对话 → session/prompt → 读取 notifications → SSE │ Kiro 自动
|
|
|
- │ 持久化
|
|
|
-用户加载历史 → session/load(sessionId) │
|
|
|
- ▼
|
|
|
-空闲 30min → kill 进程 → 下次使用时重启 + session/load 恢复
|
|
|
-```
|
|
|
-
|
|
|
-**Kiro 自动持久化目录:**
|
|
|
-
|
|
|
-```
|
|
|
-~/.kiro/sessions/cli/
|
|
|
-├── <session-id>.json # 会话元数据
|
|
|
-└── <session-id>.jsonl # 对话事件日志
|
|
|
-```
|
|
|
-
|
|
|
-### 10.7 限制与注意事项
|
|
|
-
|
|
|
-| 项目 | 说明 |
|
|
|
-| ---------- | ------------------------------------------------------- |
|
|
|
-| 并发限制 | 同一用户 Mutex 串行(ACP 不支持同 session 并行 prompt) |
|
|
|
-| 最大进程数 | 限制 20 个并发 kiro-cli acp 进程 |
|
|
|
-| 空闲超时 | 30 分钟无活动 kill 进程(再次使用时自动恢复) |
|
|
|
-| 请求超时 | 单次 prompt 最多等待 120 秒 |
|
|
|
-| MCP 配置 | 所有会话共享项目 .kiro/settings/mcp.json |
|
|
|
-| Kiro 订阅 | 需确保服务器上 Kiro 已登录且订阅有效 |
|
|
|
-
|
|
|
-### 10.8 前端实现要点
|
|
|
-
|
|
|
-**实现位置:** `src/layout/header/Actions` 中,作为顶部栏全局操作按钮,点击展开 AI Chat 侧边抽屉。
|
|
|
-
|
|
|
-**目录结构:**
|
|
|
-
|
|
|
-```
|
|
|
-src/layout/header/Actions/
|
|
|
-├── AiChat/
|
|
|
-│ ├── index.vue # 入口按钮 + NDrawer 容器
|
|
|
-│ ├── ChatPanel.vue # 聊天面板(消息列表 + 输入)
|
|
|
-│ ├── MessageItem.vue # 单条消息(支持 Markdown 渲染)
|
|
|
-│ ├── ToolCallCard.vue # 工具调用展示卡片
|
|
|
-│ ├── StreamingText.vue # 流式文本显示组件
|
|
|
-│ ├── useAiChat.ts # 核心逻辑:SSE 连接、消息管理
|
|
|
-│ └── interface.ts # 类型定义
|
|
|
-```
|
|
|
-
|
|
|
-**入口组件 `AiChat/index.vue`:**
|
|
|
-
|
|
|
-```vue
|
|
|
-<template>
|
|
|
- <!-- 顶部栏按钮 -->
|
|
|
- <NButton text @click="drawerShow = true">
|
|
|
- <template #icon>
|
|
|
- <span class="i-ph:chat-circle-dots" />
|
|
|
- </template>
|
|
|
- </NButton>
|
|
|
-
|
|
|
- <!-- 侧边抽屉 -->
|
|
|
- <NDrawer v-model:show="drawerShow" :width="480" placement="right">
|
|
|
- <NDrawerContent title="AI 助手" closable>
|
|
|
- <ChatPanel />
|
|
|
- </NDrawerContent>
|
|
|
- </NDrawer>
|
|
|
-</template>
|
|
|
-```
|
|
|
-
|
|
|
-**`useAiChat.ts` 核心逻辑:**
|
|
|
-
|
|
|
-```typescript
|
|
|
-export function useAiChat() {
|
|
|
- const messages = ref<ChatMessage[]>([])
|
|
|
- const isStreaming = ref(false)
|
|
|
-
|
|
|
- async function sendMessage(content: string) {
|
|
|
- // 添加用户消息
|
|
|
- messages.value.push({ role: 'user', content })
|
|
|
- isStreaming.value = true
|
|
|
-
|
|
|
- // 添加 AI 消息占位
|
|
|
- const aiMessage: ChatMessage = { role: 'assistant', content: '', toolCalls: [] }
|
|
|
- messages.value.push(aiMessage)
|
|
|
-
|
|
|
- // 发起 SSE 请求(使用框架的 fetch,自动带 token)
|
|
|
- const response = await fetch(baseUrl + '/ai/chat', {
|
|
|
- method: 'POST',
|
|
|
- headers: {
|
|
|
- 'Content-Type': 'application/json',
|
|
|
- Authorization: `Bearer ${token}`,
|
|
|
- },
|
|
|
- body: JSON.stringify({
|
|
|
- message: content,
|
|
|
- history: messages.value.slice(0, -1), // 不含当前占位
|
|
|
- }),
|
|
|
- })
|
|
|
-
|
|
|
- // 读取 SSE 流
|
|
|
- const reader = response.body!.getReader()
|
|
|
- const decoder = new TextDecoder()
|
|
|
-
|
|
|
- while (true) {
|
|
|
- const { done, value } = await reader.read()
|
|
|
- if (done) break
|
|
|
-
|
|
|
- const text = decoder.decode(value)
|
|
|
- // 解析 SSE 事件,逐步更新 aiMessage.content
|
|
|
- parseSSEEvents(text, aiMessage)
|
|
|
- }
|
|
|
-
|
|
|
- isStreaming.value = false
|
|
|
- }
|
|
|
-
|
|
|
- return { messages, isStreaming, sendMessage }
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-**`ChatPanel.vue` 基本结构:**
|
|
|
-
|
|
|
-```vue
|
|
|
-<template>
|
|
|
- <div class="flex h-full flex-col">
|
|
|
- <!-- 消息列表 -->
|
|
|
- <div class="flex-1 overflow-y-auto p-4 space-y-4">
|
|
|
- <MessageItem v-for="msg in messages" :key="msg.id" :message="msg" />
|
|
|
- <!-- 流式输出中的光标闪烁 -->
|
|
|
- <span v-if="isStreaming" class="animate-pulse">▊</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 输入区域 -->
|
|
|
- <div class="border-t p-4">
|
|
|
- <NInput
|
|
|
- v-model:value="inputText"
|
|
|
- type="textarea"
|
|
|
- :autosize="{ minRows: 1, maxRows: 4 }"
|
|
|
- placeholder="输入消息...(Shift+Enter 换行)"
|
|
|
- @keydown.enter.exact.prevent="handleSend"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-```
|
|
|
-
|
|
|
-### 10.9 消息渲染
|
|
|
-
|
|
|
-| 内容类型 | 渲染方式 |
|
|
|
-| -------- | ---------------------------------- |
|
|
|
-| 普通文本 | Markdown 渲染(支持代码高亮) |
|
|
|
-| 工具调用 | 折叠卡片,显示工具名 + 参数 + 结果 |
|
|
|
-| 表格数据 | 自动识别 JSON 数组,渲染为表格 |
|
|
|
-| 错误信息 | 红色提示卡片 |
|
|
|
-
|
|
|
-## 11. 安全考虑
|
|
|
-
|
|
|
-| 风险 | 措施 |
|
|
|
-| --------------- | ------------------------------------------------------------ |
|
|
|
-| AI 误操作 Git | 不配置 Git MCP Server |
|
|
|
-| 敏感数据泄露 | Tools 只返回必要字段,不返回密码/token/密钥 |
|
|
|
-| AI 误操作 Plane | create_feedback 限制只能创建 Intake,不能删除/修改已有 Issue |
|
|
|
-| MCP Server 崩溃 | 使用`server.WithRecovery()` 中间件恢复 panic |
|
|
|
-| 环境变量泄露 | 使用`${VAR}` 引用,不硬编码 |
|
|
|
-| 数据量过大 | Tools 返回结果限制最大条目数,分页查询 |
|
|
|
-| Kiro 进程泄漏 | SessionManager 定时扫描超时进程并 kill |
|
|
|
-| 用户并发冲突 | 同一用户 Mutex 锁,防止并行调用 Kiro |
|
|
|
-| 磁盘占用 | 会话目录定期清理,限制历史文件大小 |
|
|
|
-| Kiro 订阅额度 | 监控使用量,超额时返回友好提示 |
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
-## 12. 关于 A2A(原 ACP)
|
|
|
-
|
|
|
-当前阶段不需要 A2A。适合引入的场景:
|
|
|
-
|
|
|
-- 多个独立 AI Agent 协作(代码审查 Agent + 测试 Agent + 部署 Agent)
|
|
|
-- 跨团队/跨系统的 Agent 通信
|
|
|
-
|
|
|
-如果后续需要:
|
|
|
-
|
|
|
-- A2A Go SDK: `github.com/a2aproject/a2a-go`
|
|
|
-- A2A 规范: `https://a2aprotocol.ai`
|