--- title: "feat: Skill 激活前置条件 + 来源标记 + 风险守卫学习" status: active date: 2026-06-24 type: feat origin: "SkillHarness (arXiv:2606.20636) + Agent Skills survey (arXiv:2602.12430) 对比分析" --- ## Summary 借鉴 SkillHarness 论文(Macro/Micro Skill 分离、风险守卫 R、监督偏差)与 Agent Skills 综述(4 层门控权限模型、渐进式披露、26.1% 社区 skill 漏洞率)的观点,为 AgentKit 的 Skill 子系统补齐三个当前缺失的能力: 1. **激活前置条件(preconditions)+ 来源标记(provenance)** 作为 `SkillConfig` 基础设施,preconditions 通过 system_prompt 注入实现软检查。 2. **16 个存量 Skill YAML 的 preconditions 全量审查与补充**(引擎模板除外)。 3. **RiskGuardLearner** 从失败轨迹学习风险守卫建议,强制人工审查后应用(不自动应用)。 明确**不**做基于轨迹的 skill 创建或边界细化(L2/L3)——只做 L1 风险守卫学习——因为 AgentKit 的 skill 是人工编写的 YAML,论文核心问题(轨迹学习导致的监督偏差)在此不存在。 ## Problem Frame SkillHarness 论文的核心贡献是 Macro/Micro Skill 分离 + 风险守卫 R,实验显示自动从轨迹学习的 skill 有 75% 不安全,引入风险守卫后不安全 skill 减少 57.1%。Agent Skills 综述指出 26.1% 的社区 skill 存在漏洞,并提出 4 层门控权限模型与 Artifacts vs In-use 区分。 对照 AgentKit 现状: | 论文观点 | AgentKit 现状 | 差距 | |---------|--------------|------| | Macro Skill 激活前置条件(preconditions) | SkillConfig 无 preconditions 字段;`@skill:xxx` 命中即无条件执行 | **缺失** | | Skill 来源标记(provenance / Artifacts vs In-use) | SkillLoader 三种加载路径(YAML / SKILL.md / entry_points)均不记录来源 | **缺失** | | 危险能力告警 | entry_points 加载第三方 Skill 时无危险能力 warning | **缺失** | | 风险守卫 R(从失败轨迹学习) | EvolutionMixin 只优化 prompt(reflect→optimize→AB test),不学习 skill 级风险守卫 | **缺失** | | 4 层门控权限模型 | 已有 alignment 守卫(v5)+ quality_gate,部分覆盖 | 部分实现 | | 渐进式披露 | 已有 disclosure_level(v3) | 已实现 | | 监督偏差(轨迹学习 skill) | skill 是人工编写 YAML,不从轨迹学习 | **不适用**(问题不存在) | 关键洞察:论文的监督偏差问题在 AgentKit 不存在(人工编写 skill),因此**不引入** L2(skill 边界细化)和 L3(从轨迹创建新 skill)。只引入 L1(从失败轨迹学习风险守卫建议),且必须人工审查。 ## Requirements - **R1**:`SkillConfig` 新增 `preconditions: list[str] | None` 与 `provenance: str` 字段,完全向后兼容(旧 YAML 无字段时取默认值),`from_dict` / `to_dict` 正确序列化。 - **R2**:`build_skill_system_prompt` 在拼装基础 prompt 后追加 preconditions 段落(软检查,不增加额外 LLM 调用);preconditions 为空时不改变现有 prompt 输出。 - **R3**:`SkillLoader` 三条加载路径记录 provenance(`"yaml:"` / `"skill_md:"` / `"entry_point:"`);entry_points 加载时若 Skill 声明了危险能力(terminal / code_execution / file_write / shell / system_admin)发出 `logger.warning`。 - **R4**:10 个业务 Skill YAML 审查并补充 preconditions 字段;6 个引擎模板(react/direct/rewoo/reflexion/plan_exec/goal_driven)不需要 preconditions。 - **R5**:`RiskGuardLearner` 从 `ExperienceStore` 检索失败轨迹,经 LLM 分析生成 `RiskGuardSuggestion`(preconditions 候选 + 理由 + 置信度),**不自动应用**,输出供人工审查。 - **R6**:CLI 新增 `agentkit skill learn-risk-guards` 命令,触发 RiskGuardLearner 并以 Rich 表格打印建议清单,明确标注"待人工审查"。 ## Key Technical Decisions ### KTD1:preconditions 通过 system_prompt 注入(软检查),不做硬 LLM 调用 **决策**:preconditions 作为提示词约束注入 system_prompt,由 LLM 在执行时自行判断是否满足,而非在 skill 激活前发起一次额外 LLM 调用做硬校验。 **理由**:硬校验会在每次 skill 激活时增加一次 LLM 调用延迟(~500ms-2s)与 token 成本。AgentKit 的 `@skill:xxx` 路由追求零成本显式匹配(见 `RequestPreprocessor` Layer 0)。软检查符合"显式调用即信任用户意图"的现有设计哲学;preconditions 更多是引导 LLM 在条件不满足时拒绝或澄清,而非阻断路由。 **代价**:preconditions 不是强保证——LLM 可能忽略。可接受的边界:preconditions 是"激活后行为约束",不是"激活前权限门控"(后者由 alignment 守卫 v5 负责)。 ### KTD2:RiskGuardLearner 不自动应用,强制人工审查 **决策**:`RiskGuardLearner` 只生成 `RiskGuardSuggestion`,不写入 SkillConfig;必须由人工审查后手动编辑 YAML 应用。 **理由**:SkillHarness 论文实验显示自动从轨迹学习的 skill 有 75% 不安全。AgentKit 虽然是"学习风险守卫建议"而非"学习新 skill",但自动写入 preconditions 仍可能引入错误约束(误判失败原因 → 错误 precondition → 阻断合法调用)。human-in-the-loop 是最低成本的安全保证。 **代价**:无法闭环自动化。可接受:风险守卫学习是低频离线操作,不是实时路径。 ### KTD3:provenance 是轻量字符串,不做 hash/签名 **决策**:`provenance` 为简单字符串(如 `"yaml:configs/skills/code_reviewer.yaml"`、`"entry_point:my_rag_skill"`),不做内容 hash 或签名校验。 **理由**:AgentKit 当前无供应链合规需求,provenance 的用途仅是"在日志和 `skill info` 中区分来源",便于排查"哪个 skill 来自第三方 entry_point"。引入 hash/签名会增加加载路径复杂度且当前无消费者。 **代价**:无法检测第三方 skill 被篡改。升级路径:未来若有合规需求,可在 provenance 字符串中追加 `:sha256=` 后缀,向后兼容。 --- ## Scope Boundaries ### In scope - `SkillConfig` 新增 `preconditions` / `provenance` 字段及序列化 - `build_skill_system_prompt` 注入 preconditions - `SkillLoader` 三路径记录 provenance + entry_points 危险能力 warning - 10 个业务 Skill YAML 补充 preconditions - `RiskGuardLearner` 新模块(仅生成建议,不自动应用) - `agentkit skill learn-risk-guards` CLI 命令 ### Out of scope - 从轨迹学习创建新 skill(L3)——论文监督偏差问题在 AgentKit 不存在 - 从轨迹细化 skill 边界(L2)——同上 - preconditions 的硬校验 LLM 调用——见 KTD1 - provenance 的 hash/签名——见 KTD3 - 4 层门控权限模型的完整实现——alignment 守卫 v5 已部分覆盖,本次不扩展 - RiskGuardLearner 自动应用闭环——见 KTD2 ### Deferred to follow-up work - `skill info` CLI 展示 preconditions / provenance 字段(U6 之外的小增强,可后续补) - RiskGuardSuggestion 的持久化存储(当前只打印,未来可存入 ExperienceStore) - 第三方 skill 的内容签名校验(见 KTD3 升级路径) --- ## Implementation Units ### U1. SkillConfig preconditions + provenance 字段基础设施 **Goal**:为 `SkillConfig` 新增 `preconditions` 与 `provenance` 字段,完成 `__init__` / `from_dict` / `to_dict` 三处改造,向后兼容。 **Requirements**:R1 **Dependencies**:无(基础设施单元,后续 U2/U3/U4 依赖此单元) **Files**: - Modify: `src/agentkit/skills/base.py` - Test: `tests/unit/test_skill_config_preconditions.py` **Approach**: - 在 `SkillConfig.__init__` 签名末尾新增 `preconditions: list[str] | None = None` 与 `provenance: str = ""` 两个参数(放在 v6 `fallback_strategies` 之后,作为 v7 字段)。 - `__init__` 体内赋值 `self.preconditions = preconditions` 与 `self.provenance = provenance`。 - `from_dict` 增加 `preconditions=data.get("preconditions")` 与 `provenance=data.get("provenance", "")`。 - `to_dict` 增加 `d["preconditions"] = self.preconditions` 与 `d["provenance"] = self.provenance`。 - 不新增校验逻辑(preconditions 是字符串列表,provenance 是字符串,无合法值约束)。 **Patterns to follow**:v6 `fallback_strategies` 字段的添加方式(`src/agentkit/skills/base.py` 的 `__init__` 签名、`from_dict`、`to_dict` 三处对称改造)。 **Test scenarios**: - *Happy path*:`SkillConfig(name="x", agent_type="y", preconditions=["用户已登录"], provenance="yaml:test.yaml")` 构造成功,字段可读。 - *Happy path*:`SkillConfig.from_dict({"name":"x","agent_type":"y"})` 不传新字段时,`preconditions` 为 None、`provenance` 为 `""`(向后兼容)。 - *Happy path*:`from_dict` 传入 preconditions 列表与 provenance 字符串时正确解析。 - *Edge case*:`to_dict()` 输出包含 `preconditions` 与 `provenance` 键,值与构造时一致。 - *Edge case*:`preconditions=[]`(空列表)与 `preconditions=None` 在 `to_dict` 中区分保留。 **Verification**:`python3 -m pytest tests/unit/test_skill_config_preconditions.py -x -q` 通过;现有 `tests/unit/` 中涉及 SkillConfig 的测试不回归。 --- ### U2. build_skill_system_prompt 注入 preconditions **Goal**:`build_skill_system_prompt` 在拼装基础 prompt 后,若 `skill_config.preconditions` 非空,追加 preconditions 段落,引导 LLM 在条件不满足时拒绝或澄清。 **Requirements**:R2 **Dependencies**:U1 **Files**: - Modify: `src/agentkit/chat/skill_routing.py` - Test: `tests/unit/test_skill_system_prompt_preconditions.py` **Approach**: - 在 `build_skill_system_prompt` 现有 `"\n\n".join(prompt_parts)` 之后,检查 `skill_config.preconditions`。 - 若非空列表,追加一段格式化文本(标题如 `## Activation Preconditions`,逐条列出 preconditions,并附一句"若任一条件不满足,请拒绝执行或向用户澄清")。 - preconditions 为空或 None 时,返回值与现状完全一致(不改变现有行为)。 **Patterns to follow**:`build_skill_system_prompt` 现有的 `prompt_parts.append` + `"\n\n".join` 模式(`src/agentkit/chat/skill_routing.py`)。 **Test scenarios**: - *Happy path*:skill_config 有 preconditions=`["需要代码仓库访问权限", "当前分支非 main"]` 时,输出 prompt 包含 `## Activation Preconditions` 段落与两条条件文本。 - *Happy path*:skill_config.preconditions 为 None 时,输出 prompt 与不传 preconditions 时完全一致(字节级)。 - *Edge case*:skill_config.preconditions 为空列表 `[]` 时,不追加 preconditions 段落。 - *Edge case*:skill_config 无 prompt 字段时,函数返回 None(现有行为不变)。 - *Integration*:preconditions 段落出现在 identity/context/instructions 等基础段落之后。 **Verification**:`python3 -m pytest tests/unit/test_skill_system_prompt_preconditions.py -x -q` 通过。 --- ### U3. SkillLoader 三路径 provenance 记录 + entry_points 危险能力 warning **Goal**:`SkillLoader` 的三条加载路径(`_load_skill_from_file` / `load_from_skill_md` / `load_from_entry_points`)在加载后设置 `config.provenance`;entry_points 路径额外检查危险能力并 `logger.warning`。 **Requirements**:R3 **Dependencies**:U1 **Files**: - Modify: `src/agentkit/skills/loader.py` - Test: `tests/unit/test_skill_loader_provenance.py` **Approach**: - 在模块顶部定义 `_DANGEROUS_CAPABILITIES = frozenset({"terminal", "code_execution", "file_write", "shell", "system_admin"})`。 - `_load_skill_from_file`:`SkillConfig.from_yaml(path)` 后设置 `config.provenance = f"yaml:{path}"`。 - `load_from_skill_md`:`SkillMdParser.to_skill_config(...)` 后设置 `config.provenance = f"skill_md:{path}"`。 - `load_from_entry_points`:每个 Skill 加载后设置 `skill.config.provenance = f"entry_point:{ep.name}"`,并检查 `skill.config.capabilities`(CapabilityTag 列表)中是否有 tag 命中 `_DANGEROUS_CAPABILITIES`,命中则 `logger.warning`。 - provenance 设置在 `register` 之前,确保注册到 registry 的 config 已带 provenance。 **Patterns to follow**:`load_from_entry_points` 现有的 `logger.info` 日志模式(`src/agentkit/skills/loader.py`);`CapabilityTag` 的 `tag` 字段访问方式(`src/agentkit/skills/schema.py`)。 **Test scenarios**: - *Happy path*:`_load_skill_from_file` 加载 YAML 后,`skill.config.provenance` 为 `"yaml:"`。 - *Happy path*:`load_from_skill_md` 加载后,`skill.config.provenance` 为 `"skill_md:"`。 - *Happy path*:`load_from_entry_points` 加载后,`skill.config.provenance` 为 `"entry_point:"`。 - *Error path*:entry_points 加载的 Skill 声明了 `capabilities: [{tag: "shell"}]` 时,`logger.warning` 被调用且包含 skill 名与危险能力名。 - *Edge case*:entry_points 加载的 Skill 无 capabilities 或 capabilities 为空时,不触发 warning。 - *Edge case*:YAML 中已有 `provenance` 字段时,加载路径的设置覆盖它(加载路径是权威来源)。 **Verification**:`python3 -m pytest tests/unit/test_skill_loader_provenance.py -x -q` 通过。 --- ### U4. 10 个业务 Skill YAML 审查并补充 preconditions **Goal**:审查 10 个业务 Skill YAML,根据每个 skill 的实际语义补充 `preconditions` 字段;6 个引擎模板不补充。 **Requirements**:R4 **Dependencies**:U1(字段必须先存在) **Files**: - Modify: `configs/skills/code_reviewer.yaml` - Modify: `configs/skills/geo_optimizer.yaml` - Modify: `configs/skills/content_generator.yaml` - Modify: `configs/skills/competitor_analyzer.yaml` - Modify: `configs/skills/benchmark_runner.yaml` - Modify: `configs/skills/trend_agent.yaml` - Modify: `configs/skills/monitor.yaml` - Modify: `configs/skills/citation_detector.yaml` - Modify: `configs/skills/schema_advisor.yaml` - Modify: `configs/skills/deai_agent.yaml` **Approach**: - 逐个审查每个业务 skill 的 identity / instructions / tools / capabilities,提炼出"激活此 skill 的前置条件"(如"需要可访问的代码仓库"、"需要网络连接"、"输入必须包含待审查的代码片段")。 - preconditions 用中文短句,2-4 条为宜,聚焦"条件不满足会导致 skill 无法正常工作或产生误导"的场景。 - 引擎模板(`react_agent` / `direct_agent` / `rewoo_agent` / `reflexion_agent` / `plan_exec_agent` / `goal_driven_agent`)是通用执行模板,不补充 preconditions。 - 不修改 YAML 的其他字段,只新增 `preconditions` 键。 **Patterns to follow**:现有 YAML 的字段缩进与风格(如 `configs/skills/code_reviewer.yaml` 的 2 空格缩进、字符串引号风格)。 **Test scenarios**: - *Test expectation: none -- 纯配置变更,无行为代码*。验证方式:`SkillConfig.from_yaml` 对每个修改后的 YAML 加载成功且 `preconditions` 字段非空(引擎模板为 None)。 **Verification**:`agentkit skill list` 正常加载全部 16 个 skill 无报错;10 个业务 skill 的 `preconditions` 字段非空。 --- ### U5. RiskGuardLearner 从失败轨迹学习风险守卫建议 **Goal**:新建 `RiskGuardLearner` 模块,从 `ExperienceStore` 检索失败轨迹,经 LLM 分析生成 `RiskGuardSuggestion` 列表(preconditions 候选 + 理由 + 置信度),不自动应用。 **Requirements**:R5 **Dependencies**:U1(preconditions 字段概念)、`ExperienceStore`(已存在) **Files**: - Create: `src/agentkit/evolution/risk_guard_learner.py` - Test: `tests/unit/test_risk_guard_learner.py` **Approach**: - 定义 `RiskGuardSuggestion` dataclass:`skill_name: str`、`precondition: str`、`reason: str`、`confidence: float`、`source_experience_ids: list[str]`。 - `RiskGuardLearner` 类:`__init__(experience_store, llm_gateway, model="default")`。 - `async def learn(self, skill_name: str | None = None, top_k: int = 20) -> list[RiskGuardSuggestion]`: - 从 `ExperienceStore.search(query="failure", top_k=top_k, task_type=None)` 检索失败轨迹(`outcome == "failure"`)。 - 若 `skill_name` 指定,过滤属于该 skill 的轨迹。 - 构建 LLM prompt:输入失败轨迹摘要(goal / steps_summary / failure_reasons / optimization_tips),要求 LLM 输出"该 skill 应补充的 preconditions 候选"JSON。 - 解析 LLM 响应为 `RiskGuardSuggestion` 列表。 - LLM 失败时返回空列表并 `logger.warning`(不抛异常)。 - 明确不做:不写入 SkillConfig、不修改 YAML、不调用任何"应用"方法。 **Patterns to follow**:`LLMReflector`(`src/agentkit/evolution/llm_reflector.py`)的 `__init__(llm_gateway, model)` 签名、`_sanitize_for_prompt` 提示词安全处理、LLM 失败时返回默认值的容错模式。 **Test scenarios**: - *Happy path*:ExperienceStore 返回 3 条失败轨迹,LLM 返回合法 JSON,`learn()` 返回 3 条 `RiskGuardSuggestion`,字段完整。 - *Happy path*:`skill_name` 过滤生效——只返回该 skill 的建议。 - *Error path*:LLM 调用抛异常时,`learn()` 返回空列表且不抛异常。 - *Error path*:LLM 返回非法 JSON 时,`learn()` 返回空列表并 `logger.warning`。 - *Edge case*:ExperienceStore 返回空列表时,`learn()` 返回空列表(不调用 LLM)。 - *Edge case*:`confidence` 字段被 clamp 到 [0.0, 1.0] 区间。 **Verification**:`python3 -m pytest tests/unit/test_risk_guard_learner.py -x -q` 通过;模块不导入任何"写入 SkillConfig"的路径。 --- ### U6. CLI 命令 learn-risk-guards **Goal**:新增 `agentkit skill learn-risk-guards` 命令,触发 `RiskGuardLearner`,以 Rich 表格打印建议清单,明确标注"待人工审查"。 **Requirements**:R6 **Dependencies**:U5 **Files**: - Modify: `src/agentkit/cli/skill.py` - Test: `tests/unit/test_cli_skill_learn_risk_guards.py` **Approach**: - 在 `skill_app` 下新增 `@skill_app.command("learn-risk-guards")` 命令。 - 参数:`--skill`(可选,指定 skill 名)、`--top-k`(默认 20)、`--server-url`(可选,远程模式预留,本地模式优先)。 - 本地模式:构造 `ExperienceStore`(需 PostgreSQL,若无则提示"需要 PostgreSQL"并退出)+ `LLMGateway`,实例化 `RiskGuardLearner`,调用 `learn()`。 - 用 Rich `Table` 打印建议:列含 Skill / Precondition / Confidence / Reason。 - 表格上方打印醒目提示:"以下为自动生成的风险守卫建议,**必须人工审查后手动编辑 YAML 应用**,不会自动生效。" - 无建议时打印"未从失败轨迹中学习到风险守卫建议"。 **Patterns to follow**:`skill list` 命令的 Rich `Table` 构造与 `rprint` 模式(`src/agentkit/cli/skill.py`);`skill list` 的本地/远程双模式结构。 **Test scenarios**: - *Happy path*:`RiskGuardLearner.learn()` 返回 2 条建议时,命令输出包含 Rich 表格与 2 行建议,且包含"人工审查"提示文本。 - *Happy path*:`learn()` 返回空列表时,命令输出"未从失败轨迹中学习到风险守卫建议"。 - *Error path*:PostgreSQL 不可用时,命令打印明确错误信息并以非零码退出。 - *Edge case*:`--skill` 参数透传给 `learn(skill_name=...)`。 **Verification**:`python3 -m pytest tests/unit/test_cli_skill_learn_risk_guards.py -x -q` 通过;`agentkit skill learn-risk-guards --help` 正常显示帮助。 --- ## Risks & Dependencies - **依赖 PostgreSQL**:U5/U6 依赖 `ExperienceStore`(PostgreSQL + pgvector)。单元测试需 mock ExperienceStore,不依赖真实数据库。 - **LLM 成本**:U5 的 `learn()` 会发起一次 LLM 调用,但属低频离线操作,风险可控。 - **向后兼容**:U1 新增字段必须不破坏现有 16 个 YAML 加载与现有 SkillConfig 测试——通过默认值保证。 - **preconditions 软检查的局限性**:KTD1 明确 preconditions 不是强保证;若未来需要硬保证,需在 `RequestPreprocessor._resolve_explicit_skill` 中增加校验逻辑(本次不做)。 - **YAML 审查的主观性**:U4 的 preconditions 内容依赖人工语义判断,需逐个 skill 阅读后提炼,无法自动化。 ## Sources & Research - **SkillHarness 论文**(arXiv:2606.20636):Macro/Micro Skill 分离、风险守卫 R、监督偏差、57.1% 不安全 skill 减少。核心借鉴:preconditions 概念 + 风险守卫从失败学习 + 不自动应用。 - **Agent Skills 综述**(arXiv:2602.12430):4 层门控权限模型、渐进式披露、26.1% 社区 skill 漏洞率、Artifacts vs In-use 区分。核心借鉴:provenance 来源标记 + 危险能力告警。 - **AgentKit 现状代码**:`src/agentkit/skills/base.py`(SkillConfig v1-v6 字段演进)、`src/agentkit/chat/skill_routing.py`(build_skill_system_prompt)、`src/agentkit/skills/loader.py`(三路径加载)、`src/agentkit/evolution/llm_reflector.py`(LLM 分析器模式)、`src/agentkit/evolution/experience_store.py`(失败轨迹检索)。 - **外部研究未运行**:本计划基于论文观点与代码现状的直接对照,未发起额外外部研究(论文已在上一轮对话中深度学习)。