尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

程序员英语学习自动化:间隔重复与GitHub Actions实现闭环

程序员英语学习自动化:间隔重复与GitHub Actions实现闭环 最近在技术社区里看到一个很有意思的仓库名ZuodaoTech / everyone-can-use-english。单从名字看它的目标很清楚——让每个人都能用上英语。但真正让我觉得值得写的不是这个仓库本身有什么黑科技而是它背后代表的一类思路把英语学习从一个“靠意志力坚持”的问题变成一个“靠机制自动运转”的工程问题。程序员学英语有一个非常常见的怪圈网盘里存了几十个 G 的资料收藏夹里躺了几十篇方法论文章每天打开手机刷十分钟单词三个月后还在第一页。问题从来不是学习资源不够而是没有一套能持续运转的流程。代码恰恰是最擅长表达流程的东西。如果你关注过 everyone-can-use-english 这类项目会发现它们真正想解决的不是“怎么背单词”而是“怎么让输入、复习、反馈三个环节形成一个闭环并且不需要每天消耗大量决策力”。这篇文章不打算给你一个“30 天从入门到精通”的鸡汤方案。我会从工程角度拆解这类项目的通用结构再带你从零搭建一个最小可运行的英语学习自动化工具。这个工具包含四个部分语料加载、单词查询、间隔重复排程、定时自动执行。你会拿到可复制的代码和配置也可以直接把它改造成自己的英语学习工作流。1. 为什么这类项目值得你花时间关注先给一个明确判断每个人都能用英语这句话真正的价值不在“英语”而在“每个人都能用”。大多数英语学习产品默认用户需要付出大量主动学习时间。而这类技术项目的思路刚好反过来它默认用户很忙、很懒、容易被中断所以设计目标是降低使用门槛把学习动作嵌入到日常开发流程中。比如打开终端就能复习几个句子提交代码时自动触发一份英语日报看到英文文档随手就能查词并收藏成卡片。这些动作加起来每天不超过 15 分钟但胜在每天都在发生。对开发者来说这类项目的另一个价值是你可以在别人写好的框架上做二次改造。学英语的最优语料永远是你自己正在用的东西。你读什么源码、查什么文档、写什么注释都比任何现成教材更贴近你的实际水平。如果你只是把别人仓库里的内容原封不动背一遍那还是在用传统方法只是换了个高科技外壳。所以这篇文章会带着你做三件事拆解这类项目的通用结构知道哪一层是内容、哪一层是工具、哪一层是自动化用 Python 搭建一个最小闭环能管理语料、能安排复习、能生成每日任务用 GitHub Actions 把它变成无人值守的定时流程跑起来之后再根据自己的习惯迭代。2. 理解项目定位它不是“又一个背单词软件”从命名风格看everyone-can-use-english 这类仓库的定位通常非常朴素不追求看起来高科技只追求普通用户真的能用起来。要理解这类项目不能只看 README 里的功能介绍而要从结构上分清楚它包含哪几个层次。一个典型的英语学习技术项目一般可以拆成三层内容层包含句子、单词、文章、音视频链接等原始语料。这是整个系统的血液决定你每天学什么。工具层负责处理语料比如查词、语音朗读、翻译、句子收藏、生词本管理。这一层直接影响用户每天的使用体验。自动化层负责把内容按时推送到用户面前比如每日计划、间隔重复、学习数据统计。这一层解决的是“能不能坚持”的问题。很多项目从仓库外看是一套完整系统但实际能复用的往往是中间的工具层。内容需要换成你自己的自动化节奏也需要按你的日程调整。如果只看一个项目“很强大”就收藏那你得到的只是一个收藏夹条目而不是一套学习系统。判断这类项目质量最核心的指标不是功能数量而是三个问题我的语料能不能方便地加进去我的复习计划能不能自定义我每天打开它需要花多久、需要做几个操作如果这三个问题答案不理想那这个项目再花哨也不适合你。反过来如果你自己写一套最小工具哪怕只有两个命令但只要每天好用它对你产生的价值远大于任何通用软件。2.1 千万不要把“收集工具”当成“开始学习”这是我在技术社区里看到最普遍的现象。看到一个不错的英语学习仓库第一反应是 star、fork、收藏然后就没有然后了。原因是工具本身不产生学习动力只有当工具和你的真实使用场景绑定后它才有效。所以下面内容的关键点是你可以照着搭一套工具并把你的真实语料放进去。3. 核心机制输入、间隔重复、反馈要理解这类项目的原理先掌握三个概念输入、间隔重复、反馈。输入指的是你每天接触到的英文材料。对于程序员来说优质输入源非常丰富英文技术文档、开源项目的 commit message、英文技术博客、GitHub Issue 讨论、Stack Overflow 回答。问题不是找不到输入而是输入太零散今天看了一段明天就忘了构不成积累。间隔重复是一种基于记忆曲线的复习策略。核心思想是与其在一个单词上反复背很多次不如在即将遗忘的临界点提醒一次。刚学的内容可能当天就复习随后变成两天后、四天后、一周后。程序负责计算下一个复习时间点用户只需要根据记忆程度打分。这是目前公认对长期记忆最省力的机制之一。反馈指的是每次学习后立刻知道“我记对了吗”。这种反馈可以来自词典释义、例句翻译也可以来自一段自动朗读的音频。反馈越及时越不容易把错误理解固化成长期记忆。没有反馈的背单词本质上是在无限重复第一遍的模糊印象。这三者组合起来就是完整闭环今天读英文文档遇到一个句子把它加入语料库系统生成中文释义和例句明天打开终端系统按照间隔重复排程推给你几个句子你判断自己是否记住记错的句子进入今天的“待重学”列表系统为你生成一份新的例句和解释一周后系统再次推送这个句子如果你已经记住它会进入更长的复习周期。用表格看会更清晰机制解决的问题没有它会怎样输入语料缺少真实语境背了单词不会用遗忘快间隔重复缺少长期复习节奏今天学明天忘低效重复即时反馈缺少正确性确认错误理解被反复强化这也能解释为什么很多人用背单词软件觉得“背了但不会用”它只解决了输入没有解决真实的反馈和复习节奏。而一个能由你自己掌控语料的工具才能真正把这三个机制串起来。4. 环境准备与项目目录规划开始写代码前先确认基础环境。本文的示例以 Python 3 为主使用 sqlite3 作为本地存储不需要额外安装数据库服务。4.1 环境要求操作系统Windows、macOS、Linux 均可Python建议 3.10 及以上版本Git用于管理配置和语料文件依赖PyYAML、requests安装命令见下。如果你本机没有 Python可以先到官网安装。安装完成后建议创建虚拟环境避免污染系统依赖。mkdir english-toolkit cd english-toolkit python3 -m venv venv source venv/bin/activate # Windows 使用 venv\Scripts\activate pip install pyyaml requests4.2 推荐目录结构为了后续改造方便推荐按“语料、存储、脚本、配置”四个维度组织目录english-toolkit/ ├── corpus/ │ └── daily.yaml # 原始语料文件 ├── data/ │ └── english.db # SQLite 数据库运行后生成 ├── scripts/ │ ├── init_db.py # 初始化数据库并导入语料 │ ├── lookup.py # 单词查询 │ ├── srs.py # 间隔重复排程 │ ├── daily.py # 生成每日学习报告 │ └── config.py # 公共配置项 ├── requirements.txt └── .github/ └── workflows/ └── daily-english.yml这套结构的好处有两点。第一语料文件是纯文本天然支持 Git 版本管理你今天加了哪些句子、改了哪些翻译都有记录。第二数据和代码分离数据库文件不会污染 Git 仓库后续即使换一套前端界面底层语料仍然可以复用。5. 用最小实现跑通“人人可用”的闭环下面开始写代码。我不建议一开始就做一个大而全的平台先跑通最小闭环更重要。整个过程包括定义语料格式、导入数据库、实现间隔重复排程、生成每日任务、用 GitHub Actions 定时自动执行。5.1 定义语料格式内容层是一切的基础。我选择 YAML 作为语料格式原因是它可读性强、支持注释、适合版本管理也能很容易地和脚本、编辑器工具配合。创建corpus/daily.yaml# corpus/daily.yaml cards: - word: efficient sentence: This solution is more efficient than the old one. translation: 这个方案比旧的更高效。 tags: [adjective, programming] - word: maintain sentence: It is important to maintain backward compatibility. translation: 保持向后兼容性很重要。 tags: [verb, development] - word: review sentence: Please review the pull request before merging. translation: 合并前请先审查这个拉取请求。 tags: [verb, workflow]这里每条卡片包含四个字段单词、原句、翻译、标签。字段并不多但已经足够支撑一套最小闭环。标签字段的作用是后续按主题筛选比如你只看“development”相关句子。如果你愿意也可以加入音频文件名、图片路径等字段这不会影响核心逻辑。5.2 初始化数据库并导入语料创建scripts/init_db.py# scripts/init_db.py import sqlite3 import yaml DB_PATH data/english.db CORPUS_PATH corpus/daily.yaml def init_db(): db sqlite3.connect(DB_PATH) db.execute( CREATE TABLE IF NOT EXISTS cards ( id INTEGER PRIMARY KEY AUTOINCREMENT, word TEXT NOT NULL, sentence TEXT NOT NULL, translation TEXT, tags TEXT, status INTEGER NOT NULL DEFAULT 0, review_count INTEGER NOT NULL DEFAULT 0, next_review_date TEXT NOT NULL DEFAULT (date(now)) ) ) db.commit() db.close() print(数据库初始化完成 DB_PATH) def import_cards(): with open(CORPUS_PATH, encodingutf-8) as f: data yaml.safe_load(f) db sqlite3.connect(DB_PATH) cursor db.cursor() inserted_count 0 for card in data.get(cards, []): cursor.execute( INSERT INTO cards (word, sentence, translation, tags) VALUES (?, ?, ?, ?) , ( card[word], card[sentence], card.get(translation, ), ,.join(card.get(tags, [])), ), ) inserted_count 1 db.commit() db.close() print(导入卡片数量 str(inserted_count)) if __name__ __main__: init_db() import_cards()这段代码做了三件事创建cards表字段中包含复习次数review_count和下次复习日期next_review_date读取 YAML 语料文件把每张卡片插入数据库标签字段用逗号连接存储。注意存储路径data/目录需要存在如果不存在可以先运行mkdir -p dataWindows 下是mkdir data。5.3 实现间隔重复排程间隔重复是整个工具的核心。这里采用一个非常简单的算法适合作为起步实现如果用户回答“记得”下次复习时间按复习次数递增比如第 1 次 1 天第 2 次 2 天第 3 次 4 天如果用户回答“不记得”把复习次数清零下次复习时间回到 1 天后今天到期且未复习的卡片就是要完成的今日任务。创建scripts/srs.py# scripts/srs.py import sqlite3 import sys from datetime import date, timedelta DB_PATH data/english.db def get_due_cards(limit: int 5): db sqlite3.connect(DB_PATH) db.row_factory sqlite3.Row cur db.cursor() rows cur.execute( SELECT id, word, sentence, translation, review_count FROM cards WHERE next_review_date date(now) ORDER BY next_review_date LIMIT ? , (limit,), ).fetchall() db.close() return rows def update_review_status(card_id: int, remembered: bool): db sqlite3.connect(DB_PATH) cur db.cursor() row cur.execute( SELECT review_count FROM cards WHERE id ?, (card_id,) ).fetchone() if row is None: db.close() return review_count row[0] if remembered: review_count 1 interval_days min(2 ** review_count, 30) else: review_count 0 interval_days 1 next_review_date (date.today() timedelta(daysinterval_days)).isoformat() cur.execute( UPDATE cards SET review_count ?, next_review_date ?, status 1 WHERE id ? , (review_count, next_review_date, card_id), ) db.commit() db.close() def run_session(limit: int 5): due_cards get_due_cards(limit) if not due_cards: print(今天没有待复习的卡片任务结束。) return for card in due_cards: print(\n单词 card[word]) print(例句 card[sentence]) print(翻译 card[translation]) answer input(记住了吗(y/n): ).strip().lower() update_review_status(card[id], answer y) print(已更新复习状态。) if __name__ __main__: limit int(sys.argv[1]) if len(sys.argv) 1 else 5 run_session(limit)这段代码可以用一条命令启动今日复习。运行方式python scripts/srs.py 5这里有一个容易被新手忽略的点间隔递增使用2 ** review_count虽然简单但它会在几次复习后快速膨胀到 30 天上限。这符合“低维护成本”的定位但对于需要每天接触大量生词的高强度学习者可能太慢。实际使用时你可以调整上限或改用更平滑的增长曲线比如倍增间隔但封顶在 21 天。5.4 生成每日学习日报命令行交互适合主动学习但不适合每天打开电脑时还要思考“今天要干什么”。更自然的方式是每天早上自动生成一份学习任务文件包含今天待复习的卡片、新词推荐、一个随机例句。创建scripts/daily.py# scripts/daily.py import sqlite3 from datetime import date DB_PATH data/english.db def build_daily_report(): db sqlite3.connect(DB_PATH) db.row_factory sqlite3.Row cur db.cursor() due_cards cur.execute( SELECT word, sentence, translation FROM cards WHERE next_review_date date(now) ORDER BY next_review_date LIMIT 5 ).fetchall() new_words cur.execute( SELECT word, sentence, translation FROM cards WHERE status 0 ORDER BY id DESC LIMIT 3 ).fetchall() db.close() lines [] lines.append(# 今日英语学习计划) lines.append() lines.append(日期 date.today().isoformat()) lines.append() lines.append(## 待复习卡片) lines.append() if not due_cards: lines.append(今天没有到期卡片。) else: for card in due_cards: lines.append(- card[word] | card[sentence]) lines.append( - card[translation]) lines.append() lines.append(## 新词推荐) lines.append() if not new_words: lines.append(目前没有新词。) else: for card in new_words: lines.append(- card[word] | card[sentence]) lines.append( - card[translation]) report \n.join(lines) print(report) with open(daily-report.md, w, encodingutf-8) as f: f.write(report) print(\n报告已生成daily-report.md) if __name__ __main__: build_daily_report()运行python scripts/daily.py后终端会输出一份今日学习计划同时生成daily-report.md文件。这个文件本质上是一个纯文本日报可以手动打开看也可以作为后续接入推送通道的基础。5.5 用 GitHub Actions 让流程自动跑起来前几步解决了“工具能不能用”的问题这一步解决“能不能坚持”的问题。人的意志力有限自动化可以帮我们兜底。在项目根目录创建.github/workflows/daily-english.ymlname: daily-english on: schedule: - cron: 0 22 * * * workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - name: 拉取代码 uses: actions/checkoutv4 - name: 配置 Python uses: actions/setup-pythonv5 with: python-version: 3.11 - name: 安装依赖 run: pip install pyyaml requests - name: 初始化数据库 run: python scripts/init_db.py - name: 生成每日报告 run: python scripts/daily.py - name: 上传每日报告为产物 uses: actions/upload-artifactv4 with: name: daily-report path: daily-report.md这段工作流做了三件事每天 UTC 22 点北京时间为次日早上 6 点自动运行初始化数据库生成每日报告并上传为 Artifact你可以在 GitHub Actions 页面下载查看。如果你想把日报直接推到自己的仓库可以让脚本把daily-report.md提交到某个分支然后在手机上查看。这里要提醒一句如果你计划把每天的内容提交回 GitHub 仓库请务必确认仓库是私有的避免把个人学习记录暴露在公开仓库中。5.6 一个轻量级查词辅助脚本除了复习排程这类工具还应该解决“阅读英文时随手查词”的体验。这里提供一个非常轻量的 Python 查词脚本只负责构造查询 URL 并打开浏览器# scripts/lookup.py import sys import urllib.parse import webbrowser def lookup(word): quote_word urllib.parse.quote(word.strip()) url https://dict.example.com/search?q quote_word webbrowser.open(url) print(已打开查词页面 url) if __name__ __main__: if len(sys.argv) 2: print(用法python scripts/lookup.py word) sys.exit(1) lookup(sys.argv[1])运行python scripts/lookup.py efficient脚本中的dict.example.com是占位地址实际使用时替换成你常用的词典服务。如果你有本地字典数据也可以改成直接查询本地文件。查词的重点不在于写一个多复杂的程序而在于把“查词”做成一个两秒内能完成的动作这样遇到生词时才不会因为心理负担而跳过。6. 运行结果与效果验证写到这里整套最小系统已经具备。现在我们从头跑一遍验证每一步是否正常。第一步初始化并导入语料python scripts/init_db.py预期输出数据库初始化完成data/english.db 导入卡片数量3第二步生成每日学习报告python scripts/daily.py预期输出包含 “今日英语学习计划”并且“待复习卡片”区域会出现 3 张卡片因为刚导入的卡片默认复习日期就是今天。第三步执行一次间隔重复复习python scripts/srs.py 3终端会逐条显示单词、例句、翻译并询问是否记住。如果你输入y下一次复习日期会按指数间隔递增如果你输入n该卡片的复习次数会清零明天重新出现。判断系统是否跑通可以看三个标志数据库文件data/english.db正常生成daily-report.md文件中包含你导入的 3 个句子srs.py运行后数据库里卡片的next_review_date字段发生变化。这三个标志都满足说明“输入、重复、反馈”的最小闭环已经成立。剩下的工作就是往语料库里不断加入你自己遇到的真实句子。7. 常见问题与排查方法在实际运行中新手最容易遇到下面几个问题。问题现象可能原因排查方式解决方案导入语料时报错FileNotFoundErrordata目录不存在或 YAML 文件路径不对查看当前工作目录检查文件路径先创建目录mkdir -p data确认corpus/daily.yaml路径正确运行init_db.py报模块找不到没有安装 PyYAML或未激活虚拟环境执行pip list查看依赖执行pip install pyyaml requestssrs.py能运行但没有任何复习卡片导入卡片时设置的下次复习日期是未来日期查看数据库内容查询SELECT * FROM cards把卡片next_review_date改为今天或删除后重新导入GitHub Actions 每天都没执行cron 时区设置与本地不一致或 Actions 没有开启在仓库 Actions 页面查看运行记录GitHub Actions 默认 UTC 时间调整 cron 为期望的 UTC 时间确认仓库 Actions 已启用浏览器无法打开查词页面lookup.py中 URL 用了不可访问的示例地址运行脚本检查打印的 URL替换成实际可访问且合规的词典地址其中“导入卡片之后却没有复习卡片”是最容易踩的坑。原因通常是重复执行了init_db.py多次第二次执行时默认的next_review_date仍然是今天反而不容易出问题如果改过默认值就要检查 YAML 文件是否设置了未来日期字段。定位问题的方法是打开 SQLite 数据库直接查询sqlite3 data/english.db SELECT id, word, review_count, next_review_date FROM cards如果你没有安装 sqlite3 命令也可以改成在 Python 里查询效果一样。8. 最佳实践与工程建议从“一个能跑的工具”到“一套能长期坚持的系统”中间还差不少工程细节。这一章给出几个适合实际使用的建议。8.1 每天只保证一个最小闭环不要一开始就给自己定“每天背 50 个单词”这样的目标。最小闭环的意义在于哪怕你今天很忙也只需要打开终端跑一句python scripts/srs.py 3完成 3 张卡片即可。自动化系统会负责把剩下的卡片安排到后面。稳定的小规模闭环长期效果远好于偶尔一次的大规模突击。8.2 语料来自你自己的英文环境这是我认为最重要的一条。与其用别人编好的通用例句不如把你今天真实遇到的句子放进去。比如你查了一个技术文档里的backward compatibility就把这个句子记下来再加上你自己写的翻译。这样的卡片天然带上下文复习时更容易触发记忆而不是机械地背一个孤零零的单词。如果你的项目里已经有英文 README 或代码注释可以写一个小脚本批量抽取包含目标单词的句子。把这个脚本放在scripts/目录下以后每浏览一份新文档都能快速扩充语料库。8.3 敏感信息和隐私边界如果使用 GitHub Actions 跑定时任务要特别注意仓库权限。个人学习记录的句子、翻译、复习历史都属于隐私数据建议放在私有仓库中。如果在工作流中需要发送邮件或调用外部服务密钥信息务必要通过 GitHub Secrets 配置不要硬编码进 YAML 文件或 Python 脚本。发送邮件或调用任何外部 API 之前先确认你对该服务有合法使用权限并遵循最小授权原则。8.4 保持图表与数据可追溯间隔重复算法看似简单但不同版本之间的行为差异会影响长期效果。每次修改算法尽量同步更新卡片表结构或版本号并在daily-report.md头部记录算法版本。否则三个月后你会发现系统行为变了却不知道是哪次改动引起的。8.5 不要执着于完美很多人在搭建工具时会陷入一个误区总想一次性把功能做得完整比如加入语音识别、聊天机器人、进度图表。这些功能确实有价值但对一个刚开始建立学习习惯的人来说反而会分散注意力。先用最小闭环跑两周确认每天都会主动打开系统再逐步增加新功能。工具的进化应该来自真实使用中的痛点而不是想象中的功能清单。9. 总结回到项目名everyone-can-use-english。这类项目的核心价值不是提供一份完美的英语学习资料而是建立一套你可以持续运行的机制。机制一旦建立每天输入什么、复习哪些词、间隔多久都可以由系统替你规划和记录。这篇文章从一个关于“人人可用英语”的仓库名出发拆解了英语学习技术项目的三个层次内容层、工具层、自动化层。然后带你用 Python 搭建了一套最小系统包括 YAML 语料管理、SQLite 存储、间隔重复排程、每日报告生成以及 GitHub Actions 定时执行。整个过程没有依赖外部数据库也没有复杂的前端界面核心逻辑只有四个脚本在任何有 Python 的机器上都能跑起来。如果你想真正复刻这类项目建议从今天就开始找一篇你在读的英文技术文档摘出 5 个句子写成 YAML跑一遍init_db.py和srs.py。当你能把自己每天输入的内容变成下一张复习卡片的时候你就不再只是一个学习工具的使用者而是这个学习系统的建设者。这一步做完后面无论加语音、加统计还是接入 AI 对话练习都会是顺水推舟的事情。
返回列表