
ADK-python Skills 与 SkillToolset 实战程序化 Skill、目录加载与动态工具激活【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-pythonSkills 是 ADKAgent Development Kit中用来扩展 Agent 能力的专用文件夹内含指令、参考资料、资产与可执行脚本Agent 会根据用户查询动态搜索、加载并运行其中的资源。本文以仓库中的官方样例contributing/samples/environment_and_skills/skills/README.md及其配套实现为核心完整讲解如何在 Python 中以编程方式声明 Skill、如何从目录结构加载 Skill、如何通过SkillToolset将 Skill 注册进 Agent并深入源码揭示adk_additional_tools动态工具激活、脚本执行与三级渐进披露机制的底层原理读完即可在 ADK 项目中落地一套可复用的 Skill 体系。Skills 是什么一个自带指令、资料与脚本的能力包在 ADK 中Skill 是专门化的指令、参考资料、资产和脚本组成的文件夹集合用于扩展 Agent 的能力边界。与把全部指令硬编码进系统提示词不同Skill 采用按需加载策略Agent 先看到每个 Skill 的名称与描述再根据用户问题决定是否加载完整指令、读取参考资料、甚至运行其中捆绑的脚本。从数据模型看src/google/adk/skills/models.py一个完整的 Skill 由三个层级构成层级数据模型内容加载时机L1Frontmatter名称、描述、许可证、兼容性、metadata等元数据用于 Skill 发现discoveryL2Skill.instructionsSKILL.md正文中的 Markdown 指令触发 Skill 时加载L3Resourcesreferences/补充说明、assets/数据资产、scripts/可执行脚本按需加载Skill模型同时持有这三部分并提供了便捷属性name与description直接透传 frontmatter 中的值。这套 L1/L2/L3 设计正是渐进披露progressive disclosure的载体模型不必在每一轮都背负所有 Skill 的完整内容只在需要时才逐层取用从而有效控制上下文占用。样例全景一个会查客服时间、查天气的 skills_agent本文围绕的官方样例位于 contributing/samples/environment_and_skills/skills/核心实现是 agent.py它演示了四条关键能力程序化 Skills直接在 Python 中构建support-hours-skill基于目录的 Skills从目录结构加载weather-skillSkill 元数据与附加工具通过adk_additional_tools声明 Skill 依赖的工具使这些工具仅在对应 Skill 被激活时才动态出现脚本执行借助代码执行器Code Executor运行 Skill 内捆绑的 Python 脚本。官方示例输入与预期行为README 提供了四组输入覆盖了 Skill 体系的全部典型路径用户输入触发链路涉及能力What are the support hours for Tokyo?触发support-hours-skill调用get_timezone并读取support_policy.txt程序化 Skill 动态工具 参考资料What is the current weather in SF?加载weather-skill读取weather_info.md参考文件目录 Skill 参考资料Can you fetch the current humidity for Mountain View?通过run_skill_script执行scripts/get_humidity.py脚本执行What is the wind speed in Seattle?加载weather-skill动态激活并调用get_wind_speed动态工具激活架构图README 中的架构图清晰展示了 Agent、SkillToolset 与各 Skill 及其资源之间的引用关系即Agent 只直接持有SkillToolset一个工具具体能做什么完全由 toolset 背后的 Skill 集合决定。如何在 Python 中以编程方式声明一个 Skill当 Skill 内容较短、由程序动态生成、或来自数据库而不想维护一整套目录时可以直接用models.Skill在代码中构造。样例中的support-hours-skill就是典型from google.adk.skills import models support_hours_skill models.Skill( frontmattermodels.Frontmatter( namesupport-hours-skill, descriptionA skill to check customer support hours..., metadata{adk_additional_tools: [get_timezone]}, ), instructionsStep 1: Look up the timezone... Step 2: Read references/support_policy.txt..., resourcesmodels.Resources( references{ support_policy.txt: Customer support is available Monday through Friday..., }, ), )完整版见 agent.pyinstructions被设计为三步式操作指引先用get_timezone查时区、再读references/support_policy.txt理解客服政策、最后结合时区向用户解释支持时间references则以键值对形式内嵌了策略文本——无需真实文件模型也能通过load_skill_resource读取到它。Frontmatter 字段与校验规则从 models.py 的Frontmatter实现看字段如下字段类型默认值说明namestr必填kebab-case或启用特性后的 snake_case标识符最长 64 字符且需与目录名一致descriptionstr必填说明 Skill 的用途与使用时机最长 1024 字符licensestr \| NoneNoneSkill 内容的许可证ADK 不解释该字段compatibilitystr \| NoneNone兼容性自由文本最长 500 字符allowed_toolsstr \| NoneNone预批准工具的空格分隔列表同时接受 YAML 键allowed-toolsADK 仅存储透传不强制实施metadatadict[str, Any]{}客户端专属属性ADK 会读取其中的adk_additional_tools与adk_inject_state两个键模型校验值得注意name会被 NFKC 归一化后匹配^[a-z0-9](-[a-z0-9])*$kebab-case不允许前导、尾随或连续的分隔符metadata校验器要求adk_additional_tools必须是字符串列表adk_inject_state必须是布尔值否则直接抛ValueErrormodels.py。关键提示description是模型决定要不要用这个 Skill的唯一依据应写成做什么、何时用而不是一行标题。此外从 docs/guides/skills/skill/index.md 的说明可知若启用了上下文缓存context_cache_config使用adk_additional_tools激活新工具会改变工具列表导致激活后的下一次请求缓存未命中。如何从目录加载一个 SkillSkill 也可以组织成文件夹每个文件夹必须包含一个SKILL.md文件。样例中的weather-skill目录结构如下见 contributing/samples/environment_and_skills/skills/skills/weather-skill/weather-skill/ ├── SKILL.md ├── references/ │ └── weather_info.md └── scripts/ └── get_humidity.py对应加载代码from google.adk.skills import load_skill_from_dir weather_skill load_skill_from_dir( pathlib.Path(__file__).parent / skills / weather-skill )SKILL.md 的写法与解析规则weather-skill的 SKILL.md 展示了标准格式YAML frontmatter以---包裹声明name、description与metadata.adk_additional_tools正文则是给模型的多步指令。解析逻辑位于 src/google/adk/skills/_utils.py 的_parse_skill_md_content文件必须以---开头frontmatter 必须是可被yaml.safe_load解析的映射随后_load_skill_from_dir会递归加载references/、assets/、scripts/三个子目录——UTF-8 可解码的文件存为str否则存为bytes这保证了 PNG 等二进制资产能完整存取scripts/下的源码则包装成Script对象非 UTF-8 的脚本会被记录警告并跳过src/google/adk/skills/_utils.py。_load_skill_from_dir还会做一道硬性校验frontmatter 中的name必须与目录名完全一致否则抛出ValueErrorsrc/google/adk/skills/_utils.py。目录名与 Skill 名不一致是新手最容易踩的坑。参考资料与脚本内容references/weather_info.md查看原文提供旧金山的静态天气信息scripts/get_humidity.py查看原文是一个接收--location参数、模拟返回湿度数据的命令行脚本负责演示运行 Skill 内脚本的能力。注册 SkillToolset 并挂载到 AgentSkillToolset用于把全部 Skill 与动态工具打包然后作为tools列表中的一项传给 Agentagent.pyfrom google.adk.tools.skill_toolset import SkillToolset from google.adk.code_executors.unsafe_local_code_executor import UnsafeLocalCodeExecutor my_skill_toolset SkillToolset( skills[support_hours_skill, weather_skill], additional_tools[GetTimezoneTool(), get_wind_speed], code_executorUnsafeLocalCodeExecutor(), ) root_agent Agent( nameskills_agent, tools[my_skill_toolset], )其中GetTimezoneTool是继承BaseTool的异步工具声明了get_timezone的 FunctionDeclarationrun_async返回模拟时区结果get_wind_speed则是普通 Python 函数两者都会在对应 Skill 被激活时才真正进入模型视野详见下文。SkillToolset 构造参数从 src/google/adk/tools/skill_toolset.py 的SkillToolset.__init__看它支持以下参数参数类型默认值说明skillslist[models.Skill] \| NoneNone要注册的 Skill 列表重名会抛ValueErrorregistrySkillRegistry \| NoneNone可选 Skill 注册表配置后启用search_skills动态发现code_executorBaseCodeExecutor \| NoneNone用于执行 Skill 脚本的代码执行器environmentBaseEnvironment \| NoneNone用于执行脚本的环境与code_executor二选一同时指定会报错skills_folderPath \| str \| NoneNoneSkill 在环境文件系统中的物化路径绝对路径需搭配environmentscript_timeoutint300shell 脚本执行的超时秒数subprocess.run的 timeoutPython 脚本不受此限制additional_toolslist[ToolUnion] \| NoneNone在对应 Skill 激活时提供给模型的附加工具BaseTool、BaseToolset或普通函数tool_name_prefixstr \| NoneNone工具名前缀tool_filterToolPredicate \| list[str] \| NoneNone工具筛选条件additional_tools中的普通函数会被自动包装为FunctionToolskill_toolset.py所以样例里get_wind_speed作为普通函数传入即可直接使用。adk_additional_tools按需激活的动态工具这是本样例最有代表性的机制。support-hours-skill的 frontmatter 中声明metadata{adk_additional_tools: [get_timezone]}weather-skill的 SKILL.md 中声明get_wind_speed。其工作流程如下对应源码 skill_toolset.pyLoadSkillTool.run_async成功加载某个 Skill 后会把该 Skill 名写入 session state 的_adk_activated_skill_{agent_name}键skill_toolset.py下一次SkillToolset.get_tools调用时_resolve_additional_tools_from_state读取已激活的 Skill 名汇总其adk_additional_tools声明的工具名在additional_tools提供的候选工具中按名匹配把命中项追加到动态工具列表并检测与核心工具的重名冲突skill_toolset.py。这带来一个关键收益get_timezone、get_wind_speed这类工具不会在每一轮都出现在模型的工具列表中只有当相关 Skill 被激活后才注入既避免工具列表臃肿也让模型的工具选择更聚焦。需要说明的是若声明了工具名但在additional_tools中未提供匹配项该名字会被静默忽略、不会报错因此拼写需与函数名严格一致参见 docs/guides/skills/skill/index.md。底层五大工具与三级渐进披露Skill 一旦进入SkillToolsettoolset 就会向模型发布四个核心工具配置了 registry 时还有第五个search_skills定义见 skill_toolset.py工具名作用对应层级list_skills以 XML 格式列出所有 Skill 的名称与描述available_skillsskillname...见 prompt.pyL1load_skill加载指定 Skill 的完整指令返回skill_name、instructions、frontmatterL2load_skill_resource读取 Skill 内references/、assets/、scripts/下的单个文件L3run_skill_script执行 Skillscripts/目录下的脚本L3search_skills可选通过SkillRegistry做语义/关键词检索动态发现 Skill注册表模型按list_skills→load_skill→load_skill_resource/run_skill_script的顺序逐层取用。SkillToolset.process_llm_request会把一段 Skill 使用指引注入系统指令_build_skill_system_instructionskill_toolset.py其中明确规定加载 Skill 后必须在同一轮内继续完成指令所要求的工具调用不能以空回复结束回合load_skill_resource只能访问 Skill 捆绑文件不得用于读取用户运行时提供的文档。脚本执行机制与安全边界run_skill_script的执行路径skill_toolset.py为校验skill_name与file_path必填参数args字典或字符串列表、short_options、positional_args之间存在互斥约束定位脚本支持scripts/get_humidity.py这类带前缀路径也支持裸文件名解析执行器优先用 toolset 的code_executor其次回退到 Agent 的code_executor两者皆无则返回NO_CODE_EXECUTOR错误_SkillScriptCodeExecutor把 Skill 的全部 references/assets/scripts 物化到一个临时目录带路径穿越防护阻止..与绝对路径逃逸再通过runpy.run_pathPython或subprocess.run.sh/.bash受 300 秒超时约束执行。支持的脚本类型为.py、.sh、.bash其他扩展名返回UNSUPPORTED_SCRIPT_TYPE。此外load_skill_resource与run_skill_script都内置了幻觉防护同一 invocation 内资源/脚本查找连续失败会从软错误升级为RESOURCE_NOT_FOUND_FATAL/SCRIPT_NOT_FOUND_FATAL要求模型停止重试并向用户报告防止模型对路径进行无休止的猜测skill_toolset.py。安全警示样例使用UnsafeLocalCodeExecutorREADME 与 agent.py 均明确标注其存在安全隐患不应在生产环境使用。生产场景应选用沙箱化执行器或配置environment例如基于容器的执行环境二者在SkillToolset构造时二选一。用测试数据验证完整调用链样例的 tests/ 目录提供了四份 JSON 会话记录support_hours.json、current_weather.json、current_humidity.json、wind_speed.json可作为 Agent 测试的 golden 数据。以 current_humidity.json 为例事件流完整呈现了渐进披露过程用户提问 Can you fetch the current humidity for Mountain View?模型调用list_skills得到两个 Skill 的名称与描述XML 格式模型调用load_skill(skill_nameweather-skill)返回 frontmatter含adk_additional_tools: [get_wind_speed]与分步指令同时 session state 记录_adk_activated_skill_skills_agent: [weather-skill]模型调用run_skill_script(skill_nameweather-skill, file_pathscripts/get_humidity.py, args{location: Mountain View})脚本输出Fetching live humidity for Mountain View... 45% (Simulated)状态为successAgent 汇总输出 The current humidity in Mountain View is 45% (Simulated).而 wind_speed.json 则演示了动态工具激活的另一半load_skill之后模型直接调用get_wind_speed(locationSeattle)该工具由adk_additional_tools注入返回 The wind speed in Seattle is 10 mph.。源码层面仓库的单元测试覆盖了上述机制的多个侧面tests/unittests/tools/test_skill_toolset.py 验证了 SkillToolset 的初始化约束code_executor与environment互斥、skills_folder必须为绝对路径、重复 Skill 名报错、附加工具从 state 解析、脚本参数校验与错误升级逻辑tests/unittests/skills/test__utils.py 覆盖了load_skill_from_dir的目录加载、frontmatter 解析与 zip/GCS 加载路径。阅读这些测试可以快速理解各边界行为。更多加载方式与相关资源除load_skill_from_dir之外src/google/adk/skills/init.py 还导出了如下 APIload_skill_from_dir_async/load_skills_from_dir/load_skills_from_dir_async批量加载目录树下所有含 SKILL.md 的子目录异步版本通过asyncio.to_thread在 worker 线程执行不阻塞事件循环src/google/adk/skills/_utils.pyload_skill_from_gcs_dir/list_skills_in_gcs_dir含异步版本从 GCS 存储桶加载/列出 Skill需要安装google-cloud-storage或google-adk[gcp]SkillRegistrySkill 注册表配合search_skills工具做动态发现参考 src/google/adk/skills/skill_registry.pyFrontmatter/Resources/Script/Skill四个数据模型可直接导入用于程序化构造。若想进一步深入推荐阅读仓库中的 docs/guides/skills/skill/index.mdSkill 的完整指南含 frontmatter 字段总表、adk_inject_state会话状态注入、Resources 访问器说明以及 docs/guides/skills/skill_registry/index.md注册表机制。在 contributing/samples/environment_and_skills/ 目录下还有skills_agent、skills_agent_gcs、skills_inject_state等进阶样例分别演示 Skill Agent 化、GCS 托管与状态注入场景可以作为本文场景的延伸实践。小结四步接入 Skill 能力把本样例的实践提炼成接入清单声明或组织 Skill内容简短用models.Skill程序化构造内容较多则建目录务必保证SKILL.md的 frontmattername与目录名一致注册工具集用SkillToolset(skills[...], additional_tools[...])打包需要跑脚本时配置code_executor或environment生产环境禁止使用UnsafeLocalCodeExecutor挂载 Agent把 toolset 实例放入Agent(tools[...])并按需通过metadata.adk_additional_tools声明动态工具验证链路参照 tests/ 中的 JSON 会话记录检查list_skills → load_skill → load_skill_resource/run_skill_script全链路输出。掌握这四步你就拥有了让 Agent按需取用专业能力包的完整工具箱指令按需加载、资料按需读取、脚本按需执行、工具按需激活一切尽在SkillToolset的掌控之中。【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考