背景
在 AI 时代,自然语言处理已经是我们获取信息的“第一工具”。我作为一个接触电脑较早的人,以及更重要的是拼音拼不准的南方人,自然五笔输入法是我的首选。如果没了五笔,我感觉自己几乎不会打字。虽然日常输入熟悉的汉字很快,但一旦遇到“提笔忘字”或不知道如何拆解的生僻字,思路往往会被打断。即便有些输入法可以反查五笔,但有时你仍然不知道它为何这么打。
为了解决这个痛点,周末闲着无事开发了个 Alfred Workflow,实现快速查看某个字是如何打的并且显示五笔拆字过程,方便真正理解你为何会打不出这个字。 当然作为技术文章,我更想分享的是:在 AI 的帮助下,我是如何突破开发过程中的重重困难的,而非 Workflow 本身。
效果展示

你还可以修改一下 里面的命令使其打出其它编码是如何拆解的。只需要修改过滤展示(–only 参数)
alfred_wubi.py 支持通过 --only 选择要展示的字段,逗号分隔(不区分大小写):
- summary:总体汇总行
- 编码:num5, num6, num9, wb86, wb98, wbx (新世纪), strokes
- 拆解图片:num6_parts, num9_parts, wb86_parts, wb98_parts, wbx_parts
分别是:王码 5/6/9 键、五笔 86/98/新世纪、笔画序列。
示例: 当前默认展示五笔 86 编码及其拆解:
| |
如果你是五笔输入法爱好者,只是想使用这个插件,那么跳到文章后面部分即可找到相关链接。接下来我会讲一下技术实践啦。
调研与选型
在开始开发前,我调研了现有的开源方案,发现 alfred-wubi-workflow 已经是 6 年前更新的仓库,其依赖的 chaiwubi.com 也已无法访问。经过搜索网站,我找到了两个可用的五笔反查源:
- 打字吧 (http://www.daziba.cn)
- 王码官方 (http://www.wangma.com.cn)
王码官方的数据显然更权威,不仅有 86/98 版,还有新世纪版和数字王码。考虑到刚才那个仓库依赖的网站已不可用,我就打算傍个大款,就选择王码了。但它有一个巨大的拦路虎:查询时必须输入 4 位数字验证码。

这意味着,想要集成在工具中自动化查询,必须先破解它的验证码。
梳理整体逻辑
我将需求以及关键截图告诉 AI:
| |
AI 基于网页进行自动分析,并给出了它的分析结果:
| |
这个处理流程细节满满,感觉它对这个网站的分析已经很透彻了,将这个过程保存为文档,后续交给 AI 作为实现的上下文。
核心挑战:攻克验证码
这是整个项目最核心,也是最有意思的部分。为了解决这个 4 位数字验证码,我尝试了四种方案,见证了从“传统算法”到“深度学习”的降维打击。
方案一:模板匹配
最直觉的想法,当然也是 AI 提议下,我下载了一批验证码(20 个),切分出 0-9 的数字图片作为“模板”。识别时,拿目标图片去和模板逐一比对。
相关代码如下:
| |
刚开始用这个方法跑了一下,我在默认重试 5 次后,发现还是会出现有些验证码过失败了。仔细查看发现这个方案的一些问题:
- 对于旋转/位移敏感:只要数字稍微歪一点,模板匹配就会匹配错误。例如 把
3认成了0(正确=9301, Template=9001)。 - 相似度陷阱:
3和8极其容易混淆,6和8也是高频混淆对。
方案二:使用 EasyOCR
为了验证方案一的准确率,我想引入另一个 OCR 来校验一下。于是我接入了流行的开源库 EasyOCR。
| |
使用虽然简单,它需要下载一个比较大的模型,比我们上面的模板匹配要好一些,但整体感受还是不理想。比如EasyOCR 经常把背景噪点强行识别为数字,导致多读位数。例如真实是 1889,EasyOCR 读成了 18889,多读了一位,可能是噪点被当成了8。再比如0 经常被误读为 8 或 6。
方案三:Tesseract
看起来这个 EasyOCR 可能对我们这个专属场景并不太合适,AI 又建议我使用老牌 OCR 引擎 Tesseract。
| |
这个结果更差,有不少图片无法识别,更别说准确率了。即使识别出来,准确度也很低,偶尔能出几个正确的。说来也神奇,它倒是有些能把 EasyOCR 认错的给整对,我也是奇了个怪。
方案四:训练自己的 CNN 模型
到这里我有点生气了,为何看似这么简单的验证码,这几个方法的效果都不尽人意呢?!
在 LLM 的建议下,我决定“杀鸡用牛刀”:训练一个专门识别这 4 位数字的卷积神经网络(CNN)。 有多个强大的 LLM 作为编程伙伴,以前想都不敢想的训练自己的模型,现在 闭眼冲 (自信又莽撞)了 :P
1. 训练数据从何而来
数据当然是直接从网页拉取,这里主要说数据的标注过程。 前面的模型或方法虽然弱, 但好歹能够识别出一些信息,我不想手动去标注几百张图,那就让两个弱模型(Template Matching 和 EasyOCR)打打工,由它们初步标注出数据,我在对有异议的内容进行人工纠错。
后续随着我们自己的 CNN 模型也具备一定能力,让它也参与标注,我们实际手工要修改的数据越来越少。看 100 张图实际也就 1-2 分钟搞定。
2. 模型设计
LLM 帮我生成了一个轻量级的 CNN 结构 (PyTorch),核心还是经典的“卷积提特征 + 全连接分类”:
| |
训练时的 Loss Design:因为有 4 个输出,Loss 也是 4 部分的总和:
| |
同时准备好训练脚本,我们只要指定数据集路径,就能开始训练:
| |
3. 训练过程
本着边跑边看,我分了多轮进行训练,这样我们的标注也会越来越准确。
- 第一轮:先抓取 20 张图,让 Template Matching 和 EasyOCR 同时跑,人工校对后,得到了这三个方案的准确率:
Model Accuracy Correct Total Template Matching 100.0% 20 20 EasyOCR 65.0% 13 20 Tesseract 20.0% 4 20
然后基于这个训练了第一版 CNN 模型。
- 第二轮:基于第一轮的模型,再抓取 20 张图, 这样加前面共 40 张图,让 CNN 模型和其它方案一起跑,得到四个方案的对比数据:
| Model | Accuracy | Correct | Total |
|---|---|---|---|
| EasyOCR | 75.0% | 15 | 20 |
| Template Matching | 50.0% | 10 | 20 |
| Tesseract | 25.0% | 5 | 20 |
| CNN (Round 1) | 5.0% | 1 | 20 |
可以看到只经过第一轮训练的模型( 20 张图片),识别效果很差,只有 5.0%。 我们 将这20 张图加入训练集,继续训练第二版CNN 模型。
- 第三轮:再抓取 60 张图(为了凑个 100),再次让 CNN 模型和 其它方案同时跑。
| Model | Accuracy | Correct | Total |
|---|---|---|---|
| EasyOCR | 60.0% | 36 | 60 |
| Template Matching | 51.7% | 31 | 60 |
| CNN (Round 2) | 33.3% | 20 | 60 |
| Tesseract | 21.7% | 13 | 60 |
已经看过 40 张图的 CNN 模型正确率已经从 5% 上升到 33.3%。然后让它继续学这 60 张图:
| |
现在看了 100 张图,CNN 模型会怎么样呢?
- 第四轮:基于第三轮的模型,再抓取 100 张图,再次对比:
| Model | Accuracy | Correct | Total |
|---|---|---|---|
| CNN (Round 3) | 83.0% | 83 | 100 |
| EasyOCR | 60.0% | 60 | 100 |
| Template Matching | 45.0% | 45 | 100 |
| Tesseract | 16.0% | 16 | 100 |
惊喜,居然从 33.3% 上升到 83.0%。这才看了 100张图呢,我这不又准备了 100 张素材,我有预感,似乎宝剑就要锻造出炉了。
| |
现在这个模型已经经过了 200 张图的训练,让我们拭目以待!
- 第五轮:我拉了全新的 100 张测试集,让模型再跑一次,这一次我没有标注,我将 CNN 和其它不同模型的识别结果对比,看下结果。Status 列中的状态是以 CNN 的角度来看和其它模型的差别:
- ✅ Trusted:模型和至少 2 个其它模型一致,可信。
- ❌ Unique:模型和所有模型都不一致,需要确认。
- ❓ Possible:模型只和其中一个一致,需要人工判断。
以下节选一部分:
| File | Original | Template | EasyOCR | Tesseract | Custom CNN | Status |
|---|---|---|---|---|---|---|
| vc0000.bmp | 0000 | 8681 | 8681 | 8684 | 8681 | ✅ Trusted |
| vc0001.bmp | 0001 | 6560 | 6560 | 6568 | 6560 | ✅ Trusted |
| vc0002.bmp | 0002 | 9001 | 93041 | 9304 | 9301 | ❌ Unique |
| vc0003.bmp | 0003 | 4710 | 4710 | 7418 | 4710 | ✅ Trusted |
| vc0004.bmp | 0004 | 5325 | 5822 | 5225 | 5225 | ❓ Possible |
| vc0005.bmp | 0005 | 0489 | 0489 | 0489 | ✅ Trusted | |
| vc0006.bmp | 0006 | 6918 | 6998 | 6998 | 6998 | ✅ Trusted |
| vc0007.bmp | 0007 | 3643 | 8648 | 8648 | ❓ Possible | |
| vc0008.bmp | 0008 | 3626 | 6626 | 6626 | 6626 | ✅ Trusted |
| vc0009.bmp | 0009 | 0602 | 0602 | 8682 | 0602 | ✅ Trusted |
| vc0010.bmp | 0010 | 2458 | 2747 | 2453 | 2453 | ❓ Possible |
| vc0011.bmp | 0011 | 5001 | 5381 | 5384 | 5381 | ❓ Possible |
| vc0012.bmp | 0012 | 8467 | 84767 | 8467 | ❓ Possible | |
| vc0013.bmp | 0013 | 8531 | 0541 | 3534 | 3531 | ❌ Unique |
| vc0014.bmp | 0014 | 7157 | 9197 | 9197 | ❓ Possible | |
| vc0015.bmp | 0015 | 4360 | 4360 | 4366 | 4360 | ✅ Trusted |
| vc0016.bmp | 0016 | 9769 | 974 | 9709 | 9769 | ❓ Possible |
| vc0017.bmp | 0017 | 9215 | 0275 | 0275 | ❓ Possible | |
| vc0018.bmp | 0018 | 2025 | 2025 | 2825 | 2025 | ✅ Trusted |
| vc0019.bmp | 0019 | 3504 | 8524 | 8524 | ❓ Possible | |
| vc0020.bmp | 0020 | 8690 | 3698 | 32698 | 3698 | ❓ Possible |
不看不知道,一检查吓一跳,这些CNN 和其它模型不一致的结果中,惊人的发现————CNN 识别的正确率高达 100%,为了确认不是花眼,我再次检查了这 100 张图,完全正确!
| Model | Accuracy | Correct | Total |
|---|---|---|---|
| CNN (Round 4) | 100.0% | 100 | 100 |
| EasyOCR | 63.0% | 63 | 100 |
| Template Matching | 38.0% | 38 | 100 |
| Tesseract | 17.0% | 17 | 100 |
这意味着,在识别这个网页的验证码这个特定任务上,我们的小模型已经“超神”了。它不仅完爆了 Template Matching,也大幅超越了 EasyOCR,而整个模型文件只有 7.9MB 大小。 这或许就是我们自己的领域专用视觉模型了。 有了它我很有信心可以将验证码的识别重试次数从 5 改到 1,咱不太可能失败了,哈哈,满意的笑了。
组装 Workflow
攻克了验证码,剩下的就是组装一下 Python 胶水代码给Alfred Workflow调用了。
AI 火速编写了 alfred_wubi.py,流程如下:
- 请求页面1:获取 Session 和验证码图片。
- 模型推理:加载我的
captcha_cnn.pth,瞬间识别出验证码。 - 构造 Payload:带上验证码 POST 请求页面 2。
- 解析 HTML:用 BeautifulSoup 提取五笔编码和拆字图 URL。
- 输出:JSON 格式给 Alfred 显示。
| |
这里对于 Python 库的依赖,我们可以使用.venv 来管理,避免和系统环境冲突。 你可以这样使用这个项目:
| |
然后使用 .venv/bin/python 来运行 python alfred_wubi.py。
后记
本文所提到的 Workflow 以及训练整个过程及数据已经开源在GitHub,你可以在这里查看:https://github.com/kevin1sMe/alfred-wubi-workflow。
文章到这里就是尾声啦,这其实是周末折腾其它过程中的小插曲,感觉挺有意思给大家一起分享下。现在我们打造的这个五笔反查工具,能够让我们告别某些生僻不会打的字。就像我前面截图中,“肃”字你会打吗?更关键的是通过这次折腾,让我更深刻感受到,在 AI 辅助编程的加持下,个人开发者解决问题的边界被极大地拓宽了。
以前遇到“需要训练一个模型来识别验证码”这种需求,可能因为觉得门槛太高就放弃了。但现在:
- 代码:LLM 帮我写好了 CNN 结构、帮我准备各种脚本,配合我一步步训练。
- 数据:LLM 帮我设计了自动化的标注脚本。
我只需要专注于聊清需求、定义问题和决策方案。从零开始到模型落地,只用了短短1-2个小时,这或许就是 AI 时代的编程范式吧。但是要整理出本文,为了将过程数据完整重现,我又重新一步步跑了一次,严谨的记录和对比了各个轮次的效果,再加上代码开源及整理,这里居然花了周末的一整个晚上。看在这么认真的份上,小手点个关注、点个赞不过分吧:)
持续折腾,不断进步,我们一起加油。期待下次有机会继续分享更好玩的内容,再会!
我是个爱折腾技术的工程师,也乐于分享。欢迎点赞、关注、分享,更欢迎一起探讨技术问题,共同学习,共同进步。为了获得更及时的文章推送,欢迎关注我的公众号:爱折腾的风

