---
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:<path>"` / `"skill_md:<path>"` / `"entry_point:<ep_name>"`）；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=<hash>` 后缀，向后兼容。

---

## 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:<path>"`。
- *Happy path*：`load_from_skill_md` 加载后，`skill.config.provenance` 为 `"skill_md:<path>"`。
- *Happy path*：`load_from_entry_points` 加载后，`skill.config.provenance` 为 `"entry_point:<ep.name>"`。
- *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`（失败轨迹检索）。
- **外部研究未运行**：本计划基于论文观点与代码现状的直接对照，未发起额外外部研究（论文已在上一轮对话中深度学习）。
