从零制作 Skill,并用真实项目跑通

字数 5943,阅读大约需 30 分钟

从零制作 Skill,并用真实项目跑通

AI 应用架构演进实践 · 第 06 集 · X-ray 三部曲(上)

学习 Skill 最省力的办法,不是先背完概念,而是亲手走一遍完整流程。今天我们就从一个空文件夹开始,做出能被 Agent 调用的 Skill。

先看一个真实场景:接手陌生项目时,最费劲的往往不是写代码,而是在几十层目录里“考古”——它到底做什么?入口在哪?哪些文件值得先读?

为了把流程讲清楚,我选择制作一个叫 X-ray 的示例 Skill:进入陌生仓库后调用它,AI 会先扫描,再挑关键文件阅读,最后生成一份能直接打开的 xray-report.html

X-ray 只是这次的练习题,不是标准答案。 你真正要学的是“描述任务 → 准备脚本和资料 → 安装 → 调用 → 验收”这套方法。以后完全可以把它换成代码审查、周报整理、接口文档生成,或者任何你经常重复做的事情。

picture.image

上集主线:制作 X-ray、装进 Agent 工具,并在真实仓库完成第一次本地闭环

这一集会稍长,因为我们要一次完成两个动作:从零制作 X-ray,再把它装进 CodeBuddy,在一个真实仓库里跑通第一次闭环。

  • 预计用时:35~50 分钟;代码可以直接复制,不要求提前会 Python。
  • 成功标志:测试目录里出现 xray-data.jsonxray-report.html,浏览器能打开一份完整的项目分析报告。
  • 今天不做:不发布 GitHub,不碰 ClawHub,也不运行测试仓库自己的项目代码。

不用先把 Skill 的所有原理背下来。今天的目标很朴素:像小时候抄一遍代码那样,把一条完整路线亲手走通,手感自然就来了。

1. 先准备四样东西

第一次出现的工具,我们都只讲“马上要用的那一点”。已经装好的,直接跳过。

  • CodeBuddy IDE:一款带 Agent 能力的 AI 编程工具,本集用它加载并调用 X-ray。Windows 10+、macOS 和 Linux 都有安装包;官方安装说明在这里。能打开一个本地文件夹并进入 Agent 对话,就算准备完成。
  • Python 3:负责运行扫描脚本。在 PowerShell 执行 python --version,能看到 Python 3.x 就不用重装;如果系统只认 py --version,后文把 python 换成 py 即可。
  • Git:负责把测试项目克隆到电脑。执行 git --version,能看到版本号就算过关。
  • VS Code:选装。素材里的部分代码编辑画面来自 VS Code 风格界面;只用 CodeBuddy 也能完成,不需要为了截图长得一样再装一套编辑器。

公司电脑如果没有安装权限,先走组织的软件准入流程。教程可以等等,安全制度不适合“曲线救国”。

2. Skill 到底是什么?

说白了,Skill 是一套保存下来的做事方法。

普通提示词像临时口头交代;Skill 更像 Agent 的“岗位说明书 + 工具箱”。下次换一个项目,不用重新解释几十行要求,只要调用 /x-ray,Agent 就知道应该先扫描、再读证据、最后交付报告。

OpenAI 的可复用 Skill 教程采用同样的分层思路。不同工具的安装目录和唤起方式会不同,但下面四个位置很好记:

picture.image

一个 Skill 的四个位置:说明、脚本、分析规则与报告模板

  • SKILL.md:告诉 Agent 什么时候上班、按什么流程工作、哪些事不能做。
  • scripts/:负责数文件、识别配置等确定性工作。
  • references/:保存分析规则,帮助 Agent 区分事实和推断。
  • assets/:保存最终报告会用到的模板。

X-ray 的设计原则只有一句:代码负责测量,Agent 负责理解,HTML 负责展示。

3. 搭好 X-ray 的空骨架

这一步的作用,是先把 Skill 的四类内容分开放好,后面不会把说明、脚本和模板搅成一锅粥。

先在桌面创建一个名为 x-ray 的文件夹。你可以使用 CodeBuddy、VS Code,或者直接用系统文件管理器。

picture.image

先创建一个名为 x-ray 的空文件夹

接着在里面创建三个文件夹和一个文件:

  x-ray/
├─ assets/
├─ references/
├─ scripts/
└─ SKILL.md

也可以在 PowerShell 中一次完成:

 New-Item -ItemType Directory -Force x-ray
Set-Location x-ray
New-Item -ItemType Directory -Force assets, references, scripts
New-Item -ItemType File -Force SKILL.md

picture.image

X-ray 的基础目录包含 assets、references、scripts 和 SKILL.md

看到什么算成功: 左侧文件树和截图一样,有三个文件夹与 SKILL.md。现在它还不会干活,但办公室已经装修完了。

4. 写 SKILL.md:先把岗位说清楚

SKILL.md 相当于写给 Agent 的岗位说明书:它决定什么时候触发、按什么顺序工作,以及哪些事绝对不能做。

把下面内容完整写入 SKILL.md

---
name: x-ray
description: 扫描一个陌生的软件项目,快速识别项目类型、技术栈、架构、文件结构、复杂度和学习价值。适用于用户希望快速理解、探索、检查或接手一个陌生代码库的场景。
---

# X-ray

分析当前软件项目,并生成一份简洁、可视化的项目概览。

## 目标

调用 X-ray 时:

1. 扫描项目目录结构。
2. 判断项目是什么类型。
3. 识别主要技术栈。
4. 找出重要目录和关键文件。
5. 推断项目的整体架构。
6. 评估项目复杂度。
7. 判断这个项目适合哪些方向的人学习。
8. 推荐理解项目的阅读顺序。
9. 最终生成一个独立可打开的 HTML 可视化报告。

## 安全规则

默认把项目视为只读。

不要:

- 修改项目源代码;
- 安装依赖;
- 执行项目代码;
- 读取或暴露 `.env` 等文件中的敏感信息;
- 执行未知脚本。

优先使用静态分析和文件读取来理解项目。

picture.image

在 SKILL.md 中写清目标、流程与只读安全边界

这里最重要的不是写得多,而是三件事写清楚:什么时候触发、要交付什么、不能碰什么。 陌生仓库里的脚本不能因为名字亲切就随手运行,.env 也不是项目欢迎词。

5. 写第一个脚本:先学会“数”

大模型擅长理解,但不适合自己数几百个文件。这一步先把“数文件、认语言”交给脚本,得到可靠的一手数据。

scripts 目录创建 scan_repo.py

picture.image

在 scripts 目录创建 scan_repo.py

接下来正文直接提供可复制的完整代码。为了不让同一段内容占两遍版面,长代码截图不再重复插入;我们只保留创建文件、执行命令和结果验收的真实画面。清晰代码原图仍完整保存在本集图片集中。

复制下面的完整代码:

from pathlib import Path
from collections import Counter
import json
import sys

IGNORE_DIRS = {
    ".git",
    "node_modules",
    ".next",
    "dist",
    "build",
    "__pycache__",
    ".venv",
    "venv",
}

LANGUAGE_MAP = {
    ".py""Python",
    ".js""JavaScript",
    ".jsx""JavaScript",
    ".ts""TypeScript",
    ".tsx""TypeScript",
    ".java""Java",
    ".go""Go",
    ".rs""Rust",
    ".rb""Ruby",
    ".php""PHP",
    ".cs""C#",
    ".cpp""C++",
    ".c""C",
    ".swift""Swift",
    ".kt""Kotlin",
    ".vue""Vue",
    ".svelte""Svelte",
}


def should_ignore(path: Path) -> bool:
    return any(part in IGNORE_DIRS for part in path.parts)


def scan_repository(root: Path):
    files = []
    directories = set()
    languages = Counter()

    for path in root.rglob("*"):
        if should_ignore(path.relative_to(root)):
            continue

        if path.is_dir():
            directories.add(str(path.relative_to(root)))
            continue

        files.append(str(path.relative_to(root)))

        language = LANGUAGE_MAP.get(path.suffix.lower())
        if language:
            languages[language] += 1

    return {
        "project_name": root.name,
        "total_files"len(files),
        "total_directories"len(directories),
        "languages"dict(languages.most_common()),
        "files": files,
    }


def main():
    target = Path(sys.argv[1if len(sys.argv) > 1 else ".").resolve()
    result = scan_repository(target)

    print(json.dumps(
        result,
        ensure_ascii=False,
        indent=2
    ))


if __name__ == "__main__":
    main()

它做的事情很朴素:跳过缓存和依赖目录,统计文件、目录、语言,再把文件清单交出来。模型不用自己掰手指数 174 个文件,我们已经给它配了计算器。

x-ray 根目录打开终端,执行和截图一致的命令:

python scripts/scan_repo.py .

picture.image

运行 python scripts/scan_repo.py . 测试扫描脚本

正常情况下,终端会返回一段 JSON:

picture.image

扫描脚本返回项目名、文件数、目录数与语言

第一次小成功: 能看到 project_nametotal_filestotal_directorieslanguagesfiles,说明扫描脚本已经能工作。

6. 再写一个脚本:识别技术栈

只知道“有多少文件”还不够。这个脚本会根据真实配置文件识别技术栈,让 Agent 有证据再下结论。

继续在 scripts 中创建 detect_stack.py

picture.image

继续创建用于识别技术栈的 detect_stack.py

复制下面代码:

 from pathlib import Path
import json
import sys


def load_json(path: Path):
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}


def detect_stack(root: Path):
    detected = []

    package_json = root / "package.json"

    if package_json.exists():
        detected.append("Node.js")
        data = load_json(package_json)
        dependencies = {}
        dependencies.update(data.get("dependencies", {}))
        dependencies.update(data.get("devDependencies", {}))

        rules = {
            "react": "React",
            "next""Next.js",
            "vue""Vue",
            "nuxt""Nuxt",
            "svelte""Svelte",
            "@sveltejs/kit""SvelteKit",
            "express""Express",
            "fastify""Fastify",
            "nestjs""NestJS",
            "@nestjs/core""NestJS",
            "tailwindcss""Tailwind CSS",
            "prisma""Prisma",
            "@prisma/client""Prisma",
            "drizzle-orm""Drizzle ORM",
            "typescript""TypeScript",
            "vite""Vite",
            "webpack""Webpack",
            "vitest""Vitest",
            "jest""Jest",
        }

        for package_name, technology in rules.items():
            if package_name in dependencies:
                detected.append(technology)

    if (root / "requirements.txt").exists():
        detected.append("Python")

    if (root / "pyproject.toml").exists():
        detected.append("Python")

    if (root / "Cargo.toml").exists():
        detected.append("Rust")

    if (root / "go.mod").exists():
        detected.append("Go")

    if (root / "pom.xml").exists():
        detected.append("Java / Maven")

    if (root / "build.gradle").exists():
        detected.append("Java / Gradle")

    if (root / "Dockerfile").exists():
        detected.append("Docker")

    if (root / "docker-compose.yml").exists():
        detected.append("Docker Compose")

    if (root / "docker-compose.yaml").exists():
        detected.append("Docker Compose")

    detected = list(dict.fromkeys(detected))

    return {
        "technology_stack": detected
    }


def main():
    target = Path(
        sys.argv[1] if len(sys.argv) > 1 else "."
    ).resolve()

    result = detect_stack(target)

    print(json.dumps(
        result,
        ensure_ascii=False,
        indent=2
    ))


if __name__ == "__main__":
    main()

还是在同一个终端执行:

 python scripts/detect_stack.py .

picture.image

运行 python scripts/detect_stack.py . 查看识别结果

截图里得到的是空数组 [],这不是翻车。我们此刻扫描的是 X-ray 自己,它的根目录没有 package.jsonrequirements.txt 等证据。没证据就不乱猜,恰恰是好习惯。

7. 把两份结果装进同一个 JSON

前两个脚本各管一摊,这一步给它们加一个统一入口。以后 Agent 只需要运行一次,就能拿到一份结构化数据。

创建 scripts/run_xray.py

picture.image

创建 run_xray.py 统一生成扫描数据

写入:

from pathlib import Path
import json
import sys

from scan_repo import scan_repository
from detect_stack import detect_stack


def run_xray(root: Path):
    repo_data = scan_repository(root)
    stack_data = detect_stack(root)

    result = {
        "project": repo_data,
        "stack": stack_data,
    }

    return result


def main():
    target = Path(
        sys.argv[1if len(sys.argv) > 1 else "."
    ).resolve()

    result = run_xray(target)

    output_path = Path("xray-data.json")

    output_path.write_text(
        json.dumps(
            result,
            ensure_ascii=False,
            indent=2
        ),
        encoding="utf-8"
    )

    print(f"X-ray 扫描完成")
    print(f"目标项目:{target}")
    print(f"数据文件:{output_path.resolve()}")


if __name__ == "__main__":
    main()

这个文件是统一入口。它把仓库扫描和技术栈识别合并,写成 xray-data.json,方便 Agent 后面继续处理。

8. 补三件事:关键文件、复杂度、HTML 模板

做到这里,最小骨架已经有了:说明书、扫描脚本、技术栈识别和统一入口。代码看累了可以先歇一下;你不需要立刻理解每一行 Python,只要知道每个文件负责什么、运行后应该看到什么。

接下来三个组件会把“能扫描”升级成“能给出有用报告”:找关键文件、计算可解释的复杂度、把结果放进 HTML。它们不是为了把 Python 课偷偷塞进来,而是给 Agent 提供可复用的测量工具。

先创建 scripts/find_key_files.py

picture.image

创建 find_key_files.py 寻找高信息密度文件

from pathlib import Path
import json
import sys

KEY_FILE_RULES = {
    "README.md": "项目说明",
    "README""项目说明",
    "package.json""Node.js 项目配置",
    "pyproject.toml""Python 项目配置",
    "requirements.txt""Python 依赖",
    "Cargo.toml""Rust 项目配置",
    "go.mod""Go 项目配置",
    "Dockerfile""容器部署",
    "docker-compose.yml""容器编排",
    "docker-compose.yaml""容器编排",
    "next.config.js""Next.js 配置",
    "next.config.mjs""Next.js 配置",
    "next.config.ts""Next.js 配置",
    "vite.config.js""Vite 配置",
    "vite.config.ts""Vite 配置",
    "tsconfig.json""TypeScript 配置",
    "prisma/schema.prisma""数据库模型",
    "src/main.py""Python 程序入口",
    "main.py""Python 程序入口",
    "src/main.ts""程序入口",
    "src/main.tsx""前端程序入口",
    "src/app/layout.tsx""Next.js 根布局",
    "src/app/page.tsx""Next.js 首页",
    "middleware.ts""中间件",
    "middleware.js""中间件",
}


def find_key_files(root: Path):
    key_files = []

    for relative_path, reason in KEY_FILE_RULES.items():
        path = root / relative_path

        if path.exists():
            key_files.append({
                "path": relative_path,
                "reason": reason
            })

    return {
        "key_files": key_files
    }


def main():
    target = Path(
        sys.argv[1] if len(sys.argv) > 1 else "."
    ).resolve()

    result = find_key_files(target)

    print(json.dumps(
        result,
        ensure_ascii=False,
        indent=2
    ))


if __name__ == "__main__":
    main()

它不让模型凭感觉选文件,而是先把 README、配置、入口等高信息密度位置列出来。

再创建 scripts/complexity.py

picture.image

创建 complexity.py 计算可解释的复杂度分数

from pathlib import Path
import json
import sys


def clamp(value, min_value=0, max_value=10):
    return max(min_value, min(max_value, value))


def calculate_complexity(project_data, stack_data, key_files_data):
    total_files = project_data.get("total_files"0)
    total_directories = project_data.get("total_directories"0)

    languages = project_data.get("languages", {})
    technology_stack = stack_data.get("technology_stack", [])
    key_files = key_files_data.get("key_files", [])

    size_score = min(total_files / 10010)
    structure_score = min(total_directories / 2010)
    stack_score = min(len(technology_stack) * 1.210)
    language_score = min(len(languages) * 210)
    key_file_score = min(len(key_files), 10)

    final_score = (
        size_score * 0.30
        + structure_score * 0.20
        + stack_score * 0.25
        + language_score * 0.10
        + key_file_score * 0.15
    )

    final_score = round(clamp(final_score), 1)

    if final_score < 3:
        level = "简单"
    elif final_score < 5:
        level = "中等"
    elif final_score < 7:
        level = "偏复杂"
    elif final_score < 9:
        level = "复杂"
    else:
        level = "非常复杂"

    return {
        "score": final_score,
        "level": level,
        "dimensions": {
            "size": round(size_score, 1),
            "structure": round(structure_score, 1),
            "technology_stack": round(stack_score, 1),
            "languages": round(language_score, 1),
            "key_files": round(key_file_score, 1),
        }
    }


def main():
    if len(sys.argv) < 2:
        print("用法:python complexity.py xray-data.json")
        return

    data_path = Path(sys.argv[1])
    data = json.loads(data_path.read_text(encoding="utf-8"))

    result = calculate_complexity(
        data["project"],
        data["stack"],
        data["key_files"]
    )

    print(json.dumps(
        result,
        ensure_ascii=False,
        indent=2
    ))


if __name__ == "__main__":
    main()

复杂度不是圣旨,只是一个可以解释、可以调整的起点。至少它比“模型看了一眼,觉得大概 8 分”靠谱。

然后在 assets/report-template.html 写一个最小模板:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>X-ray Report</title>
</head>
<body>
    <h1>🔍 X-ray</h1>
    <h2>{{PROJECT_NAME}}</h2>
    <p>文件数量:{{TOTAL_FILES}}</p>
    <p>目录数量:{{TOTAL_DIRECTORIES}}</p>
    <p>复杂度:{{COMPLEXITY_SCORE}} / 10</p>
    <h2>技术栈</h2>
    <div>{{TECH_STACK}}</div>
    <h2>关键文件</h2>
    <div>{{KEY_FILES}}</div>
</body>
</html>

文件树里应该能看到模板:

picture.image

在 assets 中创建 report-template.html

最后创建 scripts/render_report.py

picture.image

创建 render_report.py 把结构化数据填入模板

from pathlib import Path
import json
import sys


def render_report(data_path):
    data = json.loads(
        Path(data_path).read_text(encoding="utf-8")
    )

    script_dir = Path(__file__).resolve().parent
    template_path = (
        script_dir.parent
        / "assets"
        / "report-template.html"
    )

    template = template_path.read_text(
        encoding="utf-8"
    )

    project = data["project"]
    stack = data["stack"]
    complexity = data["complexity"]
    key_files = data["key_files"]

    tech_stack = ", ".join(
        stack["technology_stack"]
    )

    key_files_text = ""

    for item in key_files["key_files"]:
        key_files_text += (
            f"<p>{item['path']} —— "
            f"{item['reason']}</p>"
        )

    template = template.replace(
        "{{PROJECT_NAME}}",
        project["project_name"]
    )

    template = template.replace(
        "{{TOTAL_FILES}}",
        str(project["total_files"])
    )

    template = template.replace(
        "{{TOTAL_DIRECTORIES}}",
        str(project["total_directories"])
    )

    template = template.replace(
        "{{COMPLEXITY_SCORE}}",
        str(complexity["score"])
    )

    template = template.replace(
        "{{TECH_STACK}}",
        tech_stack
    )

    template = template.replace(
        "{{KEY_FILES}}",
        key_files_text
    )

    output_path = (
        Path(data_path).parent
        / "xray-report.html"
    )

    output_path.write_text(
        template,
        encoding="utf-8"
    )

    print("✅ X-ray 报告生成完成")
    print(output_path)


if __name__ == "__main__":
    render_report(sys.argv[1])

先别单独运行它。当前 run_xray.py 只稳定生成 projectstack,而这个渲染脚本还需要 key_filescomplexity。本集的真实路线是让 Agent 调用这些组件、抽样阅读源码,再生成完整 HTML;后面再把它们串成纯脚本流水线也来得及。

9. 先运行统一扫描入口

在交给 Agent 之前,我们先自己运行一次统一入口。这样如果出错,也能立刻判断是脚本问题,还是后面的 Agent 调用问题。

x-ray 根目录执行:

python scripts\run_xray.py .

picture.image

运行 python scripts/run_xray.py . 生成 xray-data.json

你应该看到“X-ray 扫描完成”、目标项目路径和数据文件路径,同时目录里多出 xray-data.json

picture.image

xray-data.json 保存脚本采集的一手事实

到这里,事实采集层已经成功。 JSON 只负责记录它真正看见的东西,不负责把未知内容脑补成“高并发微服务宇宙”。

10. 给 Agent 一份分析规则

扫描数据只告诉 Agent“看到了什么”,分析规则负责告诉它“应该怎样解释、什么时候必须承认不确定”。

references 中创建 analysis-rules.md

picture.image

在 references 中创建 analysis-rules.md

写入:

# X-ray 分析规则

先读取 `xray-data.json`,所有分析必须基于扫描得到的一手数据。

## project.total_files
用于判断项目规模。

## project.total_directories
用于判断项目的目录规模和组织程度。

## project.languages
用于判断项目主要使用的开发语言。

## project.files
用于了解项目文件结构,并选择值得进一步阅读的关键文件。

## stack.technology_stack
用于判断已经识别出的技术栈。

## 分析原则

在 `xray-data.json` 的基础上,再读取 README、配置文件和关键源码,
进一步判断:

- 这个项目是什么
- 项目类型
- 整体架构
- 关键模块
- 项目复杂度
- 适合哪些方向的人学习
- 推荐阅读顺序

所有结论必须优先依据 `xray-data.json` 和实际源码。

`references` 只负责说明“如何解释扫描数据”,不能覆盖或虚构项目的一手事实。

如果证据不足,明确标记为“不确定”,不要猜测。

这份文件的作用不是给答案,而是约束“怎么得出答案”。事实来自项目,规则只负责提醒 Agent 别演得太投入。

11. 把完整流程补回 SKILL.md

前面的文件各自已经能工作,但 Agent 还不知道如何把它们串起来。这一步把完整工作流补回 SKILL.md,相当于给它一张执行路线图。

SKILL.md 的安全规则后继续加入:

## 工作流程

当用户调用 X-ray 分析一个陌生项目时:

1. 使用 `scripts/run_xray.py` 扫描当前项目。
2. 读取扫描生成的 `xray-data.json`3. 读取 `references/analysis-rules.md`,按照其中的规则解释扫描数据。
4. 根据 `xray-data.json` 中的文件列表,进一步读取:
   - README
   - 项目配置文件
   - 程序入口
   - 关键源码文件
5. 基于真实扫描数据和实际源码,分析:
   - 这个项目是什么
   - 项目类型
   - 技术栈
   - 文件结构
   - 整体架构
   - 项目复杂度
   - 适合哪些方向的人学习
   - 推荐阅读顺序
6. 最终生成一个 HTML 可视化项目报告。

## 原则

- 优先依据 `xray-data.json` 和实际源码。
- `references` 只提供分析方法,不提供项目事实。
- 不确定的信息明确标记为“不确定”。
- 不修改被分析项目的源代码。
- 不安装依赖。
- 不执行未知项目代码。

现在 X-ray 的“大脑说明书、测量工具、判断规则和报告模板”都齐了。下一步不再盯着代码看,我们直接把它扔进真实项目。

12. 选一个你想分析的项目

这里不要求你必须使用 AIFriends:

  • 手边有自己的项目:直接使用自己的公开项目,或确认允许发送给当前模型服务的项目。
  • 暂时没有合适项目:跟着截图使用 AIFriends,最容易对照结果。

不要把未经允许的公司仓库或敏感代码交给云端 Agent。示例可以换,数据边界不能靠勇气突破。

为了和截图一致,可以在桌面新建 测试X-ray 文件夹。

picture.image

新建测试X-ray文件夹,准备第一次真实项目验收

进入这个文件夹,执行和截图一致的 SSH 命令:

 git clone git@github.com:ppshux/AIFriends.git

picture.image

克隆本集使用的公开测试仓库;截图采用 Git SSH 地址

如果你还没有配置 GitHub SSH Key,就用官方仓库页面提供的 HTTPS 地址:

git clone https://github.com/ppshuX/AIFriends.git

本次截图使用 AIFriends,只是为了演示和方便对照;它不是教程的主角,也不是制作 Skill 的必选项。

两条命令只选一条。看到 Cloning into 'AIFriends'... 并顺利结束,就说明测试项目已经准备好;我们不会安装它的依赖,也不会运行它。

13. 用 CodeBuddy 打开测试目录

这一步是让 CodeBuddy 把测试项目当作当前工作目录。这样调用 /x-ray 时,它才知道应该分析谁。

用 CodeBuddy 打开刚刚的 测试X-ray 文件夹。

picture.image

用 CodeBuddy 打开测试文件夹

第一次使用 CodeBuddy 的读者,回看第 1 节的官方下载入口即可。这里的成功标志只有一个:左侧能看到刚克隆的项目文件,右侧能打开 Agent 对话。

14. 把本地 X-ray 装进 CodeBuddy

Skill 文件夹做好了,不等于 Agent 已经能看见它。这一步要把 X-ray 放进 CodeBuddy 实际读取的 Skill 目录。

我们直接把真实实验里的话原样交给 Agent:

把我桌面的 x-ray 放到你的skill目录里

picture.image

让 CodeBuddy 把桌面的 x-ray 放入本地 Skill 目录

CodeBuddy 会找到桌面的 x-ray,再把它放进自己的 Skill 目录。Windows 上通常是:

 C:\Users\你的用户名.codebuddy\skills\x-ray

picture.image

CodeBuddy 完成本地 Skill 安装并提示重启

截图里的关键信息是安装目录与“需要重启/重载”。完成后彻底重启 CodeBuddy,让它重新扫描 Skills。

15. 调用 /x-ray,生成第一份真实报告

前面都是搭积木,现在才是真正的验收:如果 /x-ray 能被识别,并为测试项目生成报告,这个 Skill 才算跑通。

重启后,在对话框输入 /x。列表中能看到 /x-ray,说明安装成功。

picture.image

重启后输入斜杠加 x,列表中已经出现 x-ray

选中它,直接回车,不需要额外写提示词:

/x-ray

picture.image

直接执行 /x-ray,不需要另外编写提示词

CodeBuddy 会先运行扫描脚本,再读取 JSON、分析规则、README、配置与必要源码。

picture.image

CodeBuddy 开始运行 X-ray 并读取扫描脚本

等它完成后,测试目录里应该出现:

xray-data.json
xray-report.html

打开 HTML,先看项目结构与关键技术组件:

picture.image

第一份报告展示项目结构与技术组件

继续往下看复杂度、适合的学习方向和推荐阅读顺序:

picture.image

第一份报告给出复杂度、适合方向和推荐阅读顺序

最后回到报告顶部,确认项目名和关键指标:

picture.image

第一份 X-ray 项目解剖报告已经生成

上集通关: 第一份真实项目报告已经生成。此时我们不只是“写了几个文件”,而是亲手完成了“制作 Skill → 本地安装 → 真实项目调用 → 交付 HTML”的第一次闭环。

16. 三个最容易卡住的地方

  • 终端提示找不到 Python:依次试 python --versionpy --version,后续统一使用能显示 Python 3 的那个命令。
  • 重启后没有 /x-ray:检查 %USERPROFILE%.codebuddy\skills\x-ray\SKILL.md 是否存在,并确认 SKILL.md 文件名没有变成 SKILL.md.txt
  • 只有 JSON,没有 HTML:JSON 只代表脚本层完成;继续等待 Agent 抽样阅读与生成报告,并查看对话里是否出现文件读取或写入失败。

还有一个容易被忽略的边界:X-ray 不修改目标项目源码,但会在测试目录写出 xray-data.jsonxray-report.html。如果用于公司仓库,还要先确认代码能否发送给当前模型服务,并检查报告里是否包含内部路径、仓库名或业务信息。

17. 收尾:我们真正做成了什么

picture.image

上集通关:X-ray 已在真实仓库中生成第一份项目解剖报告

这一集完成了三件事:

  1. SKILL.md + scripts + references + assets 做出 X-ray;
  2. 把它装进 CodeBuddy,并成功唤起 /x-ray
  3. 用一个真实仓库生成第一份可以打开的项目解剖报告。

这时的 X-ray 已经不是一段聊天记录,而是一套可以重复调用的工作方法。

更重要的是,你已经掌握了制作 Skill 的通用套路。哪怕你对“项目 X 光机”没有兴趣,也可以保留目录结构和验证方法,把里面的任务换成自己的需求。

下一集只增加一个变量:把它发布到 GitHub,再从仓库重新安装,并换一个项目验证“换个地方还能用”。


上集已完成“制作 Skill + 本地真实调用”。清晰原图、完整代码和后续两集持续更新在:AI 应用架构演进实践。下一集把 X-ray 发布到 GitHub。

0
0
0
0
评论
未登录
暂无评论