# NetaClaw Agent/Skill 管理迁移设计文档

> **日期**: 2026-04-12
> **状态**: 已批准
> **范围**: 将 Agent 管理、Skill 管理、Agent 对话页面从旧接口迁移到 NetaClaw 运行时

---

## 1. 背景与目标

现有前端 3 个页面（Agent 管理、Skill 管理、Agent 对话）调用的是旧的 `/admin/agent/*` 和 `/open/agent/*` 接口体系，后端对应旧的 LangChain Agent 模块。

NetaClaw 模块已从 OpenClaw（小龙虾）迁移了 Agent 运行时（ReAct 循环、工具系统、LLM 提供商），但缺少管理层接口。

**目标：**
- 后端在 NetaClaw 模块补全 Agent CRUD、Skill 管理、会话管理接口
- 前端统一切到 NetaClaw 接口
- 对话通信从 SSE 改为 WebSocket
- 删除旧 agent 模块代码和数据库表

## 2. 核心决策

| 决策项 | 结论 | 理由 |
|--------|------|------|
| 旧模块处理 | 直接删除 | 旧数据是保险审核场景，电商场景用不上 |
| Agent 存储 | 数据库 + 后台管理 | 保持管理页面 CRUD 体验 |
| 通信方式 | WebSocket 流式 | 与 NetaClaw 现有 WS Gateway 一致 |
| Skill 管理 | SKILL.md + 数据库状态 | 文件定义内容，数据库控制启用/禁用 |
| 数据库表 | 全部新建 netaclaw_ 前缀 | 旧 agent_* 表和数据全部删除 |

## 3. 数据库设计

### 3.1 新建表

#### `netaclaw_agent` — Agent 配置

| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | int | PK, AUTO_INCREMENT | 主键 |
| createTime | varchar(255) | NOT NULL | 创建时间 |
| updateTime | varchar(255) | NOT NULL | 更新时间 |
| tenantId | int | nullable, INDEX | 租户ID |
| name | varchar(100) | UNIQUE, NOT NULL | 唯一标识，如 `agent_xxxxx` |
| label | varchar(200) | NOT NULL | 显示名称 |
| description | text | nullable | 描述 |
| icon | varchar(100) | nullable | 图标 |
| systemPrompt | text | nullable | 系统提示词 |
| skills | json | nullable | 关联 Skill 名称列表 `string[]` |
| modelConfig | json | nullable | `{apiUrl, apiKey, modelId, contextWindow}` |
| config | json | nullable | `{welcomeMessage, middleware: {maxToolRounds, ...}}` |
| status | int | NOT NULL, DEFAULT 0, INDEX | 0=草稿, 1=已发布 |

#### `netaclaw_skill` — Skill 状态管理

| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | int | PK, AUTO_INCREMENT | 主键 |
| createTime | varchar(255) | NOT NULL | 创建时间 |
| updateTime | varchar(255) | NOT NULL | 更新时间 |
| tenantId | int | nullable, INDEX | 租户ID |
| name | varchar(100) | UNIQUE, NOT NULL | 对应 SKILL.md 的 name |
| label | varchar(200) | NOT NULL | 显示名称 |
| description | text | nullable | 描述 |
| icon | varchar(100) | nullable | 图标 |
| category | varchar(50) | nullable | 分类 |
| skillType | varchar(20) | nullable | compute/llm/multimodal |
| tags | json | nullable | 标签 |
| config | json | nullable | 配置 |
| status | int | NOT NULL, DEFAULT 1, INDEX | 0=禁用, 1=启用 |
| version | varchar(20) | nullable | 版本号 |

### 3.2 复用表（已存在，无数据）

- **`netaclaw_session`** — 增加 `agentId` int 字段关联 Agent
- **`netaclaw_message`** — 不改

### 3.3 删除表

- `agent_info`, `agent_skill`, `agent_session`, `agent_message`
- `agent_checkpoints`, `agent_checkpoint_writes`, `agent_configs`, `skill_configs`

## 4. 后端接口设计

### 4.1 Agent 管理 Controller

文件：`netaclaw/controller/agent.ts`

| 方法 | 路径 | 参数 | 返回 |
|------|------|------|------|
| POST | `/admin/netaclaw/agent/page` | `{page, size, keyWord?}` | 分页列表 |
| POST | `/admin/netaclaw/agent/add` | Agent 完整对象 | `{id}` |
| POST | `/admin/netaclaw/agent/update` | Agent 完整对象 | 成功/失败 |
| POST | `/admin/netaclaw/agent/delete` | `{ids: number[]}` | 成功/失败 |
| GET | `/admin/netaclaw/agent/info` | `?id=number` | Agent 详情 |
| POST | `/open/netaclaw/agent/list` | 无 | 已发布 Agent 列表 |

### 4.2 Skill 管理 Controller

文件：`netaclaw/controller/skill.ts`

| 方法 | 路径 | 参数 | 返回 |
|------|------|------|------|
| GET | `/admin/netaclaw/skill/metas` | 无 | Skill 元数据列表（SKILL.md + DB 合并） |
| POST | `/admin/netaclaw/skill/setStatus` | `{name, status}` | 成功/失败 |

**合并逻辑：** SkillLoader 扫描 SKILL.md 文件获取内容，与数据库 `netaclaw_skill` 表的 status 字段合并。如果 SKILL.md 存在但数据库无记录，自动创建记录（默认启用）。

### 4.3 会话管理 Controller

文件：`netaclaw/controller/session.ts`

| 方法 | 路径 | 参数 | 返回 |
|------|------|------|------|
| POST | `/open/netaclaw/session/list` | `{userId?}` | 会话列表 |
| POST | `/open/netaclaw/session/messages` | `{sessionId}` | 消息历史 |
| POST | `/open/netaclaw/session/delete` | `{sessionId}` | 成功/失败 |
| POST | `/open/netaclaw/session/deleteAll` | `{userId?}` | 成功/失败 |

### 4.4 WebSocket Gateway 增强

文件：`netaclaw/gateway/server.ts`

**客户端 → 服务端：**
```typescript
// chat 事件增加 agentId
{ type: 'chat', sessionId?: string, content: string, agentId?: number }
```

**服务端 → 客户端（新增事件）：**
```typescript
{ type: 'skill_start', sessionId, name, label }
{ type: 'skill_end', sessionId, name, status, result?, tokens? }
{ type: 'progress', sessionId, name, step?, detail?, percent? }
{ type: 'token_update', sessionId, input, output, total, apiCalls }
```

**agentId 处理流程：**
1. 收到 chat 事件时，如果有 agentId，从 `netaclaw_agent` 表读取配置
2. 用 Agent 的 modelConfig 初始化 LLM 提供商
3. 用 Agent 的 systemPrompt + skills 构建系统提示
4. 调用 `runAgent()` 执行

## 5. 前端迁移设计

### 5.1 Store 改造 (`store/chat.ts`)

**API 路径替换：**

| 旧路径 | 新路径 |
|--------|--------|
| `POST /open/agent/info/list` | `POST /open/netaclaw/agent/list` |
| `POST /open/agent/chat/chat` (SSE) | WebSocket `/netaclaw` (chat 事件) |
| `POST /open/agent/chat/messages` | `POST /open/netaclaw/session/messages` |
| `POST /open/agent/chat/sessions` | `POST /open/netaclaw/session/list` |
| `POST /open/agent/chat/deleteSession` | `POST /open/netaclaw/session/delete` |
| `POST /open/agent/chat/deleteAllSessions` | `POST /open/netaclaw/session/deleteAll` |
| `POST /open/agent/chat/contextTokens` | 移除（WS token_update 事件替代） |
| `POST /open/agent/chat/status` | 移除（WS 连接状态替代） |
| `POST /open/agent/chat/reconnect` | 移除（WS 自动重连替代） |

**通信方式改造：**
- 移除 SSE（fetch stream + EventSource）逻辑
- 新增 WebSocket 连接管理：
  - 连接：页面加载时建立 WS 连接到 `ws://localhost:8003/netaclaw`
  - 心跳：定时发送 ping，收到 pong 确认
  - 断线重连：连接断开后自动重连，指数退避
  - 发送消息：通过 WS 发送 `{type: 'chat', sessionId, content, agentId}`
- WS 事件映射到 store 状态：
  - `token` → 追加 assistant 消息内容
  - `thinking` → 追加思考内容
  - `tool_call` → 记录工具调用
  - `tool_result` → 记录工具结果
  - `skill_start` → 添加 skillProgress 条目
  - `progress` → 更新 skillProgress
  - `skill_end` → 完成 skillProgress
  - `token_update` → 更新 token 统计
  - `done` → 标记完成，更新 sessionId
  - `error` → 显示错误

### 5.2 页面改造

**`agent-list.vue`：**
- `/admin/agent/info/page` → `/admin/netaclaw/agent/page`
- `/admin/agent/info/update` → `/admin/netaclaw/agent/update`
- `/admin/agent/info/delete` → `/admin/netaclaw/agent/delete`

**`skills.vue`：**
- `/admin/agent/skill/metas` → `/admin/netaclaw/skill/metas`
- `/admin/agent/skill/setStatus` → `/admin/netaclaw/skill/setStatus`

**`chat.vue`：**
- 移除 SSE 相关代码
- 使用 store 中的 WS 连接发送/接收消息
- `/admin/agent/info/info` → `/admin/netaclaw/agent/info`
- `/admin/base/comm/upload` → 保持不变（通用上传接口）

**`agent-edit.vue`：**
- `/admin/agent/info/add` → `/admin/netaclaw/agent/add`
- `/admin/agent/info/update` → `/admin/netaclaw/agent/update`
- `/admin/agent/info/info` → `/admin/netaclaw/agent/info`
- `/admin/agent/skill/metas` → `/admin/netaclaw/skill/metas`

## 6. 删除清单

### 6.1 后端删除

- 旧 agent 模块目录（如果存在 `src/modules/agent/`）
- 旧 agent 相关 Entity 文件
- 旧 LangChain 相关依赖（已在之前的设计文档中列出）

### 6.2 数据库删除

```sql
DROP TABLE IF EXISTS agent_info;
DROP TABLE IF EXISTS agent_skill;
DROP TABLE IF EXISTS agent_session;
DROP TABLE IF EXISTS agent_message;
DROP TABLE IF EXISTS agent_checkpoints;
DROP TABLE IF EXISTS agent_checkpoint_writes;
DROP TABLE IF EXISTS agent_configs;
DROP TABLE IF EXISTS skill_configs;
```

### 6.3 前端

不删除目录，只改内部实现（API 路径和通信方式）。

## 7. 联调要点

1. **后端先行**：先完成 Entity + Controller + Service，确保接口可用
2. **WS 联调**：用 WebSocket 客户端工具测试 chat 事件的完整流程
3. **前端适配**：逐页面替换 API 路径，先改管理页面（简单），再改对话页面（复杂）
4. **数据验证**：确保 Agent 创建/编辑/删除、Skill 启用/禁用、会话 CRUD 全部正常
5. **流式验证**：确保 WS 的 token/thinking/tool_call/skill_start/done 等事件正确推送和渲染
