十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI Agent 技能工程化:从 Prompt 到 Skill 的进阶实践

AI Agent 技能工程化:从 Prompt 到 Skill 的进阶实践 在很多技术团队里AI Agent 的落地都卡在同一个地方模型很强Agent 很笨。强的是对话能力笨的是具体干活。你让它改代码它能改得像模像样你问它“我们项目的发布流程是什么”“这份日志里的高频报错集中在哪几个接口”它就容易开始一本正经地编。把所有规则都塞进提示词提示词会越来越长、越来越不可维护把能力直接做成工具又涉及服务、协议、鉴权太重了。夹在提示词和工具之间的这一层正是 Agent Skill 要解决的位置。最近我注意到 ConardLi / garden-skills 这个项目。名字很有画面感garden 是花园skills 是技能。表面看它是一个把 AI Agent 技能整理成“花园”的仓库往深一层想“garden”这个词本身也传达了这类项目真正想表达的理念技能不是一次写死、永不变化的静态文件而是需要像植物一样被持续照料、修剪、培育的资产。这个判断也是这篇文章想展开的核心观点——AI Agent 真正从“能聊天”走向“能干活”靠的不只是模型升级而是把技能当成一套可积累、可维护、可组合的工程资产。这篇文章会从问题出发讲清楚 Skill 是什么、和 Prompt / Tool 有什么区别再以 garden-skills 这类技能集合为切入点演示如何上手使用别人的技能、如何从零构建一个自己的 Skill、如何验证它真的被 Agent 调用最后给出常见问题排查和工程上的最佳实践。如果你是正在做 Agent 应用或者准备把 Agent 引入团队协作的开发者这篇文章应该能帮你省下不少试错成本。1. garden-skills 真正要解决的问题一个 Agent 项目要想真实投入使用首先要回答的问题就是你的 Agent 会做什么、不会做什么大部分团队在第一版都会把答案写在提示词里。做一个客服助手就把客服话术写进 system prompt做一个代码助手就把代码规范、打包命令、发布流程写进上下文做一个数据分析助手就把公司数据字典、报表口径写进前置说明。这种方案在 Demo 阶段没有任何问题一旦进入真实项目问题就开始集中爆发。第一个问题是提示词膨胀。业务规则一多提示词轻松写到几千字模型越往后越容易忽略靠前的约束。更麻烦的是不同业务规则之间存在优先级冲突靠自然语言很难做清晰的裁决。你告诉它“回复要简洁”又告诉它“必须给出完整排查过程”模型每次都在两种要求之间摇摆。第二个问题是不可复用。这个项目的客服话术换一个项目完全用不了A 团队辛苦总结的日志排查经验B 团队不知道又要从零积累。团队内部的“会干活的知识”基本处于口口相传状态组织记忆力非常弱。第三个问题是不可测试。提示词写得好不好只能靠人工反复试。你很难对一段提示词做单元测试、做版本对比、做回归验证。一旦提示词被多人修改过最后连谁改了什么、为什么改都说不清楚。这些痛点不是模型能力提升就能自动解决的。模型理解力再强也需要有人把某个任务的标准做法、工具调用方式、结果校验方法组织成一个可复用的单元。这部分工作就是 Skill 的定位。从项目命名来看garden-skills 想做的更像是把零散的 Agent 技能集中管理起来形成一套可以通过“目录结构 描述文件 脚本”复用的技能花园。相比单条提示词它把“完成某类任务的经验”整体打包让 Agent 在遇到对应场景时自动选择使用。更值得留意的是“花园”这个隐喻还强调了一层意思技能库不维护就会荒废需要持续修剪、补种、淘汰。真正拉开团队差距的往往不是第一个 Skill 写得多好而是后续能不能把技能库持续养下去。2. 基础概念Skill、Tool、Prompt 到底有什么区别想用好 garden-skills 这类项目先要把一个基础概念理清楚Skill 不是 Prompt也不是 Tool。很多人会把三者混在一起导致整个 Agent 工程的架构边界非常模糊。2.1 三个概念的边界先用一句通俗的话概括Prompt 是“告诉模型该怎么想”的文本。Tool 是“让模型能做什么”的外部功能。Skill 是“教模型怎么把一件复杂事做完”的能力包。举一个更贴近开发的例子。假设你要让 Agent 帮忙做代码评审用 Prompt 实现就是写一段几百字的评审规则“请检查代码风格、异常处理、日志规范……”这是最轻量的方式但换个团队、换个语言这段 Prompt 基本作废。用 Tool 实现就是开发一个调用静态检查服务的接口比如接入 ESLint、SonarQube。它解决的是“能不能自动跑检查”的问题但不负责“检查结果出来后怎么组织评审意见”。用 Skill 实现就是在一个目录里同时放评审规则、检查命令、报告模板、历史评审示例。Agent 在拿到一个 pull request 时先判断“这个任务应该调用 code-review 技能”然后加载技能里的文档按里面的步骤执行检查最后按模板输出评审结论。2.2 一张表看懂区别维度PromptSkillTool本质文本指令能力包文档 脚本 资源外部可调用功能触发方式用户或系统注入模型按需判断调用用户、应用或 Agent 框架调用可复用性低高中可测试性低高高典型内容规则、语境、示例SKILL.md、脚本、参考文档API、命令、SDK维护成本低但易失控中等结构清晰后可维护较高涉及服务治理适合场景对话控制、临时约束复杂任务的完整方法论固化系统交互、副作用操作这句话值得重复一遍不要用 Prompt 去做本该由 Skill 做的事也不要为了一个简单判断去写一个 Tool。分层是技能体系的第一课。2.3 模型是如何决定调用哪个 Skill 的这是很多新手最容易忽略的机制Skill 不是由用户手动指定执行的而是由模型根据任务的语义描述自动判断的。每个 Skill 的 SKILL.md 里都有一个 description 字段。模型在读到一个用户请求时会把这个请求和各个 Skill 的 description 做匹配匹配度高才加载对应的 Skill 内容。也就是说Skill 的 description 写得好不好直接决定了 Agent 会不会在正确的时机使用它。这一点在后面的实操部分还会反复出现。3. 一个 Skill 的标准结构从 SKILL.md 到脚本要判断 garden-skills 这类仓库里的技能好不好用首先要学会看一个 Skill 的内部结构。目前主流 Agent 平台的 Skill 约定比较接近一个 Skill 就是一个独立目录核心文件是 SKILL.md其余文件按功能组织。3.1 常见目录结构log-analyzer/ ├── SKILL.md ├── scripts/ │ ├── analyze.py │ └── requirements.txt ├── assets/ │ └── report_template.md └── references/ └── examples.md各文件职责如下SKILL.md技能说明书也是技能入口。包含元信息name、description和执行指南。scripts/具体执行任务的脚本。Skill 里最核心的可执行部分通常放在这里。assets/模板、数据文件、静态资源。比如报告模板、配置文件。references/参考文档、示例、最佳实践。用于给模型提供“怎么把活干好”的上下文。3.2 SKILL.md 到底写什么SKILL.md 是整个技能的入口。模型先读它再决定要不要加载 scripts 和 references。一个推荐的写法是--- name: log-analyzer description: 分析应用日志文件提取高频异常、统计错误码分布并生成 Markdown 格式的巡检报告。当用户希望排查线上问题、分析日志、定位错误时使用。 --- # 日志分析技能 ## 适用场景 - 用户提供了日志文件路径。 - 用户希望从日志中发现异常趋势或高频报错。 ## 执行步骤 1. 使用 scripts/analyze.py 分析日志文件。 2. 根据脚本输出结果生成巡检报告。 3. 报告必须包含时间范围、异常数量、Top 错误、改进建议。 ## 依赖 - Python 3.9 及以上 - 使用命令python3 scripts/analyze.py --help 查看参数说明这里有两个关键点。第一frontmatter 里的 name 和 description 是模型判断是否调用技能的依据。description 要写清楚“什么时候用”而不是“技能是什么”。比如“当用户希望排查线上问题、分析日志、定位错误时使用”就比“这是一个日志分析工具”更容易被模型命中。第二正文里的执行步骤不一定要写成脚本逻辑但一定要写清楚边界。比如“报告必须包含哪些内容”“哪些情况属于异常”“输出格式是什么”。这些规则会被模型当成行为约束直接影响最终输出质量。3.3 脚本在 Skill 里的角色底层逻辑很简单模型读文档做判断脚本做确定性计算。Skill 之所以比纯 Prompt 可靠是因为它能调用脚本把日志解析、数据聚合、格式校验这些确定性动作交给代码完成。模型只在“判断场景、编排步骤、组织输出”这些需要语义理解的地方发挥作用。所以在设计 Skill 时一个核心原则是能在脚本里实现的逻辑就不要让模型自由发挥。4. 上手实践如何使用 garden-skills 这类技能集合下面进入实操。由于不同仓库的目录结构可能不同具体命令以该仓库 README 为准。这里以 garden-skills 一类典型的技能集合为例演示通用接入流程。4.1 第一步获取技能集合把仓库克隆到本地git clone https://github.com/ConardLi/garden-skills.git cd garden-skills克隆后先不要急着复制文件先看目录结构ls -la一般来说技能集合会有一个集中存放技能的目录比如skills/。也有仓库会把每个技能放在独立子目录里并配一个总览 README。先找到存放技能的根目录再进入下一步。4.2 第二步阅读每个技能的说明书进入一个技能目录后重点看 SKILL.md 的 frontmatter 部分确认它解决什么问题、依赖什么环境。cat skills/log-analyzer/SKILL.md这一步非常重要。很多使用技能集合的人会栽在这里看到目录很多就直接复制结果有些技能依赖 Python 3.11有些依赖 Node.js 20复制完一运行就报错。先花五分钟看依赖说明能省下后面一整天的排查时间。4.3 第三步把技能安装到 Agent 的 skills 目录不同 Agent 工具对 Skill 的安装位置定义不同。以 Claude Code 为例全局技能通常放在~/.claude/skills/项目级技能放在.claude/skills/。mkdir -p ~/.claude/skills cp -r skills/log-analyzer ~/.claude/skills/验证一下目录是否完整ls -la ~/.claude/skills/log-analyzer只要能看到 SKILL.md 和 scripts 目录说明安装成功。如果你使用的是自研 Agent可能需要在代码里指定 skill 的加载路径具体以框架文档为准。4.4 第四步测试技能是否能被自动触发安装完成后重启 Agent 进程然后直接提出一个匹配该 Skill 描述的任务。分析一下 server.log 里最常见的 5 个错误并整理成一份报告如果 Agent 正确加载了 log-analyzer 技能它会先执行脚本分析日志再按 SKILL.md 里的报告模板输出结果。如果响应里完全看不到技能相关中间过程说明可能没有触发成功需要回到 SKILL.md 的 description 描述上检查。5. 从零构建一个“仓库健康体检” Skill完整示例理解现有技能的结构之后真正有价值的能力是设计自己的 Skill。这一节我们从一个实际场景出发手把手构建一个“仓库健康体检”技能。它适合作为团队内部代码仓库准入检查的辅助工具。5.1 场景定义代码仓库里经常出现这类问题README 缺失、.gitignore 没配、依赖没有锁定、大文件被误入库。每次人工检查都要开着 GitHub 页面一个个点开看费时费力。我们把这个检查过程封装成一个 Skill让 Agent 在收到“帮我看下仓库是否规范”这类请求时自动执行。5.2 创建目录结构repo-health/ ├── SKILL.md └── scripts/ ├── check_repo.py └── requirements.txt先创建目录mkdir -p repo-health/scripts5.3 编写 SKILL.md文件路径repo-health/SKILL.md--- name: repo-health description: 对本地代码仓库进行常规健康体检检查 README 是否存在、.gitignore 是否配置、依赖是否锁定、历史提交大小等。当用户希望评估仓库规范程度、准备开源、或做代码库准入检查时使用。 --- # 仓库健康体检技能 ## 适用场景 - 用户提供一个本地仓库路径。 - 用户希望了解仓库在工程规范上的缺失项。 ## 执行步骤 1. 使用 scripts/check_repo.py 扫描仓库。 2. 脚本会输出每个检查项的状态OK、WARN、FAIL。 3. 根据脚本结果生成简要报告并给出改进建议。 ## 输出要求 - 按检查项逐条列出结果。 - 每项给出明确结论通过、警告或失败。 - 失败项必须给出可执行的修改建议。5.4 编写检查脚本文件路径repo-health/scripts/check_repo.py#!/usr/bin/env python3 仓库健康检查脚本输出检查项结果与改进建议。 import os import subprocess import sys from pathlib import Path def repo_root() - Path: if len(sys.argv) 1: return Path(sys.argv[1]).resolve() return Path.cwd() def check_git(root: Path) - dict: return { item: Git 仓库, status: OK if (root / .git).exists() else FAIL, message: 已初始化 if (root / .git).exists() else 当前目录不是 Git 仓库, } def check_readme(root: Path) - dict: names [README.md, README.rst, README.txt, REAMDE] for name in names: if (root / name).exists(): return {item: README, status: OK, message: f存在 {name}} return {item: README, status: WARN, message: 缺少 README 文档} def check_gitignore(root: Path) - dict: p root / .gitignore if not p.exists(): return {item: .gitignore, status: WARN, message: 缺少 .gitignore} content p.read_text(encodingutf-8, errorsignore).strip() if not content: return {item: .gitignore, status: WARN, message: .gitignore 为空} return {item: .gitignore, status: OK, message: .gitignore 已配置} def check_license(root: Path) - dict: for name in [LICENSE, LICENSE.md, COPYING]: if (root / name).exists(): return {item: LICENSE, status: OK, message: 存在许可证文件} return {item: LICENSE, status: INFO, message: 未检测到许可证内部仓库可忽略} def check_dependency_lock(root: Path) - list: results [] markers [ (package.json, [package-lock.json, yarn.lock, pnpm-lock.yaml]), (requirements.txt, [poetry.lock, Pipfile.lock]), (go.mod, [go.sum]), ] for manifest, locks in markers: if not (root / manifest).exists(): continue found [lock for lock in locks if (root / lock).exists()] if found: results.append( { item: f依赖锁定 ({manifest}), status: OK, message: f存在 {found[0]}, } ) else: results.append( { item: f依赖锁定 ({manifest}), status: WARN, message: f{manifest} 存在但未找到锁文件, } ) return results def check_large_files(root: Path, limit_mb: int 10) - dict: large [] for dirpath, _, filenames in os.walk(root): if .git in Path(dirpath).parts: continue for name in filenames: p Path(dirpath) / name try: size p.stat().st_size if size limit_mb * 1024 * 1024: large.append((str(p.relative_to(root)), size)) except OSError: continue if large: detail 、.join(f{p} ({round(s/1024/1024, 1)}MB) for p, s in large[:5]) return { item: 大文件检查, status: WARN, message: f超过 {limit_mb}MB 的文件: {detail}, } return { item: 大文件检查, status: OK, message: f未发现超过 {limit_mb}MB 的文件, } def format_result(r: dict) - str: icon {OK: [OK] , WARN: [WARN], FAIL: [FAIL], INFO: [INFO]}.get( r[status], [INFO] ) return f{icon} {r[item]}: {r[message]} def main(): root repo_root() print(f检查仓库: {root}\n) results [check_git(root), check_readme(root), check_gitignore(root), check_license(root)] results.extend(check_dependency_lock(root)) results.append(check_large_files(root)) for r in results: print(format_result(r)) print(\n检查完成。) if __name__ __main__: main()这个脚本用纯标准库写成不需要额外安装第三方依赖所以 requirements.txt 可以留空也可以只写一行注释。脚本会依次检查 Git 仓库状态、README、.gitignore、许可证、依赖锁文件和大文件并输出带状态的检查结果。5.5 解释关键设计这个 Skill 的设计里有一个很容易被忽略的点脚本输出的是结构化文本而不是让模型自己去算结果。真正决定“这个仓库是否规范”的判断逻辑全部在代码里模型只负责把检查结果组织成报告、补充改进建议。这样做的好处是结果稳定、可复现不会出现模型“看错”文件大小这种低级错误。还有一点值得说明SKILL.md 的 description 里写了“准备开源、或做代码库准入检查时使用”这是在帮模型划清触发边界。如果没有这句模型可能在你随口说“帮我看下这个项目”时也触发体检反而显得多余。6. 运行结果与效果验证6.1 独立运行脚本先在命令行里直接运行脚本验证逻辑本身是否正确cd repo-health python3 scripts/check_repo.py .预期输出示例检查仓库: /path/to/repo-health [OK] Git 仓库: 已初始化 [WARN] README: 缺少 README 文档 [OK] .gitignore: 已配置 [INFO] LICENSE: 未检测到许可证内部仓库可忽略 [WARN] 依赖锁定 (package.json): package.json 存在但未找到锁文件 [OK] 大文件检查: 未发现超过 10MB 的文件 检查完成。只要打印出上述内容说明脚本本身没问题。如果报错优先检查 Python 版本和当前目录。6.2 验证 Skill 是否被 Agent 正确加载把 repo-health 复制到 Agent 的 skills 目录cp -r repo-health ~/.claude/skills/然后重启 Agent 进程向 Agent 提问帮我检查一下 /path/to/my-project 这个仓库规范不规范如果技能被正确触发你会看到 Agent 先运行脚本再基于脚本输出撰写报告。如果 Agent 只是泛泛回答“需要检查 README、.gitignore……”而没有实际执行脚本说明技能没有被加载重点检查 frontmatter 格式和目录位置。很多人在这个环节遇到的坑是改了 SKILL.md 或脚本后Agent 仍然使用旧逻辑。这是因为部分 Agent 工具对 skills 目录有缓存修改后必须重启进程或者执行工具提供的 reload 命令。7. 常见问题与排查方法问题现象可能原因排查方式解决方案Agent 完全没有调用技能description 写得不清晰模型不知道何时使用查看 SKILL.md 的 description 字段用“当用户希望……时使用”明确触发条件技能被调用了但输出不稳定正文执行步骤不够具体检查 SKILL.md 中的执行步骤和输出要求补充明确输出格式、必须字段、禁止行为脚本执行报错依赖环境不匹配独立运行脚本查看报错堆栈在 SKILL.md 的依赖节注明版本要求技能目录复制后不生效放错目录或缺少 SKILL.md检查 skills 目录下是否存在 SKILL.md按 Agent 工具的规范放置并重启进程修改技能后仍走旧逻辑技能被缓存查看是否有热加载或缓存机制重启 Agent 进程或执行 reload技能被过度调用Token 成本上升description 触发范围过大观察哪些请求会触发技能收窄 description只在真正相关时触发脚本输出内容重复出现Skill 的正文要求模型重复输出脚本结果检查 SKILL.md 是否要求“逐字复述脚本输出”改为“基于脚本输出生成摘要报告”排在第一位的最常见问题依然和 description 有关。这是一个需要反复强调的点模型判断技能是否可用的唯一依据就是 frontmatter 里的 description。这个字段写得太笼统模型不知道该不该用写得太具体模型又会过度匹配。理想的写法是包含“任务类型”和“触发场景”两个要素。8. 最佳实践与工程建议8.1 命名规范动词开头一眼看懂技能目录名和 name 字段建议用动词或“对象 动作”的风格例如log-analyzer、code-reviewer、release-note-generator。避免使用agent-001这类无法表达语义的名字。名字里的信息量直接决定了后续维护时团队成员的查找效率。8.2 description 是技能的灵魂写 description 时把自己想象成一个搜索引擎用户请求就是搜索词description 就是页面标题和摘要。它必须覆盖可能的表达变体比如“分析日志”“看下报错”“排查线上问题”可能指向同一个技能。建议在 description 中同时出现动词和业务场景词并测试至少三种不同的用户说法确认都能命中。8.3 坚持自包含原则一个 Skill 目录应该包含它运行所需的全部内容脚本、模板、参考文档、依赖说明。不要出现“先到某个内网盘下载数据文件”这种外部依赖。技能一旦依赖外部环境可移植性就会断崖式下降。团队之间共享技能时最理想的状态是“复制目录即可用”。8.4 把确定性逻辑放进脚本模型擅长的是理解、判断、生成文本不擅长的是精确计算、解析结构化数据、判断文件大小。凡是能做确定性处理的逻辑尽量放到脚本里。这样既能提高输出稳定性也能减少模型在无关细节上的 Token 消耗。8.5 最小权限与安全边界Skill 里的脚本会在 Agent 运行环境中执行。必须保持最小权限原则脚本不应该读取无关目录不应该拥有比当前用户更高的权限更不应该把密钥、令牌写死在脚本或 SKILL.md 里。在团队内部共享技能时建议在评审清单里加一项“敏感信息扫描”。涉及删除文件、修改配置、发布变更等高风险操作需要明确要求模型在执行前向用户确认并在测试环境验证之后再使用。8.6 用 Git 管理技能版本技能本质上是一份代码资产应该纳入版本管理。每次修改 SKILL.md 或脚本都走 git让团队能回溯“这个技能的判断逻辑是什么时候改的”。更高阶一点的做法是给每个 Skill 配一个冒烟测试脚本比如用一个很小的示例数据验证脚本能跑通、输出格式符合预期。技能库越大冒烟测试的收益越明显。8.7 给技能设定退出条件一个训练有素的技能不仅要知道什么时候执行还要知道什么时候不执行。在 SKILL.md 里显式写明“以下情况不需要使用本技能”能有效避免模型在无关场景里强行套用。这个细节看似简单实际效果非常明显它直接降低了误触发率和无效 Token 消耗。9. 总结与后续学习方向回到文章开头的判断AI Agent 的竞争力正在从“模型智商”转向“工程化技能”。garden-skills 这类技能集合项目给我们的启发不在于某一个技能写得多漂亮而在于它把“技能需要被持续建设”这件事变成了一种可见的工程实践。你 clone 一个技能库、试用几个技能只是第一步真正有价值的是建立一套属于自己的技能维护流程技能的提出、评审、测试、发布、淘汰每一环都应该有明确规则。读完这篇文章你可以按下面顺序做一次完整的实践clone 一份 garden-skills 或其他技能集合仓库阅读 2 到 3 个技能的 SKILL.md理解它们的描述写法。把其中一个技能安装到你的 Agent 环境验证是否能在真实请求中触发。按照第 5 节的示例为你的团队构建第一个自己的 Skill内容可以是你们最常做的重复性任务。给这个 Skill 配一个冒烟测试然后提交到团队仓库。接下来值得深入的方向还有不少Skill 与 MCP 服务如何配合、多 Agent 场景下技能如何共享、技能触发准确率如何评测、如何用版本化方式管理技能集。这些话题都建立在同一个基础上先动手写出第一个真正能用的 Skill。一个项目里最有价值的能力往往是那些被组织起来、能反复使用的经验。智能体时代也是一样。
返回列表