GPU_GUARD_MONOREPO/docs/superpowers/plans/2026-04-18-tool-management-and-agent-tool-governance-impl-plan.md
2026-05-20 21:39:12 +08:00

1085 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Tool 管理 + Agent 工具授权 + 多模态 OCR 前置治理 实施文档
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 为 Neta 实现一套真正可落地的 Tool 治理体系,包括全局 Tool 管理、Agent 级 toolset/tool 授权、运行时统一 Tool 解析、Prompt Builder 接入、前端管理页面和后续多模态 OCR 接入的前置能力。
**Architecture:** 保留现有 `catalog.ts` 作为代码注册层,新增 `netaclaw_tool` 作为全局治理表,扩展 `netaclaw_agent``toolsets/tools` 配置,新增 `tool_registry.ts``tool_resolver.ts` 统一打通 catalog、DB 配置、Agent 授权、模型能力约束和运行时 Tool 实例组装。前端新增 Tool 管理页和 Agent 编辑页中的工具配置 Tab。Prompt Builder 改为消费 resolver 的结果,而不是静态推导工具列表。
**V1 Scope Constraint:** 首版 Agent 授权模型收敛为 `toolsets + tools.disabled``tools.enabled` 不进入首版实施,避免 UI、运行时、数据库语义同时过重。
**Tech Stack:** MySQL + TypeORM + Midway.js + Vue 3 + Element Plus + TypeScript
**Spec:** `docs/superpowers/specs/2026-04-18-tool-management-and-agent-tool-governance-design.md`
---
## 一、实施范围
本实施覆盖以下内容:
1. 数据库表与字段设计落库
2. 后端 Tool 元数据同步与运行时解析
3. Agent 配置模型扩展
4. Prompt Builder 接入 Tool Resolver
5. 前端 Tool 管理页面
6. 前端 Agent 编辑页工具配置
7. 联调、验收、回滚预案
本实施不直接实现 OCR但会为 OCR 接入完成全部前置基础设施。
---
## 二、文件结构
### 新增文件
| 文件 | 职责 |
|------|------|
| `packages/backend/src/modules/netaclaw/entity/tool.ts` | Tool 全局治理实体 |
| `packages/backend/src/modules/netaclaw/service/tool_registry.ts` | catalog -> DB 同步、后台查询 |
| `packages/backend/src/modules/netaclaw/service/tool_resolver.ts` | 运行时统一工具解析 |
| `packages/backend/src/modules/netaclaw/controller/admin/tool.ts` | Tool 管理接口 |
| `packages/frontend/src/modules/agent/views/tools.vue` | Tool 管理页面 |
### 修改文件
| 文件 | 改动 |
|------|------|
| `packages/backend/src/entities.ts` | 注册新实体 |
| `packages/backend/src/modules/netaclaw/tools/catalog.ts` | 扩展 ToolSchema 元数据 |
| `packages/backend/src/modules/netaclaw/tools/common.ts` | 对齐 visibility/capability 类型 |
| `packages/backend/src/modules/netaclaw/entity/agent.ts` | 新增 `toolsets``tools` 字段 |
| `packages/backend/src/modules/netaclaw/service/agent_executor.ts` | 改为使用 Tool Resolver |
| `packages/backend/src/modules/netaclaw/gateway/server.ts` | 改为使用 Tool Resolver |
| `packages/backend/src/modules/netaclaw/service/crew_orchestrator.ts` | 接入 Tool Resolver |
| `packages/backend/src/modules/netaclaw/service/crew_delegate.ts` | 接入 Tool Resolver |
| `packages/backend/src/modules/netaclaw/runtime/prompt_builder.ts` | 接入 resolved tool names + prompt hints |
| `packages/backend/src/modules/netaclaw/runtime/prompt_guidance.ts` | 支持 tool prompt hint 注入 |
| `packages/backend/src/modules/netaclaw/service/skill_context.ts` | 改为消费 resolver 输出的 builtin tool names |
| `packages/backend/src/modules/netaclaw/controller/agent.ts` | previewPrompt 接入 resolver |
| `packages/frontend/src/modules/agent/config.ts` | 新增 Tool 管理菜单 |
| `packages/frontend/src/modules/agent/views/agent-edit.vue` | 新增“工具配置”Tab |
| `packages/frontend/src/modules/agent/types/index.d.ts` | 扩展 Agent 类型定义 |
---
## 三、数据库实施
## Task 1: 新增 Tool 治理表
**Files:**
- Create: `packages/backend/src/modules/netaclaw/entity/tool.ts`
- Modify: `packages/backend/src/entities.ts`
- [ ] **Step 1: 创建 `tool.ts` Entity**
```typescript
// packages/backend/src/modules/netaclaw/entity/tool.ts
import { BaseEntity } from '../../base/entity/base.js';
import { Column, Entity, Index } from 'typeorm';
@Entity('netaclaw_tool')
export class NetaClawToolEntity extends BaseEntity {
@Index({ unique: true })
@Column({ comment: 'Tool 名称', length: 100 })
name: string;
@Column({ comment: '展示名', length: 200, nullable: true })
label: string;
@Index()
@Column({ comment: '所属 toolset', length: 50 })
toolset: string;
@Column({ comment: '描述', type: 'text', nullable: true })
description: string;
@Column({ comment: '可见性', length: 20, nullable: true })
visibility: string;
@Column({ comment: '能力要求', length: 20, nullable: true })
capability: string;
@Index()
@Column({ comment: '状态 0=禁用 1=启用', default: 1 })
status: number;
@Column({ comment: '是否核心工具', default: 0 })
isCore: number;
@Column({ comment: '是否允许禁用', default: 1 })
canDisable: number;
@Column({ comment: 'Prompt Hint 覆写', type: 'text', nullable: true })
promptHint: string;
@Column({ comment: '排序', default: 0 })
sort: number;
@Column({ comment: '扩展字段', type: 'json', nullable: true })
extra: Record<string, unknown>;
}
```
说明:
- `toolset/visibility/capability/isCore/canDisable` 属于代码注册镜像字段
- 后台只允许修改 `label/description/status/promptHint/sort/extra`
- 不允许将运行时能力语义下放为运营配置
- [ ] **Step 2: 在 `entities.ts` 注册 Entity**
仿照现有模式添加:
```typescript
import * as entityXX from './modules/netaclaw/entity/tool';
```
并在 `entities` 数组中追加:
```typescript
...Object.values(entityXX),
```
- [ ] **Step 3: 启动后端验证表创建**
Run: `cd packages/backend && npx midway-bin dev`
Expected:
- `netaclaw_tool` 自动建表成功
- [ ] **Step 4: 提交**
```bash
git add packages/backend/src/modules/netaclaw/entity/tool.ts packages/backend/src/entities.ts
git commit -m "feat(netaclaw): add netaclaw_tool entity for global tool governance"
```
---
## Task 2: 扩展 Agent 表
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/entity/agent.ts`
- [ ] **Step 1: 新增 `toolsets` 和 `tools` 字段**
`NetaClawAgentEntity` 中新增:
```typescript
@Column({ type: 'json', comment: '启用的 toolset 列表', nullable: true })
toolsets: string[];
@Column({ type: 'json', comment: '工具精细配置', nullable: true })
tools: {
disabled?: string[];
};
```
- [ ] **Step 2: 启动后端验证字段增加**
Expected:
- `netaclaw_agent` 表新增 `toolsets``tools`
- [ ] **Step 3: 提交**
```bash
git add packages/backend/src/modules/netaclaw/entity/agent.ts
git commit -m "feat(netaclaw): extend agent entity with toolsets and tools config"
```
---
## 四、后端基础设施实施
## Task 3: 扩展 catalog 元数据
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/tools/catalog.ts`
- Modify: `packages/backend/src/modules/netaclaw/tools/builtin/*.ts`(按需)
- [ ] **Step 1: 扩展 `ToolSchema`**
将:
```typescript
export interface ToolSchema {
name: string;
toolset: string;
description: string;
}
```
改为:
```typescript
export interface ToolSchema {
name: string;
toolset: string;
description: string;
visibility?: 'internal' | 'tool' | 'skill';
capability?: 'text' | 'vision' | 'multimodal';
isCore?: boolean;
canDisable?: boolean;
supportsPromptHint?: boolean;
}
```
- [ ] **Step 2: 增加 catalog 查询方法**
新增:
```typescript
export function getAllToolSchemas(): ToolSchema[] { ... }
export function getToolSchema(name: string): ToolSchema | undefined { ... }
export function getToolNamesByToolset(toolset: string): string[] { ... }
```
- [ ] **Step 3: 为核心工具补默认元数据**
至少给以下工具补齐:
- `bash`
- `read_file`
- `write_file`
- `list_dir`
- `patch`
- `clarify`
- `todo`
建议规则:
- `base` 工具默认 `capability=text`
- `clarify/todo` 默认 `isCore=1`
- `todo``visibility=internal`
- `clarify``visibility=tool`
- [ ] **Step 4: 预留 `vision` / `document` toolset 常量**
不必现在接入 OCR只需允许这些 toolset 名存在。
- [ ] **Step 5: 编译验证**
Run: `cd packages/backend && npm run build`
- [ ] **Step 6: 提交**
```bash
git add packages/backend/src/modules/netaclaw/tools/catalog.ts packages/backend/src/modules/netaclaw/tools/builtin
git commit -m "feat(netaclaw): extend tool catalog metadata for governance"
```
---
## Task 4: 新增 Tool Registry Service
**Files:**
- Create: `packages/backend/src/modules/netaclaw/service/tool_registry.ts`
- [ ] **Step 1: 创建 Service**
职责:
1. 读取 catalog 全量工具
2. 同步到 `netaclaw_tool`
3. 分页查询
4. 返回 Agent 配置可选工具
建议结构:
```typescript
@Provide()
@Scope(ScopeEnum.Singleton)
export class NetaClawToolRegistryService {
@InjectEntityModel(NetaClawToolEntity)
toolRepo: Repository<NetaClawToolEntity>;
async syncCatalogToDb() { ... }
async page(params) { ... }
async info(id: number) { ... }
async update(data) { ... }
async all() { ... }
async listForAgentConfig() { ... }
}
```
- [ ] **Step 2: 实现 `syncCatalogToDb()`**
逻辑:
1. 读取 `getAllToolSchemas()`
2. DB 无记录则插入
3. DB 已有记录则保留人工字段,仅补齐缺失元数据
4. catalog 中不存在但 DB 中存在的记录不物理删除
启动策略:
- 后端启动时自动执行一次幂等 `syncCatalogToDb()`
- `/admin/netaclaw/tool/sync` 仅作为人工刷新入口
- 不允许把首屏正确性依赖在手工点击同步按钮上
默认回填规则:
- `label = name`
- `status = 1`
- `capability = schema.capability ?? 'text'`
- `visibility = schema.visibility ?? 'tool'`
- `isCore = schema.isCore ? 1 : 0`
- `canDisable = schema.canDisable ?? (schema.isCore ? 0 : 1)`
- [ ] **Step 3: 实现 `update()` 的保护逻辑**
要求:
- `isCore=1 && canDisable=0` 时,禁止将 `status` 改为 0
- `name/toolset/visibility/capability/isCore/canDisable` 默认不允许后台修改
-`supportsPromptHint !== true`,则禁止写入 `promptHint`
- [ ] **Step 4: 编译验证**
- [ ] **Step 5: 提交**
```bash
git add packages/backend/src/modules/netaclaw/service/tool_registry.ts
git commit -m "feat(netaclaw): add tool registry service for catalog-db sync"
```
---
## Task 5: 新增 Tool Resolver Service
**Files:**
- Create: `packages/backend/src/modules/netaclaw/service/tool_resolver.ts`
- [ ] **Step 1: 创建解析接口**
```typescript
interface ResolveToolParams {
agent: NetaClawAgentEntity | null;
modelCapability?: 'text' | 'vision' | 'multimodal';
memoryEnabled?: boolean;
hasSkills?: boolean;
crewRole?: 'master' | 'sub';
}
interface ResolveToolResult {
tools: AnyAgentTool[];
toolNames: string[];
builtinToolNames: string[];
toolPromptHints: Record<string, string>;
disabledReasons: Array<{ name: string; reason: string }>;
}
```
- [ ] **Step 2: 实现 toolset 展开逻辑**
默认规则:
1. 老 Agent 无 `toolsets` 时:
- 使用 `TOOLSET_DEFAULTS`
2.`toolsets` 时:
-`toolsets` 从 catalog 展开
3. 再剔除 `tools.disabled`
- [ ] **Step 3: 实现全局 Tool 配置过滤**
`netaclaw_tool` 查询配置,过滤:
- `status=0`
- 不满足场景约束
- [ ] **Step 4: 实现 capability 过滤**
统一判断:
```typescript
function matchCapability(toolCap: string, modelCap?: string): boolean { ... }
```
规则:
- `text` 工具允许任意模型
- `vision` 工具要求 `vision|multimodal`
- `multimodal` 工具要求 `multimodal`
- [ ] **Step 4.1: 补齐模型能力来源**
要求:
- 优先在 `model_channel.ts` 的运行时解析接口中直接返回 `capability`
- `agent_executor.ts` / `gateway/server.ts` / `crew_*` 禁止各自重复解析模型能力
- 若 Agent 未绑定 channel需定义统一 fallback:
- 显式配置 capability 时用显式值
- 未配置时按 `text` 处理,并在 disabledReasons 中保留解释能力
- [ ] **Step 5: 组装运行时工具实例**
这里不要复刻 Hermes 的 handler registry。
Neta 应继续按现有工厂方式组装:
- 静态工具:
- `bashTool`
- `readFileTool`
- `writeFileTool`
- `listDirTool`
- `patchTool`
- `clarifyTool`
- Memory 工具:
-`memoryEnabled` 时工厂创建
- Skill 工具:
-`hasSkills` 时工厂创建
- Crew 工具:
-`crewRole=master` 时工厂创建
- [ ] **Step 5.1: 输出 `builtinToolNames` 给 skill context**
要求:
- resolver 需要区分“所有注入工具名”和“提供给 skill system 的 builtin tool names”
- `buildSkillContext()` 不再使用硬编码 builtin 列表
- [ ] **Step 6: 输出 `toolPromptHints`**
`netaclaw_tool.promptHint` 收集:
```typescript
{
patch: '...',
clarify: '...'
}
```
- [ ] **Step 7: 编译验证**
- [ ] **Step 8: 提交**
```bash
git add packages/backend/src/modules/netaclaw/service/tool_resolver.ts
git commit -m "feat(netaclaw): add tool resolver for runtime tool governance"
```
---
## Task 6: 新增 Tool 管理 Controller
**Files:**
- Create: `packages/backend/src/modules/netaclaw/controller/admin/tool.ts`
- [ ] **Step 1: 创建 Admin Controller**
接口:
- `/admin/netaclaw/tool/page`
- `/admin/netaclaw/tool/info`
- `/admin/netaclaw/tool/update`
- `/admin/netaclaw/tool/all`
- `/admin/netaclaw/tool/sync`
- `/admin/netaclaw/tool/forAgent`
- [ ] **Step 2: `sync` 接口调用 `syncCatalogToDb()`**
建议首次进入页面前手动调用一次,也可在服务启动时懒同步。
- [ ] **Step 3: 启动后端验证接口可达**
- [ ] **Step 4: 提交**
```bash
git add packages/backend/src/modules/netaclaw/controller/admin/tool.ts
git commit -m "feat(netaclaw): add admin tool controller"
```
---
## 五、运行时接入实施
## Task 7: 改造 agent_executor.ts
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/service/agent_executor.ts`
- [ ] **Step 1: 注入 `NetaClawToolResolverService`**
新增:
```typescript
@Inject()
toolResolver: NetaClawToolResolverService;
```
- [ ] **Step 2: 删除 `defaultTools` 硬编码依赖**
从:
```typescript
private readonly defaultTools: AnyAgentTool[] = [...]
```
迁移为 resolver 统一输出。
- [ ] **Step 3: 在解析模型后得到 `modelCapability`**
从当前 channel / modelConfig 推导 capability:
1. 优先调用 `model_channel.ts` 统一运行时解析接口
2. 直接拿到 `capability`
3. 禁止在 executor 内手写重复解析逻辑
- [ ] **Step 4: 调用 resolver**
```typescript
const resolvedTools = await this.toolResolver.resolve({
agent: agentEntity,
modelCapability,
memoryEnabled: !!memoryConfig?.enabled,
hasSkills: !!agentEntity.skills?.length,
});
```
- [ ] **Step 5: 将 `resolvedTools.builtinToolNames` 传给 `buildSkillContext()`**
替换现在的硬编码:
```typescript
const builtinToolNames = ['bash', 'read_file', 'write_file', 'list_dir', 'patch'];
```
-- [ ] **Step 6: 将 `resolvedTools.toolNames` 传给 Prompt Builder**
替换现在的:
```typescript
collectAvailableToolNames(...)
```
为:
```typescript
availableToolNames: resolvedTools.toolNames
```
- [ ] **Step 7: 将 `resolvedTools.tools` 传给 runAgent**
- [ ] **Step 8: 编译验证**
- [ ] **Step 9: 提交**
```bash
git add packages/backend/src/modules/netaclaw/service/agent_executor.ts
git commit -m "refactor(netaclaw): agent executor uses tool resolver"
```
---
## Task 8: 改造 gateway/server.ts
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/gateway/server.ts`
- [ ] **Step 1: 注入 Tool Resolver**
- [ ] **Step 2: 替换默认工具拼装**
要求:
- WS 路径与 REST 路径使用相同解析逻辑
- 不再各自维护工具集合
- [ ] **Step 3: Prompt Builder 改用 resolved tool names**
- [ ] **Step 4: 编译验证**
- [ ] **Step 5: 提交**
```bash
git add packages/backend/src/modules/netaclaw/gateway/server.ts
git commit -m "refactor(netaclaw): gateway uses tool resolver"
```
---
## Task 9: 改造 crew_orchestrator.ts / crew_delegate.ts
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/service/crew_orchestrator.ts`
- Modify: `packages/backend/src/modules/netaclaw/service/crew_delegate.ts`
- [ ] **Step 1: master 场景接入 resolver**
`crewRole='master'`
- [ ] **Step 2: sub 场景接入 resolver**
`crewRole='sub'`
- [ ] **Step 3: 验证 `delegate_*` 只在 master 中出现**
- [ ] **Step 4: 编译验证**
- [ ] **Step 5: 提交**
```bash
git add packages/backend/src/modules/netaclaw/service/crew_orchestrator.ts packages/backend/src/modules/netaclaw/service/crew_delegate.ts
git commit -m "refactor(netaclaw): crew runtime uses tool resolver"
```
---
## 六、Prompt Builder 实施
## Task 10: prompt_builder.ts 接入 Tool Prompt Hint
**Files:**
- Modify: `packages/backend/src/modules/netaclaw/runtime/prompt_builder.ts`
- Modify: `packages/backend/src/modules/netaclaw/runtime/prompt_guidance.ts`
- Modify: `packages/backend/src/modules/netaclaw/service/skill_context.ts`
- Modify: `packages/backend/src/modules/netaclaw/controller/agent.ts`
- [ ] **Step 1: 扩展 `getToolBehaviorGuidance()`**
从:
```typescript
getToolBehaviorGuidance(toolNames: string[])
```
改为:
```typescript
getToolBehaviorGuidance(
toolNames: string[],
toolPromptHints?: Record<string, string>
)
```
逻辑:
- 若某 Tool 有 DB `promptHint` 覆写,则优先使用覆写
- 否则回退默认 guidance
- [ ] **Step 2: Prompt Builder 接收 `toolPromptHints`**
`BuildSystemPromptParams` 中新增:
```typescript
toolPromptHints?: Record<string, string>;
```
- [ ] **Step 3: skill_context 改为消费 resolver 输出**
要求:
- `buildSkillContext()` 的 builtin tool names 参数由 resolver 提供
- 不能再保留硬编码 builtin 工具列表
- [ ] **Step 4: previewPrompt 接口接入 resolver**
让预览接口返回:
- `layers`
- `toolNames`
- `disabledReasons`
这样前端可解释“为什么某工具没有被注入”。
- [ ] **Step 5: 编译验证**
- [ ] **Step 6: 提交**
```bash
git add packages/backend/src/modules/netaclaw/runtime/prompt_builder.ts packages/backend/src/modules/netaclaw/runtime/prompt_guidance.ts packages/backend/src/modules/netaclaw/service/skill_context.ts packages/backend/src/modules/netaclaw/controller/agent.ts
git commit -m "feat(netaclaw): prompt builder supports resolved tools and prompt hints"
```
---
## 七、前端实施
## Task 11: 新增 Tool 管理菜单
**Files:**
- Modify: `packages/frontend/src/modules/agent/config.ts`
- [ ] **Step 1: 在 Skill 管理上方插入路由**
```typescript
{
path: '/agent/tools',
meta: { label: 'Tool 管理' },
component: () => import('./views/tools.vue')
},
```
- [ ] **Step 2: 本地验证菜单顺序**
- [ ] **Step 3: 提交**
```bash
git add packages/frontend/src/modules/agent/config.ts
git commit -m "feat(frontend): add tool management route"
```
---
## Task 12: 实现 Tool 管理页
**Files:**
- Create: `packages/frontend/src/modules/agent/views/tools.vue`
- [ ] **Step 1: 创建页面骨架**
包含:
- 筛选区
- 表格区
- 编辑抽屉
- 同步按钮
- [ ] **Step 2: 对接接口**
使用:
- `/admin/netaclaw/tool/page`
- `/admin/netaclaw/tool/update`
- `/admin/netaclaw/tool/sync`
- [ ] **Step 3: 页面字段**
表格列:
- name
- label
- toolset
- capability
- visibility
- isCore
- status
- promptHint 状态
- [ ] **Step 4: 编辑抽屉**
允许编辑:
- label
- description
- status
- promptHint
- sort
只读:
- name
- toolset
- capability
- visibility
- isCore
- canDisable
- [ ] **Step 5: 对核心工具加禁用保护**
前端禁用开关,后端再次校验。
- [ ] **Step 6: 浏览器验证**
验证:
- 页面可打开
- 同步后出现工具列表
- 可编辑提示词
- 核心工具不能关闭
- [ ] **Step 7: 提交**
```bash
git add packages/frontend/src/modules/agent/views/tools.vue
git commit -m "feat(frontend): add tool management page"
```
---
## Task 13: 扩展前端 Agent 类型
**Files:**
- Modify: `packages/frontend/src/modules/agent/types/index.d.ts`
- [ ] **Step 1: 为 AgentInfo 增加字段**
新增:
```typescript
toolsets?: string[];
tools?: {
disabled?: string[];
};
```
- [ ] **Step 2: 编译验证**
- [ ] **Step 3: 提交**
```bash
git add packages/frontend/src/modules/agent/types/index.d.ts
git commit -m "feat(frontend): extend agent types with toolsets and tools"
```
---
## Task 14: 改造 agent-edit.vue
**Files:**
- Modify: `packages/frontend/src/modules/agent/views/agent-edit.vue`
- [ ] **Step 1: 新增“工具配置”Tab**
位置:
-`Skill配置` 平级
- [ ] **Step 2: 新增 toolset 多选区**
数据源:
- `/admin/netaclaw/tool/forAgent`
从接口中提取唯一 toolset 列表。
- [ ] **Step 3: 新增工具精细控制双栏**
展示:
- 可用工具
- 已禁用覆盖
最小实现建议:
- 左栏: 可选工具
- 右栏: 已禁用工具
通过 `toolsets` 先决定默认启用范围,`tools.disabled` 做剔除。
- [ ] **Step 4: loadAgent 回填**
回填:
- `toolsets`
- `tools.disabled`
- [ ] **Step 5: handleSave 提交**
请求体追加:
```typescript
toolsets: form.value.toolsets,
tools: form.value.tools,
```
- [ ] **Step 6: Prompt 预览展示被过滤工具**
若后端 previewPrompt 返回:
- `toolNames`
- `disabledReasons`
则页面增加一个提示区域显示。
- [ ] **Step 7: 浏览器验证**
验证:
- 可勾选 toolsets
- 可禁用单工具
- 保存后再次打开可回填
- preview 可看到过滤原因
- [ ] **Step 8: 提交**
```bash
git add packages/frontend/src/modules/agent/views/agent-edit.vue
git commit -m "feat(frontend): add agent toolsets and tools configuration tab"
```
---
## 八、联调与验收
## Task 15: 数据同步验证
- [ ] **Step 1: 启动后端**
- [ ] **Step 2: 调用 `/admin/netaclaw/tool/sync`**
Expected:
- `netaclaw_tool` 中出现 catalog 全量工具
- [ ] **Step 3: 检查核心字段**
至少检查:
- `todo`
- `clarify`
- `bash`
- `read_file`
- `patch`
---
## Task 16: Agent 工具授权联调
- [ ] **Step 1: 新建一个 Agent**
配置:
- `toolsets = ['base', 'planning']`
- `tools.disabled = ['bash']`
- [ ] **Step 2: 预览 Prompt**
Expected:
- `bash` 不在 toolNames 中
- `read_file/write_file/list_dir/patch/todo` 仍在
- [ ] **Step 3: 发起真实对话**
构造任务要求执行 bash。
Expected:
- 模型看不到 `bash`
- 不应产生 bash tool call
---
## Task 17: capability 过滤联调
- [ ] **Step 1: 准备一个 text 模型 Agent**
- [ ] **Step 2: 准备一个代码注册层声明 `capability=vision` 的测试 Tool**
要求:
- 不通过后台或 DB 手工修改 `capability`
- 若暂时没有真实视觉工具,可在本地临时注册一个测试 Tool 用于联调
- [ ] **Step 3: 预览 Prompt**
Expected:
- 该工具被过滤
- disabledReasons 中出现 `capability_mismatch`
---
## Task 18: Tool Prompt Hint 联调
- [ ] **Step 1: 在 Tool 管理页给 `patch` 写入 promptHint**
- [ ] **Step 2: 预览 Prompt**
Expected:
- Layer 4 中优先出现 DB 覆写内容,而不是默认 guidance
---
## 九、验收标准
以下全部满足才算完成:
### 数据库
- `netaclaw_tool` 表存在
- `netaclaw_agent` 新增 `toolsets/tools`
### 后端
- catalog 可同步到 DB
- Tool Resolver 成为统一事实来源
- `model_channel.ts` 统一提供运行时 `capability`
- REST/WS/Crew 三条路径都走 resolver
- skill_context 消费 resolver 输出的 builtin tool names
- previewPrompt 可返回 toolNames 和 disabledReasons
### 前端
- 出现 Tool 管理菜单与页面
- Tool 管理页可编辑全局状态和 promptHint
- Agent 编辑页可配置 toolsets 与单工具覆盖
- Prompt 预览能看到工具生效与过滤原因
### 行为
- 全局禁用的工具不会被注入
- Agent 禁用的工具不会被注入
- capability 不满足的工具不会被注入
- 核心不可禁用工具不能被后台关闭
---
## 十、回滚预案
若某阶段出问题,按以下顺序回滚。
### 1. 页面级回滚
- 隐藏 `/agent/tools`
- 隐藏 Agent 编辑页中的“工具配置”Tab
不影响现有 Agent 基本能力。
### 2. 运行时回滚
若 resolver 逻辑异常,可临时回退:
- `agent_executor.ts` 恢复 `defaultTools`
- `gateway/server.ts` 恢复原工具拼装
数据库结构可保留,不影响运行。
### 3. 数据级回滚
- `netaclaw_tool` 表可保留
- `toolsets/tools` 字段即使存在,也不影响老代码
因此本方案具备较好的渐进式上线条件。
---
## 十一、实施顺序建议
建议严格按以下顺序推进:
1. 数据库实体
2. catalog 扩展
3. tool_registry
4. tool_resolver
5. model capability 统一解析链路
6. agent_executor / gateway / crew 接入
7. prompt_builder / skill_context 接入
7. Tool 管理页
8. Agent 编辑页工具配置
9. 联调验收
不要先做前端页面。否则会出现“配置存在但运行时无效”的假闭环。
---
## 十二、后续 OCR 接入说明
当本实施完成后,接入 OCR 的工作将降维为一项普通功能开发:
1.`catalog.ts` 注册 `vision_ocr`
2. 设置:
- `toolset='vision'`
- `capability='vision'`
3. 在 Tool 管理页全局启用
4. 在 Agent 工具配置中勾选
5. 由 resolver 自动判断模型是否支持
也就是说这份实施文档完成后OCR 不再是架构问题,而只是业务工具实现问题。