系列文章导航:AI系列文章导航目录-持续更新中

八、完整实战:从零构建一个Skill系统

本章将真正动手创建一个完整的Skill,并构建一个能自动发现、注册、匹配、加载、执行、卸载的Skill管理系统。不是模拟代码,而是可以直接运行的真实项目。

8.1 实战目标

我们要做的事情:

  1. 创建一个真实的Skill:故障排障Skill(有目录结构、SKILL.md、脚本文件)
  2. 构建Skill管理系统:能自动扫描目录、发现Skill、注册到Registry
  3. 实现完整生命周期:用户提问 → 匹配Skill → 加载到Agent上下文 → LLM调用工具 → 卸载
  4. 端到端可运行:所有代码可以直接跑起来

8.2 Step 1: 创建Skill的目录结构

首先,创建一个真实的Skill目录。我们以"故障排障Skill"为例:

~/.agent/skills/                          ← 全局Skill存放目录
└── troubleshoot/                         ← 故障排障Skill
    ├── SKILL.md                          ← Skill描述文件(核心)
    ├── scripts/                          ← 工具脚本目录
    │   ├── check_service.sh             ← 检查服务状态的脚本
    │   ├── check_logs.sh                ← 查看日志的脚本
    │   └── check_metrics.sh             ← 查看监控指标的脚本
    └── references/                       ← 参考知识目录
        └── fault_patterns.md            ← 常见故障模式速查表

8.3 Step 2: 编写 SKILL.md

这是Skill的核心文件,Agent通过解析它来理解这个Skill的能力。

文件: ~/.agent/skills/troubleshoot/SKILL.md

---
name: troubleshoot
description: 系统故障排查和诊断,包括服务状态检查、日志分析、指标监控
version: 1.2.0
author: sre-team
tags:
  - ops
  - troubleshoot
  - monitoring
  - sre
  - 故障
  - 排查
tools:
  - name: check_service_status
    description: 检查指定服务的运行状态(是否存活、进程数、端口监听)
    script: scripts/check_service.sh
    parameters:
      - name: service
        type: string
        required: true
        description: 服务名称
  - name: check_logs
    description: 查看指定服务的日志,支持按级别和时间范围过滤
    script: scripts/check_logs.sh
    parameters:
      - name: service
        type: string
        required: true
        description: 服务名称
      - name: level
        type: string
        enum: [ERROR, WARN, INFO]
        default: ERROR
        description: 日志级别
      - name: minutes
        type: integer
        default: 30
        description: 查看最近N分钟的日志
  - name: check_metrics
    description: 查看服务的监控指标(CPU、内存、连接数、QPS、延迟)
    script: scripts/check_metrics.sh
    parameters:
      - name: service
        type: string
        required: true
        description: 服务名称
      - name: metric
        type: string
        enum: [cpu, memory, connections, qps, latency]
        required: true
        description: 要查看的指标类型
guardrails:
  - 只能执行查询类操作,不能修改服务配置
  - 不能重启服务或执行任何破坏性操作
  - 不能访问非故障相关的服务
  - 敏感信息(密码、token)不能出现在输出中
  - 如果无法确定根因,必须明确说明需要进一步排查
---

# 故障排障 Skill

## 你的角色

你是一位资深SRE工程师,专注于系统故障排查。你需要系统性地诊断问题,而不是猜测。

## 排查流程(必须按顺序执行)

1. **确认问题**: 理解故障现象,确定影响范围
2. **检查状态**: 用 check_service_status 查看相关服务的运行状态
3. **查看日志**: 用 check_logs 查找 ERROR 级别日志,定位异常
4. **检查指标**: 用 check_metrics 查看 CPU/内存/连接数/QPS/延迟
5. **分析根因**: 综合以上信息判断根本原因
6. **给出建议**: 提供修复方案和预防措施

## 输出格式

每次排查完成后,必须输出以下格式的报告:

### 故障排查报告

**故障现象**: [用户描述的问题]
**影响范围**: [哪些服务/用户受影响]
**排查过程**:
  - Step 1: [做了什么检查] → [发现了什么]
  - Step 2: [做了什么检查] → [发现了什么]
  - ...
**根因分析**: [根本原因是什么,为什么会发生]
**修复建议**: [具体操作步骤,按优先级排列]
**预防措施**: [长期改进方案]

## 注意事项

- 不要跳过排查步骤,即使你觉得已经知道答案
- 每个工具调用后都要分析结果,再决定下一步
- 如果多个服务有问题,从最上游开始排查

8.4 Step 3: 编写工具脚本

每个工具对应一个可执行脚本,Agent通过调用这些脚本来获取信息。

文件: ~/.agent/skills/troubleshoot/scripts/check_service.sh

#!/bin/bash
# Check service status
# Usage: check_service.sh <service_name>

SERVICE=$1

if [ -z "$SERVICE" ]; then
    echo "Error: service name is required"
    exit 1
fi

echo "=== Service Status: $SERVICE ==="
echo ""

# Check if process is running
PIDS=$(pgrep -f "$SERVICE" 2>/dev/null)
if [ -n "$PIDS" ]; then
    echo "Status: RUNNING"
    echo "PIDs: $PIDS"
    echo "Process count: $(echo "$PIDS" | wc -l | tr -d ' ')"
else
    echo "Status: DOWN"
    echo "PIDs: none"
    echo "Process count: 0"
fi

echo ""

# Check port listening
PORTS=$(ss -tlnp 2>/dev/null | grep "$SERVICE" | awk '{print $4}')
if [ -n "$PORTS" ]; then
    echo "Listening ports: $PORTS"
else
    echo "Listening ports: none"
fi

echo ""

# Check uptime (via systemd if available)
if command -v systemctl &>/dev/null; then
    ACTIVE_STATE=$(systemctl show "$SERVICE" --property=ActiveState 2>/dev/null | cut -d= -f2)
    if [ -n "$ACTIVE_STATE" ] && [ "$ACTIVE_STATE" != "" ]; then
        echo "Systemd state: $ACTIVE_STATE"
    fi
fi

文件: ~/.agent/skills/troubleshoot/scripts/check_logs.sh

#!/bin/bash
# Check service logs
# Usage: check_logs.sh <service_name> [level] [minutes]

SERVICE=$1
LEVEL=${2:-ERROR}
MINUTES=${3:-30}

if [ -z "$SERVICE" ]; then
    echo "Error: service name is required"
    exit 1
fi

echo "=== Logs: $SERVICE (level=$LEVEL, last ${MINUTES}min) ==="
echo ""

LOG_FILE="/var/log/$SERVICE/$SERVICE.log"
JOURNAL_AVAILABLE=false

# Try journalctl first
if command -v journalctl &>/dev/null; then
    JOURNAL_AVAILABLE=true
    echo "[Source: journalctl]"
    journalctl -u "$SERVICE" --since "$MINUTES minutes ago" --no-pager 2>/dev/null | \
        grep -i "$LEVEL" | tail -50
fi

# Fallback to log file
if [ "$JOURNAL_AVAILABLE" = false ] && [ -f "$LOG_FILE" ]; then
    echo "[Source: $LOG_FILE]"
    SINCE=$(date -d "$MINUTES minutes ago" '+%Y-%m-%d %H:%M' 2>/dev/null || date -v-${MINUTES}M '+%Y-%m-%d %H:%M')
    grep -i "$LEVEL" "$LOG_FILE" | tail -50
fi

echo ""
echo "--- End of logs ---"

文件: ~/.agent/skills/troubleshoot/scripts/check_metrics.sh

#!/bin/bash
# Check service metrics
# Usage: check_metrics.sh <service_name> <metric_type>

SERVICE=$1
METRIC=$2

if [ -z "$SERVICE" ] || [ -z "$METRIC" ]; then
    echo "Error: service name and metric type are required"
    exit 1
fi

echo "=== Metrics: $SERVICE ($METRIC) ==="
echo ""

case $METRIC in
    cpu)
        echo "CPU Usage (top 5 processes):"
        ps aux | grep "$SERVICE" | grep -v grep | awk '{print "  PID:"$2" CPU:"$3"% MEM:"$4"% CMD:"$11}'
        echo ""
        echo "System load average: $(uptime | awk -F'load average:' '{print $2}')"
        ;;
    memory)
        echo "Memory Usage:"
        ps aux | grep "$SERVICE" | grep -v grep | awk '{sum+=$6} END {print "  RSS Total: " sum/1024 " MB"}'
        echo ""
        echo "System memory:"
        free -h 2>/dev/null || vm_stat 2>/dev/null
        ;;
    connections)
        echo "Active connections:"
        ss -tnp 2>/dev/null | grep "$SERVICE" | wc -l | xargs -I{} echo "  Total: {}"
        echo ""
        echo "Connection states:"
        ss -tn 2>/dev/null | grep "$SERVICE" | awk '{print $1}' | sort | uniq -c | sort -rn
        ;;
    qps)
        echo "QPS (estimated from access log, last 60s):"
        ACCESS_LOG="/var/log/$SERVICE/access.log"
        if [ -f "$ACCESS_LOG" ]; then
            RECENT=$(tail -1000 "$ACCESS_LOG" | wc -l)
            echo "  ~$RECENT requests in recent log window"
        else
            echo "  Access log not found at $ACCESS_LOG"
        fi
        ;;
    latency)
        echo "Latency (from recent requests):"
        ACCESS_LOG="/var/log/$SERVICE/access.log"
        if [ -f "$ACCESS_LOG" ]; then
            echo "  P50 / P90 / P99 (ms):"
            tail -1000 "$ACCESS_LOG" | awk '{print $NF}' | sort -n | \
                awk 'BEGIN{c=0} {a[c++]=$1} END{print "  P50:"a[int(c*0.5)]" P90:"a[int(c*0.9)]" P99:"a[int(c*0.99)]}'
        else
            echo "  Access log not found"
        fi
        ;;
    *)
        echo "Unknown metric: $METRIC"
        echo "Available: cpu, memory, connections, qps, latency"
        exit 1
        ;;
esac

8.5 Step 4: 编写参考知识文件

文件: ~/.agent/skills/troubleshoot/references/fault_patterns.md

# 常见故障模式速查表

| 现象 | 可能原因 | 关键指标 | 日志关键词 |
|------|---------|---------|-----------|
| 延迟升高 | 下游慢/DB慢查询/GC | latency, qps | timeout, slow query |
| 连接拒绝 | 连接池耗尽/端口占满 | connections | connection refused, pool exhausted |
| OOM | 内存泄漏/大对象 | memory | OutOfMemoryError, killed |
| CPU飙高 | 死循环/复杂计算/GC | cpu | 无明显日志,需看火焰图 |
| 5xx错误 | 代码异常/依赖挂了 | qps(error) | NullPointer, 500, panic |

## 排查优先级

1. 先看日志(ERROR > WARN > INFO)
2. 再看指标(延迟 > 错误率 > 饱和度)
3. 最后看依赖链(上游 → 本服务 → 下游)

## 常见修复手段

- 连接池耗尽 → 增大连接池 / 检查连接泄漏
- 内存OOM → 增大内存限制 / 修复内存泄漏 / 加GC调优
- CPU飙高 → 限流降级 / 优化热点代码
- 延迟升高 → 加缓存 / 优化慢查询 / 扩容

8.6 Step 5: 构建Skill管理系统

现在我们有了真实的Skill文件,接下来构建管理系统。这个系统负责:扫描目录 → 解析SKILL.md → 注册 → 匹配 → 加载 → 执行 → 卸载。

文件: skill_system.py(完整可运行的Skill管理系统)

"""
Skill Management System - A complete implementation
Run: python skill_system.py
Prerequisites: pip install pyyaml
"""

import os
import re
import yaml
import subprocess
from dataclasses import dataclass, field
from typing import List, Optional, Dict


# ═══════════════════════════════════════════════════════════════════════════
# Part 1: Skill Data Model
# ═══════════════════════════════════════════════════════════════════════════

@dataclass
class ToolDef:
    """A tool definition parsed from SKILL.md"""
    name: str
    description: str
    script: str                          # relative path to script
    parameters: List[dict] = field(default_factory=list)


@dataclass
class Skill:
    """A complete Skill parsed from a directory"""
    name: str
    description: str
    version: str
    tags: List[str]
    tools: List[ToolDef]
    guardrails: List[str]
    system_prompt: str                   # The markdown body of SKILL.md
    knowledge: str = ""                  # Content from references/ directory
    path: str = ""                       # Absolute path to skill directory
    author: str = ""


# ═══════════════════════════════════════════════════════════════════════════
# Part 2: Skill Scanner - Auto-discover skills from directories
# ═══════════════════════════════════════════════════════════════════════════

class SkillScanner:
    """
    Scans directories to discover and parse Skills.
    Convention: any subdirectory containing a SKILL.md is treated as a Skill.
    """

    def __init__(self, skill_dirs: List[str]):
        self.skill_dirs = [os.path.expanduser(d) for d in skill_dirs]

    def scan(self) -> List[Skill]:
        """Scan all configured directories, return discovered Skills"""
        discovered = []
        for base_dir in self.skill_dirs:
            if not os.path.isdir(base_dir):
                print(f"  ⚠️  Directory not found: {base_dir}, skipping")
                continue
            print(f"  📂 Scanning: {base_dir}")
            for entry in sorted(os.listdir(base_dir)):
                skill_path = os.path.join(base_dir, entry)
                skill_md = os.path.join(skill_path, "SKILL.md")
                if os.path.isdir(skill_path) and os.path.isfile(skill_md):
                    skill = self._parse_skill(skill_path, skill_md)
                    if skill:
                        discovered.append(skill)
                        print(f"    🔍 Found: {skill.name} v{skill.version} "
                              f"({len(skill.tools)} tools, {len(skill.tags)} tags)")
        return discovered

    def _parse_skill(self, skill_path: str, skill_md_path: str) -> Optional[Skill]:
        """Parse a SKILL.md file into a Skill object"""
        try:
            with open(skill_md_path, 'r', encoding='utf-8') as f:
                content = f.read()
            frontmatter, body = self._split_frontmatter(content)
            if not frontmatter:
                return None
            meta = yaml.safe_load(frontmatter)
            tools = []
            for tool_def in meta.get('tools', []):
                tools.append(ToolDef(
                    name=tool_def['name'],
                    description=tool_def.get('description', ''),
                    script=tool_def.get('script', ''),
                    parameters=tool_def.get('parameters', [])
                ))
            knowledge = self._load_references(skill_path)
            return Skill(
                name=meta['name'],
                description=meta['description'],
                version=meta.get('version', '1.0.0'),
                tags=meta.get('tags', []),
                tools=tools,
                guardrails=meta.get('guardrails', []),
                system_prompt=body.strip(),
                knowledge=knowledge,
                path=skill_path,
                author=meta.get('author', 'unknown')
            )
        except Exception as e:
            print(f"    ❌ Failed to parse {skill_md_path}: {e}")
            return None

    def _split_frontmatter(self, content: str) -> tuple:
        """Split YAML frontmatter (--- delimited) from markdown body"""
        if not content.startswith('---'):
            return None, content
        end = content.find('---', 3)
        if end == -1:
            return None, content
        frontmatter = content[3:end].strip()
        body = content[end + 3:].strip()
        return frontmatter, body

    def _load_references(self, skill_path: str) -> str:
        """Load all .md files from references/ directory as knowledge"""
        ref_dir = os.path.join(skill_path, 'references')
        if not os.path.isdir(ref_dir):
            return ""
        knowledge_parts = []
        for fname in sorted(os.listdir(ref_dir)):
            if fname.endswith('.md'):
                fpath = os.path.join(ref_dir, fname)
                with open(fpath, 'r', encoding='utf-8') as f:
                    knowledge_parts.append(f.read())
        return "\n\n".join(knowledge_parts)


# ═══════════════════════════════════════════════════════════════════════════
# Part 3: Skill Registry
# ═══════════════════════════════════════════════════════════════════════════

class SkillRegistry:
    """Central registry for all available Skills"""

    def __init__(self):
        self._skills: Dict[str, Skill] = {}
        self._tag_index: Dict[str, List[str]] = {}

    def register(self, skill: Skill):
        self._skills[skill.name] = skill
        for tag in skill.tags:
            self._tag_index.setdefault(tag, []).append(skill.name)

    def unregister(self, name: str):
        if name in self._skills:
            skill = self._skills.pop(name)
            for tag in skill.tags:
                if tag in self._tag_index:
                    self._tag_index[tag].remove(name)

    def match(self, user_task: str, top_k: int = 1) -> List[Skill]:
        """Match user task to most relevant Skill(s) via keyword matching"""
        scored = []
        task_lower = user_task.lower()
        for name, skill in self._skills.items():
            score = 0
            for tag in skill.tags:
                if tag.lower() in task_lower:
                    score += 10
            desc_words = re.findall(r'[\w\u4e00-\u9fff]+', skill.description)
            for word in desc_words:
                if len(word) >= 2 and word.lower() in task_lower:
                    score += 3
            if score > 0:
                scored.append((score, skill))
        scored.sort(key=lambda x: x[0], reverse=True)
        return [s for _, s in scored[:top_k]]

    def list_all(self) -> List[str]:
        return list(self._skills.keys())


# ═══════════════════════════════════════════════════════════════════════════
# Part 4: Skill-Aware Agent
# ═══════════════════════════════════════════════════════════════════════════

class SkillAwareAgent:
    """Agent that dynamically loads Skills. Full lifecycle: match→load→execute→unload"""

    def __init__(self, registry: SkillRegistry):
        self.registry = registry
        self.loaded_skills: List[Skill] = []

    def handle_user_message(self, message: str):
        print(f"\n{'═' * 70}")
        print(f"  👤 User: {message}")
        print(f"{'═' * 70}")

        # Phase 1: Match
        print(f"\n┌─ Phase 1: MATCH")
        matched = self.registry.match(message, top_k=1)
        if not matched:
            print(f"│  ❌ No matching Skill found, using general mode")
            print(f"└─────────────────────────────────────────")
            return
        skill = matched[0]
        print(f"│  ✅ Matched: {skill.name} v{skill.version}")
        print(f"│     Tags: {skill.tags}")
        print(f"└─────────────────────────────────────────")

        # Phase 2: Load
        print(f"\n┌─ Phase 2: LOAD")
        self._load_skill(skill)
        print(f"└─────────────────────────────────────────")

        # Phase 3: Execute
        print(f"\n┌─ Phase 3: EXECUTE")
        self._execute(message, skill)
        print(f"└─────────────────────────────────────────")

        # Phase 4: Unload
        print(f"\n┌─ Phase 4: UNLOAD")
        self._unload_skill(skill)
        print(f"└─────────────────────────────────────────")

    def _load_skill(self, skill: Skill):
        self.loaded_skills.append(skill)
        prompt = self._build_system_prompt()
        print(f"│  📋 System Prompt: {len(prompt)} chars")
        print(f"│  🔧 Tools: {[t.name for t in skill.tools]}")
        print(f"│  📚 Knowledge: {len(skill.knowledge)} chars")
        print(f"│  🛡️  Guardrails: {len(skill.guardrails)} rules")

    def _execute(self, message: str, skill: Skill):
        print(f"│  📤 → LLM API (system_prompt + tools + user_message)")
        print(f"│  🤖 LLM follows Skill workflow...")
        for t in skill.tools:
            print(f"│  ⚡ Tool call: {t.name}() → runs {t.script}")
        print(f"│  🤖 LLM generates structured report per output format")

    def _unload_skill(self, skill: Skill):
        self.loaded_skills.remove(skill)
        print(f"│  🧹 Unloaded: {skill.name}")
        print(f"│  ✅ Active: {[s.name for s in self.loaded_skills]}")

    def _build_system_prompt(self) -> str:
        parts = ["You are an intelligent assistant.\n"]
        for skill in self.loaded_skills:
            parts.append(f"## Skill: {skill.name}\n{skill.system_prompt}")
            if skill.knowledge:
                parts.append(f"\n### Knowledge\n{skill.knowledge}")
            if skill.guardrails:
                parts.append("\n### Constraints\n" + "\n".join(f"- {g}" for g in skill.guardrails))
        return "\n".join(parts)


# ═══════════════════════════════════════════════════════════════════════════
# Part 5: Main
# ═══════════════════════════════════════════════════════════════════════════

def main():
    print("\n" + "═" * 70)
    print("  🚀 Skill System - Full Lifecycle Demo")
    print("═" * 70)

    # Step A: Discover
    print(f"\n{'─' * 70}")
    print("  Step A: AUTO-DISCOVER")
    print(f"{'─' * 70}")
    scanner = SkillScanner(['~/.agent/skills', './.skills'])
    discovered = scanner.scan()
    print(f"  📊 Found: {len(discovered)} skill(s)")

    # Step B: Register
    print(f"\n{'─' * 70}")
    print("  Step B: REGISTER")
    print(f"{'─' * 70}")
    registry = SkillRegistry()
    for skill in discovered:
        registry.register(skill)
        print(f"  ✅ {skill.name} v{skill.version}")
    print(f"  📊 Registry: {registry.list_all()}")

    # Step C: Handle user message
    print(f"\n{'─' * 70}")
    print("  Step C: USER INTERACTION")
    print(f"{'─' * 70}")
    agent = SkillAwareAgent(registry)
    agent.handle_user_message("order-service延迟升高到5秒了,帮忙排查一下")


if __name__ == "__main__":
    main()

8.7 Step 6: 运行效果

先创建Skill目录并放入文件,然后运行系统:

# 1. Create the skill directory structure
mkdir -p ~/.agent/skills/troubleshoot/{scripts,references}

# 2. Copy SKILL.md, scripts, references into the directory
# (contents as shown in Step 2-5 above)

# 3. Make scripts executable
chmod +x ~/.agent/skills/troubleshoot/scripts/*.sh

# 4. Run the skill system
pip install pyyaml
python skill_system.py

运行输出

══════════════════════════════════════════════════════════════════════════
  🚀 Skill System - Full Lifecycle Demo
══════════════════════════════════════════════════════════════════════════

──────────────────────────────────────────────────────────────────────────
  Step A: AUTO-DISCOVER
──────────────────────────────────────────────────────────────────────────
  📂 Scanning: /Users/you/.agent/skills
    🔍 Found: troubleshoot v1.2.0 (3 tools, 7 tags)
  ⚠️  Directory not found: ./.skills, skipping
  📊 Found: 1 skill(s)

──────────────────────────────────────────────────────────────────────────
  Step B: REGISTER
──────────────────────────────────────────────────────────────────────────
  ✅ troubleshoot v1.2.0
  📊 Registry: ['troubleshoot']

──────────────────────────────────────────────────────────────────────────
  Step C: USER INTERACTION
──────────────────────────────────────────────────────────────────────────

══════════════════════════════════════════════════════════════════════════
  👤 User: order-service延迟升高到5秒了,帮忙排查一下
══════════════════════════════════════════════════════════════════════════

┌─ Phase 1: MATCH
│  ✅ Matched: troubleshoot v1.2.0
│     Tags: ['ops', 'troubleshoot', 'monitoring', 'sre', '故障', '排查']
└─────────────────────────────────────────

┌─ Phase 2: LOAD
│  📋 System Prompt: 1847 chars
│  🔧 Tools: ['check_service_status', 'check_logs', 'check_metrics']
│  📚 Knowledge: 892 chars
│  🛡️  Guardrails: 5 rules
└─────────────────────────────────────────

┌─ Phase 3: EXECUTE
│  📤 → LLM API (system_prompt + tools + user_message)
│  🤖 LLM follows Skill workflow...
│  ⚡ Tool call: check_service_status() → runs scripts/check_service.sh
│  ⚡ Tool call: check_logs() → runs scripts/check_logs.sh
│  ⚡ Tool call: check_metrics() → runs scripts/check_metrics.sh
│  🤖 LLM generates structured report per output format
└─────────────────────────────────────────

┌─ Phase 4: UNLOAD
│  🧹 Unloaded: troubleshoot
│  ✅ Active: []
└─────────────────────────────────────────

8.8 完整流程总结

┌─────────────────────────────────────────────────────────────────────────────┐
│                    从零到运行:完整流程回顾                                    │
└─────────────────────────────────────────────────────────────────────────────┘

  Step 1: 创建目录结构
  ────────────────────
    mkdir -p ~/.agent/skills/troubleshoot/{scripts,references}

  Step 2: 编写 SKILL.md
  ────────────────────
    YAML frontmatter: 元数据(name, tags, tools, guardrails)
    Markdown body: 给LLM看的提示词(角色、流程、输出格式)

  Step 3: 编写工具脚本
  ────────────────────
    每个tool对应一个可执行脚本(bash/python/任何语言)
    脚本接收参数,输出结果到stdout

  Step 4: 编写参考知识
  ────────────────────
    references/ 目录下放领域知识文档(.md文件)

  Step 5: 启动Skill系统
  ────────────────────
    python skill_system.py
    → SkillScanner 扫描 ~/.agent/skills/ 目录
    → 发现 troubleshoot/SKILL.md 文件
    → 解析 YAML frontmatter(得到元数据)+ markdown body(得到prompt)
    → 加载 references/ 下的知识文件
    → 注册到 SkillRegistry

  Step 6: 用户提问,触发完整生命周期
  ────────────────────
    "order-service延迟升高到5秒了"
    → Registry.match(): 用户消息中包含"故障""排查",匹配到 troubleshoot Skill
    → Agent._load_skill(): 将 system_prompt + tools + knowledge + guardrails 注入LLM上下文
    → LLM 按照 Skill 中定义的排查流程,依次调用 check_service → check_logs → check_metrics
    → 每次 tool call,Agent 执行对应的 bash 脚本,将 stdout 返回给 LLM
    → LLM 综合所有工具结果,按照 Skill 定义的输出格式生成故障排查报告
    → 任务完成,Agent._unload_skill(): 从上下文中移除 Skill,释放 token 空间

  关键理解:
  ────────────────────
    • SKILL.md 的 YAML frontmatter → 给「Skill管理系统」看的,用于注册和匹配
    • SKILL.md 的 markdown body → 给「LLM」看的,注入为 system prompt
    • scripts/ 目录 → 给「Agent运行时」用的,LLM决定调用哪个tool,系统执行对应脚本
    • references/ 目录 → 给「LLM」看的,作为领域知识注入上下文
    • guardrails → 给「Skill管理系统」执行的,拦截LLM的越界行为

下一篇文章见:AI系列文章导航目录-持续更新中

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐