基于Claude API的AI技能开发:使用anthropics/skills脚手架构建智能体应用
1. 项目概述一个面向AI技能开发的“脚手架”工具如果你最近在尝试基于Claude API或者类似的大型语言模型LLM开发一些应用可能会遇到一个共同的痛点从零开始构建一个结构清晰、易于维护、且能充分发挥LLM潜力的应用框架并不是一件轻松的事。你需要考虑如何组织提示词Prompt、如何管理对话历史、如何处理工具调用Function Calling、如何设计评估流程等等。anthropics/skills这个项目正是为了解决这些问题而生的一个官方工具包。简单来说你可以把它理解为一个为“AI技能”或“AI智能体Agent”开发量身定制的“脚手架”或“样板工程”。它由Anthropic公司Claude模型的创造者官方发布提供了一套经过实践检验的最佳实践、可复用的代码模块和开发范式。它的核心目标不是提供一个开箱即用的最终产品而是为你铺好一条高效、规范的开发道路让你能快速启动项目并专注于实现核心的业务逻辑而不是反复纠结于底层架构。这个项目特别适合以下几类开发者一是希望基于Claude API构建复杂对话应用或智能体的工程师二是正在探索LLM应用模式需要一个高质量参考实现的研究者或爱好者三是团队内部希望统一AI应用的开发标准提升协作效率的技术负责人。接下来我将深入拆解这个项目的设计思路、核心组件并分享如何利用它来构建一个属于自己的AI技能。2. 核心架构与设计哲学解析2.1 什么是“技能”Skill在anthropics/skills的语境里“技能”是一个高度抽象和封装的概念。它不仅仅是一个能回答问题的聊天机器人。一个完整的“技能”通常包含以下几个核心要素明确的职责与边界一个技能应该有清晰、单一的功能定义。例如“会议纪要生成器”、“代码审查助手”、“旅行规划专家”。这避免了功能混杂让系统更易于理解和维护。结构化的提示词工程技能的核心“大脑”由精心设计的系统提示词System Prompt驱动。这个提示词不仅定义了技能的角色和能力还规定了它的思考流程、输出格式以及可调用的工具。工具集成能力一个强大的技能不能只靠“空想”它需要能调用外部工具来获取信息或执行操作。比如一个“天气查询”技能需要能调用天气API一个“文件处理”技能需要能读写本地文件。skills项目提供了优雅的工具定义、注册和调用机制。对话状态管理技能需要记住上下文。skills项目内置了对话历史Message History的管理能够自动处理多轮对话的上下文拼接并支持设定历史长度限制以优化token使用和模型表现。可配置的执行参数每个技能的调用都可以配置不同的模型参数如温度temperature、最大输出token数max_tokens等以适应不同的场景需求。这种设计哲学将AI应用开发从“写一个庞大的、难以维护的脚本”转变为“组合和配置一个个高内聚、低耦合的技能模块”。它倡导的是一种模块化、工程化的开发思想。2.2 项目核心目录结构剖析下载或克隆anthropics/skills项目后你会看到一个非常清晰、典型的Python项目结构。理解这个结构是高效使用它的第一步。skills/ ├── skills/ # 核心Python包目录 │ ├── __init__.py │ ├── skill.py # 核心的 Skill 基类定义 │ ├── tools/ # 工具相关的模块 │ ├── prompts/ # 提示词模板管理 │ └── ... # 其他核心模块如历史记录管理、配置等 ├── examples/ # 官方示例学习的最佳材料 │ ├── quickstart/ # 快速入门示例 │ ├── calculator/ # 计算器技能示例 │ └── ... # 更多复杂示例 ├── tests/ # 单元测试 ├── pyproject.toml # 项目依赖和构建配置 └── README.md # 项目说明文档关键文件解读skill.py与Skill基类这是整个项目的基石。所有你自定义的技能都需要继承这个Skill类。它封装了与Claude API通信、工具调用循环、历史管理、错误处理等几乎所有通用逻辑。作为开发者你大部分时间只需要关注如何重写或扩展它的几个关键方法比如_run方法定义技能的核心执行逻辑和_get_tools方法定义技能可用的工具列表。examples/目录这是宝藏。官方提供了从简到繁的一系列示例。强烈建议从quickstart开始然后仔细研究calculator。这个计算器示例虽然功能简单但它完整演示了如何定义一个技能、如何创建工具、如何处理工具调用结果并继续对话是理解整个工作流的绝佳模板。pyproject.toml现代Python项目的标准配置文件。它明确了项目的依赖如anthropicSDK,pydantic用于数据验证等你可以直接使用pip install -e .命令在开发模式下安装本项目及其所有依赖。这种结构的好处在于它强制性地将代码、配置、示例和测试分离使得项目既易于上手又便于进行大规模的开发和团队协作。3. 从零开始构建你的第一个AI技能理论说得再多不如动手实践。让我们以构建一个“智能时间管理顾问”技能为例一步步走完开发流程。这个技能能帮用户分析待办事项估算耗时并给出日程安排建议。3.1 环境准备与项目初始化首先确保你的开发环境就绪。# 1. 克隆官方仓库或直接下载 git clone https://github.com/anthropics/skills.git cd skills # 2. 创建并激活一个独立的Python虚拟环境强烈推荐 python -m venv venv # 在Windows上: venv\Scripts\activate # 在Mac/Linux上: source venv/bin/activate # 3. 以“可编辑”模式安装本项目及其依赖 pip install -e . # 4. 设置你的Anthropic API密钥 # 方法一设置环境变量最安全适合生产 # export ANTHROPIC_API_KEYyour-api-key-here # 方法二在代码中临时设置仅用于测试 import os os.environ[“ANTHROPIC_API_KEY”] “your-api-key-here”注意API密钥是访问Claude模型的通行证务必妥善保管不要将其硬编码在提交到版本控制系统的代码中。使用环境变量或专门的密钥管理服务是行业最佳实践。3.2 定义技能类与系统提示词接下来我们在项目外新建一个自己的目录来开发技能例如my_time_advisor。在其中创建time_advisor.py。# my_time_advisor/time_advisor.py import asyncio from typing import List, Optional from pydantic import BaseModel, Field from skills import Skill, tool from skills.models import Message # 首先定义技能处理过程中可能用到的数据模型。 # 使用Pydantic可以确保数据的结构化和类型安全。 class TodoItem(BaseModel): 单个待办事项的模型 name: str Field(description任务名称) estimated_hours: float Field(description预估所需小时数, ge0.0) priority: str Field(description优先级可选‘高’ ‘中’ ‘低’, default中) class ScheduleRecommendation(BaseModel): 日程推荐模型 task_name: str suggested_day: str suggested_time_slot: str notes: Optional[str] None # 然后创建我们的技能类继承自 Skill class TimeManagementAdvisor(Skill): 智能时间管理顾问技能 # 技能的“名字”用于标识 name time_management_advisor # 技能的“描述”会作为元信息的一部分帮助模型理解自身角色 description 一个帮助用户分析待办事项、估算时间并提供日程安排建议的AI助手。 # 最重要的部分系统提示词。它定义了技能的“人格”和“行为准则”。 system_prompt 你是一位专业、高效且富有同理心的时间管理顾问。 你的核心职责是帮助用户梳理他们的待办事项进行合理的时间估算并基于他们的可用时间如果提供生成可行的日程安排建议。 请遵循以下工作流程 1. **信息收集**首先请用户列出他们的待办事项。对于每个事项引导用户给出任务名称和预估耗时如果用户无法预估你可以根据描述提供参考建议。 2. **分析与规划**获得事项列表后计算总耗时。如果用户提供了每日可用时间例如“我每天有4小时空闲”请将任务分配到具体的日期和时间段生成一个日程表。分配时需考虑任务的优先级和用户的精力周期例如复杂任务放在上午。 3. **输出建议**最终输出一个清晰、结构化的日程建议。使用表格或列表形式呈现让用户一目了然。 在整个对话中请保持积极、鼓励的态度。如果用户的任务量明显超出时间容量请友善地提醒他们并建议调整优先级或拆分任务。 # 初始化方法可以在这里设置一些技能级别的参数 def __init__(self, **kwargs): super().__init__(**kwargs) # 可以在这里初始化一些内部状态例如一个虚拟的“日历” self.schedule_cache [] # _run 方法是技能执行的主入口。当用户调用技能时此方法被触发。 # message 是用户的输入stream 控制是否流式输出。 async def _run(self, message: str, stream: bool False) - str: # 这里我们直接使用父类的默认运行逻辑它会自动处理与Claude的对话、 # 工具调用等。对于大多数技能你不需要重写此方法除非有特殊逻辑。 # 父类的 _run 会结合 system_prompt, _get_tools 和对话历史来工作。 return await super()._run(message, stream) # _get_tools 方法返回此技能可以使用的所有工具列表。 # 工具是技能与外界交互的“手”和“脚”。 async def _get_tools(self): # 返回我们定义的工具函数列表。tool 装饰器会将普通函数转换为技能可用的工具。 return [self.analyze_tasks, self.generate_schedule] # 工具一分析任务列表 tool async def analyze_tasks(self, tasks: List[TodoItem]) - str: 分析用户提供的待办事项列表计算总耗时并给出初步观察。 Args: tasks: 待办事项列表每个事项包含名称、预估小时数和优先级。 Returns: 分析结果的文本摘要。 if not tasks: return 未接收到有效的待办事项列表。 total_hours sum(task.estimated_hours for task in tasks) high_priority_tasks [t for t in tasks if t.priority “高”] analysis f ## 任务分析报告 **总任务数**: {len(tasks)} **总预估耗时**: {total_hours:.1f} 小时 **高优先级任务数**: {len(high_priority_tasks)} **任务清单**: for i, task in enumerate(tasks, 1): analysis f{i}. **{task.name}** - 预估: {task.estimated_hours}小时 优先级: {task.priority}\n if total_hours 40: analysis \n ⚠️ 提醒总耗时较长建议考虑任务拆分或重新评估优先级。 elif len(high_priority_tasks) 3: analysis \n ⚠️ 提醒高优先级任务较多可能造成精力分散建议聚焦核心任务。 # 将分析结果也存入缓存供后续生成日程使用 self._cached_tasks tasks return analysis # 工具二生成日程建议 tool async def generate_schedule(self, available_hours_per_day: float, start_day: str “明天”) - List[ScheduleRecommendation]: 基于已分析的任务和用户每日可用时间生成日程安排建议。 注意需要先调用 analyze_tasks 工具。 Args: available_hours_per_day: 用户每天可用于处理这些任务的小时数。 start_day: 开始安排的日期默认为“明天”。 Returns: 一个日程推荐对象的列表。 if not hasattr(self, ‘_cached_tasks’) or not self._cached_tasks: return [ScheduleRecommendation( task_name错误, suggested_dayN/A, suggested_time_slotN/A, notes请先使用‘analyze_tasks’工具提供任务列表。 )] tasks self._cached_tasks # 按优先级排序高 中 低 priority_order {“高”: 0, “中”: 1, “低”: 2} sorted_tasks sorted(tasks, keylambda x: priority_order[x.priority]) recommendations [] current_day start_day daily_remaining_hours available_hours_per_day day_counter 0 for task in sorted_tasks: task_hours task.estimated_hours # 如果当前天剩余时间不够安排到下一天 while task_hours daily_remaining_hours: # 将当前天剩余时间填满如果有 if daily_remaining_hours 0: # 这里简化处理将大任务拆分到多天是更复杂的逻辑 pass # 跳到下一天 day_counter 1 current_day f“{start_day}后的第{day_counter}天” daily_remaining_hours available_hours_per_day # 分配任务到当前天的一个时间段这里简化了时间段计算 time_slot f“上午{daily_remaining_hours - task_hours 1}:00 - {daily_remaining_hours 1}:00” rec ScheduleRecommendation( task_nametask.name, suggested_daycurrent_day, suggested_time_slottime_slot, notesf“优先级{task.priority}” ) recommendations.append(rec) daily_remaining_hours - task_hours if daily_remaining_hours 0: day_counter 1 current_day f“{start_day}后的第{day_counter}天” daily_remaining_hours available_hours_per_day self.schedule_cache recommendations return recommendations3.3 运行与测试你的技能技能定义好后我们需要一个简单的脚本来运行它。创建run_advisor.py。# my_time_advisor/run_advisor.py import asyncio import os from time_advisor import TimeManagementAdvisor async def main(): # 1. 实例化技能 advisor TimeManagementAdvisor() # 2. 开始对话循环 print(“时间管理顾问已上线输入‘退出’或‘quit’结束对话。\n”) while True: try: user_input input(“你: “) if user_input.lower() in [“退出”, “quit”, “exit”]: print(“顾问: 再见祝你高效每一天”) break # 3. 调用技能的 run 方法注意是异步的 response await advisor.run(user_input) print(f“\n顾问: {response}\n”) except KeyboardInterrupt: print(“\n对话被中断。”) break except Exception as e: print(f“\n出错啦: {e}”) if __name__ “__main__”: # 运行异步主函数 asyncio.run(main())现在在终端运行python run_advisor.py你就可以和你的时间管理顾问对话了。试着输入“我有三个任务写周报要2小时优先级高准备会议材料要1.5小时优先级中阅读行业报告要3小时优先级低。我每天只有2小时空闲时间从明天开始帮我安排一下。”你会看到技能首先调用analyze_tasks工具模型会自动根据你的描述构造出符合TodoItem模型的列表参数然后调用generate_schedule工具最终生成一个结构化的日程建议。4. 高级特性与最佳实践探索掌握了基础技能构建后我们来看看anthropics/skills项目提供的更多强大功能和在实际开发中积累的经验。4.1 工具调用的高级控制工具调用是智能体能力的核心扩展。skills项目通过tool装饰器简化了定义但背后有更多细节可以控制。参数验证与文档如上例所示使用pydantic.BaseModel作为工具参数类型可以自动获得强大的数据验证和清晰的API文档模型会读取字段的description。这极大地提高了工具调用的可靠性和可理解性。错误处理在工具函数内部务必做好错误处理try-except。如果工具执行失败应该返回清晰的错误信息而不是抛出未处理的异常这有助于模型理解问题并可能尝试其他策略或向用户请求澄清。副作用与状态管理工具可以修改技能实例的状态如我们例子中的_cached_tasks和schedule_cache。这是实现多轮对话中信息传递的关键。但要小心管理状态的生命周期避免不同对话会话之间的状态污染。对于需要持久化或共享的状态应考虑外部存储如数据库。4.2 提示词模板化与动态生成直接将长段系统提示词写在类里可能不利于维护。skills项目鼓励将提示词模板化。# 假设我们有一个 prompts.py from string import Template TIME_ADVISOR_PROMPT_TEMPLATE Template(“”” 你是一位${advisor_style}的时间管理顾问。 你的核心职责是帮助用户梳理他们的待办事项... 用户通常的可用时间是 ${typical_availability}。 请保持${tone}的态度。 “””) # 在技能类中动态生成提示词 class DynamicTimeAdvisor(Skill): def __init__(self, advisor_style“专业”, tone“积极鼓励”, typical_availability“2-4小时”): self.system_prompt TIME_ADVISOR_PROMPT_TEMPLATE.substitute( advisor_styleadvisor_style, tonetone, typical_availabilitytypical_availability ) super().__init__()这样你可以轻松创建不同风格如“严格型”、“轻松型”的顾问实例而无需复制多个类。4.3 对话历史的管理与优化Skill基类自动管理对话历史message_history。但你需要关注两点历史长度与Token消耗长时间对话会导致历史越来越长消耗大量token并可能让模型遗忘早期重点。Skill类通常有参数可以限制历史消息条数或总token数。你需要根据技能的特性和成本预算进行配置。历史摘要对于超长对话一种高级技巧是定期或在历史达到一定长度时让模型自己生成一个当前对话的摘要然后用这个摘要替换掉大部分旧的历史记录只保留最近几条原始消息。这能有效压缩上下文保留核心信息。skills项目可能没有内置此功能但你可以通过重写相关方法或创建一个“总结历史”的工具来实现。4.4 技能的组合与编排真正的强大之处在于技能的复用和组合。你可以构建一个“技能库”然后通过一个“主控技能”或“路由技能”来根据用户意图调用不同的子技能。class MasterAssistant(Skill): def __init__(self): self.sub_skills { “time”: TimeManagementAdvisor(), “calculator”: CalculatorSkill(), # 假设有另一个计算器技能 “researcher”: ResearchAssistantSkill(), # 研究助手技能 } super().__init__() async def _run(self, message: str, stream: bool False) - str: # 简单的意图识别实际应用可能需要更复杂的NLP模型 if “时间” in message or “安排” in message or “任务” in message: return await self.sub_skills[“time”].run(message) elif “计算” in message or “ - * /” in message: return await self.sub_skills[“calculator”].run(message) else: # 默认或通用回复 return “我可以帮你管理时间、计算或者查找资料。请告诉我具体需要什么”这种架构使得构建复杂的、多功能的AI助手变得模块化和可持续。5. 常见问题、调试技巧与性能优化在实际开发中你肯定会遇到各种问题。以下是一些常见坑点及解决方案。5.1 工具调用失败或参数不匹配问题模型没有按预期调用工具或者调用时参数结构错误。排查步骤检查工具定义确保tool装饰器正确应用工具函数有清晰的文档字符串”””docstring”””并且参数有类型提示和Field(description…)。模型严重依赖这些信息来理解如何调用工具。启用调试日志anthropicSDK 和skills项目通常有日志功能。设置logging.basicConfig(levellogging.DEBUG)可以查看详细的API请求和响应包括模型决定调用哪个工具、传递了什么参数。这是最直接的调试手段。简化测试先用一个最简单的工具例如一个返回固定字符串的工具测试确保基础流程通畅再逐步增加复杂度。审查系统提示词在系统提示词中明确指示模型“在需要时使用可用的工具”并简要说明工具用途。有时模型需要明确的指令才会主动使用工具。5.2 响应速度慢或Token消耗过高问题技能响应慢或者API调用成本迅速上升。优化策略精简提示词系统提示词不是越长越好。删除冗余的、泛泛而谈的指令聚焦于核心行为规范。用词精准、直接。管理对话历史如前所述合理设置max_tokens和max_messages。对于闲聊类技能历史可以短一些对于需要深度上下文的分析类技能可以长一些但要警惕成本。使用更合适的模型Claude 3系列有 Haiku、Sonnet、Opus 等多个版本它们在速度、成本和能力上有所权衡。对于工具调用这类任务Sonnet通常是性价比很高的选择。在技能初始化时可以通过参数指定模型。实现缓存对于工具调用中获取的、不经常变化的外部数据如某些配置信息、静态知识可以考虑在本地或内存中缓存结果避免重复调用外部API或计算。5.3 技能行为不稳定或“幻觉”问题技能有时会忽略指令输出格式不符合要求或捏造信息。应对方法强化输出格式指令在系统提示词中使用非常明确的格式要求。例如“请始终以JSON格式输出包含 ‘analysis’ 和 ‘schedule’ 两个键。” 或者“你的最终回答必须以‘## 建议总结’开头。”使用结构化输出Structured Outputs这是Claude API的高级特性可以强制模型以你指定的JSON Schema格式输出。skills项目未来可能会更深度地集成此功能。目前你可以在调用模型时传入response_format参数来尝试。后处理与验证不要完全信任模型的原始输出。对于关键信息编写代码对输出进行解析和验证。例如如果技能返回一个日期用datetime库检查其有效性如果返回一个数字检查其是否在合理范围内。迭代优化提示词AI技能开发是一个高度迭代的过程。观察模型在哪里出错然后有针对性地修改提示词。常见的技巧包括提供更具体的例子Few-shot Learning在提示词中强调“如果不知道就说不知道不要编造”以及将复杂任务分解成模型更容易遵循的步骤链Chain-of-Thought。5.4 异步Async编程注意事项skills项目大量使用async/await这是为了高效处理可能阻塞的I/O操作如网络请求。入口点确保你的主程序使用asyncio.run(main())来启动。不要在同步函数中直接调用异步方法如果你在普通的同步函数如Flask/Django的视图函数中需要调用技能需要使用asyncio.create_task或在一个已运行的事件循环中调用。对于Web后端通常有异步框架如FastAPI与之配合。并发处理async使得并发处理多个用户请求变得更容易。你可以为每个用户会话创建一个独立的Skill实例然后利用异步IO同时处理它们而无需为每个请求创建昂贵的线程。构建一个稳定、高效的AI技能三分靠框架七分靠细致的调试和持续的优化。anthropics/skills提供了一个坚实的起点和一套优秀的模式但最终技能的质量取决于你对业务逻辑的理解、对提示词的雕琢以及对异常情况的周全处理。从一个小而美的技能开始不断迭代是掌握这门新艺术的最佳路径。