1080 lines
24 KiB
Markdown
1080 lines
24 KiB
Markdown
# Tool 管理 + Agent 工具授权 + 多模态 OCR 前置治理 设计文档
|
||
|
||
> 日期: 2026-04-18
|
||
> 范围: Neta-monorepo 后端 + 前端 + 数据模型
|
||
> 参考: Hermes Agent 工具注册 / toolset / tools config 体系
|
||
> 目标: 基于 Hermes 的成熟做法,结合 Neta 当前架构,设计一套真正可落地的 Tool 管理方案
|
||
|
||
---
|
||
|
||
## 1. 背景与问题
|
||
|
||
你当前的真实诉求并不只是“加一个 OCR 功能”,而是:
|
||
|
||
1. 给 Neta 增加可治理的 Tool 管理能力
|
||
2. 让 Agent 可以显式选择允许使用哪些工具
|
||
3. 让工具的提示词注入、能力要求、启停状态进入后台管理
|
||
4. 为多模态 OCR 这类能力提供稳定落点
|
||
|
||
这件事之所以必须先做设计,而不是直接上 OCR,是因为 OCR 一旦落地,会立刻依赖以下治理能力:
|
||
|
||
- 它属于哪个 toolset
|
||
- 是否全局可用
|
||
- 哪些 Agent 可以使用
|
||
- 当前模型是否支持视觉/多模态
|
||
- 提示词里怎么引导模型使用它
|
||
|
||
如果这些不先补齐,OCR 只会成为一个继续硬编码在运行时里的“特殊工具”,后续浏览器、网页抽取、图像理解、文档解析都会重复同样的问题。
|
||
|
||
---
|
||
|
||
## 2. 先看 Hermes 是怎么做的
|
||
|
||
Hermes 的工具管理不是一个单页面,而是一套三层结构。
|
||
|
||
## 2.1 Hermes 的三层结构
|
||
|
||
### 第一层: 单工具注册中心
|
||
|
||
文件:
|
||
|
||
- `hermes-agent-main/tools/registry.py`
|
||
|
||
职责:
|
||
|
||
1. 每个工具文件在模块加载时调用 `registry.register(...)`
|
||
2. 注册内容包括:
|
||
- `name`
|
||
- `toolset`
|
||
- `schema`
|
||
- `handler`
|
||
- `check_fn`
|
||
- `requires_env`
|
||
- `is_async`
|
||
- `description`
|
||
- `emoji`
|
||
3. 运行时由 `registry.get_definitions()` 和 `registry.dispatch()` 统一取 schema 和执行
|
||
|
||
关键特点:
|
||
|
||
- 工具注册中心同时保存“元数据 + 执行 handler”
|
||
- `check_fn` 用来判断工具是否真的可用
|
||
- 工具并不直接在 UI 层管理,而是在运行时层先统一注册
|
||
|
||
### 第二层: Toolset 组合层
|
||
|
||
文件:
|
||
|
||
- `hermes-agent-main/toolsets.py`
|
||
|
||
职责:
|
||
|
||
1. 定义工具分组,如 `web`、`vision`、`browser`、`file`
|
||
2. 支持 toolset 组合和递归解析
|
||
3. 平台不是勾单个工具,而是勾 toolset
|
||
|
||
关键特点:
|
||
|
||
- toolset 是产品管理的最小单位
|
||
- toolset 可组合
|
||
- 平台默认不是直接选单工具,而是按能力集启用
|
||
|
||
### 第三层: 配置与 Provider-aware Setup 层
|
||
|
||
文件:
|
||
|
||
- `hermes-agent-main/hermes_cli/tools_config.py`
|
||
|
||
职责:
|
||
|
||
1. 提供工具配置 UI
|
||
2. 不同平台配置不同 toolset
|
||
3. 工具启用后,如果需要 API Key,会立即进入 provider 配置流程
|
||
4. 配置最终落到 `~/.hermes/config.yaml`
|
||
|
||
关键特点:
|
||
|
||
- Hermes 管的重点其实是 `toolset`,不是单个 tool
|
||
- 对需要外部依赖的工具,配置 UI 会联动 provider 配置
|
||
- 平台维度强于 Agent 维度
|
||
|
||
---
|
||
|
||
## 3. Neta 当前现状分析
|
||
|
||
Hermes 的思路成熟,但 Neta 不能直接照搬。原因是两边的产品中心不同。
|
||
|
||
## 3.1 Neta 已经有的能力
|
||
|
||
### 1. 已有轻量工具目录
|
||
|
||
文件:
|
||
|
||
- `packages/backend/src/modules/netaclaw/tools/catalog.ts`
|
||
|
||
当前能力:
|
||
|
||
- 已能注册 `name + toolset + description`
|
||
- 已有 `TOOLSET_DEFAULTS = ['base', 'planning', 'interaction']`
|
||
- 已按 `import` 触发注册
|
||
|
||
这意味着:
|
||
|
||
- Neta 不是“没有工具系统”
|
||
- Neta 缺的是“运行时工具治理 + 后台配置”
|
||
|
||
### 2. 已有 Tool 可见性体系
|
||
|
||
文件:
|
||
|
||
- `packages/backend/src/modules/netaclaw/tools/common.ts`
|
||
|
||
当前能力:
|
||
|
||
- 已有 `ToolVisibility = 'internal' | 'tool' | 'skill'`
|
||
|
||
这说明 Neta 已经考虑了:
|
||
|
||
- 哪些工具对用户可见
|
||
- 哪些工具是运行时内部工具
|
||
|
||
这是比 Hermes 更贴近前端对话 UI 的一层。
|
||
|
||
### 3. 已有 Skill 系统
|
||
|
||
当前 Skill 本质是:
|
||
|
||
- 提示词能力包
|
||
- 通过 `read_skill/read_skill_file/skill_manage` 辅助使用
|
||
|
||
不是工具执行引擎。
|
||
|
||
所以 OCR 不适合先做成 Skill 本体,这个判断仍然成立。
|
||
|
||
### 4. 已有模型通道系统
|
||
|
||
文件:
|
||
|
||
- `packages/backend/src/modules/netaclaw/service/model_channel.ts`
|
||
- `packages/backend/src/modules/netaclaw/entity/model_channel.ts`
|
||
|
||
当前能力:
|
||
|
||
- 已有 channel
|
||
- 已有 model 列表
|
||
- 已有 `capability` 字段
|
||
|
||
这比 Hermes 的 env/config 模式更强,因为 Neta 已经把模型配置结构化进数据库了。
|
||
|
||
## 3.2 Neta 当前真正缺的能力
|
||
|
||
### 1. 运行时工具实例还是硬编码的
|
||
|
||
文件:
|
||
|
||
- `packages/backend/src/modules/netaclaw/service/agent_executor.ts`
|
||
|
||
当前:
|
||
|
||
```typescript
|
||
private readonly defaultTools: AnyAgentTool[] = [
|
||
bashTool, readFileTool, writeFileTool, listDirTool, patchTool, clarifyTool
|
||
];
|
||
```
|
||
|
||
问题:
|
||
|
||
- 后台配置无法控制这里
|
||
- 新工具只能继续改代码
|
||
- Tool catalog 和实际执行源没有完全打通
|
||
|
||
### 2. Agent 没有工具授权字段
|
||
|
||
文件:
|
||
|
||
- `packages/backend/src/modules/netaclaw/entity/agent.ts`
|
||
|
||
当前 Agent 只有:
|
||
|
||
- `skills`
|
||
- `modelConfig`
|
||
- `config`
|
||
|
||
没有:
|
||
|
||
- `tools`
|
||
- `toolsets`
|
||
- `tool policy`
|
||
|
||
### 3. Prompt Builder 只知道 toolset,不知道 Tool 配置
|
||
|
||
文件:
|
||
|
||
- `packages/backend/src/modules/netaclaw/runtime/prompt_builder.ts`
|
||
|
||
当前 `collectAvailableToolNames()` 是按默认 toolset 和条件拼工具名,不知道:
|
||
|
||
- 工具是否被后台禁用
|
||
- Agent 是否勾选
|
||
- 当前模型是否支持
|
||
- 某个工具是否有专属 Prompt Hint 覆写
|
||
|
||
### 4. 前端没有 Tool 管理页,也没有 Agent 工具选择
|
||
|
||
当前前端只有:
|
||
|
||
- Agent 管理
|
||
- Skill 管理
|
||
- 模型管理
|
||
|
||
没有:
|
||
|
||
- Tool 管理
|
||
- Agent 工具配置
|
||
|
||
---
|
||
|
||
## 4. 设计结论: Hermes 哪些要学,哪些不能照搬
|
||
|
||
## 4.1 要学习的部分
|
||
|
||
### 1. 学 Hermes 的“三层拆分”
|
||
|
||
要拆成:
|
||
|
||
1. 代码注册层
|
||
2. Toolset 组织层
|
||
3. 配置治理层
|
||
|
||
Neta 现在已经有前两层雏形,重点要补第三层,并把三层串起来。
|
||
|
||
### 2. 学 Hermes 的“toolset 先行”
|
||
|
||
不要一上来只做“Agent 勾选单工具”。
|
||
|
||
真正可扩展的模型是:
|
||
|
||
- 先管理 toolset
|
||
- 再允许细粒度控制单工具
|
||
|
||
因为未来 OCR 不会是唯一工具,后面还会有:
|
||
|
||
- vision
|
||
- browser
|
||
- web
|
||
- document
|
||
- data extraction
|
||
|
||
### 3. 学 Hermes 的“可用性检查”
|
||
|
||
Hermes 每个工具可绑定 `check_fn`。
|
||
|
||
Neta 也应该引入类似概念,但不必完全复刻函数式注册。Neta 更适合做成:
|
||
|
||
- `requiredCapability`
|
||
- `requiredConfig`
|
||
- `sceneConstraint`
|
||
|
||
由运行时统一判断。
|
||
|
||
### 4. 学 Hermes 的“启用工具时同步配置依赖”
|
||
|
||
Hermes 开某些 toolset 时会进入 provider 配置流程。
|
||
|
||
Neta 不需要 CLI 式交互,但要在后台 UI 上体现:
|
||
|
||
- 这个工具依赖什么
|
||
- 模型是否满足
|
||
- 是否需要辅助模型
|
||
|
||
## 4.2 不能直接照搬的部分
|
||
|
||
### 1. 不能照搬“平台级配置优先”
|
||
|
||
Hermes 的核心入口是 CLI / Telegram / Discord 等平台,所以它以“平台启用哪些 toolset”为中心。
|
||
|
||
Neta 的核心入口是“数据库中配置的 Agent”。
|
||
|
||
所以 Neta 应以:
|
||
|
||
- 系统全局 Tool 配置
|
||
- Agent 级 Tool 授权
|
||
|
||
为中心,而不是平台级。
|
||
|
||
### 2. 不能照搬“注册中心同时持有 handler”
|
||
|
||
Hermes 的 registry 直接持有 handler。
|
||
|
||
Neta 当前内置工具有静态工具,也有工厂工具:
|
||
|
||
- memory 工具需要 provider
|
||
- skill 工具需要 skillLoader
|
||
- crew 工具需要运行时上下文
|
||
|
||
所以 Neta 不适合把所有 handler 都塞进统一 registry。
|
||
|
||
Neta 更适合:
|
||
|
||
- `catalog.ts` 管 schema 元数据
|
||
- `tool_resolver.ts` 管运行时实例组装
|
||
|
||
### 3. 不能照搬 config.yaml 模式
|
||
|
||
Hermes 的配置落在文件。
|
||
|
||
Neta 已经有:
|
||
|
||
- DB Agent
|
||
- DB Model Channel
|
||
- Admin 前端
|
||
|
||
因此 Tool 配置必须进入数据库和后台页面,而不是文件。
|
||
|
||
---
|
||
|
||
## 5. 面向 Neta 的最优方案
|
||
|
||
综合 Hermes 的成熟做法和 Neta 当前项目结构,Neta 的最优方案应是:
|
||
|
||
### 方案核心
|
||
|
||
1. 保留现有 `catalog.ts` 作为代码注册层
|
||
2. 扩展 `catalog.ts` 元数据,补齐 toolset / capability / core 属性
|
||
3. 新增 DB Tool 配置表,承接全局治理
|
||
4. Agent 新增 `toolsets + tools` 配置
|
||
5. 新增运行时 Tool Resolver,统一生成最终工具实例
|
||
6. Prompt Builder 从静态 toolset 推断,升级为“读取 Tool Resolver 结果”
|
||
|
||
这才是适合 Neta 的版本,而不是直接复刻 Hermes。
|
||
|
||
---
|
||
|
||
## 6. 总体架构设计
|
||
|
||
分成 5 层。
|
||
|
||
### 第 1 层: 代码注册层
|
||
|
||
现有文件:
|
||
|
||
- `packages/backend/src/modules/netaclaw/tools/catalog.ts`
|
||
|
||
职责:
|
||
|
||
- 注册 Tool 元数据
|
||
- 不负责运行时 handler
|
||
|
||
建议扩展:
|
||
|
||
```typescript
|
||
export interface ToolSchema {
|
||
name: string;
|
||
toolset: string;
|
||
description: string;
|
||
visibility?: 'internal' | 'tool' | 'skill';
|
||
capability?: 'text' | 'vision' | 'multimodal';
|
||
isCore?: boolean;
|
||
canDisable?: boolean;
|
||
supportsPromptHint?: boolean;
|
||
}
|
||
```
|
||
|
||
说明:
|
||
|
||
- `visibility` 与当前 `common.ts` 对齐
|
||
- `capability` 为多模态 OCR 预留
|
||
- `isCore/canDisable` 用于后台保护
|
||
- `supportsPromptHint` 用于限定哪些工具能做专属提示词覆写
|
||
- 上述字段中,`visibility/capability/isCore/canDisable/supportsPromptHint` 的真相源应为代码注册层
|
||
- DB 仅同步镜像用于展示、筛选和治理判断,不应允许后台直接改写这些运行时语义字段
|
||
|
||
### 第 2 层: Toolset 管理层
|
||
|
||
继续保留当前 toolset 体系,但要正式化。
|
||
|
||
当前已有:
|
||
|
||
- `base`
|
||
- `planning`
|
||
- `interaction`
|
||
- `memory`
|
||
- `skill`
|
||
- `crew`
|
||
|
||
建议新增:
|
||
|
||
- `vision`
|
||
- `document`
|
||
|
||
不要一开始就分太细,但要给 OCR 留出明确归属。
|
||
|
||
### 第 3 层: 全局 Tool 治理层
|
||
|
||
新增数据库表 `netaclaw_tool`。
|
||
|
||
这个表承接:
|
||
|
||
- 全局启用/禁用
|
||
- 展示名称
|
||
- 排序
|
||
- Prompt Hint 覆写
|
||
|
||
不承接:
|
||
|
||
- `capability` 覆写
|
||
- `visibility` 覆写
|
||
- `toolset` 覆写
|
||
|
||
原因:
|
||
|
||
- 这些字段属于代码注册层的运行时真相
|
||
- 若允许后台改写,会导致 resolver、prompt、实际 handler 能力产生漂移
|
||
|
||
### 第 4 层: Agent 工具授权层
|
||
|
||
Agent 上新增两个维度:
|
||
|
||
- `toolsets`
|
||
- `tools`
|
||
|
||
原因:
|
||
|
||
- 只做 `tools` 太细,配置成本高
|
||
- 只做 `toolsets` 又不够灵活
|
||
|
||
所以需要“toolset 粗授权 + tool 细覆盖”的混合方案。
|
||
|
||
### 第 5 层: 运行时解析层
|
||
|
||
新增 `tool_resolver.ts`,统一计算:
|
||
|
||
- 当前 Agent 最终可用工具实例
|
||
- 当前 Prompt 最终可见工具名
|
||
- 被过滤工具和原因
|
||
|
||
---
|
||
|
||
## 7. 数据模型设计
|
||
|
||
## 7.1 新增表 `netaclaw_tool`
|
||
|
||
| 字段 | 类型 | 约束 | 说明 |
|
||
|------|------|------|------|
|
||
| id | int | PK, auto | 主键 |
|
||
| name | varchar(100) | unique | Tool 名称,对应代码注册名 |
|
||
| label | varchar(200) | nullable | 展示名 |
|
||
| toolset | varchar(50) | indexed | 所属 toolset |
|
||
| description | text | nullable | 展示描述 |
|
||
| visibility | varchar(20) | nullable | internal/tool/skill |
|
||
| capability | varchar(20) | nullable | text/vision/multimodal |
|
||
| status | int | indexed, default 1 | 0=禁用 1=启用 |
|
||
| isCore | int | default 0 | 是否核心工具 |
|
||
| canDisable | int | default 1 | 是否允许后台关闭 |
|
||
| promptHint | text | nullable | Tool 专属提示词覆写 |
|
||
| sort | int | default 0 | 排序 |
|
||
| extra | json | nullable | 预留字段 |
|
||
| createTime | datetime | auto | 创建时间 |
|
||
| updateTime | datetime | auto | 更新时间 |
|
||
| deleteTime | datetime | nullable | 软删除 |
|
||
|
||
补充约束:
|
||
|
||
- `toolset/visibility/capability/isCore/canDisable` 为代码镜像字段,只读
|
||
- 后台仅允许修改 `label/description/status/promptHint/sort/extra`
|
||
|
||
## 7.2 扩展 `netaclaw_agent`
|
||
|
||
V1 在 Agent 表新增 2 个字段:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| toolsets | json | Agent 启用的 toolset 列表 |
|
||
| tools | json | Agent 额外精细化工具配置 |
|
||
|
||
建议结构:
|
||
|
||
```json
|
||
{
|
||
"disabled": ["clarify"]
|
||
}
|
||
```
|
||
|
||
说明:
|
||
|
||
- `toolsets` 用于粗粒度启用能力集
|
||
- V1 的 `tools` 仅保留 `disabled`
|
||
- `tools.enabled` 暂不进入首版,避免 UI、运行时和数据模型过早复杂化
|
||
- 若后续确有“跨 toolset 单工具白名单”诉求,再增补 `tools.enabled`
|
||
|
||
最终解析优先级:
|
||
|
||
1. 从 `toolsets` 展开默认工具
|
||
2. 应用 `tools.disabled`
|
||
|
||
为什么这样设计:
|
||
|
||
- 更接近 Hermes 的 toolset 思路
|
||
- 又能满足 Neta 首版足够实用的精细控制
|
||
|
||
## 7.3 模型能力约束
|
||
|
||
当前 `model_channel.models` 已有 `capability` 字段,但需统一语义。
|
||
|
||
标准值:
|
||
|
||
- `text`
|
||
- `vision`
|
||
- `multimodal`
|
||
|
||
统一规则:
|
||
|
||
| Tool capability | 模型 capability | 满足 |
|
||
|------|------|------|
|
||
| text | text/vision/multimodal | 是 |
|
||
| vision | vision/multimodal | 是 |
|
||
| multimodal | multimodal | 是 |
|
||
| vision | text | 否 |
|
||
| multimodal | text/vision | 否 |
|
||
|
||
补充要求:
|
||
|
||
- `model_channel.ts` 必须提供统一的模型能力解析接口
|
||
- `resolveForAgent()` 或等价运行时接口必须显式返回 `capability`
|
||
- REST / WS / Crew 不允许各自重复推导能力,必须复用同一链路
|
||
|
||
---
|
||
|
||
## 8. 后端设计
|
||
|
||
## 8.1 新增文件
|
||
|
||
| 文件 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| Entity | `packages/backend/src/modules/netaclaw/entity/tool.ts` | Tool 配置实体 |
|
||
| Service | `packages/backend/src/modules/netaclaw/service/tool_registry.ts` | Tool 元数据同步服务 |
|
||
| Service | `packages/backend/src/modules/netaclaw/service/tool_resolver.ts` | Tool 运行时解析服务 |
|
||
| Controller | `packages/backend/src/modules/netaclaw/controller/admin/tool.ts` | Tool 管理接口 |
|
||
|
||
## 8.2 Tool Registry Service
|
||
|
||
职责:
|
||
|
||
1. 从 `catalog.ts` 读取所有注册工具
|
||
2. 将元数据同步到 `netaclaw_tool`
|
||
3. 返回后台使用的 Tool 列表
|
||
|
||
与 Hermes 的区别:
|
||
|
||
- Hermes registry 直接管 handler
|
||
- Neta 的 `tool_registry.ts` 只管治理元数据
|
||
|
||
这是因为 Neta 有大量运行时工厂工具,不能直接复刻 Hermes 的 handler 注册模型。
|
||
|
||
同步策略:
|
||
|
||
- 服务启动时执行一次幂等自动同步,保证首屏与运行时不会因空库失真
|
||
- `/admin/netaclaw/tool/sync` 仅作为人工刷新与补录入口
|
||
- catalog 中已删除的工具默认不物理删除 DB 记录,而是标记为“已脱离代码注册”
|
||
|
||
## 8.3 Tool Resolver Service
|
||
|
||
这是本方案最关键的新增层。
|
||
|
||
职责:
|
||
|
||
1. 根据 Agent 配置展开 toolset
|
||
2. 合并全局 Tool 配置
|
||
3. 过滤不可用工具
|
||
4. 组装最终 Tool 实例
|
||
5. 生成 Prompt Builder 使用的工具名列表
|
||
6. 向 skill context 构建过程暴露最终可用工具名,避免 skill 指导信息与运行时注入脱节
|
||
|
||
接口建议:
|
||
|
||
```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:
|
||
| 'globally_disabled'
|
||
| 'agent_toolset_not_enabled'
|
||
| 'agent_tool_disabled'
|
||
| 'capability_mismatch'
|
||
| 'scene_filtered';
|
||
}>;
|
||
}
|
||
```
|
||
|
||
### 8.3.1 解析流程
|
||
|
||
```text
|
||
catalog 全量工具
|
||
-> 根据 agent.toolsets 展开
|
||
-> 去掉 agent.tools.disabled
|
||
-> 过滤全局 status=0
|
||
-> 过滤 capability 不满足
|
||
-> 过滤 scene 不满足
|
||
-> 输出 tools + toolNames + builtinToolNames + toolPromptHints
|
||
```
|
||
|
||
### 8.3.2 为什么必须有这一层
|
||
|
||
没有 `tool_resolver.ts`,Neta 会继续出现:
|
||
|
||
1. catalog 是一套
|
||
2. prompt 是一套
|
||
3. executor 是一套
|
||
4. 后台页面又是一套
|
||
|
||
这四套来源会很快失真。
|
||
|
||
`tool_resolver.ts` 的价值,就是把它们收敛成单一事实来源。
|
||
|
||
## 8.4 Tool 管理接口
|
||
|
||
| 端点 | 方法 | 功能 |
|
||
|------|------|------|
|
||
| `/admin/netaclaw/tool/page` | POST | Tool 分页查询 |
|
||
| `/admin/netaclaw/tool/info` | GET | Tool 详情 |
|
||
| `/admin/netaclaw/tool/update` | POST | 更新 Tool 配置 |
|
||
| `/admin/netaclaw/tool/all` | GET | 获取全部 Tool 列表 |
|
||
| `/admin/netaclaw/tool/sync` | POST | 同步 catalog 到 DB |
|
||
| `/admin/netaclaw/tool/forAgent` | GET | 获取 Agent 配置可选工具 |
|
||
|
||
限制:
|
||
|
||
- 不开放 handler 编辑
|
||
- 不开放 schema 编辑
|
||
- 核心不可禁用工具由后端兜底校验
|
||
|
||
## 8.5 Prompt Builder 改造
|
||
|
||
当前 `prompt_builder.ts` 的问题是静态。
|
||
|
||
改造方向:
|
||
|
||
### 从:
|
||
|
||
```typescript
|
||
collectAvailableToolNames({
|
||
memoryEnabled,
|
||
hasSkills,
|
||
crewRole,
|
||
})
|
||
```
|
||
|
||
### 改为:
|
||
|
||
```typescript
|
||
const resolved = await toolResolver.resolve(...);
|
||
const toolNames = resolved.toolNames;
|
||
```
|
||
|
||
并支持 Tool Prompt Hint 注入:
|
||
|
||
```typescript
|
||
getToolBehaviorGuidance(toolNames, promptHints)
|
||
```
|
||
|
||
其中 `promptHints` 来自 `netaclaw_tool.promptHint`。
|
||
|
||
同时需要补一处现有耦合:
|
||
|
||
- `buildSkillContext()` 当前仍依赖硬编码 builtin tool names
|
||
- 改造后必须消费 resolver 产出的 `builtinToolNames`
|
||
- 否则工具治理生效后,skill prompt 仍会引用已被禁用的工具
|
||
|
||
---
|
||
|
||
## 9. 前端设计
|
||
|
||
## 9.1 菜单结构
|
||
|
||
在 `Skill 管理` 上方新增:
|
||
|
||
- `Tool 管理`
|
||
|
||
路由:
|
||
|
||
```typescript
|
||
{ path: '/agent/tools', meta: { label: 'Tool 管理' } }
|
||
```
|
||
|
||
## 9.2 Tool 管理页设计
|
||
|
||
文件建议:
|
||
|
||
- `packages/frontend/src/modules/agent/views/tools.vue`
|
||
|
||
页面结构:
|
||
|
||
### 顶部筛选栏
|
||
|
||
- 搜索
|
||
- toolset 筛选
|
||
- capability 筛选
|
||
- status 筛选
|
||
- 同步工具按钮
|
||
|
||
### 列表区
|
||
|
||
字段:
|
||
|
||
- Tool 名称
|
||
- 展示名
|
||
- toolset
|
||
- capability
|
||
- visibility
|
||
- 核心标签
|
||
- 启用状态
|
||
- Prompt Hint 状态
|
||
- 操作
|
||
|
||
### 编辑抽屉
|
||
|
||
可编辑:
|
||
|
||
- label
|
||
- description
|
||
- status
|
||
- promptHint
|
||
- sort
|
||
|
||
只读:
|
||
|
||
- name
|
||
- toolset
|
||
- capability
|
||
- visibility
|
||
- isCore
|
||
- canDisable
|
||
|
||
## 9.3 Agent 编辑页改造
|
||
|
||
当前 `agent-edit.vue` 只有 Skill 配置,没有 Tool 配置。
|
||
|
||
新增一个平级 Tab:
|
||
|
||
- `工具配置`
|
||
|
||
不要放到高级设置,理由:
|
||
|
||
1. Tool 是一等能力
|
||
2. 后续 OCR 就在这里开关
|
||
3. 这是 Agent 可用能力的核心组成部分
|
||
|
||
### 9.3.1 UI 结构
|
||
|
||
建议分成两部分:
|
||
|
||
#### 第一部分: Toolset 配置
|
||
|
||
- 多选 `base/planning/interaction/memory/skill/crew/vision/document`
|
||
|
||
#### 第二部分: Tool 精细控制
|
||
|
||
- 左侧当前 toolset 展开的工具
|
||
- 右侧已禁用覆盖
|
||
|
||
每个 Tool 展示:
|
||
|
||
- label
|
||
- toolset tag
|
||
- capability tag
|
||
- core tag
|
||
- 简介
|
||
|
||
### 9.3.2 交互规则
|
||
|
||
- toolset 勾选后,默认带出该组工具
|
||
- 可对单个工具做禁用覆盖
|
||
- V1 不支持“额外加开不在当前 toolset 内的工具”
|
||
- 这样可以确保授权心智、UI 和 resolver 优先级保持简单一致
|
||
|
||
这是对 Hermes“toolset 优先”的本地化改造。
|
||
|
||
原因:
|
||
|
||
- 完全照 Hermes 只配 toolset,不够细
|
||
- 完全只配 tool,不利于规模扩展
|
||
|
||
混合模式是最适合 Neta 的。
|
||
|
||
## 9.4 Prompt 预览增强
|
||
|
||
Agent 编辑页已有 prompt 预览,应扩展返回:
|
||
|
||
- 最终生效 toolNames
|
||
- 被过滤 tools 和原因
|
||
- tool prompt hint 来源
|
||
|
||
这对 OCR 非常重要,因为视觉工具最容易因 capability 不满足而消失。
|
||
|
||
---
|
||
|
||
## 10. 对 OCR / 多模态能力的直接影响
|
||
|
||
本设计不是直接实现 OCR,但要明确它如何承接 OCR。
|
||
|
||
后续 OCR 方案建议:
|
||
|
||
### Tool 归属
|
||
|
||
- `vision_ocr` 属于 `vision` 或 `document` toolset
|
||
|
||
### capability
|
||
|
||
- `vision_ocr.capability = 'vision'`
|
||
|
||
### Agent 体验
|
||
|
||
- Tool 管理页中可全局启用/禁用
|
||
- Agent 编辑页中可勾选
|
||
- 若当前模型不支持视觉,则显示不可用原因
|
||
|
||
### Prompt 注入
|
||
|
||
可通过 `promptHint` 告诉模型:
|
||
|
||
- 什么时候优先用 OCR
|
||
- OCR 适合抽文字,不适合复杂推理
|
||
- 识别后需要继续结构化处理时如何组合其他工具
|
||
|
||
这就是为什么必须先做 Tool 治理,再做 OCR。
|
||
|
||
---
|
||
|
||
## 11. 与现有 Neta 代码的具体衔接点
|
||
|
||
## 11.1 `tools/catalog.ts`
|
||
|
||
从当前的轻量结构:
|
||
|
||
```typescript
|
||
interface ToolSchema {
|
||
name: string;
|
||
toolset: string;
|
||
description: string;
|
||
}
|
||
```
|
||
|
||
扩展成带治理元数据的结构。
|
||
|
||
## 11.2 `tools/common.ts`
|
||
|
||
当前已有 `visibility`,这是很好的基础。
|
||
|
||
建议:
|
||
|
||
- catalog 的 `visibility` 与 common.ts 保持同一枚举
|
||
- 运行时由 resolver 统一读取
|
||
- DB 中的 `visibility` 仅作为镜像字段供后台查询,不作为独立真相源
|
||
|
||
## 11.3 `service/agent_executor.ts`
|
||
|
||
这里是必须动的关键文件。
|
||
|
||
当前 `defaultTools` 硬编码必须下沉到 `tool_resolver.ts`。
|
||
|
||
否则任何 Tool 管理页面都是伪配置。
|
||
|
||
同时还要一起改:
|
||
|
||
- `buildSkillContext()` 的 `builtinToolNames` 输入
|
||
- 不能继续保留当前硬编码列表
|
||
|
||
## 11.4 `entity/agent.ts`
|
||
|
||
新增:
|
||
|
||
- `toolsets`
|
||
- `tools`
|
||
|
||
以支持 Hermes 式 toolset 思路和 Neta 式单 Agent 精细控制的结合。
|
||
|
||
## 11.5 `runtime/prompt_builder.ts`
|
||
|
||
从“根据几个布尔值猜工具列表”,升级为“读取 resolver 结果”。
|
||
|
||
---
|
||
|
||
## 12. 兼容性策略
|
||
|
||
## 12.1 老 Agent
|
||
|
||
老 Agent 没有 `toolsets/tools` 时:
|
||
|
||
- 默认视为启用 `TOOLSET_DEFAULTS`
|
||
- 保存后写入明确配置
|
||
|
||
## 12.2 老 Tool
|
||
|
||
老 Tool 首次同步到 DB 时:
|
||
|
||
- label = name
|
||
- status = 1
|
||
- capability = text
|
||
- promptHint = null
|
||
|
||
其中:
|
||
|
||
- `capability/visibility/toolset` 来自 catalog 镜像
|
||
- 不是后台运营配置
|
||
|
||
## 12.3 老 Prompt
|
||
|
||
如果没有 DB 配置的 promptHint,就继续使用代码默认 guidance。
|
||
|
||
---
|
||
|
||
## 13. 风险与控制
|
||
|
||
## 13.1 风险: 设计过重
|
||
|
||
控制:
|
||
|
||
- 不做 handler 可视化管理
|
||
- 不做 schema 可视化编辑
|
||
- 不做 plugin marketplace
|
||
- 第一版只做内置工具治理
|
||
|
||
## 13.2 风险: 页面做完但运行时不生效
|
||
|
||
控制:
|
||
|
||
- `tool_resolver.ts` 作为单一事实来源
|
||
- `agent_executor.ts` / `gateway/server.ts` 全部接入 resolver
|
||
|
||
## 13.3 风险: capability 配置不统一
|
||
|
||
控制:
|
||
|
||
- capability 枚举统一
|
||
- `model_channel.ts` 统一返回模型 capability
|
||
- resolver 中集中判断
|
||
- 后台不允许编辑 tool capability
|
||
|
||
## 13.4 风险: toolset 和 tool 配置冲突
|
||
|
||
控制:
|
||
|
||
优先级固定为:
|
||
|
||
1. 全局禁用
|
||
2. agent toolsets 展开
|
||
3. agent tools.disabled 剔除
|
||
4. capability 过滤
|
||
|
||
V1 收敛策略:
|
||
|
||
- 首版不引入 `tools.enabled`
|
||
- 先用 `toolsets + disabled` 完成 80% 场景
|
||
- 降低实现复杂度与解释成本
|
||
|
||
## 13.5 风险: Tool 管理与 Skill 上下文失真
|
||
|
||
控制:
|
||
|
||
- resolver 输出 `builtinToolNames`
|
||
- `buildSkillContext()` 改为消费 resolver 输出
|
||
- previewPrompt 也返回同一结果,保证前后端解释一致
|
||
|
||
---
|
||
|
||
## 14. 文件变更清单
|
||
|
||
| 操作 | 位置 | 文件 |
|
||
|------|------|------|
|
||
| 新增 | backend | `src/modules/netaclaw/entity/tool.ts` |
|
||
| 新增 | backend | `src/modules/netaclaw/service/tool_registry.ts` |
|
||
| 新增 | backend | `src/modules/netaclaw/service/tool_resolver.ts` |
|
||
| 新增 | backend | `src/modules/netaclaw/controller/admin/tool.ts` |
|
||
| 修改 | backend | `src/modules/netaclaw/tools/catalog.ts` |
|
||
| 修改 | backend | `src/modules/netaclaw/tools/common.ts` |
|
||
| 修改 | backend | `src/modules/netaclaw/entity/agent.ts` |
|
||
| 修改 | backend | `src/modules/netaclaw/service/agent_executor.ts` |
|
||
| 修改 | backend | `src/modules/netaclaw/gateway/server.ts` |
|
||
| 修改 | backend | `src/modules/netaclaw/runtime/prompt_builder.ts` |
|
||
| 修改 | backend | `src/modules/netaclaw/runtime/prompt_guidance.ts` |
|
||
| 修改 | backend | `src/modules/netaclaw/service/crew_orchestrator.ts` |
|
||
| 修改 | backend | `src/modules/netaclaw/service/crew_delegate.ts` |
|
||
| 修改 | backend | `src/entities.ts` |
|
||
| 新增 | frontend | `src/modules/agent/views/tools.vue` |
|
||
| 修改 | frontend | `src/modules/agent/config.ts` |
|
||
| 修改 | frontend | `src/modules/agent/views/agent-edit.vue` |
|
||
|
||
---
|
||
|
||
## 15. 分阶段落地建议
|
||
|
||
### Phase 1: 对齐 Hermes 的核心治理思想
|
||
|
||
1. 扩展 catalog 元数据
|
||
2. 新增 `netaclaw_tool`
|
||
3. 做 catalog -> DB 同步
|
||
4. 后台 Tool 管理页
|
||
|
||
### Phase 2: 打通 Neta 运行时
|
||
|
||
1. Agent 新增 `toolsets/tools`
|
||
2. 新增 `tool_resolver.ts`
|
||
3. `agent_executor.ts` / `gateway/server.ts` 全部改接 resolver
|
||
4. `buildSkillContext()` 改成吃 resolver 结果
|
||
5. Prompt Builder 改成吃 resolver 结果
|
||
|
||
### Phase 3: 为 OCR 接入做准备
|
||
|
||
1. 新增 `vision/document` toolset
|
||
2. 能力约束与 UI 提示
|
||
3. Tool Prompt Hint 覆写
|
||
|
||
### Phase 4: 接入 OCR
|
||
|
||
1. 新增 `vision_ocr`
|
||
2. 绑定 capability=vision
|
||
3. Agent 勾选可用
|
||
4. 后续再考虑 Skill 工作流封装
|
||
|
||
---
|
||
|
||
## 16. 最终结论
|
||
|
||
参考 Hermes 之后,结论比之前更明确:
|
||
|
||
1. 你这个需求的第一优先级确实不是先做 OCR,而是先做 Tool 管理
|
||
2. 但不能只做“一个页面”,而是要补齐:
|
||
- 代码注册层
|
||
- toolset 组织层
|
||
- 全局治理层
|
||
- Agent 授权层
|
||
- 运行时解析层
|
||
3. Hermes 的核心经验要吸收:
|
||
- toolset 优先
|
||
- 统一注册
|
||
- 可用性检查
|
||
- 配置与能力联动
|
||
4. 但不能直接照搬 Hermes:
|
||
- Hermes 是平台中心
|
||
- Neta 是 Agent 中心
|
||
- Hermes 是文件配置
|
||
- Neta 应该走数据库 + 后台配置
|
||
|
||
因此,适合 Neta 的最终设计不是“单纯的工具管理页”,也不是“直接每个 Agent 勾单工具”,而是:
|
||
|
||
**全局 Tool 治理 + Agent toolset 授权 + 单工具精细覆盖 + 运行时统一解析**
|
||
|
||
这套设计完成后,多模态 OCR 才有一个真正稳固的落点。
|