21 KiB
| title | status | date | type | origin |
|---|---|---|---|---|
| feat: Skill 激活前置条件 + 来源标记 + 风险守卫学习 | active | 2026-06-24 | feat | SkillHarness (arXiv:2606.20636) + Agent Skills survey (arXiv:2602.12430) 对比分析 |
Summary
借鉴 SkillHarness 论文(Macro/Micro Skill 分离、风险守卫 R、监督偏差)与 Agent Skills 综述(4 层门控权限模型、渐进式披露、26.1% 社区 skill 漏洞率)的观点,为 AgentKit 的 Skill 子系统补齐三个当前缺失的能力:
- 激活前置条件(preconditions)+ 来源标记(provenance) 作为
SkillConfig基础设施,preconditions 通过 system_prompt 注入实现软检查。 - 16 个存量 Skill YAML 的 preconditions 全量审查与补充(引擎模板除外)。
- 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注入 preconditionsSkillLoader三路径记录 provenance + entry_points 危险能力 warning- 10 个业务 Skill YAML 补充 preconditions
RiskGuardLearner新模块(仅生成建议,不自动应用)agentkit skill learn-risk-guardsCLI 命令
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 infoCLI 展示 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 = ""两个参数(放在 v6fallback_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:
- 定义
RiskGuardSuggestiondataclass: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(失败轨迹检索)。 - 外部研究未运行:本计划基于论文观点与代码现状的直接对照,未发起额外外部研究(论文已在上一轮对话中深度学习)。