Command Palette

Search for a command to run...

0

Bringing Agent Skills to Life: Practice of the Skill Self-Evolution System

> An engineering practice record on how to make the AI Agent's skill system "come alive".

Bringing Agent Skills to Life: Practice of the Skill Self-Evolution System

An engineering practice record on how to make the AI Agent's skill system "come alive". Based on cutting-edge research like SkillRL (arXiv 2602.08234), a lightweight solution deployed on a GPU-less VPS.

TL;DR

We built a complete Agent Skill lifecycle management system:

  • 56 skills, each with structured principle / when_to_apply / common_mistakes
  • Semantic retrieval: embedding vector matching, not keyword guessing
  • Failure closed-loop: wrong skill used → auto-record → auto-downgrade → auto-trigger evolution
  • Reflection system: task ends → auto-decide if reflection is needed → extract patterns → avoid pitfalls next time
  • SkillGraph: DAG path search + SkillBank field linking, supporting composition recommendations

Core code ~4500 lines Python + 160 lines Bash, fully TDD, 50+ tests all green.


1. Problem: Agent Skills Are "Dead"

Most Agent frameworks treat skills as a read-only library:

user request → match skill → load into prompt → execute → end

No feedback loop. When correct, you don't know why. When wrong, you don't know why. Skill quality depends entirely on manual maintenance.

Our goal is to close this loop:

user request → match skill → execute → success/failure → record outcome → update skill quality → better matching next time

2. System Architecture

┌─────────────────────────────────────────────────────┐
│                  Hermes Agent                        │
│                                                     │
│  ┌──────────┐  ┌──────────┐  ┌──────────────────┐  │
│  │ Skill     │  │ Skill    │  │ Unified          │  │
│  │ Index     │  │ Graph    │  │ Reflection       │  │
│  │ (Search)  │  │ (Compose)│  │ (Reflection)     │  │
│  └─────┬────┘  └────┬─────┘  └────────┬─────────┘  │
│        │            │                  │             │
│        ▼            ▼                  ▼             │
│  ┌─────────────────────────────────────────────┐    │
│  │           skill-index.json                   │    │
│  │  (56 skills, 384d embeddings, quality scores) │    │
│  └─────────────────────────────────────────────┘    │
│        │            │                  │             │
│        ▼            ▼                  ▼             │
│  ┌──────────┐  ┌──────────┐  ┌──────────────────┐  │
│  │ .usage.json│  │failure_  │  │ compound.sh      │  │
│  │ (Usage Stats)│  │log.jsonl │  │(Post-task Reflect)│  │
│  └──────────┘  └──────────┘  └──────────────────┘  │
└─────────────────────────────────────────────────────┘

Core Components

ComponentFileResponsibility
Skill Indexskill_index.py (887 lines)Embedding semantic search + quality scoring + index building
Skill Graphskill_graph.py (421 lines)DAG path search + SkillBank field linking
Skill Evolutionskill_evolution.py (925 lines)Skill self-evolution toolset (7 tools)
Skill Rankingskill_ranking.py (198 lines)Thompson Sampling skill selection
Skill Discoveryskill_discovery.py (655 lines)N-gram trajectory analysis + auto-generate SKILL.md
Skill Usageskill_usage.py (900 lines)Usage stats + record_outcome()
Unified Reflectionunified_reflection.py (582 lines)Unified reflection module (event recording + pattern extraction + suggestion retrieval)
Compound Systemcompound.sh (161 lines)Post-task reflection shell entry + auto-evolve

3. SkillBank Structuring: From Free Text to Structured Fields

Inspired by the SkillRL paper, we added three structured fields to each skill:

{
  "name": "code-review",
  "description": "Code review skill",
  "principle": "First understand the intent, then review the implementation; focus on correctness and maintainability",
  "when_to_apply": "When reviewing code, writing PRs, or checking quality",
  "common_mistakes": [
    "Only check syntax, not logic",
    "Ignore edge cases",
    "Don't verify test coverage"
  ]
}

These three fields are automatically extracted from the SKILL.md body:

def _extract_principle(body: str) -> str:
    """Extract core methodology from Steps / How to / first paragraph"""
    # Prioritize the first item under Steps
    # Fall back to How to section
    # Finally take the first paragraph
 
def _extract_when_to_apply(body: str) -> str:
    """Extract from When to use / Triggers / When to load"""
 
def _extract_common_mistakes(body: str) -> list[str]:
    """Extract from Notes/Pitfalls/Caveats/Warnings"""

Extraction rate: Among 56 skills, 44 have principle (79%), 31 have common_mistakes (55%), 23 have when_to_apply (41%).

Why This Matters

  1. SkillGraph linking: suggest_composition() now matches not only provides but also when_to_apply
  2. Enhanced recommendation: find_paths() results include principle and common_mistakes as warnings
  3. RL training foundation: These structured fields are the reward signal foundation for future GRPO training

4. Semantic Retrieval: Embeddings Don't Guess

skill_index.py uses paraphrase-multilingual-MiniLM-L12-v2 (384-dim) for semantic search:

# During index construction: generate embedding for each skill
text = f"{name} {description} {tags} {triggers} {body_preview}"
embedding = model.encode(text, normalize_embeddings=True)
 
# At search time: query embedding vs all skill embeddings
scores = cosine_similarity(query_embedding, all_embeddings)
top_k = sorted(scores, reverse=True)[:limit]

Degradation strategy: When sentence-transformers is unavailable, automatically fall back to hash-based embedding (MD5 bucketing) to ensure functionality.

Actual results:

  • "deploy" → matches server-operations (score 0.82)
  • "debug" → matches debugging-toolkit (score 0.79)
  • "review" → matches code-review (score 0.85)

5. Failure Closed-Loop: Record When Wrong, Fix When Recorded

5.1 Usage Tracking

Each time a skill is used, _update_skill_usage() updates .usage.json:

{
  "code-review": {
    "use_count": 12,
    "total_outcomes": 10,
    "success_rate": 0.7
  }
}

5.2 Failure-Driven Evolution

def _trigger_skill_evolution(event):
    """Consistently low success rate → mark for review"""
    if success_rate < 0.3 and total > 5:
        _flag_for_review(skill_name, entry)
    if "not found" in error_msg:
        _log_discovery_trigger(event)  # Trigger skill discovery

5.3 Auto-Evolve (New)

compound.sh reflect now automatically detects skill-related tasks:

# Extract skill names from files parameter
skills_from_path=$(echo "$files" | grep -oP 'skills/\K[^/]+' | sort -u)
skills_from_md=$(echo "$files" | grep -oP '([^/]+)/SKILL\.md' | ...)
 
# Auto-call evolve
for skill_name in $all_skills; do
    python3 unified_reflection.py evolve "$skill_name" "$outcome"
done

Effect: compound.sh reflect error_recovered high 0 0 "skills/code-review/SKILL.md" automatically marks code-review as a successful usage.