1. 项目概述为什么你需要一个“技能插槽”而不是一整本说明书我第一次在生产环境里给AI代理加第7个功能时系统提示词已经膨胀到2800多token。那不是一段指令那是一份《AI代理使用手册修订版第三章第五节附录B》。用户问“怎么查数据库”代理先得花半秒把整本手册翻一遍再从“数据库查询规范v2.3.1”那一章里定位到对应段落——这还没算上它自己可能记混了“v2.3.1”和“v2.3.0”的区别。更糟的是当产品同学说“再加个PDF解析功能”时我盯着那个密密麻麻的prompt手指悬在键盘上迟迟不敢敲下回车。不是不会写是写了之后谁来维护谁来测试谁来确保新加的PDF解析说明不会让原本好好的Web搜索逻辑突然失灵这种“把所有能力塞进一个大口袋”的做法在小项目里是权宜之计在真实业务里就是定时炸弹。pydantic-ai-skills就是为拆掉这颗炸弹而生的。它不教你怎么做agent也不重写LLM调用逻辑它只解决一个极其具体、极其痛的问题如何让AI代理的能力像手机App一样按需安装、即点即用、互不干扰。你不用再把“怎么连数据库”“怎么调API”“怎么生成报告”的全部细节一股脑塞进系统提示词里。你只需要告诉代理“嘿你有这些技能菜单——查文献、算数学、读文档。等真要用的时候再把对应技能的说明书完整加载进来。” 这就是它说的“progressive disclosure”渐进式披露一个听起来很学术的词落地下来就是三件事发现技能、按需加载、隔离执行。它面向的是所有正在用 Pydantic AI 框架构建真实Agent的开发者尤其是那些已经踩过“prompt爆炸”坑、正被维护成本压得喘不过气的团队。它不是锦上添花的玩具而是帮你把Agent从“能跑起来”推进到“能长期维护、能快速迭代”的关键基础设施。关键词Towards AI - Medium提示我们这个项目诞生于一线工程实践它的价值不在于理论有多炫而在于你今天下午就能把它集成进现有代码明天上线后prompt token消耗直接降掉40%。2. 核心设计思路从“大杂烩”到“模块化插件”的范式转移2.1 为什么必须放弃“全量注入”模式在深入pydantic-ai-skills之前得先彻底搞清楚它要革掉的“旧命”是什么。传统Agent能力扩展本质上是一种“静态编译”思维所有你能想到的功能都提前写死在系统提示词里。比如你想让Agent能查天气就在prompt里加一段“当你需要提供天气信息时请调用weather_api(query: str)函数参数query是城市名返回JSON格式……”。这看起来很清晰但问题藏在细节里。第一可维护性灾难。当天气API升级了你需要改prompt当你要支持新城市你得在prompt里追加地理编码规则当你要加个“未来三天预报”功能你又得往prompt里塞几百字。每一次修改都意味着整个Agent的“大脑”要重新学习一遍哪怕99%的内容都没变。第二推理效率低下。GPT-4o这类模型处理长上下文是有显著开销的。你的2800token prompt哪怕用户只问了一个简单问题模型也得先把这2800token全部“消化”一遍才能开始思考。这就像你去图书馆借一本书管理员非得先把整个国家图书馆的目录卡片都摊在你面前让你自己找哪张卡片对应你要的书——过程冗长且毫无必要。第三能力耦合严重。所有功能挤在一个文本块里一旦某个功能的描述出现歧义或错误就可能污染整个推理链。比如你写“调用weather_api时若城市名为空则返回默认值”结果这个“默认值”的定义和另一个“数据库查询失败”的默认值冲突了模型就懵了。这不是模型的错是我们的设计把复杂度强行堆给了它。pydantic-ai-skills的核心洞见就是把Agent的能力管理从“文本注入”升级为“运行时插件管理”。它借鉴了操作系统加载动态链接库DLL或现代IDE加载插件的思路系统启动时只加载一个轻量级的“插件管理器”即SkillsToolset它知道有哪些插件可用list_skills但并不加载插件的具体代码。只有当Agent在推理过程中明确判断出“我现在需要查文献”它才通过load_skill(arxiv-search)这个指令把对应的技能说明书SKILL.md和执行脚本scripts/search.py动态加载进当前上下文。这个过程模型不需要“记住”所有技能它只需要理解“如何发现技能”和“如何调用技能”这两条元规则。这从根本上解耦了能力定义与能力执行让每个技能成为一个独立、可测试、可替换的单元。2.2 “渐进式披露”不是噱头而是精密的工程设计“Progressive disclosure”这个词很容易被误解为一种UI设计原则比如网页上先显示摘要点击再展开详情。但在pydantic-ai-skills里它是一个严谨的、分层的、有明确边界的技术协议。它包含四个严格定义的接口共同构成了一个闭环list_skills()这是Agent的“技能目录”。它返回一个极简的列表每个条目只有两个字段name技能名如calculator和description一句话简介如Perform calculations using Python。这个列表的长度通常不超过10行token消耗可以忽略不计。它的唯一作用就是让Agent知道“我有哪些工具箱可以选”而不涉及任何工具箱内部的构造细节。load_skill(name)这是Agent的“打开工具箱”。当Agent决定使用某个技能时它调用此函数。pydantic-ai-skills会立刻将该技能目录下的SKILL.md文件全文加载进当前上下文。这个文件包含了该技能的全部使用说明、输入输出规范、注意事项等。这才是真正的“说明书”但它只在需要时才出现。read_skill_resource(skill_name, resource_name)这是Agent的“查阅附件”。一个技能往往不止一份说明书还可能有模板、参考数据、配置文件等。比如一个“生成周报”的技能除了主说明书还可能有一个templates/weekly_report.md模板文件。read_skill_resource允许Agent按需读取这些辅助资源避免把所有附件都打包进主说明书进一步精简核心上下文。run_skill_script(skill_name, script_name, args)这是Agent的“动手操作”。当说明书里说“请运行calculate.py脚本来执行计算”Agent就调用此函数。pydantic-ai-skills会安全地启动一个子进程执行该Python脚本并将args作为参数传入。脚本的输出通常是JSON会被捕获并返回给Agent供其下一步推理使用。这四步环环相扣形成了一条清晰的“决策-加载-查阅-执行”流水线。它之所以有效是因为它把Agent的“认知负担”做了精准切分list_skills负责宏观决策选哪个工具load_skill负责中观理解这个工具怎么用read_skill_resource和run_skill_script负责微观操作查资料、干实事。每一层都只暴露它该暴露的信息绝不越界。这种设计让Agent的“大脑”始终处于一种轻量、聚焦的状态而不是一个塞满各种说明书的混乱仓库。2.3 为何选择Pydantic AI生态技术栈的深思熟虑pydantic-ai-skills没有选择从零造轮子而是坚定地扎根于Pydantic AI生态这绝非偶然。Pydantic AI本身就是一个以“类型安全”和“结构化”为核心理念的框架。它强制你为Agent的输入、输出、工具调用定义清晰的Pydantic模型BaseModel。pydantic-ai-skills正是将这一理念从单次调用的“数据契约”延伸到了整个Agent能力的“架构契约”。首先类型安全是可靠性的基石。在pydantic-ai-skills中每一个技能Skill对象、每一个资源SkillResource、每一个脚本的参数args都通过Pydantic模型进行严格校验。比如你在calculator技能的calculate.py脚本里定义了--expression参数那么run_skill_script在调用时就会自动检查传入的args字典里是否包含expression键其值是否为字符串。如果传错了框架会在执行前就抛出清晰的ValidationError而不是让脚本在子进程中崩溃导致Agent收到一个无法解析的错误信息。这种“Fail Fast”机制把大量潜在的运行时错误拦截在了编译期和配置期。其次结构化是可维护性的保障。Pydantic AI的Agent类其toolsets参数就是一个List[Toolset]。pydantic-ai-skills的SkillsToolset就是这样一个标准的、符合Pydantic AI接口规范的Toolset实现。这意味着你可以像添加一个普通的工具集一样把它无缝集成进任何已有的Pydantic AI Agent中无需修改Agent的核心逻辑。你甚至可以同时拥有SkillsToolset、DatabaseToolset、FilesystemToolset等多个工具集它们彼此独立由Agent统一调度。这种基于接口的松耦合设计是大型项目得以演进的关键。最后生态协同是未来的门票。pydantic-ai-skills明确声明兼容agentskills.io开放标准。这个标准由Anthropic牵头制定并已被Microsoft、OpenAI等巨头采纳。这意味着你今天用pydantic-ai-skills写的arxiv-search技能其SKILL.md文件的结构、命名规范小写、短横线分隔、长度≤64字符完全符合行业通用标准。未来如果你的Agent需要迁移到另一个支持agentskills.io的平台这些技能文件几乎可以“开箱即用”。这是一种面向未来的投资它保证了你的工程资产不会被某个特定框架所锁定。3. 核心细节解析从一个SKILL.md文件看透整个框架3.1 文件即契约SKILL.md的精妙结构与强制约定在pydantic-ai-skills的世界里SKILL.md不仅仅是一个Markdown文件它是一份具有法律效力的“能力契约”。这份契约的甲方是Agent它需要知道如何使用这个技能乙方是开发者他需要定义这个技能的行为而pydantic-ai-skills框架则是公证处负责确保双方都严格遵守条款。因此它的结构被设计得既简洁又不容妥协。一个合法的SKILL.md文件必须包含两个部分YAML Frontmatter前置元数据和Markdown Body主体内容。缺一不可格式错误即视为无效技能。YAML Frontmatter是契约的“标题页”它用最精炼的语言向Agent宣告这个技能的身份。它强制要求两个字段name: 技能的唯一标识符。它必须是小写字母、数字和短横线-的组合且总长度不能超过64个字符。例如pydanticai-docs是合法的而Pydantic AI Docs (v2)或my_awesome_skill_for_docs则会被框架拒绝。这个约束看似苛刻实则是为了保证跨平台兼容性。想象一下如果一个技能名叫data-processor-v2.1-beta另一个平台的解析器可能只认data-processor这就造成了歧义。强制小写和短横线是为了消除所有可能的格式歧义让名字成为纯粹的、无状态的标识符。description: 一句不超过140个字符的简介。它必须足够清晰让Agent仅凭这句话就能判断这个技能是否与当前任务相关。例如Quick reference for Pydantic AI framework就比Docs about Pydantic AI好得多因为它点明了“Quick reference”这个核心价值暗示了这是一个用于快速查阅的技能而非一个需要深度学习的教程。提示Frontmatter里的其他字段如version,author是可选的但强烈建议填写。它们虽然不参与运行时逻辑却是团队协作和审计追踪的宝贵信息。一个没有作者和版本号的技能就像一本没有署名和出版日期的书出了问题你根本不知道该找谁。Markdown Body是契约的“正文”它详细规定了技能的使用方法、边界条件和预期行为。这里没有自由发挥的空间框架对它的内容有隐含的、但至关重要的期待第一层级标题#必须是技能名称。这并非语法要求而是最佳实践。它让Agent在加载说明书时能立刻锚定上下文“哦我现在看的是pydanticai-docs技能的说明书”。这是一种强大的心理暗示能显著降低Agent的认知负荷。内容必须聚焦于“如何使用”。这里不是写技术博客的地方。你不应该在这里解释Pydantic AI的原理也不应该写“为什么我们要用这个技能”。你应该写“要获取Pydantic AI的完整文档请访问 https://ai.pydantic.dev/llms-full.txt”“要创建一个基础Agent请使用以下代码片段from pydantic_ai import Agent; agent Agent(openai:gpt-4o)”。每一条指令都应该是一个Agent可以直接执行或引用的动作。代码块必须准确且可执行。文中出现的任何Python代码块都应该是经过验证的、能直接复制粘贴运行的。因为Agent可能会将这些代码块作为其自身推理的“事实依据”。如果代码里有个拼写错误比如pydantic_ai写成了pydantic-aiAgent照着抄就会得到一个运行时错误而这错误的根源却在你的说明书里。我曾经见过一个技能的SKILL.md它的Body里洋洋洒洒写了2000字讲了Pydantic的历史、创始人故事、社区文化……唯独没写一句“怎么用”。结果Agent加载后面对用户“怎么创建Agent”的问题它只能茫然地复述那些无关的历史故事。这就是违背了“内容必须聚焦于‘如何使用’”这一铁律的后果。一个优秀的SKILL.md应该像一本瑞士军刀的说明书每一页都告诉你这个小刀片是用来开罐头的那个小剪刀是用来剪指甲的清晰、直接、无废话。3.2 脚本即服务从calculate.py看安全、可控的代码执行如果说SKILL.md是Agent的“操作手册”那么scripts/目录下的Python脚本就是Agent的“机械臂”。pydantic-ai-skills允许你将复杂的、需要精确控制的逻辑封装成独立的Python程序由Agent在需要时调用。这极大地扩展了Agent的能力边界让它不再局限于LLM的文本生成而是可以真正地“做事”。但这也带来了巨大的安全挑战你真的敢让一个由LLM驱动的、可能被恶意提示词诱导的Agent去随意执行任意Python代码吗答案是绝对不行。pydantic-ai-skills对此有一套严密的“沙盒”机制。以calculator技能为例它的scripts/calculate.py脚本表面看只是一个简单的eval表达式求值器。但它的精妙之处在于它是一个被精心设计的、最小化的、有边界的命令行工具。首先它遵循严格的命令行接口CLI规范。它使用argparse来解析参数强制要求--expression参数。这意味着Agent在调用run_skill_script时必须显式地提供一个args字典其中必须包含expression键。框架会自动将这个字典序列化为命令行参数如--expression 2**10然后启动子进程。这种强约束杜绝了Agent传入一堆乱七八糟参数的可能性。脚本的入口是清晰的、唯一的。其次它实现了最小权限原则。脚本内部eval函数的执行环境被严格限制。虽然示例代码里没有显式地传入globals和locals字典但在生产环境中你必须这样做。一个安全的calculate.py应该长这样import argparse import json import sys import ast import operator # 定义一个白名单操作符 SAFE_OPERATORS { ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul, ast.Div: operator.truediv, ast.USub: operator.neg, ast.Pow: operator.pow, } def safe_eval(node): if isinstance(node, ast.Constant): # Python 3.6 return node.value elif isinstance(node, ast.Num): # Python 3.6 return node.n elif isinstance(node, ast.BinOp): left safe_eval(node.left) right safe_eval(node.right) op SAFE_OPERATORS.get(type(node.op)) if op is None: raise ValueError(fUnsupported operator: {type(node.op)}) return op(left, right) elif isinstance(node, ast.UnaryOp): operand safe_eval(node.operand) op SAFE_OPERATORS.get(type(node.op)) if op is None: raise ValueError(fUnsupported operator: {type(node.op)}) return op(operand) else: raise ValueError(fUnsupported expression type: {type(node)}) if __name__ __main__: parser argparse.ArgumentParser() parser.add_argument(--expression, requiredTrue, helpPython expression to evaluate) args parser.parse_args() try: # 使用ast.literal_eval或自定义safe_eval绝对禁止直接eval() # 这里用ast.parse 自定义遍历比literal_eval更灵活但仍安全 tree ast.parse(args.expression, modeeval) result safe_eval(tree.body) print(json.dumps({result: result})) except Exception as e: print(fError: {e}, filesys.stderr) sys.exit(1)这段代码的核心是用ast.parse将字符串解析成抽象语法树AST然后只允许执行白名单内的操作符加、减、乘、除、幂、负号。它彻底杜绝了eval(__import__(os).system(rm -rf /))这种毁灭性攻击。pydantic-ai-skills框架本身也提供了script_timeout配置项你可以设置一个全局超时时间比如5秒一旦脚本执行超过这个时间子进程会被强制终止防止恶意脚本耗尽系统资源。最后它保证了输出的确定性与可解析性。脚本的最终输出必须是标准的JSON格式{result: 1024}。pydantic-ai-skills会捕获子进程的stdout并尝试将其解析为Python字典。如果解析失败框架会将原始错误信息返回给AgentAgent就可以据此做出“脚本执行失败”的判断。这种标准化的输入/输出契约是Agent能够可靠地“理解”脚本结果的前提。如果脚本输出的是纯文本“Result is 1024”Agent就需要额外的、脆弱的文本解析逻辑来提取数字这大大增加了出错的概率。3.3 程序化技能当能力需要在运行时“活”起来文件型技能file-based skills是pydantic-ai-skills的基石它完美解决了能力的“静态复用”问题。但现实世界远比文件系统复杂。有时候你的Agent需要的能力是高度动态的、依赖于实时状态的、甚至是每次调用都不同的。比如一个“监控告警”技能它需要连接到当前部署环境的Prometheus实例而这个实例的URL、认证Token都是在Agent启动时从环境变量或配置中心动态加载的。你不可能把这些敏感信息硬编码在SKILL.md文件里。这时候就需要pydantic-ai-skills的另一把利器程序化技能Programmatic Skills。程序化技能的本质是将一个Skill对象直接在Python代码中创建、配置和注册。它绕过了文件系统的约束让你可以用任何编程手段来构造一个技能。这赋予了技能前所未有的灵活性和表现力。让我们看一个真实的例子一个“数据库模式探测”技能。它的目标是让Agent能随时获取当前数据库的最新表结构以便在生成SQL查询时能确保字段名是正确的。from pydantic_ai import Agent, RunContext from pydantic_ai_skills import Skill, SkillsToolset, SkillResource # 1. 创建一个空的Skill对象 db_schema_skill Skill( namedb-schema-probe, descriptionProbe the live database to get its current schema, content# Database Schema Probe\nUse this skill to fetch the up-to-date table structure. ) # 2. 添加一个动态资源get_schema() db_schema_skill.resourcedef def get_schema(ctx: RunContext) - str: 这是一个装饰器定义的资源函数。它会在Agent调用 read_skill_resource(db-schema-probe, schema) 时被触发。 # 关键ctx.deps 是一个依赖注入容器里面可以放任何你想要的东西 # 这里我们假设 ctx.deps.database 已经被初始化为一个数据库连接池 if not hasattr(ctx.deps, database): raise RuntimeError(Database dependency not configured) # 执行一个SQL查询获取所有表的列信息 schema_info ctx.deps.database.execute( SELECT table_name, column_name, data_type FROM information_schema.columns WHERE table_schema public ORDER BY table_name, ordinal_position ).fetchall() # 将结果格式化为Markdown表格方便Agent阅读 markdown_table | Table | Column | Type |\n|---|---|---|\n for row in schema_info: markdown_table f| {row.table_name} | {row.column_name} | {row.data_type} |\n return f## Current Database Schema\n\n{markdown_table} # 3. 添加一个可执行脚本generate_sql() db_schema_skill.scriptasync def generate_sql(ctx: RunContext, natural_language_query: str) - str: 这是一个装饰器定义的异步脚本函数。它会在Agent调用 run_skill_script(db-schema-probe, generate_sql, ...) 时被触发。 # 同样我们可以访问 ctx.deps 中的任何依赖 # 这里我们可能需要一个SQL生成模型或者一个预训练的SQL模板引擎 # 为了简化我们模拟一个简单的逻辑 if user in natural_language_query.lower(): return SELECT * FROM users; elif order in natural_language_query.lower(): return SELECT * FROM orders WHERE status pending; else: return SELECT COUNT(*) FROM users; # 4. 将这个程序化技能加入到SkillsToolset中 skills_toolset SkillsToolset(skills[db_schema_skill])这段代码展示了程序化技能的三大核心优势动态依赖注入Dependency Injectionctx.deps是RunContext的一个属性它就像一个万能的工具箱。你可以在Agent初始化时将数据库连接、HTTP客户端、缓存实例等任何运行时依赖注入到ctx.deps中。然后在db_schema_skill.resource或db_schema_skill.script装饰的函数里你就可以随时随地、安全地访问它们。这使得技能不再是孤立的、静态的文本而是深深嵌入到你的应用生态中的一个活的组件。运行时逻辑Runtime Logicget_schema函数不是一个固定的字符串而是一个可以执行任意Python代码的函数。它可以发起网络请求、查询数据库、调用外部API、读取配置文件。它的返回值str会被pydantic-ai-skills当作一个动态生成的资源内容供Agent查阅。这意味着Agent看到的永远是数据库的“最新快照”而不是一个可能已经过时的、写死在文件里的旧Schema。类型安全的异步支持Type-Safe Async Supportdb_schema_skill.scriptasync装饰器明确告诉框架这是一个异步函数。框架会正确地await它的执行并将结果返回给Agent。更重要的是Pydantic的类型注解- str依然有效框架会在调用前根据args的类型提示对传入的参数进行校验。这保证了即使是最复杂的、异步的、依赖外部服务的技能也能享受到Pydantic AI框架带来的类型安全红利。程序化技能是pydantic-ai-skills从“能力管理工具”跃升为“应用集成平台”的关键一步。它模糊了Agent技能与普通业务代码之间的界限让Agent真正成为了你整个应用架构中的一个有机组成部分而不是一个游离在外的、需要特殊照顾的“AI模块”。4. 实操过程从零开始搭建一个可运行的“研究助手”4.1 环境准备与依赖安装五分钟完成初始化在开始编码之前我们必须确保开发环境干净、一致。pydantic-ai-skills是一个相对轻量的库但它依赖于Pydantic AI生态因此我们需要一个现代的Python环境推荐3.10和一个虚拟环境来隔离依赖。这一步看似简单却是后续所有步骤顺利进行的基石。我见过太多人因为跳过这一步而在后面遇到各种莫名其妙的版本冲突白白浪费数小时。首先创建并激活一个虚拟环境。这能确保你的项目依赖不会污染系统Python也不会与其他项目产生冲突。# 创建一个名为 venv 的虚拟环境 python -m venv venv # 激活虚拟环境Linux/macOS source venv/bin/activate # 激活虚拟环境Windows venv\Scripts\activate.bat接下来安装核心依赖。pydantic-ai-skills本身非常轻量但它的“搭档”Pydantic AI框架以及一个实际可用的LLM模型提供商我们选用OpenAI作为示例是必不可少的。# 安装 pydantic-ai-skills 及其核心依赖 pip install pydantic-ai-skills # 安装 Pydantic AI 框架 pip install pydantic-ai # 安装 OpenAI Python SDK用于调用 gpt-4o pip install openai # 可选安装 python-dotenv用于管理API密钥 pip install python-dotenv注意pydantic-ai是pydantic-ai-skills的上游依赖它提供了Agent、RunContext等核心类。openaiSDK 则是与OpenAI API通信的桥梁。python-dotenv并非必需但它是一种业界最佳实践能让你把敏感的API密钥从代码中抽离出来放到.env文件里避免意外提交到Git仓库。安装完成后我们来验证一下环境是否正常。创建一个简单的test_install.py文件from pydantic_ai_skills import SkillsToolset from pydantic_ai import Agent print(✅ pydantic-ai-skills and pydantic-ai imported successfully!) # 尝试创建一个空的SkillsToolset看是否会报错 try: toolset SkillsToolset() print(✅ SkillsToolset initialized successfully!) except Exception as e: print(f❌ Failed to initialize SkillsToolset: {e})运行它python test_install.py。如果看到两个✅恭喜你环境已经准备就绪。如果报错请仔细检查错误信息最常见的原因是openai版本过低需要1.0.0或pydantic版本冲突pydantic-ai需要pydantic2.0.0。4.2 构建第一个文件型技能“Pydantic AI 文档速查”现在我们来亲手创建第一个技能。按照pydantic-ai-skills的约定所有文件型技能都存放在一个目录下每个技能是一个子目录里面必须包含一个SKILL.md文件。我们为这个技能起名为pydanticai-docs目标是让它成为Agent的Pydantic AI框架“速查手册”。首先在项目根目录下创建skills文件夹并在其中创建pydanticai-docs子文件夹mkdir -p skills/pydanticai-docs然后创建skills/pydanticai-docs/SKILL.md文件。请务必严格按照我们前面讲解的结构来编写--- name: pydanticai-docs description: Quick reference for Pydantic AI framework --- # Pydantic AI Docs Quick reference for building agents with Pydantic AI. ## Instructions For detailed information, fetch the full docs at: https://ai.pydantic.dev/llms-full.txt ## Quick Examples **Basic Agent:** python from pydantic_ai import Agent agent Agent(openai:gpt-4o) result agent.run_sync(Your question)Using Tools:from pydantic_ai import Agent from pydantic_ai_tools import DatabaseTool agent Agent( modelopenai:gpt-4o, tools[DatabaseTool()] )这个文件的要点我们再强调一遍 - YAML Frontmatter里name和description必须存在且符合规范。 - Markdown Body的第一行标题# Pydantic AI Docs必须与name字段语义一致。 - 内容全是“如何使用”的干货没有一句废话。 - 代码块是真实、可运行的示例它们将成为Agent知识库的一部分。 保存文件后你的第一个技能就已经“注册”完成了。它现在只是一个静态文件还没有被Agent“看见”。下一步就是让Agent发现它。 ### 4.3 编写Agent主程序将技能“插”进Agent 这是最关键的一步将SkillsToolset集成到你的Pydantic AI Agent中。我们将编写一个完整的research_assistant.py文件它将创建一个Agent并赋予它pydanticai-docs技能。 python import asyncio import os from pydantic_ai import Agent, RunContext from pydantic_ai_skills import SkillsToolset # 1. 初始化 SkillsToolset指向我们创建的 skills 目录 skills_toolset SkillsToolset(directories[./skills]) # 2. 创建 Agent 实例 # 注意model 字符串 openai:gpt-4o 是 Pydantic AI 的标准格式 # 它会自动使用 OPENAI_API_KEY 环境变量 agent Agent( modelopenai:gpt-4o, instructionsYou are a helpful assistant., toolsets[skills_toolset] # 将技能工具集注入Agent ) # 3. 【关键】为Agent注入技能的“元指令” # 这个装饰器函数会在Agent每次生成响应前被调用 # 它的作用是将所有已发现技能的名称和简介动态地注入到Agent的上下文中 agent.instructions async def add_skills(ctx: RunContext) - str | None: This function is called by the Agent before it starts processing a user message. It asks the SkillsToolset to generate a string containing the list of all available skills. This string will be appended to the Agents system prompt. return await skills_toolset.get_instructions(ctx) # 4. 主函数运行Agent async def main(): # 让Agent处理一个关于Pydantic AI的问题 result await agent.run(How do I create a basic Pydantic AI agent?) print( Agent Response:) print(result.output) if __name__ __main__: # 设置OpenAI API Key生产环境请使用 .env 文件 os.environ[OPENAI_API_KEY] your_actual_api_key_here # 运行主函数 asyncio.run(main())这段代码的精妙之处在于agent.instructions装饰器。它不是一个普通的函数而是一个“钩子”hook。每当Agent准备处理一个新的用户消息时Pydantic AI框架都会自动调用这个函数并将它的返回值一个字符串追加到当前的系统提示词system prompt末尾。skills_toolset.get_instructions(ctx)这个方法会调用list_skills()并生成一个类似这样的字符串You have access to the following skills: - pydanticai-docs: Quick reference for Pydantic AI framework To use a skill, call the appropriate tool function.这个字符串就是Agent的“技能菜单”。它只有短短几行却为Agent提供了发现和调用技能的全部元信息。Agent看到这个菜单后如果用户的问题是“怎么创建Agent”它就能立刻联想到pydanticai-docs这个技能并在后续的推理中调用load_skill(pydanticai-docs)来加载完整的说明书。运行这个脚本python research_assistant.py。你会看到Agent输出一段文字其中很可能就包含了我们SKILL.md文件里写的“Basic Agent”代码示例。这证明技能已经被成功发现、加载并应用了。4.4 进阶实战为Agent添加“ArXiv文献搜索”技能现在我们来挑战一个更复杂的、真正有实用价值的技能arxiv-search。这个技能的目标是让Agent能根据用户的自然语言查询自动搜索ArXiv上的最新学术论文。这需要我们结合文件型技能和程序化技能的优势。首先创建skills/arxiv-search目录并编写SKILL.md--- name: arxiv-search description: Search academic papers on arXiv.org --- # ArXiv Search Skill Use this skill to find the latest research papers on arXiv. ## Instructions 1. Use run_skill_script(arxiv-search, search, {query: transformer architectures, max_results: 5}) to perform a search. 2. The script will return a JSON list of papers, each with title, authors, summary, and pdf_url. 3. Format the results for the user in a