# iAs 工具系统设计 ## 核心理念 **一切皆 Skill。【todo:向内置工具转变】** 没有"内置工具"和"外部技能"的区别——所有工具都是 SKILL.md,区别仅在来源: - **系统 skills** — `resources/skills/` 目录,随 iAs 分发,只读 - **用户 skills** — `skills/` 项目目录,用户自己添加 加载时自动合并,同名时用户 skills 覆盖系统 skills。 --- ## 架构 ``` ┌──────────────────────────────────────────────────────────┐ │ LLM │ │ generate_reply() ←→ tool_choice → tool_execute(result) │ └─────────────────────┬────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ SkillRegistry │ │ │ │ ┌──────────────────┐ ┌────────────────────────────┐ │ │ │ 系统 Skills │ │ 用户 Skills │ │ │ │ resources/skills/ │ │ skills/ │ │ │ │ │ │ │ │ │ │ • datetime │ │ • query_qweather/ │ │ │ │ • weather │ │ • search_tavily/ │ │ │ │ • search_web │ │ • start_pc/ │ │ │ │ • email │ │ • ... │ │ │ │ • shell_exec │ │ │ │ │ │ • schedule │ │ │ │ │ └────────┬──────────┘ └────────────┬──────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Approval Gate │ │ │ │ risk == High → 确认码审批 / Low → 自动执行 │ │ │ │ 审批过程对 LLM 完全透明 │ │ │ └──────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────┘ ``` --- ## 核心类型 ```rust /// 风险等级(仅两级) #[derive(Debug, Clone, PartialEq, Deserialize)] #[serde(rename_all = "lowercase")] pub enum RiskLevel { Low, // 只读/安全,自动执行 High, // 写操作/有风险,需微信确认码审批 } /// 技能来源 #[derive(Debug, Clone, PartialEq)] pub enum SkillSource { System, // resources/skills/ User, // skills/ } /// 技能元数据(从 SKILL.md 解析) #[derive(Debug, Clone, Deserialize)] pub struct SkillSpec { pub name: String, pub description: String, pub risk_level: RiskLevel, pub parameters: serde_json::Value, // JSON Schema pub timeout_secs: u64, } /// 技能(加载到内存后) pub struct Skill { pub spec: SkillSpec, pub source: SkillSource, pub dir: PathBuf, pub execute_command: String, } ``` --- ## SKILL.md 格式 每个技能是一个目录,包含 `SKILL.md` 文件: ```markdown # Get Current Datetime 获取当前日期时间(北京时间 UTC+8)。 ## Risk Level Low ## Parameters \`\`\`json { "type": "object", "properties": { "format": { "type": "string", "description": "时间格式: full | date | time", "enum": ["full", "date", "time"], "default": "full" } } } \`\`\` ## Execute \`\`\`bash #!/usr/bin/env bash scripts/datetime.sh \`\`\` ``` --- ## 内置 Skills 一览 随 iAs 分发的系统 skills: | Skill | 风险 | 说明 | |-------|------|------| | `get_current_datetime` | Low | 获取当前时间(UTC+8) | | `query_weather` | Low | 和风天气查询 | | `search_web` | Low | Tavily 网络搜索 | | `email` | High | 收发邮件 | | `execute_shell` | High | 执行 shell 命令 | | `list_scheduled_tasks` | Low | 列出定时任务 | | `manage_scheduled_task` | High | 增删改定时任务 | --- ## SkillRegistry ```rust pub struct SkillRegistry { skills: HashMap>, } impl SkillRegistry { pub async fn load(system_dir: &str, user_dir: &str) -> Result; pub fn list_specs(&self) -> Vec<&SkillSpec>; pub fn list_specs_by_risk(&self, level: RiskLevel) -> Vec<&SkillSpec>; pub fn get(&self, name: &str) -> Option<&Skill>; /// 执行技能(含审批流程) pub async fn execute( &self, name: &str, params: serde_json::Value, ctx: &ExecutionContext, ) -> Result; } pub struct ExecutionContext { pub user_id: String, pub db: Option>, /// 发送微信消息的回调 pub send_wechat: Option Result<(), String> + Send + Sync>>, /// 等待用户回复的回调(返回用户消息文本) pub wait_for_reply: Option Result, String> + Send + Sync>>, } ``` --- ## 审批流程(透明模式) **核心原则:审批过程对 LLM 完全不可见。** LLM 只看到最终结果。 ``` LLM 调用 High 风险技能 │ ▼ SkillRegistry::execute() │ ├── 查找 Skill ├── risk_level == High? │ └── YES ──────────────────────────────────────────┐ │ │ ▼ │ ┌──────────────────────────────────────────┐ │ │ 等待阶段(LLM 不感知) │ │ │ │ │ │ ① 生成 6 位确认码(如 482731) │ │ │ ② SHA-256 哈希存入 pending_approvals │ │ │ ③ 通过微信发送确认消息给用户: │ │ │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ ⚠️ 操作确认 │ │ │ │ │ │ │ │ │ │ 技能:send_email │ │ │ │ │ 参数:收件人 xxx@xxx.com │ │ │ │ │ │ │ │ │ │ 确认码:482731 │ │ │ │ │ 回复确认码以继续 │ │ │ │ │ 回复 0 或「取消」以取消 │ │ │ │ │ (5分钟内有效,最多3次尝试) │ │ │ │ └─────────────────────────────┘ │ │ │ │ │ │ ④ 等待用户回复 │ │ │ │ │ │ │ ├── 回复正确确认码 ──┐ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌──────────────┐ │ │ │ │ │ ⑤ 执行技能 │ │ │ │ │ │ ⑥ LLM 看到 │ │ │ │ │ │ 执行结果 │ │ │ │ │ └──────────────┘ │ │ │ │ │ │ │ ├── 回复错误确认码 │ │ │ │ → "确认码错误,还剩 N 次" │ │ │ │ → 重试(最多 3 次) │ │ │ │ → 3 次都错 │ │ │ │ → LLM 看到: │ │ │ │ "用户拒绝了你的调用: │ │ │ │ send_email" │ │ │ │ │ │ │ ├── 回复 0 / 「取消」 │ │ │ │ → LLM 看到: │ │ │ │ "用户拒绝了你的调用: │ │ │ │ send_email" │ │ │ │ │ │ │ └── 5 分钟超时 │ │ │ → LLM 看到: │ │ │ "用户没有确认操作: │ │ │ send_email" │ │ └──────────────────────────────────────────┘ ``` ### LLM 视角(两种可能) ``` ✅ 通过: LLM: 调用 send_email({to: "xxx", subject: "..."}) 系统: { success: true, message: "邮件已发送" } ❌ 拒绝: LLM: 调用 send_email({to: "xxx", subject: "..."}) 系统: { success: false, error: "用户拒绝了你的调用:send_email" } ``` LLM 不知道确认码的存在,不知道审批过程。它只知道自己调用了工具,然后得到了结果或拒绝。 --- ## 数据库表 ```sql -- 待审批的工具调用 CREATE TABLE pending_approvals ( id UUID PRIMARY KEY, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), expires_at TIMESTAMPTZ NOT NULL, -- 5分钟后过期 user_id TEXT NOT NULL, skill_name TEXT NOT NULL, params JSONB NOT NULL, code_hash TEXT NOT NULL, -- 确认码 SHA-256(不存明文) attempts_left INTEGER NOT NULL DEFAULT 3, -- 剩余尝试次数 status TEXT NOT NULL DEFAULT 'pending', -- pending | approved | rejected | expired result JSONB, consumed_at TIMESTAMPTZ ); ``` --- ## Skills 目录结构 ``` resources/skills/ # 系统内置 Skills(随 iAs 分发) ├── get_current_datetime/ │ ├── SKILL.md │ └── scripts/datetime.sh ├── query_weather/ │ ├── SKILL.md │ └── scripts/weather.sh ├── search_web/ │ ├── SKILL.md │ └── scripts/search.sh ├── email/ │ ├── SKILL.md │ └── scripts/email.sh ├── execute_shell/ │ ├── SKILL.md │ └── scripts/shell.sh ├── list_scheduled_tasks/ │ ├── SKILL.md │ └── scripts/list.sh └── manage_scheduled_task/ ├── SKILL.md └── scripts/manage.sh skills/ # 用户 Skills(用户自行添加) ├── query_qweather/ │ ├── SKILL.md │ └── scripts/query.sh ├── search_tavily/ │ ├── SKILL.md │ └── scripts/search.sh └── start_pc/ ├── SKILL.md └── scripts/wake.sh ``` --- ## 实施步骤 | 步骤 | 内容 | 预估 | |------|------|------| | Step 1 | SkillSpec/Skill/SkillRegistry 核心类型 + 注册表 | 半天 | | Step 2 | SKILL.md 解析器 + 目录扫描(system + user 合并) | 半天 | | Step 3 | 技能执行器:子进程管理 + 参数 JSON 传递 + 结果解析 | 半天 | | Step 4 | 系统 Skills 脚本实现(7 个 bash 脚本) | 1 天 | | Step 5 | 审批系统:pending_approvals 表 + 确认码生成/验证 + 微信透明通知 | 1 天 | | Step 6 | LLM function calling 集成 + 审计日志 | 1 天 |