簡述

  • Hanzi Flow 是一款中文閱讀應用:你輸入真實句子的拼音,它會挑選下一個句子,讓其中維持 2 到 5 個你還不認識的漢字。
  • 它取用了 79,000+ 句 Tatoeba 句子。以 GPT-4o-mini 檢查規則式拼音後修正了 10,336 處錯誤,例如 著 被讀成 zhu4,實際上應為 zhe。
  • 每個漢字的熟練度是移動平均,間隔複習從一小時起算,因此新字會在同一次練習中重複出現數次。
  • 它是本機優先:不需帳號,學習進度留在網頁瀏覽器中,並且可離線使用。

Hanzi Flow 是一款圍繞單一理念打造的漢字練習應用:自適應句子挑選。它會依據你目前的熟練度,從 79,000+ 個真實例句中挑出含 2 到 5 個生字的句子,讓你維持在 90% 至 95% 的理解區間。不必管理牌組,只要輸入拼音練習即可。

原始碼: github.com/brianhliou/hanzi-flow

另開獨立頁面 →

現有工具的問題

中文學習應用基本上分成三派,而它們都有缺點。

像 Anki 這類字卡應用要你背誦孤立的漢字。你花在整理牌組的時間比真正學習的時間更多。等到終於在真實文章裡看到某個字,你卻認不出來,因為你學它時完全脫離了任何語境。

像 Pleco 這類辭典應用查東西很好用,但完全是被動的。你讀了、懂了,卻什麼也沒留下。沒有主動回想,也沒有輸入練習。

閱讀應用與家教給你的要嘛是童書(無聊),要嘛是母語者內容(難度過高)。你會覺得乏味或被壓垮,兩者都無法培養流暢度。

缺少的那一塊是維持心流。也就是 90% 到 95% 的理解區間,你有挑戰但不至於挫敗。你需要難度恰當的句子、自動挑選,並透過輸入進行主動回想。

我做了什麼

Hanzi Flow 是具備自適應難度的句子練習。你讀中文、輸入拼音,應用會依你對每個漢字的掌握程度挑出下一個句子。它有 Anki 的間隔重複卻不用管理牌組;有 Duolingo 的練習節奏,但用的是真實句子而非會話手冊的例句。

練習介面,逐字輸入整句

這個應用:

  • 來自 Tatoeba 的 79,000+ 個句子(真實用法,而非教科書例句)
  • 4,000+ 個漢字 - HSK 1-9 再加上約 1,000 個 HSK 以外的漢字
  • 自適應演算法 - 依你的熟練度挑出含 2 到 5 個生字的句子
  • 熟練度追蹤 - 字級分數搭配間隔重複(EWMA + SRS)
  • 對齊 HSK 3.0 - 依官方課綱等級篩選(1-9 或 HSK 以外)
  • 字形支援 - 簡體、繁體或混合
  • 即時回饋 - 彩色視覺提示,加上 1,598 個音訊檔(涵蓋所有拼音音節)
  • 100% 本機優先 - 無帳號、無追蹤、可離線使用

你練習符合自身程度的真實句子,透過拼音輸入建立打字流暢度,而系統會隨你的進步而調整。不必手動管理牌組。

使用體驗

首次執行:設定偏好

第一次打開應用時,你要選兩件事:

字形類型:簡體、繁體或混合。這會篩選語料以符合你的目標。

HSK 等級:篩選是累積的。選「HSK 1-3」就只會得到僅使用等級 1、2、3 漢字的句子。選「HSK 以外」則會納入官方課綱之外約 1,000 個進階漢字。

你隨時可以在設定中變更。變更後,應用會清掉目前的句子佇列,並依新的篩選條件重新產生。

設定頁面,顯示字形與 HSK 等級偏好

練習循環

練習流程很直接:

  1. 讀句子 - 漢字以大字顯示
  2. 輸入拼音 - 逐字輸入,聲調可省略(wo3 或 wo 都可以)
  3. 取得回饋 - 當前字以藍色標示,錯誤則紅色閃爍並可重試(最多 4 次)
  4. 看到拼音 - 帶聲調的正確答案顯示在每個字下方
  5. 顯示翻譯 - 完成後底部可選擇顯示英文
  6. 下一句 - 按空白鍵或點按鈕

回饋是即時且視覺化的。你總是聚焦在當前的字(藍色標示)。答錯會閃紅並播放正確發音的音訊。你有 4 次機會,之後系統會往下走,並把那個字標為紫色(放棄)。系統接受多音讀法(地 同時接受 de 與 di),不過會顯示符合語境的那一個。

練習中句子顯示彩色回饋

關鍵機制在於回饋循環。現實生活中,你可能在書上看到一個字、猜錯了,卻永遠不知道答案。或者看電視完全漏掉發音。那樣的學習週期很慢。隨性的學習者可能要好幾個月才累積到足夠接觸,才能真正學會一個字。

這個應用壓縮了這個週期。你看到一個字、輸入它、立刻得到含音訊的糾正、馬上重試、再往下走。整個過程十秒。一次練習做 100 個字,你就跑完了 100 次學習週期。主動回想(輸入)、即時糾正(音訊加視覺)與高量(句子不斷出現)疊加起來,帶來被動接觸無法給你的效果。

進度追蹤

統計頁面顯示四項主要指標:

  • 已練習的漢字總數 - 你看過的不重複漢字
  • 已精熟的漢字 - 熟練度 ≥ 0.8 的字
  • 已練習的句子 - 完成的不重複句子
  • 整體正確率 - 第一次嘗試就答對的百分比

熟練度分布把漢字分成幾組:

  • 學習中(s < 0.6)- 還在建立熟悉感
  • 熟練(0.6 ≤ s < 0.8)- 快到了
  • 精熟(s ≥ 0.8)- 很穩

每個漢字都會依間隔重複記錄它下次該複習的時間。

統計頁面顯示進度總覽

熟練度分布顯示漢字分布狀況

自適應演算法(NSS)

隨機挑選會很糟。你會太常看到同樣的句子,把時間浪費在已經精熟的東西上,或被含 10 個以上生字的句子壓垮。

下一句挑選(NSS)就是挑出你下一個句子的演算法。它在新學習、間隔重複、新鮮感與難度之間取得平衡。

核心理念

最佳區間:每句 2 到 5 個生字。

  • 0 到 1 個生字 - 太簡單,只是複習
  • 2 到 5 個生字 - 剛好,挑戰夠、語境也夠
  • 6 個以上生字 - 太難,你只是在猜

這個演算法也會平衡:

  • 新學習(你從未見過的字)
  • 間隔重複(複習到期的字)
  • 新鮮感(不要反覆磨同樣的句子)
  • 多樣性(混合不同難度)

運作方式

NSS 以批次執行。你開始練習時,它會產生 10 個句子。做到第 8 個時,它會在背景預取下一批。你永遠不用等。

四個步驟:

1. 篩出合格句子

從完整語料(79K)開始。套用你的篩選條件:

  • 字形(簡體/繁體/混合)
  • HSK 等級(你選的範圍)
  • 冷卻時間(排除最近 20 分鐘看過的句子)

這會得到合格的候選池,通常是 20K 到 40K 個句子。

2. 隨機抽 300 個候選

從池中隨機取 300 個。夠大以保有多樣性,又小到能快速評分(100ms 以內)。隨機抽樣確保你每次練習看到不同的句子。

3. 為每個候選評分

對這 300 個中的每一個,依四個因子計算分數:

  • 基礎收益 - 每個字的 (1 - 熟練度) 之和。低熟練度的字分數較高。若已逾期複習,收益加倍。
  • 新鮮感 - 依距上次出現的時間給予加分。鼓勵多樣性,避免反覆磨同一句。
  • 通過懲罰 - 若你已多次完美通過這個句子,就降低分數。避免過度練習。
  • k 懲罰 - 對落在 2 到 5 個生字區間之外的句子予以懲罰。以此控制難度。

把它們加總:score = base_gain + novelty - pass_penalty - k_penalty

4. 取前 10 名、打亂、入佇列

依分數排序,取前 10 名,打亂以混合難度,加入佇列。

你練習這 10 個。剩下 2 個時,演算法會在背景再跑一次,預取下一批。

熟練度追蹤

每個漢字都有一個 0.0 到 1.0 的熟練度分數(s)。

  • s = 0.3(新字的預設值)
  • s → 1.0(持續答對)
  • s → 0.0(一直答錯)

更新採用 指數加權移動平均(EWMA),α=0.15。近期表現權重較高,但變化是漸進的。一次失誤不會讓你一落千丈,一次成功也不會虛胖。

當你答對某個字,它的穩定度(SRS 間隔)會乘以 1.2 倍。起始為 1 小時,然後 1.2 小時,再 1.44 小時。這比 Anki 那種激進的跳躍(1 天 → 3 天 → 7 天)讓漢字停留在輪替中更久。

為什麼要慢一點?當日複習很重要。你需要在一次練習中看到某個字 3 到 5 次,才能把它從短期記憶搬進長期記憶。跳太快會錯過這個時間窗。

當某個字到期(超過它的 next_review_ts),評分時它會取得雙倍權重。演算法會優先選含逾期漢字的句子。這是典型的間隔重複。

資料流程

要做這個,需要完整的資料:帶發音的漢字、帶翻譯的句子、難度標籤、品質篩選。以下是我建立語料的方式。

字集

從 Unicode CJK 統一表意文字(U+4E00 到 U+9FFF)開始,共 20,992 個漢字。涵蓋現代中文的每一個字,加上罕見異體與歷史字形。

接著用三個來源的資料為每個字加上資訊:

  • Unihan 資料庫 - 拼音讀音、異體字、部首拆解
  • CC-CEDICT - 英文釋義與例詞(学 → 「study; learn」,学生 → 「student」)
  • OpenCC - 簡繁對應,用於字形分類

結果:99.7% 的漢字有拼音,67% 有英文釋義,35% 有異體對應。我知道哪些字實際出現在 Tatoeba(5,000+),哪些只是理論上存在(罕見的文言字)。

漢字覆蓋曲線,顯示累計字數

這條曲線顯示漢字如何隨 HSK 等級累積。HSK 1 約有 300 字,HSK 2 再加 300 字,以此類推。到較高等級時曲線趨平,因為你逼近約 3,000 字的識字門檻。超過之後便是報酬遞減。

頻率分布符合齊夫定律:少數漢字佔絕大多數,大部分都很罕見。前 500 個漢字涵蓋 75% 的文本,前 2,000 個涵蓋 95%。這對自適應演算法很重要,因為先學高頻字能立即帶來閱讀能力。

頻率分布顯示幂次律

HSK 分級

HSK(漢語水平考試)是中國官方的能力測驗。2021 年的改版(HSK 3.0)定義了 9 個等級、共 3,000 個漢字。我整合了來自 elkmovie/hsk30 的官方字表(由政府 PDF OCR 而來)。

每個句子依其中最難的字分級:

  • 全是 HSK 1 的字?標為「1」
  • 最難的字是 HSK 3?標為「3」
  • 含 HSK 9 以外的字?標為「beyond-hsk」

這驅動了篩選。當你選「HSK 3」時,你只會看到每個字都出自等級 1 到 3 的句子。不會有意外。

詞彙成長,顯示各 HSK 等級的累計字數

句子在各 HSK 等級的分布

句子處理

從 Tatoeba 這個群眾外包的翻譯資料庫抓了 79,000+ 個中文句子。每一筆一邊是英文,一邊是中文。

挑戰:依語境判斷的拼音。 漢字會因語境有多種發音。我先用 jieba 加 pypinyin 跑第一輪,再用 GPT-4o-mini 驗證(79K 句約花 2 美元)。修正了常見多音字的 10,336 處錯誤,例如 地(de 與 di4)、著(zhe 與 zhu4)、谁(shei2 與 shui2)。

多音字範例:

  • 了:le(助詞)與 liao3(完成)
  • 行:xing2(可以)與 hang2(行列)
  • 长:zhang3(生長)與 chang2(長)

你不能只是查表。你得理解詞的語境。

步驟 1:jieba + pypinyin。 Jieba 把「我们试试看」切成 [“我们”, “试试”, “看”],然後 pypinyin 為每個詞產生拼音:我们试试看 → wo3 men shi4 shi4 kan4。大多情況可行,但在助詞與口語發音上會出錯。

步驟 2:GPT-4o-mini 驗證。 把整份語料送過 OpenAI 的 API(79K 句約 2 美元,每次呼叫批次 10 句)。提示它輸出逐字帶聲調的拼音。在 79,603 個句子中找到 10,336 處錯誤。主要修正:

  • 覺(120 處變更):pypinyin 給 jue2(感覺),OpenAI 給 jiao4(睡覺)
    • 你應該去睡覺了吧 - 「You should go to bed」
  • 著(696 處變更):pypinyin 給 zhu4(穿著),OpenAI 給 zhe(助詞)
    • 生活就是當你忙著進行你的計劃時… - 「Life is what happens when you’re busy making plans」
  • 谁(404 處變更):pypinyin 給 shui2(正式),OpenAI 給 shei2(口語)
    • 你知不知道他们是谁? - 「Do you know who they are?」
  • 长(136 處變更):pypinyin 給 zhang3(生長),OpenAI 給 chang2(長)
    • 我看见一个长头发的女生 - 「I saw a girl with long hair」

我人工檢視了最主要的那些字,並套用高信心度的修正。OpenAI 對語境的理解抓到了規則式方法漏掉的錯誤。

英文翻譯: 同樣由 GPT-4o-mini 產生(總共約 1 美元)。Tatoeba 的資料集只有約 2,000 個句子附翻譯。若只用那些,語料會從 79,000+ 砍到 2,000,自適應演算法的效果就毀了。所以我用 GPT-4o-mini 翻譯全部 79,000+ 個句子。大型語言模型擅長翻譯,因為它們會運用語境,而這正是準確中譯英所需要的。範例:

  • 我們試試看! → Let’s give it a try!
  • 你在干什麼啊? → What are you doing?
  • 今天是6月18号,也是Muiriel的生日! → Today is June 18th, and it’s Muiriel’s birthday!
  • 生日快乐,Muiriel! → Happy birthday, Muiriel!
  • 密码是”Muiriel”。 → The password is “Muiriel.”

也套用了品質篩選:

  • 字形分類 - 簡體、繁體、中性或混合
  • 粗俗語剔除 - 濾掉不雅詞彙(約 10 句)
  • 長度上限 - 移除超過 50 字的句子(約 270 句)以避免需要捲動
  • 後設句子 - 移除 Tatoeba 自我指涉的句子(約 80 句)

最終語料:79,333 個乾淨句子。

字形分布,顯示簡體/繁體/混合的比例

架構與效能

以現代網頁技術打造,針對速度與隱私最佳化。

為什麼本機優先?

  • 隱私 - 沒有帳號、沒有追蹤、沒有遙測。你的進度永不離開你的裝置。我連分析工具都沒裝。資料歸你所有。
  • 效能 - 沒有網路延遲。句子挑選在 100ms 以內完成。輸入回饋即時。統計頁面在 50ms 內載入。
  • 簡單 - 沒有後端要維護、沒有資料庫要擴充、沒有身分驗證。這個應用就是靜態檔案加上客戶端 JS。我免費託管在 Vercel。
  • 代價: 沒有跨裝置同步。在筆電和手機上的練習是各自獨立的。對 MVP 來說可以接受。大多數人有一台主要裝置。之後或許可以加上匯出/匯入,或選用性的雲端同步。

技術堆疊

前端:

  • Next.js 15 搭配 App Router
  • React 19 + TypeScript
  • Tailwind CSS
  • Dexie.js 用於 IndexedDB

資料流程:

  • Python 3.9+ 用於處理腳本
  • jieba 用於分詞
  • pypinyin 用於依語境產生拼音
  • pandas + matplotlib 用於分析
  • GPT-4o-mini 用於翻譯與拼音驗證

音訊:

  • AWS Polly(Zhiyu 語音)用於 TTS
  • 1,598 個音節,涵蓋所有聲調
  • 採 OGG 格式以兼容網頁瀏覽器

部署:

  • Vercel(零設定)
  • 靜態網站,無伺服器
  • 全球 CDN

資料載入與快取

應用在首次造訪時載入大型資料集,之後積極快取。

初次載入:

  • 79,333 個句子(約 41MB JSON)- 只抓取一次,存在記憶體中
  • 漢字對應 CSV(約 2MB)- ID、拼音、釋義
  • 音訊檔 - 依需求抓取(每個 1 到 2KB)

記憶體內快取:

  • 句子放在 JavaScript 陣列中
  • 漢字到 ID 的對應放在 Map 中(O(1) 查找)
  • 練習期間不再重新抓取

IndexedDB 持久化:

  • WordMastery 表 - 每個練習過的漢字一列(熟練度分數、SRS 間隔、下次複習時間、計數)
  • SentenceProgress 表 - 每個完成的句子一列(通過率、嘗試次數、上次出現時間)
  • SentenceQueue 表 - 存放接下來的 10 個句子(變更偏好時重新產生)

所有資料都留在你的裝置上。除了初次載入,不會有任何網路呼叫。

效能技巧:

  • 音訊預載 - 當 NSS 挑出下一個句子時,會在背景預載它的拼音音訊(3 到 5 個檔案,10KB 以內)。等你看到它時,音訊已在快取中。
  • 佇列預取 - 當你完成 10 句中的 8 句,NSS 會在背景執行以取得下一批。你永遠不用等。
  • 延遲載入 - 統計頁面只在你造訪時才計算分布,而非每次操作都算。

離線: 首次載入後,可完全離線運作。在飛機上、地鐵裡,任何地方都能練習。進度會立即存入 IndexedDB(不需要儲存按鈕)。

關鍵設計決策

聲調數字與聲調符號

應用接受聲調數字(wo3、shi4)而非符號(wǒ、shì)。為什麼?

  • 更好輸入(不需特殊鍵盤)
  • 是中文輸入法的標準做法(為真正打字做準備)
  • 無歧義(v 與 ü 等價,聲調符號需要 Unicode 組合字元)
  • 迫使你明確思考聲調(wo3 = 第三聲),而非僅靠視覺記憶

以句子為基礎的學習

為什麼用句子而非孤立詞彙?

  • 語境 - 在真實用法中學漢字。「我们试试看」教你 我们(我們)、试试(試試)、看(看)以及語法句型。
  • 閱讀練習 - 模擬真正的閱讀。培養解析字串序列的能力。
  • 打字流暢度 - 訓練整句的肌肉記憶,正如你實際會用到的樣子。
  • 難度校準 - 句子有天然的難度分布(生字數量)。詞彙層級做不到這點。
  • 動機 - 完成一個句子感覺像有進展。你在讀真正的中文,而不是反覆磨「的 的 的」字卡。

接下來

就日常練習而言,這個應用的功能已經完整。如果我再回來做,可能會加上:

  • 行動版 PWA(做成可安裝)
  • HSK 統計分布
  • 複習模式(以 SRS 為主的練習)
  • 整句音訊(完整發音,而非只有單字層級)
  • 漢字卡(字源、筆順、組詞)
  • 聲調分析(追蹤你容易混淆哪些聲調)
  • 自訂語料(匯入自己的句子)
  • 匯出/匯入(跨裝置可攜性)

這是開源專案。有想法嗎?歡迎開 issue 或 PR。

結語

做這個是為了搔自己的癢處。我想練習讀中文,又不想承擔字卡的額外負擔。真實句子、自適應難度、乾淨的輸入介面。

結果變成一趟深入探索:資料流程(79K+ 個句子的依語境拼音)、自適應演算法(EWMA + SRS)以及本機優先架構(IndexedDB + 快取)。我學到很多關於多音字、齊夫定律,以及如何為當日複習調校間隔重複。

如果你在學中文,試試看。如果你是開發者,看看這個 repo。句子挑選演算法、資料處理與本機優先的做法裡都有有趣的東西。

感謝:Tatoeba 提供句子,MDBG 提供 CC-CEDICT,elkmovie 提供 HSK 3.0 字表,Unicode 聯盟提供 Unihan。

自己試試

前往 hanzi.brianhliou.com 開始。

  1. 選擇你的字形與 HSK 等級
  2. 用聲調數字輸入拼音(wo3、ni3、ta1)
  3. 查看統計頁面了解進度
  4. 每天練習,看熟練度攀升

原始碼在 GitHub,採 MIT 授權。複製下來在本機執行:

git clone https://github.com/brianhliou/hanzi-flow.git
cd hanzi-flow/app
npm install
npm run dev

打開 http://localhost:3000。