ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Agent Skills实战:从提示词到可复用技能包的封装与生态

Agent Skills实战:从提示词到可复用技能包的封装与生态 1. 从“skills”这个标题说起它到底指什么“skills”这个词单独拎出来放在技术社区里十有八九不是指人类简历上那种“熟练掌握Office”而是指Agent Skills——一套让AI智能体Agent具备可复用、可组合、可分发能力的技能封装机制。最近围绕它的热搜词密度很高Google Cloud、GKE、npx、Claude Agent Skills、Codex Skills、Agent Skills测试、Skills开发、Skills安装包下载……这些词拼在一起勾勒出的其实是一个正在快速成型的生态把Agent的能力从“一次性提示词”变成“可安装、可调用、可版本管理的技能包”。我最早接触这个概念是在做自动化工作流的时候。当时团队里每个人都在写自己的提示词模板A写了一个“周报生成器”B写了一个“代码审查助手”C写了一个“竞品分析框架”结果就是——重复造轮子、质量参差不齐、维护成本极高。后来看到Agent Skills这套思路第一反应就是这不就是把提示词工程从“手工作坊”升级成“包管理”吗你不再需要每次从零写一段长提示词而是像npm install一样把别人写好的技能装进来直接用。这篇文章适合谁看如果你是刚听说Agent Skills、想知道它到底能干什么的开发者或者你已经在用Claude、Codex这类工具但还没系统整理过自己的技能库再或者你在团队里负责搭建AI工作流、需要一套可复用的能力管理方案那这篇内容应该能帮你省下不少摸索时间。我会从设计思路、核心机制、实操步骤、常见坑四个层面展开尽量把“为什么这么设计”和“具体怎么做”都讲清楚。2. Agent Skills的整体设计思路与核心价值2.1 为什么需要“技能”这层抽象要理解Agent Skills的价值得先看它解决了什么问题。在没有Skills机制的时候我们让Agent做一件事通常有两种方式一是直接在对话里写一段详细指令二是把指令存成一个模板文件每次复制粘贴。这两种方式在“一次性任务”场景下够用但一旦任务变复杂、需要反复执行、或者需要多人协作问题就暴露了。第一个问题是上下文膨胀。你写一个“帮我做竞品分析”的提示词可能要包含数据来源、分析维度、输出格式、注意事项动辄上千字。每次调用都把这上千字塞进上下文既浪费token又容易让模型“注意力分散”。第二个问题是不可组合。你有一个“数据清洗”技能和一个“图表生成”技能想让它们串起来用只能手动把两段提示词拼在一起拼完还得调顺序、改措辞。第三个问题是无法版本管理。提示词改了之后之前的效果就复现不了了团队里也没法共享“哪个版本最好用”。Agent Skills的设计思路本质上是把“技能”当成一个独立的、自包含的、有明确输入输出契约的单元。一个技能通常包含技能名称、描述、触发条件、执行指令可能是提示词也可能是代码、依赖项、版本号。Agent在运行时根据当前任务判断需要调用哪些技能然后按需加载。这样一来上下文里只出现“当前需要的技能”而不是“所有可能用到的指令”技能之间可以通过标准接口组合每个技能独立版本化改坏了可以回滚。提示不要把Skills理解成“更长的提示词”。它的核心区别在于“按需加载”和“可组合”这两点决定了它和传统提示词模板是不同层次的东西。2.2 技能封装的核心要素拆解一个设计良好的Agent Skill通常包含以下几个要素。我按重要性排序并解释每个要素为什么必要。技能标识与描述。这是Agent判断“要不要用这个技能”的依据。描述要写得像API文档一样精确这个技能做什么、不做什么、输入是什么、输出是什么。我见过很多人把描述写成“一个很有用的工具”结果Agent根本不知道什么时候该调用它。好的描述应该是“根据给定的Git diff生成代码审查意见输出Markdown格式包含问题严重程度分级”。触发条件。有些技能是“显式调用”的比如用户说“用代码审查技能看看这个PR”有些是“隐式触发”的比如Agent检测到用户粘贴了一段diff自动判断需要审查。触发条件写得好技能才能被正确激活。常见做法是用自然语言描述触发场景再配合一些关键词或模式匹配。执行逻辑。这是技能的主体。可以是一段结构化的提示词也可以是一段可执行代码比如Python脚本、Shell命令还可以是两者的组合。如果是代码需要明确运行环境、依赖包、输入输出格式。我个人的经验是能写成代码的就不要写成提示词因为代码的行为更确定、更容易测试、更容易复用。依赖与版本。技能可能依赖其他技能也可能依赖外部工具或库。比如一个“生成图表”的技能可能依赖“数据清洗”技能先跑完还可能依赖matplotlib这个库。版本号的作用是当技能更新后依赖它的上层技能可以选择升级或锁定旧版本避免“一改全崩”。测试用例。这是最容易被忽略但最重要的部分。一个技能如果没有测试用例你根本不知道它什么时候会失效。测试用例应该包含典型输入、预期输出、边界情况。我习惯给每个技能至少写三个测试一个正常场景、一个边界场景、一个错误场景。2.3 与MCP、npx等机制的协作关系热搜词里出现了“claude mcpservers npx”和“npx playwright install失败”这说明Agent Skills并不是孤立存在的它和MCPModel Context Protocol、npx这类工具有协作关系。简单来说MCP解决的是“Agent怎么连接外部工具和数据源”的问题Skills解决的是“Agent怎么组织和复用能力”的问题。举个例子你有一个MCP Server它封装了数据库查询能力。Agent通过MCP可以执行SQL。但“执行什么SQL、怎么分析结果、怎么呈现”这一整套逻辑就可以封装成一个Skill。Skill内部可以调用MCP Server提供的工具也可以调用本地脚本。npx在这里的角色是“技能的分发和运行载体”——很多Skills以npm包的形式发布通过npx可以直接运行不需要全局安装。这种分层设计的好处是MCP层保持稳定和通用Skills层保持灵活和多样。你可以随时新增一个Skill而不需要改动MCP Server也可以替换MCP Server的实现而不影响上层Skills的逻辑。3. 核心细节解析一个Skill从编写到运行的完整链路3.1 技能目录结构与文件组织一个标准的Skill通常以一个目录的形式存在目录名就是技能名。目录内部一般包含以下文件my-skill/ ├── SKILL.md # 技能主文件包含元数据和执行指令 ├── scripts/ # 可执行脚本目录 │ ├── main.py # 主逻辑 │ └── utils.py # 辅助函数 ├── tests/ # 测试用例 │ ├── test_normal.py │ └── test_edge.py ├── requirements.txt # Python依赖 └── README.md # 使用说明SKILL.md是整个技能的入口。它通常用YAML frontmatter写元数据用Markdown写执行指令。元数据部分包括name、description、version、author、dependencies、triggers。执行指令部分可以是自然语言描述也可以是伪代码还可以直接引用scripts目录下的脚本。我自己的习惯是元数据写得尽可能详细执行指令写得尽可能简洁。因为元数据是给Agent“看”的用来判断是否调用执行指令是给Agent“执行”的越简洁越不容易出错。如果逻辑复杂就抽到scripts里执行指令只写“运行scripts/main.py传入参数X”。注意目录名和SKILL.md里的name字段要保持一致否则某些加载器会报错。这个坑我踩过排查了半天才发现是命名不一致导致的。3.2 技能描述与触发条件的写法描述和触发条件是Skill能否被正确调用的关键。我总结了一个“三段式”写法第一段写功能这个技能做什么。用动词开头比如“生成”、“转换”、“分析”、“校验”。第二段写输入输出需要什么输入产出什么输出。输入要写清楚格式和来源输出要写清楚格式和用途。第三段写边界什么情况下不该用这个技能。这一点很多人不写导致Agent在错误场景下调用结果很糟糕。举个例子一个“代码审查”技能的描述可以这样写根据给定的Git diff生成代码审查意见。输入为统一diff格式的文本输出为Markdown格式的审查报告包含问题描述、严重程度、修改建议。不适用于审查非代码文件如配置文件、文档不适用于超过500行的diff。触发条件可以写成“当用户提供diff内容并询问代码质量时触发”或者“当用户明确说‘审查代码’时触发”。有些平台支持正则表达式触发那就写得更精确一些。3.3 执行逻辑的三种实现方式执行逻辑的实现方式直接决定了技能的灵活性、确定性和可维护性。我把它分成三种各有适用场景。纯提示词方式。技能主体就是一段结构化的提示词Agent读取后直接执行。优点是编写快、不需要运行环境缺点是行为不确定、难以测试、容易受上下文干扰。适合“创意生成”、“文本润色”这类没有标准答案的任务。脚本调用方式。技能主体是一段代码Agent负责调用并传入参数。优点是行为确定、可测试、可复用缺点是需要运行环境、需要处理依赖。适合“数据转换”、“格式校验”、“文件操作”这类有明确输入输出的任务。混合方式。提示词负责“理解和决策”脚本负责“执行和计算”。比如一个“数据分析”技能提示词部分让Agent理解用户意图、选择合适的分析方法脚本部分执行具体的统计计算。这种方式最灵活但也最复杂需要设计好提示词和脚本之间的接口。我个人的选择标准是如果任务有唯一正确答案用脚本如果没有唯一答案用提示词如果既有理解又有计算用混合。3.4 依赖管理与版本控制策略依赖管理是Skills生态里比较头疼的问题。一个技能可能依赖Python包、系统工具、其他技能、甚至特定版本的模型。如果依赖没管好就会出现“在我机器上能跑在你机器上报错”的情况。我的做法是显式声明所有依赖并锁定版本。Python依赖写在requirements.txt里用pip freeze生成精确版本。系统工具依赖写在SKILL.md的元数据里注明最低版本要求。技能之间的依赖用名称版本范围表示比如># 检查Node.js版本 node --version # 建议18以上 # 检查Python版本 python3 --version # 建议3.10以上 # 安装常用的Skills运行工具 npm install -g anthropic-ai/skills-cli # 示例具体包名以官方为准云端运行环境适合部署和共享。如果你用GKE可以把Skills打包成容器镜像通过Kubernetes部署。这样做的好处是环境一致、易于扩缩容。但配置起来复杂一些需要写Dockerfile和K8s manifest。我建议先用本地环境把技能跑通再考虑上云。工具选型方面我推荐几个常用的skills-cli用于本地管理和测试技能playwright用于需要浏览器操作的技能热搜词里提到“npx playwright install失败”后面会讲怎么解决pytest用于写测试用例。4.2 编写第一个Skill以“周报生成”为例我拿一个实际用过的技能来演示根据一周的Git提交记录生成周报。这个技能不复杂但涵盖了Skill的完整要素。首先创建目录结构mkdir weekly-report-skill cd weekly-report-skill mkdir scripts tests touch SKILL.md requirements.txt然后写SKILL.md--- name: weekly-report description: 根据Git提交记录生成周报。输入为日期范围输出为Markdown格式的周报包含完成事项、进行中事项、下周计划。不适用于非代码项目的周报生成。 version: 1.0.0 author: your-name dependencies: - python3.10 - git triggers: - 用户要求生成周报 - 用户提供日期范围并提及周报 --- # 周报生成技能 ## 执行步骤 1. 运行 scripts/collect_commits.py传入日期范围参数获取提交记录。 2. 运行 scripts/generate_report.py传入提交记录生成周报草稿。 3. 将草稿呈现给用户询问是否需要调整。 ## 输入格式 日期范围格式YYYY-MM-DD 到 YYYY-MM-DD ## 输出格式 Markdown格式包含三个部分完成事项、进行中事项、下周计划。接着写scripts/collect_commits.pyimport subprocess import sys from datetime import datetime def collect_commits(start_date, end_date): cmd [ git, log, f--since{start_date}, f--until{end_date}, --prettyformat:%h|%an|%ad|%s, --dateshort ] result subprocess.run(cmd, capture_outputTrue, textTrue) if result.returncode ! 0: print(fError: {result.stderr}, filesys.stderr) sys.exit(1) return result.stdout if __name__ __main__: start sys.argv[1] end sys.argv[2] commits collect_commits(start, end) print(commits)再写scripts/generate_report.py把提交记录按作者和日期分组生成Markdown格式的周报。这部分逻辑比较直接我就不展开代码了核心思路是按日期排序、按作者分组、提取提交信息中的关键词、生成三个部分的草稿。最后写测试用例tests/test_normal.pyimport subprocess def test_collect_commits(): result subprocess.run( [python, scripts/collect_commits.py, 2024-01-01, 2024-01-07], capture_outputTrue, textTrue ) assert result.returncode 0 assert | in result.stdout or result.stdout 跑一遍测试cd weekly-report-skill python -m pytest tests/ -v如果测试通过这个技能就可以用了。在支持Skills的Agent里把技能目录放到指定位置Agent就能在用户要求生成周报时自动调用。4.3 技能测试与调试的实操记录测试Skill和测试普通代码不太一样因为Agent的调用行为有不确定性。我的做法是分三层测试第一层单元测试。测试脚本本身的逻辑比如输入日期范围能否正确返回提交记录、输入空范围能否处理。这层用pytest就够了。第二层集成测试。模拟Agent调用技能的过程检查技能能否被正确加载、参数能否正确传递、输出是否符合预期。这层需要用到Agent平台提供的测试工具或者自己写一个模拟调用器。第三层端到端测试。在真实对话场景里测试看Agent是否在正确的时机调用技能、调用后结果是否可用。这层最耗时但也最能发现问题。我踩过的一个坑是技能在单元测试里跑得好好的但在真实对话里Agent根本不调用它。排查后发现是描述写得太模糊Agent判断“这个技能和当前任务不相关”。后来把描述改得更具体加上触发关键词问题就解决了。另一个坑是技能执行时间太长导致Agent超时。比如一个技能要跑几分钟的爬虫Agent等不了那么久。解决办法是把长任务拆成“启动任务”和“查询结果”两个技能或者用异步方式执行。4.4 技能发布与共享的注意事项如果你想把技能分享给团队或发布到公共市场有几个点需要注意。脱敏处理。技能里不要包含任何敏感信息比如API密钥、内部地址、个人数据。我见过有人把数据库连接字符串直接写在技能里发布后被人扫到后果很严重。正确做法是用环境变量或配置文件并在文档里说明如何配置。文档完整性。README要写清楚技能做什么、怎么安装、怎么配置、怎么使用、常见问题。最好附上示例输入和输出。文档写得好的技能使用率会高很多。版本兼容性。发布时注明支持的Agent平台和版本范围。有些技能依赖特定平台的API换一个平台就跑不了。如果要做跨平台需要抽象出适配层。许可证。如果是开源发布选一个合适的许可证。MIT最宽松Apache 2.0多了专利授权GPL要求衍生作品也开源。根据你的需求选。5. 常见问题与排查技巧实录5.1 安装类问题npx playwright install失败怎么处理热搜词里“npx playwright install失败”出现频率很高我专门说一下。这个问题的典型表现是运行npx playwright install时卡住、报网络错误、或者下载的浏览器无法启动。原因通常有三个网络问题、权限问题、版本不匹配。排查顺序如下先检查网络。Playwright需要从CDN下载浏览器二进制包如果网络不通就会失败。可以尝试设置镜像源或者手动下载后放到缓存目录。具体命令# 设置下载镜像示例 export PLAYWRIGHT_DOWNLOAD_HOSThttps://your-mirror.example.com # 或者手动指定浏览器路径 export PLAYWRIGHT_BROWSERS_PATH/path/to/browsers再检查权限。在Linux上如果当前用户没有写入缓存目录的权限也会失败。用ls -la看一下缓存目录的权限必要时用chmod修改。最后检查版本。Playwright的版本和浏览器版本要匹配如果package.json里锁定了旧版本但安装命令拉取了新浏览器就会不兼容。解决办法是统一版本npx playwright install --with-deps会自动安装匹配的依赖。提示如果以上都试了还是失败可以先用npx playwright install --dry-run看看它打算下载什么然后手动下载对应的包放到缓存目录。这个办法虽然笨但很有效。5.2 调用类问题Agent不调用或错误调用技能这是最常见的问题。表现是你明明写了技能但Agent要么不调用要么在错误的场景调用。不调用的原因通常是描述不够具体。Agent判断是否调用技能主要看描述和当前任务的相关性。如果描述太泛Agent可能觉得“这个技能好像能用又好像不能用”干脆不用。解决办法是把描述写具体包含明确的触发词和场景。错误调用的原因通常是触发条件太宽泛。比如你写“当用户提到代码时触发”结果用户只是随口提了一句代码Agent就调用了代码审查技能。解决办法是加限制条件比如“当用户提供diff内容并明确要求审查时触发”。还有一个隐蔽的原因是技能之间的优先级冲突。如果有两个技能都声称能处理同一类任务Agent可能随机选一个。解决办法是在描述里写清楚适用场景的差异或者用命名空间区分。5.3 执行类问题技能运行报错或超时技能运行报错的原因很多我整理了一个速查表错误类型典型表现排查方向解决办法依赖缺失ModuleNotFoundError检查requirements.txt安装缺失的包锁定版本路径错误FileNotFoundError检查相对路径和绝对路径用绝对路径或基于技能目录的路径权限不足PermissionError检查文件和目录权限修改权限或换目录超时TimeoutError检查任务耗时拆分任务或增加超时时间参数错误TypeError检查参数格式和数量在SKILL.md里写清楚参数规范超时问题特别常见。Agent平台通常有执行时间限制比如30秒或60秒。如果你的技能要跑几分钟肯定超时。解决办法有两个一是优化脚本减少不必要的计算二是把长任务拆成多个短任务用状态文件记录进度。5.4 维护类问题技能更新后旧调用失效技能更新后依赖它的上层技能或工作流可能失效。这是版本管理没做好导致的。我的做法是每次更新技能都跑一遍所有依赖它的测试用例。如果测试通过说明兼容如果失败说明有破坏性改动需要升级主版本号并通知依赖方。另外我习惯在技能目录里放一个CHANGELOG.md记录每个版本的变更内容。这样别人升级时能快速了解改了什么、要不要升级。还有一个技巧是保留旧版本。不要直接覆盖而是把旧版本归档到versions/目录下。这样如果新版本出问题可以快速回滚。6. 技能生态的扩展玩法与个人经验6.1 技能组合把多个Skill串成工作流单个技能的能力有限真正强大的是技能组合。比如你可以把“数据采集”、“数据清洗”、“数据分析”、“图表生成”、“报告撰写”五个技能串起来形成一个完整的数据分析工作流。组合的方式有两种串行和并行。串行就是前一个技能的输出作为后一个技能的输入适合有依赖关系的任务。并行就是多个技能同时执行最后汇总结果适合独立子任务。实现组合的关键是接口标准化。每个技能的输入输出格式要统一比如都用JSON都包含status、data、error三个字段。这样组合起来才顺畅。我做过一个“竞品分析”工作流包含六个技能搜索竞品信息、提取关键数据、对比分析、生成图表、撰写报告、格式化输出。整个流程跑下来大概两分钟比人工做快很多。但调试花了很久主要时间花在接口对齐上。6.2 技能市场去哪里找现成的Skills热搜词里“skills下载平台有哪些”、“skills大全”、“claude 国内安装skills 官方市场”说明很多人想找现成的技能。目前技能市场还比较分散主要有几个来源官方市场。Claude、Codex等平台都有自己的技能市场里面有一些官方和社区贡献的技能。质量相对有保障但数量有限。GitHub仓库。很多开发者会把自己的技能开源到GitHub搜索“agent-skills”或“claude-skills”能找到不少。质量参差不齐需要自己筛选。社区论坛。一些技术社区有专门的技能分享板块比如Reddit的r/AgentSkills、Discord的Skills频道。这里能找到一些实验性的技能但要注意安全。自己写。最可靠的还是自己写。现成的技能往往不能完全满足需求改别人的不如写自己的。注意从第三方下载技能时一定要审查代码。技能里可能包含恶意脚本比如窃取数据、执行危险命令。我一般会先看一遍代码确认没有可疑操作再使用。6.3 我踩过的三个坑和对应的解决方案第一个坑技能描述写得太长。我一开始觉得描述越详细越好结果写了两千多字Agent反而不知道重点在哪。后来改成“一句话功能一句话输入输出一句话边界”效果好了很多。第二个坑技能之间循环依赖。A技能依赖BB技能依赖A结果加载时死循环。解决办法是引入依赖层级禁止循环依赖或者在加载时检测并报错。第三个坑技能更新后忘记更新版本号。结果上层技能引用了旧版本行为不一致。后来我养成了习惯改完技能先更新版本号再跑测试再提交。6.4 对想入门Agent Skills的开发者的一点建议如果你刚开始接触Agent Skills我的建议是从一个小技能开始不要贪多。选一个你每天都要做的重复性任务把它封装成技能。比如“整理会议纪要”、“生成提交信息”、“格式化代码”。做完一个你就理解了整个流程再做第二个就快了。另外多看看别人写的技能。GitHub上有很多优秀的技能示例看别人怎么组织目录、怎么写描述、怎么处理错误能学到很多。我早期就是靠读别人的技能代码入门的。最后不要追求完美。技能是迭代出来的第一版能跑就行后面再慢慢优化。我见过很多人想一次写出完美的技能结果卡在细节上迟迟出不了第一版。先跑通再优化这个顺序不能反。7. 技能开发中的性能优化与安全边界7.1 减少上下文占用的技巧Agent的上下文窗口是有限资源技能设计要尽量节省。我的做法是技能描述只保留必要信息详细文档放到README里。Agent只需要知道“这个技能做什么、什么时候用”不需要知道“内部怎么实现”。实现细节放在脚本里Agent调用时不需要读取。另外技能输出要精简。有些技能返回一大堆调试信息占用了大量上下文。解决办法是只返回Agent需要的结果调试信息写到日志文件里。如果Agent需要中间结果用摘要而不是全文。还有一个技巧是延迟加载。如果技能很多不要一次性全部加载而是按需加载。Agent判断需要某个技能时再去读取它的SKILL.md。这样上下文里只出现当前用到的技能。7.2 技能执行的安全边界设定技能可以执行代码这意味着安全风险。一个恶意技能可能删除文件、发送数据、执行危险命令。设定安全边界很重要。我的做法是限制技能的文件系统访问范围。技能只能读写指定目录不能访问系统目录。限制网络访问。如果技能不需要联网就禁止网络请求。限制执行时间。超过时间限制就强制终止。审查第三方技能。使用前先看代码确认没有可疑操作。在团队协作场景下还可以建立技能审核机制新技能提交后由专人审查代码和权限通过后才能发布。7.3 技能复用与团队协作的实践在团队里推广Agent Skills最大的阻力不是技术而是习惯。大家习惯了写提示词觉得封装技能太麻烦。我的经验是先做一个“杀手级”技能让大家看到好处。比如一个“自动生成周报”的技能能帮每个人省半小时大家就有动力用了。然后建立技能库和规范。统一目录结构、统一描述格式、统一测试标准。新技能必须通过测试才能入库。定期清理不再使用的技能保持库的整洁。最后鼓励分享。每周或每两周开一次技能分享会大家展示自己新写的技能互相学习。我所在的团队就是这么做的半年下来积累了三十多个技能覆盖了日常工作的方方面面。8. 从技能到能力Agent Skills的长期价值8.1 技能作为团队知识资产技能不仅仅是工具更是知识的载体。一个写好的技能封装了“怎么做这件事”的最佳实践。新人加入团队不需要从头学起直接调用技能就能产出合格的结果。这比写文档有效得多因为文档可能过时技能是活的、可执行的。我所在的团队把技能库当成核心资产来维护。每个技能都有负责人定期更新。技能库的版本和代码库的版本同步发布。新项目启动时先看看技能库里有哪些现成的能力可以复用而不是从零开始。8.2 技能标准化对生态的影响Agent Skills生态要健康发展标准化是关键。目前不同平台的技能格式还不统一导致技能难以跨平台复用。我期待未来能出现类似“技能描述规范”、“技能接口标准”这样的共识让技能像npm包一样写一次就能到处运行。在标准形成之前我的建议是尽量把技能逻辑和平台接口分离。核心逻辑写在脚本里平台相关的部分用适配层封装。这样将来换平台时只需要改适配层不需要重写技能。8.3 我个人对技能生态的观察从最近的热搜词来看Agent Skills正处于爆发前夜。工具链在完善社区在形成平台在支持。但同时也存在泡沫很多人为了写技能而写技能做出来的东西没人用。我的判断是能解决真实问题的技能会留下来为了炫技的技能会消失。如果你现在开始投入Agent Skills建议聚焦在“高频、重复、有明确标准”的任务上。这类任务最适合封装成技能也最容易看到效果。至于那些“低频、创意、没有标准答案”的任务还是留给人类吧。最后分享一个小技巧我习惯在每天工作结束时花五分钟回顾今天做了哪些重复性操作然后挑一个封装成技能。日积月累技能库就丰富起来了。这个过程本身也很有趣你会发现很多以前没注意到的效率瓶颈。
返回列表