AI Agent的技能Skill机制这两年热度一直在涨从Claude的Agent Skills到Codex、OpenCode这些编程Agent各自推出的Skill体系玩法越来越丰富。但说实话目前社区里大量Skill还停留在把一段提示词封装成模板的水平真正能干活、能落地、能在生产环境里输出确定性结果的并不多。这次我想分享的是我基于Agent Skill机制封装的一个安全审计技能——security-audit-skill。它不是单纯扔给模型一段请你帮我检查代码安全的提示词而是一套把静态扫描、依赖漏洞核对、配置项审查、上下文感知结合在一起的完整工作流。文章会从概念边界、场景拆分、目录设计到实测效果一步步拆开讲适合正在研究Skill开发、或者想在团队里落地自动化安全审计的工程师参考。1. Skill不是插件也不是Prompt先把概念边界划清楚1.1 从Skill和Agent的区别说起网上关于Skill的讨论特别多但很多人的理解是模糊的。Skill和Agent的区别能上热搜本身就说明大家对这个概念的边界还没形成共识。我自己是这么理解的Agent是那个负责思考、计划、调用工具、执行动作的完整实体它像是一个员工而Skill更像是这个员工手里的一本操作手册加一整套工具包。Agent负责决定什么时候用、怎么用Skill负责提供具体怎么做、需要什么资源、按什么步骤做。Skill不是独立运行的它需要被Agent加载、解析、按需触发。所以Skill文件里除了要写清楚我是干什么的之外还必须写清楚什么场景下该被调用调用时需要哪些输入输出应该是什么格式——这些元信息决定了Agent能不能正确使用它。这和传统意义上的提示词模板有本质区别。提示词模板只是一段文本Agent读了之后知道该怎么做但做得好不好完全取决于模型当时的状态和理解力。Skill则是一套结构化产物它包含元信息Skill描述、触发条件、指令SKILL.md核心指南、资源检查规则表、依赖库清单、以及可执行脚本扫描器、解析器。也就是说Skill把知识和执行绑在了一起尽可能减少模型自由发挥的空间让输出保持稳定、可复现。1.2 Security Audit Skill到底长什么样具体到security-audit-skill它解决的问题很明确让Agent能够针对一个代码仓库或部署环境自动完成基础的安全审计工作。注意基础这个词很关键——它不试图替代专业渗透测试或商业级SAST工具而是把那些高频、重复、有明确规则可循的检查项固化下来让Agent在代码评审、上线前检查、依赖更新评估这些环节里自动带出安全视角。我在设计这个Skill时最先确定的是它的工作范围。审计对象有三类源代码重点是Python和JavaScript项目、依赖清单requirements.txt、package-lock.json这类、以及部署配置文件Dockerfile、docker-compose.yml、nginx.conf这类。对应的检查维度则覆盖硬编码密钥、已知漏洞依赖、危险函数调用、错误配置、权限失当等高频风险点。这个范围不是拍脑袋定的。我翻过不少安全评审报告会发现相当一部分中低级问题都集中在这些类别里。把它们固化成Skill等于把安全评审专家脑子里那套先看什么、重点关注什么的经验变成了每个Agent都可以调用的能力。2. 安全审计场景拆解一个Skill要覆盖哪些具体工作2.1 审计对象与输入形式动手写Skill之前我先把输入这件事想透了。Skill的输入设计直接决定了Agent能不能方便地调用它也决定了审计结果的可信度。security-audit-skill接受的输入是仓库路径。Agent在对话中拿到一个目录路径后Skill会先做一步摸底——扫描目录结构判断这是什么类型的项目找出所有相关的依赖文件、配置文件、源代码文件。这个摸底结果决定了后续怎么审计不是所有项目都一个模板硬套。举个例子如果检测到项目里有requirements.txt或pyproject.tomlSkill就走Python依赖审计分支如果检测到package.json就走JavaScript分支。如果目录下同时有Dockerfile和docker-compose.yml就额外走容器配置检查分支。这种分流设计让Skill面对不同类型项目时都能切中要害而不是泛泛扫一遍。2.2 审计维度和检查项设计审计维度我最终落成了以下五个每个维度下都对应一组可执行的检查项第一个维度是密钥泄露检查。这个最直接也最容易出成果。我会在Skill里内置一份正则规则库用来匹配AWS Access Key、AWS Secret Key、GitHub Token、GitLab Token、Slack Token、Google API Key、通用私钥BEGIN RSA/EC/OPENSSH PRIVATE KEY、数据库连接串含密码等常见机密信息。这个规则库是整个Skill里最核心的知识资产。第二个维度是依赖漏洞核对。实现的思路是解析依赖清单文件后提取依赖名和版本号然后通过OSVOpen Source VulnerabilitiesAPI去查询这些依赖是否存在已知漏洞。这个选择是经过权衡的——OSV提供免费、无需API Key的漏洞查询接口对于开源项目审计来说非常友好而且生态覆盖Google、GitHub、GitLab等多个数据源。第三个维度是危险函数告警。针对Python重点检查eval、exec、pickle.loads、subprocess、shellTrue、os.system等高风险调用针对JavaScript则检查eval、child_process.exec、Function()动态执行等模式。这些检查用简单的AST或正则就能实现但需要小心处理误报——比如有的项目源码里注释提到“这里不能用eval”如果不加排除逻辑就会被误报。第四个维度是依赖锁定状态检查。检查依赖清单里是否使用了精确版本号requirements.txt里有没有出现、这类范围约束。范围版本会让每次部署拉到的依赖版本不确定增加供应链风险。第五个维度是容器配置基线检查。检查Dockerfile里的基础镜像是否固定了tag或digest比如python:3.12-slim是否带具体版本号、是否以root用户运行、docker-compose.yml里的容器是否暴露了非必要端口、环境变量里是否硬编码了敏感信息。这五个维度覆盖了我在实际评审中最常遇到的高频问题而且每个维度都能转换成确定性较高的检查逻辑适合放进Skill里让Agent执行。3. 从零搭建Security Audit Skill文件结构与核心脚本3.1 Skill目录的规范结构Skill的目录结构是Agent能正确加载和使用它的基础。我最后采用的目录结构如下security-audit-skill/ ├── SKILL.md ├── scripts/ │ ├── audit.py │ ├── secret_rules.json │ ├── dependency_check.py │ ├── config_check.py │ └── report_formatter.py └── assets/ ├── dangerous_patterns.json └── container_baseline.jsonSKILL.md是技能的入口文件Agent加载Skill时首先读的就是它。scripts/目录里放的是可执行的审计脚本assets/目录里放的是规则数据文件把它们和数据分离是刻意的——规则会持续更新脚本逻辑相对稳定分开维护会更省心。这个结构对应着一个实际经验Skill越早把指令、代码、数据三者分离后续迭代越轻松。如果你把检查规则直接硬编码在SKILL.md的指令里规则一多会让Agent的指令上下文变得臃肿而且更新规则要改大段文字容易出错。把规则放到数据文件里Agent需要时读文件取规则这个模式清爽得多。3.2 SKILL.md的核心写作要点SKILL.md是整份Skill的说明书Agent靠它来判断什么时候该用这个技能、怎么用。我不建议写太长但关键信息必须到位。我写的SKILL.md核心部分大致是这样的结构--- name: security-audit description: 对代码仓库/部署配置执行安全审计。当用户要求检查代码安全、审计依赖漏洞、扫描硬编码密钥、检查容器配置安全性时使用。输入是仓库路径或文件路径输出是分级安全审计报告。 --- # Security Audit Skill ## 使用场景 - 代码评审阶段的安全检查 - 上线前部署配置审查 - 依赖更新影响评估 - 安全事故后的快速排查 ## 调用步骤 1. 用 scripts/audit.py 扫描目标仓库自动识别项目类型和相关文件 2. 根据识别结果执行密钥扫描、依赖漏洞查询、危险模式匹配、配置审查 3. 汇总所有结果用 report_formatter.py 生成统一格式报告 ## 注意事项 - 优先读取 scripts/ 目录下的脚本执行审计而不是自行推测项目结构 - 规则配置文件位于 assets/脚本会自动加载 - 输出的报告中必须标注每一项的风险等级高/中/低/提示 - 当脚本执行失败或信息不足时明确说明审计盲区这里最核心的技巧是描述要写得像触发条件而不是功能说明。光写本技能用于安全审计是不够的Agent不知道什么时候该调用它。要写明当用户要求X、Y、Z时使用这类触发信号Agent才能在你的对话上下文里准确识别并加载它。3.3 审计脚本把检查项变成可执行代码有了规则和框架真正决定Skill质量的是脚本的健壮性。我写脚本时反复提醒自己这个脚本不只是给我自己用的它会被Agent调用而Agent每次运行的环境都不完全一样所以脚本必须有很强的容错能力。audit.py是整个Skill的总入口。它做的事情是接收一个路径参数递归扫描目录树通过文件扩展名和文件名特征识别项目类型把相关的文件路径收集起来然后分派给不同的检查模块执行。secret_rules.json里存的是密钥检测的正则规则每条规则包含name、pattern、risk_level、message四个字段。比如AWS Access Key的规则长这样{ name: AWS Access Key ID, pattern: AKIA[0-9A-Z]{16}, risk_level: high, message: 检测到可能泄露的AWS Access Key需要立即撤销并轮换 }需要特别说明的是正则检测必然会带来误报和漏报的平衡问题。比如一个示例代码文件里写着AKIA1234567890EXAMPLE这明明是个占位符正则也会报。我的处理方式是在脚本里加了一个排除规则跳过常见示例、测试文件和文档目录examples/、tests/、docs/、.md文件同时对不确定的匹配结果标记为疑似而不是确认。这个折中方案牺牲了一点点召回率但大幅降低了误报对用户的干扰。dependency_check.py负责依赖漏洞查询。核心逻辑是先解析requirements.txt确认依赖名和版本号然后调用OSV API批量查询。调用时需要注意限流问题我会在脚本里加上批次控制和重试机制避免一次提交太多依赖把API打挂。config_check.py负责容器和配置文件的安全基线检查。它会检查Dockerfile里的镜像tag是否带明确版本、是否切换非root用户、docker-compose.yml里端口映射是否合理、环境变量里是否有硬编码密钥等。这些规则放在container_baseline.json里方便后续维护。report_formatter.py负责把各类检查结果汇总成统一格式的报告。我采用的输出格式是Markdown表格加分级标注每一项检查结果都有风险等级、文件位置、详细说明、修复建议四块信息。这样Agent拿到报告后可以直接基于它做进一步分析团队成员看起来也一目了然。4. 实测运行用真实代码库验证Skill效果4.1 测试环境准备为了验证这个Skill的实际表现我做了一次贴近生产环境的测试。测试对象是一个模拟的Web应用仓库差不多接近真实的业务项目一个Python的Flask应用用requirements.txt管理依赖带一个Dockerfile和docker-compose.yml项目里故意埋了几个典型的安全问题。我埋的问题包括一个真实的AWS Access Key格式字符串放在配置文件中、一个存在已知CVE的旧版本Flask依赖、一个eval(received_input)的危险调用、Dockerfile里没有切换非root用户、以及requirements.txt里使用了Django4.0这种范围版本号。测试方式是直接让Agent调用Skill给了一个仓库路径没有更多提示。观察Agent能不能自动加载Skill、按流程执行审计、并且输出结构化的结果。4.2 审计结果分析与误报处理整个审计过程跑完后Skill输出了12条独立发现其中高风险的4条、中风险的3条、低风险的3条、提示类的2条。高风险项里我埋的AWS Key、Flask旧版本、eval调用、root用户运行这四处全部被准确识别到了而且定位精确到具体行号说明正则规则和AST模式匹配的逻辑是有效的。中风险项里没有锁定版本的Django4.0也被抓到了Skill会给出建议锁到精确补丁版本。低风险项包括容器里暴露了5000端口但没有做网络策略限制这类问题。有几个误报值得注意。最典型的是我在项目注释里写了一行注意下面的示例密钥不要用于生产环境AKIA1234567890EXAMPLE——结果规则库还是给它打了疑似标签。虽然写明是疑似不算硬错误但确实会干扰使用。后来我在规则里加上针对注释行的排除逻辑这个问题才算缓解。另一个误报是README文档里引用的一个API端点示例被当成了敏感信息这个我通过把Markdown文档整体移出高置信度扫描范围来解决。这次实测给我最大的感受是Skill的效果不完全取决于规则有多全而取决于场景感知有多准。同样的规则放在代码里是真风险放在文档里是示例放在测试文件里可能是故意构造的数据。如果把所有文件一律等价对待规则越全误报越多最终结果就是用户根本不看报告了。5. 编写过程中最容易踩的坑与目录思路复盘5.1 五个高频踩坑点把security-audit-skill从0到1搭完又迭代了几轮之后我总结了五个最容易翻车的地方写在这里给想做同类Skill的人提个醒。第一个坑是把Skill写得像万能工具。一个Skill想覆盖所有场景结果哪个场景都覆盖不深。一开始我甚至想过把SAST级别的数据流分析也塞进来但后来想明白了Agent Skill的定位不是替代专业安全平台而是把确定性高的检查做成可复用能力。与其什么都沾一点不如聚焦高频场景做深做透。第二个坑是提示词写得模糊Agent不知道什么时候调用。Skill的描述部分不写清触发条件Agent可能在你要求检查一下代码的时候完全想不起来有这么一个技能可用。这一点在前面已经展开过但仍是最高频的坑之一必须反复强调。第三个坑是忽略脚本的容错。Agent调脚本和人在终端敲脚本不一样。人看到异常会停下来思考Agent很多时候会照常继续或者干脆回避脚本直接凭空回答。所以Skill里的脚本必须设计成失败时也给出结构化结果文件不存在就返回明确提示依赖查询超时就跳过该依赖并标注正则解析异常就单独记录不影响整体扫描。我在audit.py里给每一个检查模块都包了try/except保证单个模块崩溃不会影响整体。第四个坑是没有设计功能边界。Skill明确不做什么同样重要。我在SKILL.md里专门加了一段本技能不做什么——不执行动态代码分析、不进行渗透测试、不保证覆盖面等同于专业安全审计。这个设计看着不起眼实际上非常关键。它减少了用户对Skill能力的错误预期也减少了Agent在能力边界外乱尝试造成的风险。第五个坑是输了规则却不维护规则。Skill做出来不是一劳永逸的。依赖漏洞库每天都有新CVE密钥检测也要适配新平台比如现在很多团队用OpenAI Key、Anthropic Key这些密钥格式都得跟进。我把secret_rules.json、container_baseline.json这些规则文件当成活文档来维护每次安全通告里有新类型风险就会考虑要不要沉淀成一条规则。5.2 从能用到好用的迭代方向security-audit-skill目前已经能稳定完成基础审计工作但它距离一个好用的Skill还有一定距离。结合我自己的使用体验下一个版本我会优先做三件事。第一件事是按框架识别不同的安全规则集。目前的危险函数匹配是通用的没区分Flask、FastAPI、Express这些具体框架。不同框架有自己的安全陷阱比如Flask的render_template_string如果不妥善处理就可能引发SSTI按框架加载对应规则会让审计更贴近真实场景误报率也会顺势下降。第二件事是引入语义级别的密钥验证。现在的密钥检测只能做到格式匹配匹配到了就报高置信度但没法验证这个密钥是否真的有效。下一步我想把密钥格式匹配历史泄露库交叉验证上下文评分结合起来进一步降低误报。这个方向技术上可行但需要额外搭建离线库和数据源周期比较长。第三件事是把审计结果做成可与CI/CD集成的机器可读格式。现在输出的是Markdown报告给人看没问题但要在CI流程里做门禁就需要JSON或SARIF这类结构化输出。我计划在report_formatter.py里增加一个JSON输出模式方便下游流水线解析使用。说实话Skill开发这事做到这一版之后我最大的感受是它真正逼着我把零散的安全审计经验结构化了。规则不落地永远只是经验一旦写进Skill文件、配上可执行脚本它就不再依赖某个人记不记得这件事而是每次审计都会按同一标准跑一遍。这种确定性比任何口头流程都有价值。如果你也在琢磨怎么把一个团队里的隐性知识做成Agent可调用的技能我建议别贪大先挑一个过程最固定、判断标准最清晰的场景做成第一个Skill跑通了再扩展。安全审计是我挑的场景你完全可以挑别的。做成一个真正能稳定输出的Skill那个成就感是很实在的。
