如何让你的反重力技能具备可配置性(同时避免出现代码分支问题)
“反重力智能体技能”是一种非常有效的方法,可以帮助你一次性为人工智能智能体设定工作流程,并让它在各种场景中都能被重复使用。你只需编写一个简短的`SKILL.md`文件,将其放入相应的文件夹中,智能体在需要使用时就会自动加载这些配置。 然而,这类技能存在一个隐藏的局限性:它们是静态的。如果你下载了别人编写的技能代码,但希望它的行为有所改变,你就必须手动复制整个代码并进行修改。而且,最近你也应该注意到了,市面上有很多经过分叉修改的“技能版本”,这些版本往往很难进行维护。 在本次教程中,我将向你展示一种解决方法。这种方法可以让任何智能体技能读取特定项目中的配置文件,因此你完全可以使用现有的技能,只需
“反重力智能体技能”是一种非常有效的方法,可以帮助你一次性为人工智能智能体设定工作流程,并让它在各种场景中都能被重复使用。你只需编写一个简短的`SKILL.md`文件,将其放入相应的文件夹中,智能体在需要使用时就会自动加载这些配置。
然而,这类技能存在一个隐藏的局限性:它们是静态的。如果你下载了别人编写的技能代码,但希望它的行为有所改变,你就必须手动复制整个代码并进行修改。而且,最近你也应该注意到了,市面上有很多经过分叉修改的“技能版本”,这些版本往往很难进行维护。
在本次教程中,我将向你展示一种解决方法。这种方法可以让任何智能体技能读取特定项目中的配置文件,因此你完全可以使用现有的技能,只需通过编辑几行YAML格式的配置文件,就能自定义其行为——而无需直接修改原始的技能代码本身。
你会一步步学习如何构建这个系统,进行测试,并了解如何与他人共享这些配置方案,以便其他人也能将其应用到自己的项目中。
目录
你将构建什么
你将构建一个名为“可配置智能体技能”的小型工具模块。它由三个部分组成:
一个Python脚本`resolve_config.py`,它的作用是将技能的默认设置与项目特定的配置合并,并输出最终结果。
一种约定机制:每个技能都会包含两个文件:一个是`config.default.yaml`文件,其中包含了可调整的参数;另一个是`SKILL.md`文件,用于说明智能体应如何根据这些参数来执行操作。
每个项目还会对应一个配置文件`.agent/skills.config.yaml`,使用者可以在此文件中设置自己需要的参数值。
最终,你将得到一个功能完备的“`git-commit-formatter`技能模块”——某个团队可以使用它以传统的提交格式进行开发,而另一个团队则可以将它切换到使用gitmoji符号的模式来进行操作。无论哪种方式,所有团队使用的都是完全相同的代码文件,根本不存在任何分叉版本的问题。
先决条件
要顺利学习本内容,您需要具备以下条件:
已安装 Google Antigravity IDE、CLI 或 SDK。其中任意一种均可使用,因为这些工具所使用的文件格式都是相同的。
已安装 Python 3 并安装了 PyYAML。您可以通过
python -m pip install pyyaml命令来安装 PyYAML。应对终端操作和 YAML 格式有一定的了解。不过无需成为这些领域的专家即可。
如果您之前从未编写过代理技能脚本,接下来的两个章节将帮助您快速入门。
什么是 Antigravity 代理技能?
在 Antigravity 中,一个“技能”实际上是一个文件夹,其中包含一个 SKILL.md 文件,以及一些可选的脚本、模板或示例代码。SKILL.md 文件的开头部分会包含简短的 YAML 格式信息(如技能的名称和描述),随后则是用纯 Markdown 编写的指令。
重要的是:这些技能是按需加载的。代理程序在最初只会读取每个技能的描述部分;只有当用户的请求与这个描述匹配时,才会加载完整的指令并执行它们。这样的设计有助于保持代理程序的工作状态简洁且专注。
以下是一个简单的示例:这个技能用于确保提交信息遵循“常规提交规范”:
---
name: git-commit-formatter
description: 使用常规提交规范来格式化 Git 提交信息。当用户需要提交更改或编写提交消息时,可以使用此技能。
---
# Git 提交信息格式化规则
在编写提交消息时,请遵循常规提交规范:
`type(scope): description`
允许的类型包括:feat、fix、docs、style、refactor、perf、test、chore。
将这个脚本放入您的技能文件夹中,然后让代理程序执行“提交这些更改”的操作,它就会生成格式正确的提交信息。很简单且非常实用,对吧?
为什么静态技能会带来问题
现在仔细看看这个示例技能。其中允许的类型(如 feat、fix 等)是直接写在指令中的。
这种设计在大多数情况下没有问题,但当有人需要一些不同的设置时,就会出现问题。也许您的团队还使用了其他类型的操作,比如 ci;也许您更喜欢在提交信息前加上表情符号;又或者您希望每个提交都必须指定具体的操作范围。
对于静态技能来说,要想实现这些需求,唯一的办法就是复制整个脚本并修改其中的 Markdown 代码。当整个团队都在使用这样的静态技能时,每个人最终都会拥有自己修改过的版本。而当原作者发布了更新内容时,其他人的版本却无法得到更新。这样一来,这种技能就不再是一种可以被大家共享的资源,而变成了每个人都在自行修改的东西。
问题的关键在于:技能的逻辑部分应该是所有人都可以共享的,而其具体设置则应该由每个项目根据自身需求来控制。那么,我们该如何解决这个问题呢?
可配置技能解决方案
这个思路很简单。与其在指令中硬编码设置,不如让该技能本身来处理这些设置:
将其设置及其默认值保存在一个单独的
config.default.yaml文件中。在执行任何操作之前,会先读取合并后的配置文件(包括默认值以及项目级别的自定义设置)。
项目级别的自定义设置保存在名为 .agent/skills.config.yaml 的文件中,该文件位于用户项目的根目录下:
# .agent/skills.config.yaml
# 请在您的项目中编辑此文件,而不是对所有技能进行全局配置修改
git-commit-formatter:
style: gitmoji
extra_types: [ci, build]
scope_required: true
使用这种方法非常简单:只需将相应的技能添加到项目中,设置一些关键参数即可完成配置。该技能自身的文件永远不会被修改。
为了让这个机制正常工作,你需要编写一个脚本,该脚本能够读取这两个文件,将它们合并后传递给代理程序。让我们一起来编写这个脚本吧。
如何构建配置加载器
创建一个名为 resolve_config.py 的文件。它的作用是:根据技能名称读取该技能的 config.default.yaml 文件,再查找用户项目中的 .agent/skills.config.yaml 文件,并将两者合并,确保用户的自定义设置优先得到应用。
首先需要编写一个用于深度合并配置文件的辅助函数。这个函数是整个加载器的核心:
def deep_merge(base, override):
"""递归地将 override 的内容合并到 base 中。
字典类型的数据会按键进行合并;其他类型的数据(如标量、列表)则会被完全替换为 override 中对应的值。
"""
if isinstance(base, dict) and isinstance(override, dict):
merged = dict(base)
for key, value in override.items():
merged[key] = deep_merge(merged[key], value) if key in merged else value
return merged
return override
注意这里的设计意图:字典类型的数据会按键进行合并,而列表类型的数据则会被完全替换,而不会被追加到原来的列表中。这样的设计能够保证程序的行为具有可预测性。如果你需要同时保留默认值和用户自定义设置,可以在技能配置文件中使用 extra_types 这个键,如下例所示。
接下来,脚本需要找到用户项目中的配置文件。加载器会从当前目录开始查找名为 .agent/skills.config.yaml 的文件:
from pathlib import Path
def find_project_config(start: Path):
"""从指定路径开始向上查找 .agent/skills.config.yaml 文件."""
start = start.resolve()
for folder in [start, *start.parents]:
candidate = folder / ".agent" / "skills.config.yaml"
if candidate.is_file():
return candidate
return None
现在把所有这些部分组合起来。加载器会先找到技能的默认配置值,然后读取用户为该技能指定的自定义设置,将两者合并后返回最终结果:
import sys, yaml
from pathlib import Path
def resolve(skill_name, skill_dir, project_root):
defaults = yaml.safe_load((Path(skill_dir) / "config.default.yaml").read_text()) or {}
user_path = find_project_config(Path(project_root))
user_all = yaml.safe_load(user_path.read_text()) if user_path else {}
user_cfg = (user_all or "").get(skill_name, {}) or {}
return deep_merge(defaults, user_cfg)
这样就完成了整个流程。示例仓库中的完整版本还增加了命令行界面、JSON格式的输出结果以及清晰的错误提示信息,但上述逻辑才是真正需要的部分。
如何使技能具备配置功能
现在,你将把这个静态的提交技能改造成一个可配置的技能。这需要两个文件。
首先,在该技能所在的目录下创建config.default.yaml文件。这份文件会列出所有的设置选项以及默认值,这样即使用户没有进行任何配置,该技能也能正常工作:
# git-commit-formatter技能的默认配置。
style: conventional # 传统格式 | gitmoji格式
types: # 允许使用的提交类型
- feat
- fix
- docs
- style
- refactor
- perf
- test
- chore
extra_types: [] # 额外添加的类型,会叠加在`types`之上
scope_required: false # 如果设置为true,则必须指定范围:type(scope): ...
max_subject_length: 72 # 主题行的长度上限
其次,更新SKILL.md文件,使其第一条指令就是读取配置并应用这些设置。这一点非常重要:你是在告诉代理在执行其他任何操作之前先读取配置信息:
---
name: git-commit-formatter
description: 将git提交信息格式化为团队选定的样式(传统格式或gitmoji格式)。当用户需要提交更改或编写提交信息时,可以使用这个技能。该技能会读取每个项目特定的配置设置,因此团队无需直接修改此文件即可自定义提交格式。
---
# Git提交信息格式化工具(可配置)
## 第一步——读取配置信息(务必先执行这一步)
运行加载程序并查看其输出结果:
`python scripts/resolve_config.py git-commit-formatter --project-root .`
然后应用这些配置设置:
- `style`:选择“conventional”或“gitmoji”格式。
- `types` + `extra_types`:所有允许使用的提交类型。
- `scope_required`:如果设置为true,则必须指定使用范围。
- `max_subject_length`:主题行的长度上限。
## 第二步——编写提交信息
从`types` + `extra_types`中选择主要的提交类型,按照选定的`style`格式生成主题行,并确保遵守`scope_required`和`max_subject_length`的限制。
这种“让代理运行脚本并执行其输出结果”的设计方式,也是Antigravity自身所使用的验证技能所采用的机制。这种方式能够确保行为的一致性,而不会让模型依赖于内存中的临时数据。
注意extra_types这个设置是如何解决类型扩展问题的。默认的类型列表保持不变,用户自定义的额外类型会被直接添加到默认列表中。因此,即使添加了ci这样的类型,也不需要进行任何修改即可。
如何为项目添加自定义配置选项
假设你希望使用带有两种额外类型的gitmoji格式来进行提交操作。那么只需在项目中创建一个配置文件即可:
# .agent/skills.config.yaml
git-commit-formatter:
style: gitmoji
extra_types: [ci, build]
scope_required: true
你只需要修改三行配置内容,而无需打开任何代码文件或进行任何修改。下次代理执行提交操作时,就会使用这些配置设置。
而对于那些没有配置文件的项目来说,它们仍然会使用默认的“常规提交”格式。这样,你就能够通过一个配置文件来实现多种不同的行为。
如何测试你的可配置技能
你不需要让代理来检查合并操作是否正常进行。可以直接运行加载工具并查看输出结果即可。
如果没有进行任何覆盖设置,那么系统会使用默认配置:
$ python scripts/resolve_config.py git-commit-formatter --project-root .
style: conventional
scope_required: false
...
现在,加入上一节中提到的.agent/skills.config.yaml文件中的配置设置,然后再运行一次加载工具:
$ python scripts/resolve_config.py git-commit-formatter --project-root . --print-sources
style: gitmoji
scope_required: true
extra_types:
- ci
- build
types:
- feat
- fix
- docs
...
此时,style的值被设置为gitmoji,scope_required被设置为true,而那些额外的类型也会被正确显示出来(同时基础的types列表保持不变)。这证明了配置修改确实达到了预期的效果。
编写一个自动测试脚本也是很有必要的。这样,即使未来加载工具发生任何变化,也不会影响到合并操作的正常进行。测试脚本可以在临时文件夹中创建虚拟的技能配置和项目设置,然后运行加载工具,从而验证用户自定义的配置是否成功覆盖了默认值,同时确认默认值是否依然完好无损。
另外两个示例技能
这种配置模式适用于任何类型的技能。下面再举两个例子来进一步说明这一点的适用性。
变更日志生成器
这个工具的config.default.yaml文件允许用户指定输出格式(例如是否使用“keepachangelog”格式)、需要包含哪些类型的提交信息,以及是否将提交哈希链接到仓库地址。一个项目可以使用这种配置生成按类型分类的正式变更日志,而另一个项目则可能选择生成简单的列表格式。其实,这仍然是同一个技能,只是使用了不同的配置而已。
# changelog-generator config.default.yaml (excerpt)
format: keepachangelog # 可选格式:keepachangelog | conventional | simple
include_types: [feat, fix, perf]
include_authors: false
repo_url: "" # 如果设置了这个参数,提交哈希将会链接到仓库地址
许可证头添加工具
该工具的配置文件中会指定许可协议类型(Apache-2.0、MIT或自定义格式)、版权持有者,以及文件扩展名与注释格式之间的对应关系。企业只需在项目配置中设置一次这些参数,之后新生成的文件就会自动添加正确的许可证头和相应的注释格式,而无需手动进行任何修改。
# license-header-adder config.default.yaml (示例)
license: apache-2.0 # 可选值:apache-2.0 | mit | custom
holder: "你的名称或组织名"
year: auto # 自动获取当前年份
关键在于:几乎任何工具或功能都包含一些固定的配置选项。当你把这些配置选项放入config.default.yaml文件中,这些原本一次性的配置就会变成一个可以被所有人重复使用并根据需求进行调整的工具。
如何与他人分享你的代理技能
一旦你的代理技能遵循了统一的规范,它们就可以组合成更强大的功能。为了让他人更容易采用这些技能,你需要做到以下几点:
确保每个技能都是独立可用的:在每个技能的
scripts/文件夹中放置一份resolve_config.py文件,这样别人就可以将某个技能文件夹复制到任何地方,而它依然能够正常使用。为所有的配置项编写说明:在
SKILL.md文件中详细解释每个配置项的作用,让用户清楚知道自己可以调整哪些内容。发布一个索引文件:创建一个简单的
index.json文件,列出所有技能的名称、路径和配置项,这样别人就能轻松了解你的成果,并根据自己的需求进行扩展。
因为大家都遵循“先读取配置文件”的规则,所以任何人都可以发布符合规范的技能。每一个可配置的技能都会让整个生态系统变得更加有用。通过发布这样的技能,你其实也在推广一种可供他人进一步开发的标准。
总结
你最初使用的是一个行为固定的静态技能,后来将其改成了可以通过单个项目文件进行配置的动态技能。
整个设置过程非常简单:只需要一个合并函数、一套统一的规范,以及每个技能对应的config.default.yaml文件即可。
这种设计也改变了技能的共享方式——不再需要通过分支来修改某个设置,而是可以直接调整自己的配置文件。这样,所有的改进都会惠及所有使用者,而且每个人仍然能够得到自己想要的功能。
如果你想尝试这个方法,可以按照本教程中的步骤制作git-commit-formatter技能,将其添加到你的Antigravity技能文件夹中,并为该项目创建一个.agent/skills.config.yaml文件。然后将style参数从conventional改为gitmoji,你就会发现同一个技能会呈现出不同的表现效果。
接下来,你可以尝试将自己的某个技能也设置为可配置的。把那些固定的配置选项提取出来放入config.default.yaml文件中,让用户能够根据自己的需求进行自定义设置。
完整的示例代码(包括加载器、相关的测试用例以及三个示例技能)都托管在 GitHub 上,地址为 github.com/keepdeploying/configurable-agent-skills。
感谢您的阅读。如果您自己也开发出了可配置的技能,请分享出来吧。让我们一起帮助这个生态系统不断发展壮大。 相关文章
如何使用 Fastlane 和 GitHub Actions 自动化Flutter应用的发布流程,以便将其分发到 Firebase App Distribution、Google Play、TestFlight 以及 App Store Connect平台上
想象一下:现在是周五下午4点,你的团队刚刚完成了本次迭代周期的最后一项功能开发。但产品经理要求在当天结束前通过TestFlight发送一个新的版本,这样客户就可以在周末进行测试。 你打开Xcode,等待代码打包完成,处理一个昨天还不存在的签名错误,修复问题后重新打包代码,再次等待上传,然后等待App Store Connect进行处理。接着你需要为Android版本重复这些步骤,不过这次是通过Android Studio来操作的。你需要签署APK文件,登录Firebase App Distribution平台,将文件上传进去,添加测试人员,编写发布说明,最后点击发送按钮。 现在已经是下午6点4
阅读全文
如何利用Claude与MCP构建以隐私保护为首要目标的医学图像去标识化系统
想象一下,让人工智能助手来处理成千上万的医学图像。它能够运行整个处理流程,跟踪进度,总结每一项决策,并告诉你哪些文件需要人工审核——而这一切过程,它根本不需要看到任何患者的个人信息。 乍一听,这似乎是不可能的。因为通常情况下,人工智能助手需要访问它们所要帮助处理的数据。 在这个教程中,你将构建一个不会直接查看敏感医学图像的人工智能系统。相反,它会通过精心设计的工具来协调整个去标识化处理流程,确保患者的所有数据都保留在你的机器上。 使这一切成为可能的技术是“模型上下文协议”(Model Context Protocol,简称MCP)。这一开放标准允许人工智能模型调用外部工具,而不仅仅依赖它们内置
阅读全文
如何从家庭实验室环境逐步搭建出一个可用于生产环境的DevSecOps平台,并最终将其迁移至AWS环境——全书详解
在这本书中,你将从零开始构建一个金融科技交易账本,并逐步将其发展成一个可用于生产环境的DevSecOps平台。你还需要将其部署在AWS上。 该应用程序能够处理贷方和借方交易,触发合规性警报,并将所有数据存储在数据库中。你需要自行搭建相关的基础设施:包括自动化系统、扫描工具、政策执行机制、秘密管理机制、威胁检测系统以及监控系统。 完成整个开发过程后,你在面试中就可以详细解释每一个决策的来龙去脉,因为这些决策都是你亲自做出的。 这份指南并不会直接提供现成的解决方案。它会让你先自己探索和理解每个问题,然后再介绍相应的解决工具。 所有的代码、配置文件、脚本以及分步操作说明都存储在配套的仓库中。在开始之
阅读全文
如何使用JavaScript开发一款基于浏览器的PDF颜色叠加工具
有时你并不想更改PDF文件的实际内容,只是想要在文档的某些部分或全部上添加一层彩色背景而已。 这种方法在制作带有品牌标识的报告、为文档添加彩色背景、突出显示打印版内容、生成设计样稿、应用水印效果,或是为演示文稿准备材料时都非常有用。 “PDF颜色覆盖工具”能够实现这一功能——它在PDF页面上叠加一层半透明的彩色层,同时保留下方的原始文本、图片和布局。 用户无需使用图形设计软件逐页进行手动编辑,只需上传PDF文件,选择所需的覆盖颜色、调整透明度、选择混合模式,指定颜色层的显示位置,预览效果后即可下载修改后的文档。 在本教程中,你将学习如何使用JavaScript来开发这个工具。用户完全可以无需将
阅读全文