1. 从三件家务说起:AtomGit 开源大赛里的 Python Skill 实战复盘
先交代背景。AtomGit 和 OpenClaw 联合办的第一季开发大赛,主题叫「破壳·进化」,赛道分 Agent 提效专家、AI 创意生活、技能高手三个方向。我报的是技能高手赛道,要求很朴素:一个 Python 文件加一个 config 文件,能跑通就能提交。当时报名 76 人,一等奖 1 个、二等奖 2 个、三等奖 3 个,一共 6 个奖位,我最后拿了三等奖,总分 8.2。
我做的项目叫「三务管家 TriHub」,把三件每天都要重复处理的「家务」塞进一个 AI Skill 里:查快递、记账、家庭日程。这三件事单独看都不难,难的是它们分散在三四个 App 里,每天都要来回切。快递要在淘宝、京东、拼多多之间跳;记账 App 下了好几个,没一个坚持过两周;老婆说「周六交电费」,我转头就忘。它们的共同点是轻量、高频、事务性,不需要重量级应用,一个 Skill 就能兜住。
这篇文章不是获奖感言,是一份可以照着搭的复盘。我会把 Skill 的目录结构、config.json 配置片段、本地跑通命令、提交前的验证步骤都写清楚,你照着做就能搭出一个同款参赛项目。适合谁看:写过一点 Python、想参加 AtomGit 这类开源大赛、或者单纯想把日常重复事务交给 AI 的人。核心检索词就三个:AtomGit 开源大赛、Python Skill SDK、OpenClaw Skill 开发。
技术栈上没什么高深的。Skill SDK 负责把接口描述清楚,模型负责理解用户那句模糊的自然语言,业务逻辑我自己写。模型我用的是 MiMo-V2-Pro,它在解析「SF123456 到哪了」这种输入时,能准确识别出 track 意图并提取单号。下面按「问题场景 → 前置准备 → 可复制配置 → 验证请求 → 错排查 → 后续」的顺序展开,每一步都有命令和结果说明。
2. 前置准备:OpenClaw 环境与 Skill SDK 接入配置
动手之前先把环境理清楚。Skill 赛道对运行环境的要求不高,Python 3.10 以上、能装依赖、有一个能调模型的入口就行。我本地是 macOS,Linux 和 Windows 的 WSL 同样适用。整个项目最终只有三个文件:skill_trihub.py、config.json、README.md,核心代码 15KB 出头。
第一步是确认 OpenClaw 已经跑起来。我之前为了做 Hermes 集成装过一次,所以这次直接复用。如果你还没装,按官方文档走一遍即可,这里不展开安装细节,重点讲 Skill SDK 的接入。Skill SDK 的设计比我想象的简单:你绑好参数、写好接口描述,模型自己会去理解用户意图并调度。开发者只需要关注业务逻辑本身。
第二步是准备模型调用入口。Skill 要能解析自然语言,就得有一个稳定的模型 API。我用的是 TaoToken 提供的接口,它的好处是 Base URL、Key、Model ID 三件套清晰,配置进 config.json 就能用,不用改代码。官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api ,注意 API 地址不带 UTM 参数。
第三步是建仓库。AtomGit 上新建一个公开仓库,目录结构建议直接照抄我下面这份,评委看 README 和目录的第一眼就决定了他会不会认真读你的代码:
skill_trihub/ ├── skill_trihub.py # 核心代码,三个模块的入口都在这里 ├── config.json # 参数配置:模型、API、预算阈值等 └── README.md # 说明书:功能、用法、示例对话这里有个踩过的坑:很多人把三个功能写成三个文件,结果提交时不符合「1 个 Python 文件」的硬性要求。正确做法是在skill_trihub.py里用三个函数或三个类区分模块,对外只暴露一个 Skill 入口。快递、财务、日程各自独立,互不依赖,这样任何一个模块出问题都不会拖垮整体。
依赖方面只需要requests和python-dateutil,前者调接口,后者处理「周六前」这类模糊日期。装依赖:
pip install requests python-dateutil到这一步,环境、模型入口、仓库骨架都齐了。接下来进入最关键的部分:把 config.json 和 Skill 入口写对。
3. 可复制配置:config.json 与 Skill 入口片段
这一节是全文最该抄的部分。先给 config.json 的完整片段,路径就是仓库根目录下的config.json,字段名和 Skill SDK 的约定保持一致,你直接改 Key 和 Model ID 就能用:
{ "skill_name": "trihub", "version": "1.0.0", "model": { "base_url": "https://taotoken.net/api", "api_key": "sk-你的Key", "model_id": "MiMo-V2-Pro", "timeout": 30 }, "modules": { "express": { "enabled": true, "carriers": ["SF", "ZTO", "YTO", "JD"], "abnormal_keywords": ["滞留", "派送失败", "退回"] }, "finance": { "enabled": true, "budget_monthly": 5000, "alert_ratio": 0.8, "categories": ["餐饮", "交通", "购物", "居家", "其他"] }, "schedule": { "enabled": true, "default_remind_hour": 9, "birthday_repeat_yearly": true } } }三件套在这里体现得很清楚:Base URL 是https://taotoken.net/api,Key 填你自己的,Model ID 是MiMo-V2-Pro。这三个值缺一不可,后面排障章节会专门讲它们各自报什么错。
接着是 Skill 入口。skill_trihub.py的结构我拆成三层:意图识别层、模块分发层、业务实现层。意图识别层把用户那句话交给模型,让它返回一个结构化结果,比如{"intent": "track", "params": {"no": "SF123456"}}。模块分发层根据 intent 路由到对应函数。业务实现层干实际的活。
意图识别的核心片段长这样:
import json import requests def parse_intent(user_text, cfg): prompt = ( "你是三务管家的意图解析器。把用户输入解析为 JSON," "intent 只能是 track / finance / schedule 之一。" "track 提取单号 no;finance 提取金额 amount 和备注 note;" "schedule 提取事项 title 和时间 time。只输出 JSON。" ) resp = requests.post( f"{cfg['model']['base_url']}/v1/chat/completions", headers={"Authorization": f"Bearer {cfg['model']['api_key']}"}, json={ "model": cfg["model"]["model_id"], "messages": [ {"role": "system", "content": prompt}, {"role": "user", "content": user_text}, ], "temperature": 0, }, timeout=cfg["model"]["timeout"], ) content = resp.json()["choices"][0]["message"]["content"] return json.loads(content)这段代码有两个设计点值得说。一是temperature设为 0,意图解析要的是稳定,不是创意,同样的输入必须给同样的结果。二是强制「只输出 JSON」,这样json.loads不会因为模型多说了句「好的,我来帮你解析」而崩掉。如果模型偶尔不听话,可以在解析前做一次content.strip().strip('').replace('json', '')` 的清洗。
财务模块的自动分类也依赖模型。用户写「星巴克」,模型归到餐饮;写「地铁」,归到交通。分类结果写进本地 JSON 文件,按月汇总时再让模型生成一段自然语言洞察,比如「这个月外卖花了 1200,比上月多了 30%,主要原因是……」,而不是甩一张干巴巴的表格。
日程模块用dateutil处理「周六前」这类相对时间,转成绝对日期后存下来,每年生日用birthday_repeat_yearly标记循环提醒。
配置写完,先别急着提交,本地跑一遍再说。
4. 验证请求:本地跑通与提交前自检命令
配置写对不等于能跑通。我习惯先写一个最小验证脚本,单独测模型调用,确认三件套没问题,再去测业务逻辑。这样出错时能快速定位是配置问题还是代码问题。
最小验证脚本test_model.py:
import json import requests cfg = json.load(open("config.json")) resp = requests.post( f"{cfg['model']['base_url']}/v1/chat/completions", headers={"Authorization": f"Bearer {cfg['model']['api_key']}"}, json={ "model": cfg["model"]["model_id"], "messages": [{"role": "user", "content": "SF123456 到哪了"}], }, timeout=30, ) print(resp.status_code) print(resp.json()["choices"][0]["message"]["content"])跑python test_model.py,如果返回 200 并且 content 里能看出模型识别出了快递单号,说明模型入口通了。这一步过了,再跑完整的 Skill:
python skill_trihub.py --input "帮我看看这个月花了多少钱" python skill_trihub.py --input "提醒我周六前交电费" python skill_trihub.py --input "SF123456 到哪了"三条命令分别对应财务、日程、快递三个模块。实测下来,只要意图解析的 prompt 写清楚,三条路径都能正常走通。快递模块还会额外做一次异常检测:把轨迹里的「滞留」「派送失败」这些关键词交给模型判断,命中就给出处理建议,比如「联系派件员」或「申请理赔」。
提交前我做了三件事,建议你也照做。第一,检查文件数量,确认仓库里只有一个.py和一个config.json,多一个都算违规。第二,把config.json里的 Key 换成占位符,别把真实 Key 提交上去,评委不需要你的 Key 也能看代码。第三,README 里写清楚三件事:这个 Skill 解决什么问题、怎么装依赖、三条示例对话分别是什么。评委看 README 的时间可能比看代码还长。
提交到 AtomGit 的命令:
git init git add skill_trihub.py config.json README.md git commit -m "feat: TriHub 三务管家 skill" git remote add origin <你的 AtomGit 仓库地址> git push -u origin main推送成功后,去大赛页面确认作品已经出现在列表里。到这里,一个能参赛的 Skill 就完成了。
5. 常见错排查:401、local proxy failed 与 reading choices
这一节按真实报错来。我在开发和提交过程中踩过的坑,基本都集中在这几类,你遇到时可以直接对照。
401 Unauthorized。最常见,几乎都是 Key 的问题。要么 Key 填错,要么 Key 前后带了空格,要么把Bearer拼成了bearer。检查config.json里的api_key字段,确认没有多余字符。还有一种情况是 Key 过期或额度用尽,去控制台看一眼余额即可。控制台入口在 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite 。
local proxy failed。这个报错通常出现在请求根本没发出去的时候,说明 Base URL 写错了或者网络层被拦了。先确认base_url是https://taotoken.net/api,注意结尾不要多加/v1,路径拼接在代码里做。如果确认地址没错还是报这个,检查本地是否有环境变量HTTP_PROXY、HTTPS_PROXY指向了不可用的地址,清掉再试。
reading 'choices' of undefined。这是 JS 风格的报错,在 Python 里对应的是KeyError: 'choices'或TypeError: 'NoneType' object is not subscriptable。根因是resp.json()里没有choices字段,说明返回的不是标准结构。打印完整的resp.text看看到底返回了什么,通常是模型名写错、请求体格式不对,或者触发了限流返回了错误信息。确认model_id和请求体里的model字段一致。
OAuth 相关报错。如果你用的是需要 OAuth 的客户端(比如某些 CLI 工具),报错会提示 token 无效或回调失败。这类问题的排查思路是:先确认 OAuth 流程是否走完,再确认拿到的 token 有没有正确写进配置。如果你只是调 API,不走 OAuth,那这个报错一般不会出现。
模型返回的不是 JSON。意图解析时json.loads崩了。原因是模型多说了话。解决办法是在 prompt 里强调「只输出 JSON,不要任何解释」,并在解析前做一次清洗。如果还是不稳定,把temperature降到 0,或者换一个更听话的模型。
提交后作品不显示。检查仓库是不是公开的,私有仓库评委看不到。再检查文件是不是推到了默认分支,有些平台只读 main 分支。
把这几类错排掉,你的 Skill 基本就能稳定运行了。排障过程中如果需要查接口文档,文档入口在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。
6. 后续:把 Skill 用起来,比拿奖更重要
比赛结果出来那天我其实没太关注,在做别的事,后来收到短信才知道获奖了。8.2 分,三等奖,华为充电宝一个。分数拆开看:创新性 30%、完成度 30%、实用性 30%、社区投票 10%。我给自己实用性打高分,因为这三个功能我到现在还在用,不是做完就扔在那里吃灰的那种。社区投票那 10% 我拿得不多,因为没去拉票,下次再参赛会多花点精力在这块。
比拿奖更有意思的是参赛本身。你的作品放在那里被评分、被人看,这会逼你把 README 写清楚、把代码写规范、把功能跑通。以前总觉得比赛是学生的事,工作了就没时间也没心思,这次纯粹是看到「1 个 Python 文件」的门槛忍不住手痒。
如果你也想搭一个同款,我的建议是先跑通最小验证脚本,再往里加模块,别一上来就写三个功能。模型入口用 TaoToken 的三件套配好,Base URL、Key、Model ID 对齐,后面就只剩业务逻辑。想验证模型效果,可以去模型对话页面直接试 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat&utm_campaign=rewrite ;如果你打算长期做编码类或 Agent 类项目,Coding Plan 会更划算 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ;Key 的申请和管理在 API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。
项目开源在 AtomGit,欢迎 star、fork、提 PR。真要加功能的话,「水电煤缴费」这类倒是挺实用。华为充电宝还在路上,等到了我拍个开箱发评论里。