news 2026/4/25 18:52:04

基于Claude API的AI技能开发:使用anthropics/skills脚手架构建智能体应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于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的语境里,“技能”是一个高度抽象和封装的概念。它不仅仅是一个能回答问题的聊天机器人。一个完整的“技能”通常包含以下几个核心要素:

  1. 明确的职责与边界:一个技能应该有清晰、单一的功能定义。例如,“会议纪要生成器”、“代码审查助手”、“旅行规划专家”。这避免了功能混杂,让系统更易于理解和维护。
  2. 结构化的提示词工程:技能的核心“大脑”由精心设计的系统提示词(System Prompt)驱动。这个提示词不仅定义了技能的角色和能力,还规定了它的思考流程、输出格式以及可调用的工具。
  3. 工具集成能力:一个强大的技能不能只靠“空想”,它需要能调用外部工具来获取信息或执行操作。比如,一个“天气查询”技能需要能调用天气API;一个“文件处理”技能需要能读写本地文件。skills项目提供了优雅的工具定义、注册和调用机制。
  4. 对话状态管理:技能需要记住上下文。skills项目内置了对话历史(Message History)的管理,能够自动处理多轮对话的上下文拼接,并支持设定历史长度限制,以优化token使用和模型表现。
  5. 可配置的执行参数:每个技能的调用都可以配置不同的模型参数,如温度(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.pySkill基类:这是整个项目的基石。所有你自定义的技能都需要继承这个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_KEY='your-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="预估所需小时数", ge=0.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_day="N/A", suggested_time_slot="N/A", notes="请先使用‘analyze_tasks’工具提供任务列表。" )] tasks = self._cached_tasks # 按优先级排序:高 > 中 > 低 priority_order = {“高”: 0, “中”: 1, “低”: 2} sorted_tasks = sorted(tasks, key=lambda 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_name=task.name, suggested_day=current_day, suggested_time_slot=time_slot, notes=f“优先级:{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 recommendations

3.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_tasksschedule_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_style=advisor_style, tone=tone, typical_availability=typical_availability ) super().__init__()

这样,你可以轻松创建不同风格(如“严格型”、“轻松型”)的顾问实例,而无需复制多个类。

4.3 对话历史的管理与优化

Skill基类自动管理对话历史(message_history)。但你需要关注两点:

  1. 历史长度与Token消耗:长时间对话会导致历史越来越长,消耗大量token并可能让模型遗忘早期重点。Skill类通常有参数可以限制历史消息条数或总token数。你需要根据技能的特性和成本预算进行配置。
  2. 历史摘要:对于超长对话,一种高级技巧是定期(或在历史达到一定长度时)让模型自己生成一个当前对话的摘要,然后用这个摘要替换掉大部分旧的历史记录,只保留最近几条原始消息。这能有效压缩上下文,保留核心信息。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 工具调用失败或参数不匹配

问题:模型没有按预期调用工具,或者调用时参数结构错误。

排查步骤

  1. 检查工具定义:确保@tool装饰器正确应用,工具函数有清晰的文档字符串(”””docstring”””),并且参数有类型提示和Field(description=…)。模型严重依赖这些信息来理解如何调用工具。
  2. 启用调试日志anthropicSDK 和skills项目通常有日志功能。设置logging.basicConfig(level=logging.DEBUG)可以查看详细的API请求和响应,包括模型决定调用哪个工具、传递了什么参数。这是最直接的调试手段。
  3. 简化测试:先用一个最简单的工具(例如一个返回固定字符串的工具)测试,确保基础流程通畅,再逐步增加复杂度。
  4. 审查系统提示词:在系统提示词中明确指示模型“在需要时使用可用的工具”,并简要说明工具用途。有时模型需要明确的指令才会主动使用工具。

5.2 响应速度慢或Token消耗过高

问题:技能响应慢,或者API调用成本迅速上升。

优化策略

  1. 精简提示词:系统提示词不是越长越好。删除冗余的、泛泛而谈的指令,聚焦于核心行为规范。用词精准、直接。
  2. 管理对话历史:如前所述,合理设置max_tokensmax_messages。对于闲聊类技能,历史可以短一些;对于需要深度上下文的分析类技能,可以长一些,但要警惕成本。
  3. 使用更合适的模型:Claude 3系列有 Haiku、Sonnet、Opus 等多个版本,它们在速度、成本和能力上有所权衡。对于工具调用这类任务,Sonnet通常是性价比很高的选择。在技能初始化时可以通过参数指定模型。
  4. 实现缓存:对于工具调用中获取的、不经常变化的外部数据(如某些配置信息、静态知识),可以考虑在本地或内存中缓存结果,避免重复调用外部API或计算。

5.3 技能行为不稳定或“幻觉”

问题:技能有时会忽略指令,输出格式不符合要求,或捏造信息。

应对方法

  1. 强化输出格式指令:在系统提示词中,使用非常明确的格式要求。例如:“请始终以JSON格式输出,包含 ‘analysis’ 和 ‘schedule’ 两个键。” 或者“你的最终回答必须以‘## 建议总结’开头。”
  2. 使用结构化输出(Structured Outputs):这是Claude API的高级特性,可以强制模型以你指定的JSON Schema格式输出。skills项目未来可能会更深度地集成此功能。目前,你可以在调用模型时传入response_format参数来尝试。
  3. 后处理与验证:不要完全信任模型的原始输出。对于关键信息,编写代码对输出进行解析和验证。例如,如果技能返回一个日期,用datetime库检查其有效性;如果返回一个数字,检查其是否在合理范围内。
  4. 迭代优化提示词: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提供了一个坚实的起点和一套优秀的模式,但最终技能的质量,取决于你对业务逻辑的理解、对提示词的雕琢以及对异常情况的周全处理。从一个小而美的技能开始,不断迭代,是掌握这门新艺术的最佳路径。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 18:48:41

随机森林与XGBoost混合模型构建与实践

1. 随机森林与XGBoost的融合价值在机器学习实践中&#xff0c;随机森林和XGBoost都是解决分类与回归问题的利器。随机森林通过构建多棵决策树并采用投票机制降低过拟合风险&#xff0c;而XGBoost则通过梯度提升框架以迭代方式优化模型性能。将这两种方法结合形成混合集成模型&a…

作者头像 李华
网站建设 2026/4/25 18:46:29

Komodo Edit多语言支持详解:如何为你的编程语言添加完美支持

Komodo Edit多语言支持详解&#xff1a;如何为你的编程语言添加完美支持 【免费下载链接】KomodoEdit Komodo Edit is a fast and free multi-language code editor. Written in JS, Python, C and based on the Mozilla platform. 项目地址: https://gitcode.com/gh_mirrors…

作者头像 李华
网站建设 2026/4/25 18:45:43

抖音视频下载工具终极指南:如何一键批量下载无水印视频

抖音视频下载工具终极指南&#xff1a;如何一键批量下载无水印视频 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback supp…

作者头像 李华
网站建设 2026/4/25 18:45:00

Bash3Boilerplate 实战案例:构建自动化部署脚本

Bash3Boilerplate 实战案例&#xff1a;构建自动化部署脚本 【免费下载链接】bash3boilerplate Templates to write better Bash scripts 项目地址: https://gitcode.com/gh_mirrors/ba/bash3boilerplate Bash3Boilerplate 是一套强大的模板工具&#xff0c;能够帮助开发…

作者头像 李华
网站建设 2026/4/25 18:44:58

SGPlayer架构深度剖析:基于FFmpeg和Metal的高性能播放引擎

SGPlayer架构深度剖析&#xff1a;基于FFmpeg和Metal的高性能播放引擎 【免费下载链接】SGPlayer A powerful media play framework for iOS, macOS, and tvOS. 项目地址: https://gitcode.com/gh_mirrors/sg/SGPlayer SGPlayer是一款为iOS、macOS和tvOS打造的强大媒体播…

作者头像 李华
网站建设 2026/4/25 18:43:20

ncmdump:3步解锁网易云音乐加密文件,实现音乐格式自由转换

ncmdump&#xff1a;3步解锁网易云音乐加密文件&#xff0c;实现音乐格式自由转换 【免费下载链接】ncmdump 转换网易云音乐 ncm 到 mp3 / flac. Convert Netease Cloud Music ncm files to mp3/flac files. 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdump 还在为…

作者头像 李华