Skip to content

feat(ai): add Groq GPT-OSS adapter - #32

Merged
HeiTang merged 7 commits into
devfrom
feature/groq-adapter
Nov 5, 2026
Merged

HeiTang merged 7 commits into
devfrom
feature/groq-adapter

Conversation

@HeiTang

@HeiTang HeiTang commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

Remindly 新增個人 Groq Key 語意解析,固定使用 openai/gpt-oss-120b,沿用既有加密、排序、冷卻、最多三組 Key 備援與 18 秒共用等待預算。使用者在私聊輸入 /ai add groq <Key> 即可設定;Gemini 仍為預設,建立提醒仍須確認。

同時修正時間守衛只辨識合法前綴就覆寫模型的問題。例如「明天晚上八點過十分鐘」原本會把正確的 20:10 改成 20:00,現在確認時間保留為 20:10。AI 與關閉 AI 路徑也共用必要條件守衛,僅補時間不會清掉尚未釐清的條件。

供應商接入

  • Groq adapter 使用 strict JSON Schema,遞迴補 additionalProperties: false,保留 nullable 型別;無新增 SDK、依賴或資料庫 migration。
  • HTTP/連線錯誤轉成既有 ProviderError;429 依結構化 headers 分類並採用 Retry-After,不保存上游錯誤原文。截斷 chunked 回應也能進入冷卻/備援。
  • 設定 User-Agent: Remindly,解決真實 Key 測試中預設 urllib 被 Cloudflare 以 403/1010 擋下的問題。
  • Groq 模型 metadata 無可讀名稱,確認卡沿用「使用 AI 解析」,解析紀錄保存供應商與模型 ID。

共用解析守衛

  • 條件辨識與追問保留抽到 reminders/guards.py,兩條解析路徑重用,不另造解析器。已有未解條件的草稿,改時間後仍須釐清條件。

  • 明確時間修正共用 ReminderParser.explicit_update();否定或無法辨識的變更不能被填成事項。

  • 週期只有時鐘時用既有 next_fire() 計算首次日期,保留明確起始日期,避免每週一、三、五的首次日期落在週六。

  • TimeParse.is_complete 檢查解析前綴後是否尚有時刻、時間長度或時段;不完整前綴不能覆寫模型完整時間/事項。明確日期、過去/無效日期、歧義與模型格式驗證仍保留。

  • 四個已保存的實測案例(共六筆回應)現在正確保留 14:45、20:10、18:30、20:00。修正不使用案例 ID 或整句比對;另覆蓋不同日期、時刻、事項,以及普通事項中的時間詞。

  • 星期文法與提醒觸發共用 WEEKDAY_RE,支援「這個星期/這個禮拜/下個星期/下下個禮拜」等助詞變形,沿用既有週一週界;本週已過的日期不自動滾到下週。

  • 共用 new_reminder_text() 辨識另外/新增/另開等明確另建指令。只有單一明確請求才擷取新請求;一般修改、事項提及與多筆提醒不強制新建。

  • 明確新請求不帶入舊草稿上下文,模型資料先驗證格式再約束為 create,避免 update 誤標沿用舊時間、條件或週期。原始 JSON 不改寫,完整原句仍保存為新草稿來源;舊確認按鈕失效,建立仍須確認。

  • 共用追問判定依已驗證的事項完整性,清除多餘的內容詢問及模型自行提出的曆法重複提議;不比對原句或案例 ID。缺少資訊、無效時間、未定對象、多筆提醒、擅加週期與既有未解條件仍保留。原文「每個/逢工作日、假日等」視為未解條件,不能默默改成一次性提醒。

評估工具與資料

  • scripts/groq_live_eval.py 支援 --cases 選資料集;逐筆保存原始 JSON、差異、耗時及失敗事件,429 冷卻後續跑,同一輸出路徑不重送已完成請求。
  • 評分加入明確 intent 與實際路由,透過 BotRouter/ReminderService、臨時 SQLite 與 FakeTelegramClient 比較關閉 AI、模型原始資料與 AI 處理後結果。不能再以欄位完整性推定路由成功。
  • 原始模型資料僅經共用格式驗證/日期換算,不套語意守衛。對象比較統一已知 @alice 的 username/user ID 表示,不評估身份解析差異。
  • 舊資料:36 個不同案例、8 個各跑三次,共 52 次;來源與預期值指回既有回歸集。
  • 新探索:使用者同意的人工合成口語,20 個不同案例、5 個各跑三次,共 30 次。輸入與預期值在實測前凍結,雜湊由測試核對;不是使用者真實紀錄,也不是獨立第三方測試集。
  • 原始回應、凍結預期與歷史對照結果保留不變。探索的去除模型對照僅作診斷,不是產品新增模式。
  • CI 僅離線重播,不讀 Key 或呼叫 API。手動實測從 .env 載入個人 GROQ_API_KEY,不接觸正式 Telegram/資料庫。
uv run python scripts/groq_live_eval.py \
  --cases tests/fixtures/groq_exploration_2026-10-31.jsonl \
  --output /tmp/groq-exploration.jsonl

真實 API 與離線驗證結果

既有歷史資料

資料/版本 模型原始資料 AI+本機處理
10/30 回歸集:52 次真實 API 回應,最新守衛離線重播 26/52 52/52
10/31 人工探索集:20 案例、30 次真實 API 回應,完整性修正前 18/20、28/30 14/20、22/30
11/4 保持同一探索預期與原始回應,完整性修正後離線重播 18/20、28/30 18/20、28/30
11/4 補共用星期日期/新建意圖約束後離線重播 18/20、28/30 20/20、30/30

10/30 共 58 次 API 嘗試:52 次取得回應、5 次 429、1 次 request 錯誤;10/31 共 33 次嘗試:30 次取得回應、3 次 429 各冷卻 60 秒後續跑。當時人工探索組關閉 AI 為 7/20;目前共用新建意圖修正後為 8/20,不能混用不同版本的分數。

11/4 重新呼叫 Groq:同批 56 案例,86 次回應

使用 1aa8250、固定 openai/gpt-oss-120b,沿用原始預期值與固定測試時鐘。36 個回歸案例共 52 次、20 個探索案例原定 30 次;13 個易漂移案例各跑三次。另外對已知漂移的 this-sunday、replace-draft 各補兩次,讓這兩筆也各跑三次,共 86 次取得回應。未依本輪回應修改 prompt、產品程式或答案。

測試集/計分方式 關閉 AI 模型原始資料 AI+本機處理(實測當時)
回歸 52 次 51/52 28/52 50/52
回歸 36 案例,所有重複均通過 35/36 24/36 34/36
探索與補跑 34 次 12/34 32/34 34/34
探索 20 案例,所有重複均通過 8/20 18/20 20/20
合計 86 次 63/86 60/86 84/86
合計 56 案例,所有重複均通過 43/56 42/56 54/56
  • 共 93 次 API 嘗試:86 次取得回應、7 次 HTTP 429,各冷卻 60 秒後重試同一筆;無其他供應商錯誤。
  • 成功輪次含實際路由/臨時資料庫,不含冷卻:回歸平均 1.578 秒、範圍 0.547–9.536 秒;探索平均 1.094 秒、範圍 0.550–2.917 秒。
  • 「這個星期天」模型原始 2/3、最終 3/3。一筆原始 JSON 把 11/1 算成 11/6,修正前保留錯日期,修正後正確約束;「另外提醒」原始/最終皆 3/3,本輪沒有觸發原始 update 誤標,其約束仍由舊錯誤 JSON 回歸證明。
  • 相同 86 筆新 JSON 在星期/意圖修正前 5ca733f 為 83/86、修正後 1aa8250 為 84/86;新增通過一筆、沒有舊版通過而新版失敗。這隔離本機處理差異,不能推斷不同 prompt 對隨機回應的因果影響。
  • 本輪沒有「原始模型正確、被本機處理破壞」的案例。探索有 11 個案例符合關閉 AI 失敗、模型原始及最終成功,另 1 個多筆提醒由本機守衛補足;這是配對差異,不能直接宣稱 11 項獨立模型能力。

原始回應及三方結果保存為 tests/fixtures/groq_live_results_2026-11-04.jsonl、groq_exploration_results_2026-11-04.jsonl、groq_targeted_drift_results_2026-11-04.jsonl;當時差異與版本對照保存在 groq_comparison_2026-11-04.json,維持原樣。

本批多餘追問修正:原始 JSON 不變,離線重播 168/168

實測仍出現兩個案例各 1/3 次失敗:「工作日行事曆」被追問是否應每個工作日重複;補事項「延後寄包裹」被追問提醒內容。共用守衛漏認這些可由已驗證事項解決的詢問,最終留下不必要的 clarification。

本批擴充共用事項/追問語法與曆法條件約束,保留未知問題及必要追問;不使用完整原句或案例 ID。回歸測試先確認兩筆原始回應在修正前失敗、修正後通過,並覆蓋其他事項、曆法詞、缺漏資訊、無效時間、未定對象、多筆提醒及擅加週期反例。

離線重播資料 本批修正前 本批修正後
11/4 回歸 52 筆 50/52 52/52
11/4 探索及補跑 34 筆 34/34 34/34
舊回歸及探索 82 筆 82/82 82/82
合計 166/168 168/168
  • 本次新錄製 86 筆在最新守衛離線重播為 86/86;模型原始仍為 60/86,關閉 AI 仍為 63/86。兩個問題案例的三次錄製回應現在皆能進入確認卡,仍須確認才能建立提醒。
  • 原始預期、原始 JSON、當時 API 成績及歷史報告均未修改。groq_question_guard_replay_2026-11-04.json 另存程式/資料雜湊、逐筆評分與重播結果。
  • 多餘追問修正當時 make check 通過:Ruff、403 個 unit tests、smoke flow。另通過格式、git diff --check、資料雜湊與暫存內容 Key 洩漏檢查;.env 未納入提交。
  • 追問修正後沒有重新呼叫 API;86/86 是固定原始回應的離線重播結果,不能寫成最新真實 API 全過。

目前只有合成/既有回歸案例,不能推估真實使用準確率。測過的探索資料後續只能作回歸/漂移診斷,真實使用者語料與獨立標註仍待補;尚未驗證正式 Telegram/部署環境。18 秒沿用既有等待預算,並非嚴格的整次執行期限。

最後審查修正與驗證

  • 不完整時間片語只解除本機時間覆寫;額外條件、多筆提醒與週期驗證仍生效。例如「提醒我明天的晚上八點吃藥」遇到模型擅加每日週期時,會清除該週期並追問;「只在工作日吃藥」即使模型漏掉條件,也不能確認建立。
  • 週期首次日期只對沒有明確日期的時鐘重算。固定現在為 10/22 中午,「每天明晚八點提醒我吃藥」保留 10/23 20:00,不會被提前成 10/22 20:00;同樣涵蓋明早、後晚。
  • 新增 5 個回歸測試,涵蓋條件與多筆提醒、擅加/不符週期、合法週期及既有週期保留、普通事項反例,以及 Bot 確認前不得建立和確認後保存正確日期。
  • 修正提交:61f83de。本機 make check 通過:Ruff、408 個 unit tests、smoke flow;修改檔案的 Ruff 格式檢查與 git diff --check 通過。既有 Groq 錄製回應重播也通過。
  • 本批驗證使用固定模型回應與暫存 SQLite,沒有新增真實 API 請求、修改歷史模型 JSON 或案例預期,也尚未操作正式 Telegram/部署環境。
  • 最新提交 61f83de 的 GitHub CI check 已通過:執行紀錄。

@HeiTang
HeiTang merged commit 5fe3c83 into dev Nov 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant