Skip to content

Learner layer

Harry Nguyen edited this page Sep 28, 2026 · 2 revisions

Learner layer

Cập nhật theo master ở 1efe558. Khi trang này và code mâu thuẫn thì code đúng.

Lớp học từ (learner layer) là một lớp nghĩa do AI biên soạn, phủ lên trên entry Wiktionary có sẵn, để trang một từ dễ đọc như ZIM Dictionary mà không có nhược điểm của ZIM là phải cuộn hay bấm qua tab mới thấy hết. Phạm vi là 3.000 từ hay dùng nhất của mỗi ngôn ngữ en, es, zh, xuất bản ngay khi nạp xong và luôn kèm nhãn cho biết phần nào do AI viết. Batch đang chạy trên instance ở /opt/zhesen/learner, khoảng 2 entry một phút; tính đến nay 46 lớp đã xuất bản, sở hữu 197 entry kết hợp từ, còn 8.683 entry chờ. Migration supabase/migrations/0076_learner_layer.sql dựng năm bảng, sáu hàm và RLS; 0081 thêm hàm thứ bảy cùng quyền sở hữu entry kết hợp từ, 0086 tới 0088 sửa hiệu năng. Pipeline nạp dữ liệu nằm ở supabase/scripts/learner/.

5 bảng

Bảng Nội dung Khoá chính
lex.learner_entries Một lớp của một entry: 1 tới 3 từ gợi ý ngắn cho cả từ (gist_vi), trình độ CEFR, ghi chú cách dùng, model viết và model soát, version của prompt, các vấn đề reviewer nêu (review), trạng thái published hoặc hidden entry_id
lex.learner_senses Nghĩa chính theo đúng thứ tự người học gặp: từ loại, 1 tới 6 từ tiếng Việt, một câu định nghĩa tiếng Việt, định nghĩa tiếng Anh, lĩnh vực, văn phong, CEFR, và các id nghĩa gốc mà nó gộp lại (entry_id, sense_order)
lex.learner_examples 1 tới 2 câu ví dụ đã Việt hoá cho mỗi nghĩa chính, kèm pinyin cho tiếng Trung, và source_example_id khi câu lấy nguyên văn từ lex.examples (entry_id, sense_order, example_order)
lex.learner_links Mọi từ lớp nhắc tới: kết hợp từ, đồng nghĩa, trái nghĩa, từ dễ nhầm, và từ tương đương ở hai ngôn ngữ kia, mỗi cái nối tới entry đích khi từ điển đã có entry đó id bigint
lex.sense_labels Một dòng cho mỗi nghĩa gốc của một entry có lớp: nghĩa chính nào phủ nó, nhãn của nó, và gloss tiếng Việt mà lớp ghi vào lex.senses sense_id

Nạp, ẩn, khôi phục một lớp

Hàm Việc
lex.learner_load(p jsonb) Nạp một lớp, thay bản trước và giữ nguyên trạng thái published hoặc hidden, trong một transaction. Khớp mỗi từ được nhắc với một entry có sẵn, khớp câu ví dụ với lex.examples theo đúng chữ, rồi khi lớp đang published gọi learner_apply_fixes, learner_collocations và learner_relations
lex.learner_collocations(entry_id, on) Đưa các entry collocation một lớp tạo khớp với các kết hợp từ nó còn nhắc tới. Bật thì tạo entry còn thiếu, cập nhật entry chưa ai sửa tay, gắn provenance.learner_owner; tắt thì xoá mỗi entry lớp sở hữu mà không ai dùng (không trong sổ tay, không quan hệ lex_relations, không link của lớp khác, không nằm trong grammar_point_entries, không có sense của lớp khác), còn lại thì chỉ gỡ khoá sở hữu
lex.learner_apply_fixes(entry_id) Ghi gloss tiếng Việt của lớp vào lex.senses.gloss_vi ở những sense đang máy dịch hoặc trống, đánh dấu provenance.learner_fix kèm giá trị cũ. Idempotent: chạy lại không ghi đè dòng ai đó đã sửa tay sau lần ghi trước
lex.learner_unfix(entry_id) Trả lại đúng gloss cũ cho mọi dòng còn giữ giá trị của lớp, xoá khoá learner_fix
lex.learner_relations(entry_id, on) Bật hoặc tắt các dòng lex.lex_relations kiểu collocation mà lớp đã thêm vào khối cụm từ của trang một từ. Mỗi dòng ghi lại id của nó trên lex.learner_links.relation_id, nên tắt chỉ xoá đúng những dòng đó, không đụng quan hệ của một job khác
lex.learner_revert(entry_id) Gọi learner_unfix, tắt quan hệ, tắt quyền sở hữu entry kết hợp từ, rồi xoá dòng lex.learner_entries: hoàn tác toàn bộ hiệu ứng công khai của một lớp
admin.learner_set_status(entry_id, status) Hàm sau nút ẩn/hiện của /admin/learner. Đổi status, rồi gọi apply_fixes cộng bật quan hệ và quyền sở hữu khi chuyển sang published, hoặc unfix cộng tắt cả hai khi chuyển sang hidden, và ghi một dòng audit

Từ chưa có lớp AI

Một từ ngoài phạm vi 3.000, hoặc chưa tới lượt trong batch, được ghép một lớp tạm từ chính nghĩa từ điển của nó: deriveLearnerLayer (lib/dictionary/derivedLayer.ts), gọi bởi buildWordView (lib/dictionary/wordView.ts) khi entry chưa có lớp AI. Không ghi gì xuống database; lớp này mang source: 'dictionary' thay vì 'ai'. Một từ không có nghĩa thật, chỉ có nghĩa từ loại hay chỉ trỏ sang dạng từ khác, thì trả về rỗng và trang dùng bố cục classic như trước khi có lớp học từ. Ghi chú nguồn (layerNote, components/lookup/LearnerParts.tsx) khai rõ nghĩa lấy từ Wiktionary hay CC-CEDICT tuỳ ngôn ngữ, và tiếng Việt là máy dịch toàn bộ, một phần hay chưa có, khác hẳn ghi chú của lớp AI thật.

Chạy pipeline

python3 learner.py run [--lang en,es,zh] [--top 3000] [--entries id,id] [--limit N] [--workers 4] [--dry-run]
python3 learner.py load FILE...
python3 learner.py reapply

run xếp hàng entry theo tần suất của từng ngôn ngữ, gọi model viết (ag/claude-opus-4-6-thinking, dự phòng ag/gemini-3.1-pro-low khi hết quota) rồi model soát (ag/gemini-3.1-pro-low, dự phòng ag/claude-sonnet-4-6) qua 9router cho mỗi entry, dùng model đầu tiên router phục vụ và ghi lại đúng model đó vào report, rồi nạp bằng lex.learner_load. Mỗi bước ghi cache dưới LEARNER_CACHE, nên chạy lại chỉ làm lại đúng entry còn lỗi hoặc chưa chạy; một entry đã nạp đúng version prompt hiện tại (v4) bị bỏ qua. Prompt v4 thêm các kiểm tra trong validate(): mỗi kết hợp từ một dòng ở dạng từ điển, từ tương đương tiếng Trung không kèm 的 hay ngoặc, không gộp nghĩa khác từ loại, và ví dụ kết hợp từ tiếng Trung phải có pinyin. load nạp tay các file cache, dùng cho một đợt đã lưu sẵn như pilot. reapply chạy lại lex.learner_apply_fixes trên mọi entry đã nạp, không gọi AI.

Biến Việc
AI_BASE_URL, AI_API_KEY 9router, cùng cặp key và URL trợ lý AI của site dùng
SUPABASE_URL Host /rest/v1 của site
SUPABASE_SERVICE_ROLE_KEY Ghi qua PostgREST với quyền service_role
SITE_URL, REVALIDATE_SECRET Tuỳ chọn, gọi /api/revalidate ngay sau khi nạp thay vì chờ tới một tuần
LEARNER_CACHE Thư mục cache, mặc định ~/.cache/zhesen/learner

Người đọc thấy gì

  • Nhãn "câu soạn mới" trên một câu ví dụ do AI viết, không lấy nguyên văn từ nguồn có sẵn.
  • Số nghĩa Wiktionary hoặc CC-CEDICT mà mỗi nghĩa chính gộp lại, ghi dưới nghĩa dạng "Từ nghĩa ... của Wiktionary" hay "... của CC-CEDICT".
  • Một dòng ghi chú AI trên mỗi bố cục có lớp thật: "AI soạn nghĩa chính, ví dụ và kết hợp từ Wiktionary (hoặc CC-CEDICT). Một mô hình AI khác đã soát lại." Một từ chưa có lớp AI được ghi chú khác, theo mô tả ở mục trên.

Cùng tồn tại với enrichment Gemini

Một job khác, chạy tách biệt bằng Gemini, cũng ghi vào lex.senses và vào quan hệ collocation: nó đánh dấu bằng provenance.gloss_vi_before và tạo quan hệ collocation của riêng nó. Lớp học từ dùng ba khoá riêng để không đọc nhầm dấu của job kia: provenance.learner_fix cho gloss nó sửa, lex.learner_links.relation_id cho quan hệ nó thêm, và từ 0081, provenance.learner_owner cho entry kết hợp từ chính nó tạo ra. Khi ẩn hoặc khôi phục một lớp, mỗi hàm chỉ xoá hoặc gỡ đúng những gì khoá của mình đánh dấu, không đụng tới phần của job Gemini.

Hiệu năng nạp

0086 viết lại lex.gloss_terms_reload và lex.form_of_reload bằng plpgsql để mỗi lệnh tự lập plan theo entry thay vì quét toàn bảng: một lần reload giảm từ 7.523 ms xuống 15 ms. 0087 thêm index cho tra cứu entry một lớp sở hữu. 0088 thêm index cho lex.lex_relations.related_entry_id, thay một OR quét toàn bảng bằng hai probe theo index. Cộng lại, lex.learner_load trên es:de giảm từ 59.180 ms xuống 64 ms.

Clone this wiki locally