很好,这一步你已经**想清楚“为什么拆”了**,那接下来就该**最小侵入式地改 PocketFlow 项目结构**,而不是推倒重来。 我按 **“不破坏 PocketFlow 使用习惯 + 增量升级”** 的原则,给你一套**可直接落地的调整方案**。 --- # 总体目标(你现在要做的事) 在 **不改变 PocketFlow Node / Flow 编排方式** 的前提下,引入: * `brief` → **超轻量 Router** * `description + parameters` → **工具级调用** * `body` → **按需加载语义** 👉 PocketFlow 继续负责 **流程** 👉 你新增的是 **Skill Semantic Layer** --- # 一、调整 SkillSpec(核心数据结构) ## 原来(简化版) ```python @dataclass class SkillSpec: name: str description: str parameters: dict body: str run: Callable ``` ## 调整后(渐进式友好) ```python from dataclasses import dataclass from typing import Callable, Any, Optional @dataclass class SkillSpec: name: str # Stage 1:Router 用(极短) brief: str # Stage 2:工具说明 description: str parameters: dict # Stage 3:按需加载 body: Optional[str] run: Callable[[dict], Any] ``` 📌 **这是全套调整的“锚点”** --- # 二、调整 SKILL.md 规范(一次到位) 你现在的 SKILL.md 要**明确支持分层**。 ```markdown --- name: add-calc brief: 对数字列表执行加法计算 description: 对两个或多个数字进行加法运算 parameters: numbers: type: array items: number required: [numbers] --- ## 使用场景 - 求和 - 相加 - 计算总数 ## 不适用场景 - 需要乘法、减法 - 非数值输入 ``` 📌 约定: * `brief`:**10~20 token** * `description`:**工具级说明** * body:**可长、但不默认进 prompt** --- # 三、Skill Loader 调整(PocketFlow 友好版) ## 1️⃣ 解析 SKILL.md(frontmatter + body) ```python import re import yaml def parse_skill_md(text: str): pattern = r"^---\s*\n(.*?)\n---\s*\n(.*)$" m = re.match(pattern, text, re.S) if not m: raise ValueError("SKILL.md 缺少 YAML frontmatter") meta = yaml.safe_load(m.group(1)) body = m.group(2).strip() return meta, body ``` --- ## 2️⃣ load_skills(最小侵入) ```python import importlib from pathlib import Path from skills.base import SkillSpec def load_skills(root="skills"): skills = [] for p in Path(root).iterdir(): if not p.is_dir(): continue md = p / "SKILL.md" if not md.exists(): continue meta, body = parse_skill_md(md.read_text()) module = importlib.import_module(f"skills.{p.name}.skill") skills.append( SkillSpec( name=meta["name"], brief=meta.get("brief", meta["description"]), description=meta["description"], parameters=meta.get("parameters", {}), body=body, run=module.run, ) ) return skills ``` 👉 **兼容旧 skill:没有 brief 也能跑** --- # 四、调整 DecideNode(真正体现“拆分价值”) ## Stage 1:只用 brief(强烈推荐) ```python class DecideNode(Node): def prep(self, shared): return shared["query"], shared["skills"] def exec(self, data): query, skills = data index = "\n".join( f"- {s.name}: {s.brief}" for s in skills ) return llm(f""" 你可以使用以下技能(简要): {index} 用户问题: {query} 请选择最合适的技能名称,返回 JSON: {{ "skill": "skill_name" }} """) ``` 📌 **这一轮 token 极低,skill 再多也扛得住** --- ## Stage 2(可选):参数校验 / 二次确认 如果你发现 **参数经常乱填**,再加这一层: ```python def refine_skill(skill: SkillSpec, query: str): return llm(f""" 技能:{skill.name} 说明:{skill.description} 参数结构:{skill.parameters} 用户问题: {query} 请生成该技能需要的参数 JSON。 """) ``` --- ## Stage 3(仅在歧义时):拉 body ```python def disambiguate(skills, query): context = "\n".join( f"### {s.name}\n{s.body}" for s in skills ) return llm(f""" 以下是技能详细说明: {context} 用户问题: {query} 请选择最合适的技能。 """) ``` 👉 **90% 情况不会触发** --- # 五、ExecuteSkillNode 不需要任何修改 ✅ ```python class ExecuteSkillNode(Node): def exec(self, data): decision, skills = data skill = next(s for s in skills if s.name == decision["skill"]) return skill.run(decision["args"]) ``` 这正是你这套设计**最优雅的地方**。 --- # 六、这套改造对 PocketFlow 的影响 | 维度 | 影响 | | -------------- | ------ | | Node / Flow | ❌ 不变 | | 执行模型 | ❌ 不变 | | Skill 扩展 | ✅ 大幅增强 | | Token 成本 | ✅ 可控 | | MCP / tools 对齐 | ✅ 顺滑 | 👉 **PocketFlow 被你“语义升级”,但没被你“污染”** --- # 七、你现在这个阶段的“最佳状态判断” 你现在已经做到: > **Skill = 语义声明 + 运行实体 + 渐进式暴露** 这已经是: * LangGraph * OpenAI tools * MCP 背后用的**同一套思想**。 --- ## 如果你愿意下一步继续进阶 我可以直接帮你做三选一: 1. 🔌 **Skill → OpenAI tools schema 自动生成** 2. 🧠 **Skill body 向量化(SkillRAG)** 3. 🧩 **Planner + Router + Executor 三节点拆分** 你现在这个系统,已经非常值得继续往上走了。