485 lines
12 KiB
Markdown
485 lines
12 KiB
Markdown
# Phase T.1:Manifest 驱动系统
|
||
|
||
日期:2026-04-04
|
||
状态:待开始
|
||
依赖:T.0(已完成)
|
||
|
||
---
|
||
|
||
## 1. 本阶段目的
|
||
|
||
建立 Jarvis 的 Manifest 驱动工具系统:
|
||
|
||
- 定义工具 Manifest Schema
|
||
- 实现 Schema 验证
|
||
- 创建核心工具的 Manifest 文件
|
||
- 实现配置分离
|
||
|
||
---
|
||
|
||
## 2. Manifest Schema 设计
|
||
|
||
### 2.1 目录结构
|
||
|
||
```
|
||
backend/app/tools/
|
||
├── manifests/ # 工具 manifest
|
||
│ ├── file_operator.yaml
|
||
│ ├── search.yaml
|
||
│ └── web_fetch.yaml
|
||
├── schemas/ # Schema 定义
|
||
│ ├── __init__.py
|
||
│ ├── manifest.py # Manifest Schema
|
||
│ ├── tool_call.py # 工具调用 Schema
|
||
│ └── config.py # 配置 Schema
|
||
└── configs/ # 配置分离
|
||
└── .tool.example # 工具配置模板
|
||
```
|
||
|
||
### 2.2 ToolManifest Schema
|
||
|
||
```python
|
||
# tools/schemas/manifest.py
|
||
from pydantic import BaseModel, Field
|
||
from typing import Optional, List, Dict, Any
|
||
from enum import Enum
|
||
|
||
|
||
class ToolType(str, Enum):
|
||
"""工具类型"""
|
||
SYNC = "sync" # 同步执行
|
||
ASYNC = "async" # 异步执行
|
||
SERVICE = "service" # 持续服务
|
||
|
||
|
||
class RuntimeType(str, Enum):
|
||
"""运行时类型"""
|
||
PYTHON = "python"
|
||
JAVASCRIPT = "javascript"
|
||
NATIVE = "native"
|
||
|
||
|
||
class InvocationCommand(BaseModel):
|
||
"""调用命令定义"""
|
||
name: str = Field(..., description="命令名称")
|
||
description: str = Field(..., description="命令描述(给 AI 看)")
|
||
parameters: Optional[Dict[str, Any]] = Field(
|
||
default=None,
|
||
description="参数 JSON Schema"
|
||
)
|
||
required: Optional[List[str]] = Field(
|
||
default=None,
|
||
description="必需参数列表"
|
||
)
|
||
example: Optional[str] = Field(
|
||
default=None,
|
||
description="调用示例"
|
||
)
|
||
|
||
|
||
class ToolManifest(BaseModel):
|
||
"""工具 Manifest"""
|
||
manifest_version: str = Field(
|
||
default="1.0.0",
|
||
description="Manifest 版本"
|
||
)
|
||
name: str = Field(..., description="工具名称(英文,唯一)")
|
||
display_name: str = Field(..., description="显示名称(中文)")
|
||
description: str = Field(..., description="工具描述")
|
||
author: Optional[str] = Field(default=None, description="作者")
|
||
version: str = Field(default="1.0.0", description="版本号")
|
||
|
||
# 执行配置
|
||
type: ToolType = Field(default=ToolType.SYNC, description="工具类型")
|
||
runtime: RuntimeType = Field(default=RuntimeType.PYTHON, description="运行时")
|
||
entry: str = Field(..., description="执行入口(文件路径或命令)")
|
||
timeout: int = Field(default=30000, description="超时时间(毫秒)")
|
||
|
||
# 配置
|
||
config_schema: Optional[Dict[str, Any]] = Field(
|
||
default=None,
|
||
description="配置项 Schema"
|
||
)
|
||
|
||
# 能力
|
||
commands: List[InvocationCommand] = Field(
|
||
default_factory=list,
|
||
description="可用命令列表"
|
||
)
|
||
|
||
# 元数据
|
||
tags: Optional[List[str]] = Field(default=None, description="标签")
|
||
dependencies: Optional[List[str]] = Field(default=None, description="依赖工具")
|
||
enabled: bool = Field(default=True, description="是否启用")
|
||
|
||
class Config:
|
||
use_enum_values = True
|
||
```
|
||
|
||
### 2.3 ToolCall Schema
|
||
|
||
```python
|
||
# tools/schemas/tool_call.py
|
||
from pydantic import BaseModel, Field
|
||
from typing import Optional, Dict, Any, List
|
||
from datetime import datetime
|
||
|
||
|
||
class ToolCallRequest(BaseModel):
|
||
"""工具调用请求"""
|
||
tool_name: str = Field(..., description="工具名称")
|
||
command: str = Field(..., description="命令名称")
|
||
parameters: Dict[str, Any] = Field(default_factory=dict, description="参数")
|
||
timeout: Optional[int] = Field(default=None, description="超时时间")
|
||
context: Optional[Dict[str, Any]] = Field(
|
||
default=None,
|
||
description="上下文信息"
|
||
)
|
||
|
||
|
||
class ToolCallResponse(BaseModel):
|
||
"""工具调用响应"""
|
||
status: str = Field(..., description="状态: success/error")
|
||
result: Optional[Any] = Field(default=None, description="执行结果")
|
||
error: Optional[str] = Field(default=None, description="错误信息")
|
||
message: Optional[str] = Field(default=None, description="AI 友好消息")
|
||
base64: Optional[str] = Field(default=None, description="Base64 数据")
|
||
duration_ms: Optional[int] = Field(default=None, description="执行耗时")
|
||
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
||
|
||
|
||
class ToolExecutionLog(BaseModel):
|
||
"""工具执行日志"""
|
||
id: str
|
||
tool_name: str
|
||
command: str
|
||
parameters: Dict[str, Any]
|
||
status: str
|
||
duration_ms: int
|
||
error: Optional[str]
|
||
user_id: Optional[str]
|
||
agent_id: Optional[str]
|
||
created_at: datetime
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Manifest 示例
|
||
|
||
### 3.1 file_operator.yaml
|
||
|
||
```yaml
|
||
manifest_version: "1.0.0"
|
||
name: file_operator
|
||
display_name: 文件操作器
|
||
description: 强大的文件系统操作工具,支持读写、搜索、下载等功能
|
||
author: Jarvis
|
||
version: "1.0.0"
|
||
|
||
type: sync
|
||
runtime: python
|
||
entry: tools/implementations/file_operator.py
|
||
timeout: 30000
|
||
|
||
config_schema:
|
||
allowed_directories:
|
||
type: string
|
||
description: 允许操作的目录列表,逗号分隔
|
||
default: ""
|
||
max_file_size:
|
||
type: integer
|
||
description: 最大文件大小(字节)
|
||
default: 10485760
|
||
|
||
commands:
|
||
- name: read_file
|
||
description: |
|
||
读取指定路径文件的内容。支持 PDF、DOCX、XLSX 等格式自动解析。
|
||
参数:
|
||
- filePath (必需): 文件绝对路径
|
||
- encoding (可选): 编码格式,默认 utf8
|
||
parameters:
|
||
type: object
|
||
properties:
|
||
filePath:
|
||
type: string
|
||
description: 文件绝对路径
|
||
encoding:
|
||
type: string
|
||
default: utf8
|
||
required: [filePath]
|
||
|
||
- name: write_file
|
||
description: |
|
||
将内容写入文件。如果文件存在,自动创建新文件避免覆盖。
|
||
参数:
|
||
- filePath (必需): 文件绝对路径
|
||
- content (必需): 文件内容
|
||
parameters:
|
||
type: object
|
||
properties:
|
||
filePath:
|
||
type: string
|
||
content:
|
||
type: string
|
||
required: [filePath, content]
|
||
|
||
- name: list_directory
|
||
description: |
|
||
列出目录内容。
|
||
参数:
|
||
- directoryPath (必需): 目录绝对路径
|
||
- showHidden (可选): 是否显示隐藏文件
|
||
parameters:
|
||
type: object
|
||
properties:
|
||
directoryPath:
|
||
type: string
|
||
showHidden:
|
||
type: boolean
|
||
default: false
|
||
required: [directoryPath]
|
||
|
||
- name: search_files
|
||
description: |
|
||
递归搜索匹配模式的文件。
|
||
参数:
|
||
- searchPath (必需): 搜索起始目录
|
||
- pattern (必需): 文件模式,如 *.txt
|
||
parameters:
|
||
type: object
|
||
properties:
|
||
searchPath:
|
||
type: string
|
||
pattern:
|
||
type: string
|
||
required: [searchPath, pattern]
|
||
|
||
tags: [file, system, essential]
|
||
enabled: true
|
||
```
|
||
|
||
### 3.2 search.yaml
|
||
|
||
```yaml
|
||
manifest_version: "1.0.0"
|
||
name: web_search
|
||
display_name: 联网搜索
|
||
description: 语义级并发搜索引擎,支持多源搜索和结果聚合
|
||
author: Jarvis
|
||
version: "1.0.0"
|
||
|
||
type: sync
|
||
runtime: python
|
||
entry: tools/implementations/web_search.py
|
||
timeout: 60000
|
||
|
||
config_schema:
|
||
api_key:
|
||
type: string
|
||
description: 搜索引擎 API 密钥
|
||
required: true
|
||
max_results:
|
||
type: integer
|
||
description: 最大返回结果数
|
||
default: 10
|
||
|
||
commands:
|
||
- name: search
|
||
description: |
|
||
执行语义级搜索。
|
||
参数:
|
||
- query (必需): 搜索关键词
|
||
- max_results (可选): 最大结果数
|
||
- sources (可选): 搜索源列表
|
||
parameters:
|
||
type: object
|
||
properties:
|
||
query:
|
||
type: string
|
||
max_results:
|
||
type: integer
|
||
default: 10
|
||
sources:
|
||
type: array
|
||
items:
|
||
type: string
|
||
required: [query]
|
||
|
||
- name: deep_search
|
||
description: |
|
||
深度搜索,带摘要生成。
|
||
参数:
|
||
- query (必需): 研究主题
|
||
- keywords (必需): 关键词列表
|
||
parameters:
|
||
type: object
|
||
properties:
|
||
query:
|
||
type: string
|
||
keywords:
|
||
type: array
|
||
items:
|
||
type: string
|
||
required: [query, keywords]
|
||
|
||
tags: [search, web, research]
|
||
enabled: true
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Schema 验证
|
||
|
||
### 4.1 验证器
|
||
|
||
```python
|
||
# tools/schemas/validator.py
|
||
from pydantic import ValidationError
|
||
from tools.schemas.manifest import ToolManifest
|
||
|
||
|
||
def validate_manifest(data: dict) -> ToolManifest:
|
||
"""验证 Manifest 数据"""
|
||
try:
|
||
return ToolManifest(**data)
|
||
except ValidationError as e:
|
||
raise ManifestValidationError(str(e))
|
||
|
||
|
||
def validate_tool_call(data: dict) -> ToolCallRequest:
|
||
"""验证工具调用请求"""
|
||
from tools.schemas.tool_call import ToolCallRequest
|
||
try:
|
||
return ToolCallRequest(**data)
|
||
except ValidationError as e:
|
||
raise ToolCallValidationError(str(e))
|
||
|
||
|
||
class ManifestValidationError(Exception):
|
||
"""Manifest 验证错误"""
|
||
pass
|
||
|
||
|
||
class ToolCallValidationError(Exception):
|
||
"""工具调用验证错误"""
|
||
pass
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 配置分离
|
||
|
||
### 5.1 工具配置模板
|
||
|
||
```yaml
|
||
# tools/configs/.tool.example
|
||
# 文件操作器
|
||
file_operator:
|
||
allowed_directories: ""
|
||
max_file_size: 10485760
|
||
|
||
# 联网搜索
|
||
web_search:
|
||
api_key: ""
|
||
max_results: 10
|
||
```
|
||
|
||
### 5.2 配置加载器
|
||
|
||
```python
|
||
# tools/configs/loader.py
|
||
import yaml
|
||
from pathlib import Path
|
||
from typing import Dict, Any
|
||
|
||
|
||
class ConfigLoader:
|
||
"""工具配置加载器"""
|
||
|
||
def __init__(self, config_dir: Path):
|
||
self.config_dir = config_dir
|
||
self._cache: Dict[str, Any] = {}
|
||
|
||
def load(self, tool_name: str) -> Dict[str, Any]:
|
||
"""加载指定工具的配置"""
|
||
if tool_name in self._cache:
|
||
return self._cache[tool_name]
|
||
|
||
config_file = self.config_dir / f"{tool_name}.yaml"
|
||
if not config_file.exists():
|
||
return {}
|
||
|
||
with open(config_file) as f:
|
||
config = yaml.safe_load(f) or {}
|
||
|
||
self._cache[tool_name] = config
|
||
return config
|
||
|
||
def reload(self, tool_name: str) -> Dict[str, Any]:
|
||
"""重新加载配置"""
|
||
if tool_name in self._cache:
|
||
del self._cache[tool_name]
|
||
return self.load(tool_name)
|
||
|
||
def get(self, tool_name: str, key: str, default: Any = None) -> Any:
|
||
"""获取配置项"""
|
||
config = self.load(tool_name)
|
||
return config.get(key, default)
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 实现步骤
|
||
|
||
| 步骤 | 任务 | 优先级 |
|
||
|------|------|--------|
|
||
| 1 | 创建目录结构 | 🟢 高 |
|
||
| 2 | 实现 ToolManifest Schema | 🟢 高 |
|
||
| 3 | 实现 ToolCall Schema | 🟢 高 |
|
||
| 4 | 实现 Schema 验证器 | 🟢 高 |
|
||
| 5 | 创建配置加载器 | 🟢 高 |
|
||
| 6 | 创建 file_operator.yaml | 🟢 高 |
|
||
| 7 | 创建 search.yaml | 🟡 中 |
|
||
| 8 | 创建其他工具 Manifest | 🟡 中 |
|
||
| 9 | 单元测试 | 🟡 中 |
|
||
|
||
---
|
||
|
||
## 7. 核心文件变更
|
||
|
||
| 文件 | 变更 |
|
||
|------|------|
|
||
| `tools/__init__.py` | 模块初始化 |
|
||
| `tools/schemas/__init__.py` | Schema 导出 |
|
||
| `tools/schemas/manifest.py` | 新增 |
|
||
| `tools/schemas/tool_call.py` | 新增 |
|
||
| `tools/schemas/validator.py` | 新增 |
|
||
| `tools/configs/loader.py` | 新增 |
|
||
| `tools/manifests/file_operator.yaml` | 新增 |
|
||
| `tools/manifests/search.yaml` | 新增 |
|
||
|
||
---
|
||
|
||
## 8. 工作量估算
|
||
|
||
| 任务 | 工作量 |
|
||
|------|--------|
|
||
| Schema 定义 | 1 天 |
|
||
| 验证器 | 0.5 天 |
|
||
| 配置加载器 | 0.5 天 |
|
||
| Manifest 文件 | 0.5 天 |
|
||
| 单元测试 | 0.5 天 |
|
||
| **总计** | **3 天** |
|
||
|
||
---
|
||
|
||
## 9. 验收标准
|
||
|
||
- [ ] ToolManifest Schema 可正确验证 Manifest
|
||
- [ ] ToolCall Schema 可正确验证调用请求
|
||
- [ ] 配置加载器可正确加载配置
|
||
- [ ] Manifest 文件格式正确
|
||
- [ ] Schema 验证器可捕获错误
|
||
- [ ] 单元测试覆盖核心逻辑
|