讓 CareerWise 愈用愈懂你:學習與適應
25 Jul 2026CareerWise 是一個職涯諮詢 AI 服務,使用者在上面詢問面試準備、履歷健檢、轉職規劃等問題,由 AI 代理扮演職涯顧問來回答。目前的記憶機制(profile + memory)讓系統可以記住使用者的事實與偏好,但系統是被動儲存——使用者說了什麼就存什麼,不會主動根據使用者的行為調整自己的回應方式。
這篇文章要紀錄的是學習模式中最適合 CareerWise 的做法:線上學習(Online Learning)——系統在每次互動後,根據使用者的回饋和行為,動態調整後續的回應方式。總共分為四個部分:P1 使用者偏好學習、P2 回饋機制、P3 從修正中學習、P4 版本變更日誌。
P1 — 使用者偏好學習
問題:目前 CareerWise 的 system prompt 是固定的,所有使用者看到同一組回答原則。使用者必須每次重複說「我不喜歡空泛建議」、「太長了」、「可以具體一點嗎」,CareerWise 才會在當次修正,但下次又忘了。
設計決策
1. 學習來源 — 系統從哪裡取得使用者的偏好訊號。也就是說,CareerWise 要怎麼知道使用者喜歡什麼、不喜歡什麼。主要有兩種訊號來源:使用者主動說的(明確回饋)和使用者行為透露的(隱含行為)。
選擇 C — 明確回饋為主 + 隱含行為為輔:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 只靠明確回饋 | 使用者主動表達的意見,例如按 👍/👎 按鈕、在對話中說「我不喜歡條列式」、「太長了」、「這個建議很好」。優點是信號準確,缺點是使用者不常主動給回饋,資料稀疏 | |
| B) 只靠隱含行為 | 使用者沒有明說但行為透露的線索,例如閱讀時間很短(可能不滿意)、跳過回答沒看完、短期內重複問類似問題(代表上次的回答沒解決問題)。優點是不需要使用者主動操作,缺點是容易誤判(閱讀時間短可能只是分心) | |
| C) 兩者並存 | 明確回饋為主,隱含行為為輔。明確信號(修正 + 回饋)優先處理,隱含行為(跳過長篇回答的頻率)作為輔助參考 | ✅ |
選擇原因:使用者不常主動給回饋,只靠 A 資料稀疏。隱含行為(B)可能誤判(閱讀時間短可能只是分心)。C 讓明確信號(修正 + 回饋)優先,隱含行為(跳過長篇回答的頻率)輔助。
2. 儲存位置與注入方式 — 偏好資料要存在哪裡、怎麼讓 CareerWise 在回答時知道這些偏好
選擇 C — Firestore + 動態注入 system prompt:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 只存 Firestore | 偏好資料存在 Firestore,每次對話開始時從 Firestore 讀取,append 到 system prompt。跨對話持久化沒問題,但每次都要多一次 Firestore 讀取,且偏好只存在 server 端,無法在 client 端直接使用 | |
| B) 只存 system prompt | 偏好直接寫死在每次對話動態生成的 system prompt 裡,不另外存到資料庫。即時生效,但跨對話就消失了——使用者下次來又是一份乾淨的 prompt | |
| C) Firestore + 動態注入 | 存到 Firestore 確保跨對話持久化,每次載入時從 Firestore 讀取並 append 到 system prompt 結尾。整合現有 client context 機制,與 profile、memory 一起載入,server 端直接使用 | ✅ |
選擇原因:偏好需要持久化(跨對話),也需要在每次回答時被 CareerWise 知道。C 整合現有 client context 機制,將 preferences 與 profile/memory 一起載入並 append 到 system prompt 結尾。
// 注入後的 system prompt:
「你是 CareerWise — 一位擁有豐富經驗的前端工程師與職涯顧問。
...
使用者的個人檔案:現職:前端工程師,年資:3 年
使用者的偏好:喜歡簡潔回答、不喜歡條列式」
3. 觸發時機 — 什麼時候分析使用者對話並更新偏好
選擇 A — 每次回答後輕量分析 + 明確修正直接更新:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 每次回答後 | 每次對話結束後,用輕量 LLM 呼叫分析使用者的最後一則訊息,判斷是否有偏好相關內容(例如「太長了」= 喜歡簡潔、「謝謝很有幫助」= 正面回饋)。即時學習,下次對話立即生效 | ✅ |
| B) 只在使用者明確修正時 | 只在使用者說「不對」「不是」「我沒說過」這類明確修正詞時才更新偏好。好處是成本低,壞處是錯過「太長了」「這很有幫助」這類非修正但包含偏好的訊號 | |
| C) 批次分析 | 每天固定時間批次分析當天所有對話,一次更新偏好。成本最低,但學習延遲最多 24 小時——使用者早上說「太長了」,第二天才見效 |
選擇原因:A 讓學習即時發生——使用者說「太長了」後,下次對話立即生效。成本可控(每次約 100 tokens 的輕量分析)。B 錯過「謝謝很有幫助」這類正面回饋。C 學習延遲,使用者無感。
4. 注入方式 — 偏好資訊以什麼形式送進 LLM 的提示詞
選擇 A — 直接 append 到 system prompt 結尾:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) append 到 system prompt | 原 prompt 模板完全不動,只在結尾附加一段「使用者的偏好:喜歡簡潔回答、不喜歡條列式」。LLM 讀到這段後自然會調整回應風格,不需要改動原有 prompt 結構 | ✅ |
| B) 重寫 system prompt | 為每種偏好組合準備不同版本的完整 prompt(例如「簡潔版 prompt」、「詳細版 prompt」)。偏好組合會爆炸(風格 × 語氣 × 避免項目),維護成本高,不彈性 | |
| C) 作為額外 context | 偏好資訊放在 system prompt 之外,作為獨立 context 傳遞。雖然也是 LLM 會讀到的內容,但權重較低,可能被 LLM 忽略——特別是在 context 很長的時候 |
5. 生命週期 — 偏好改變時,舊的資料怎麼處理
選擇 A — 新值覆蓋舊值:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 新值覆蓋舊值 | 每次分析到新偏好直接覆蓋舊值。例如使用者原本喜歡「詳細回答」,今天說「太長了」,系統直接將 style 從 “detailed” 改為 “concise”。使用者說改就是要現在改,不需要保留「去年喜歡詳細」的記錄 | ✅ |
| B) 保留歷史版本 | 類似記憶的時間加權機制——舊偏好不刪除,但權重遞減。適用於「使用者可能反悔」的場景(昨天說喜歡簡潔,今天又說太簡略了),但偏好不是記憶,使用者不會「反悔」自己的當下設定 | |
| C) 人工確認 | 偵測到偏好改變時先問使用者「我注意到你喜歡更簡潔的回答,要更新你的偏好設定嗎?」。適合 profile 的重大變更(年資、產業變了),但偏好改變(太長了 → 簡潔)不需要確認,直接改就好 |
選擇原因:偏好的本質是「當下設定」,不是「歷史經驗」。使用者說「太長了」就是要 CareerWise 現在改,不需要保留「去年喜歡詳細」的記錄,也不需要先問使用者。
Firestore 結構
// users/{uid}/profile/data 擴充
{
current_role: "前端工程師",
years: 3,
skills: ["front-end", "development"],
goals: ["轉管理職"],
preferences: {
style: "concise", // concise | detailed
tone: "direct", // direct | warm
detail_level: "high", // high | low
avoid: ["條列式", "空泛建議"]
}
}
P2 — 回饋機制(Thumbs Up/Down)
問題:目前 CareerWise 回答後,使用者沒有任何方式表達滿意或不滿意。沒有 👍/👎 按鈕、沒有評分機制、沒有「這有幫助嗎?」的詢問。系統完全不知道哪些回答是好的、哪些需要改進。學習與適應需要明確的回饋信號——沒有回饋,系統就只能盲目猜測使用者的偏好,無法針對性地調整回應方式。
設計決策
1. 按鈕呈現 — 回饋按鈕長什麼樣子
選擇 B — 👍/👎 + 可選原因:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 只有 👍/👎 | 回饋門檻最低,按一下就好。但只能知道「使用者不喜歡」,完全不知道原因——是因為太長、太空泛、還是語氣不對?沒有原因就無法針對性改善 | |
| B) 👍/👎 + 可選原因 | 按 👎 後跳出 5 個常見原因(太長、不具體、語氣不對、空泛建議、其他),使用者選一個或多個。門檻稍微高一點(多點一下),但換來具體的改善方向。選「太長了」就知道要縮短,選「不具體」就知道要加案例 | ✅ |
| C) 四個按鈕 | 除了 👍/👎 還加上 📌(收藏)和 📋(稍後閱讀),功能看起來完整,但使用者看到四個按鈕反而不知道該按哪個,回饋意願反而降低 |
2. 儲存位置 — 回饋資料存在哪裡
選擇 B — 獨立 feedback 集合:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 擴充 memories | 把回饋資料丟進既有的 memories 集合,與偏好、事實混在一起。要查「這個月 👍 率多少」時,得從幾百筆記憶中過濾出回饋資料,查詢效率差、程式碼也容易出錯 | |
| B) 獨立 feedback 集合 | 開一個獨立的 users/{uid}/feedback/{id} 集合,每筆回饋獨立儲存,包含 rating、reason、messageId、時間戳。查詢分析直接針對這個集合,語意清楚、效能好 |
✅ |
| C) 只存偏好 | 使用者的回饋只用來更新偏好(例如 style 從 detailed 改為 concise),不保留原始的 👍/👎 記錄。好處是節省儲存空間,壞處是無法分析長期趨勢——你不知道這個月 👍 率是上升還是下降 |
// users/{uid}/feedback/{autoId}
{
rating: "up" | "down",
reason: "too_long" | "vague" | "tone" | "generic" | "other" | null,
messageId: string,
messageSnippet: string, // 前 50 字
createdAt: Timestamp
}
3. 影響後續回答 — 按 👎 後 CareerWise 會做什麼
選擇 A — 即時修正 + 記錄偏好:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 即時修正 | 使用者按 👎 後立即用同一個問題重新呼叫 LLM,並把剛剛的使用者偏好(「太長了」→ 喜歡簡潔)注入 prompt,讓新回答當下就改善。使用者立刻看到差異,感受到「它真的聽到了」 | ✅ |
| B) 下次對話生效 | 按 👎 後只記錄偏好,但當次回答不動。下次使用者再問問題時才採用新偏好。使用者會困惑「我明明按了 👎,為什麼回答沒變?」 | |
| C) 只記錄偏好 | 不重新生成回答,只在回答結尾加一句「已記錄你的回饋」。使用者知道系統收到了,但看不到實際改善,無法確認新的回答是否真的有變好 |
4. 重新生成流程 — 新回答怎麼呈現給使用者
選擇 B — 原回答保留,下方追加新回答:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 取代原回答 | 新回答直接蓋掉原本的內容。使用者如果後悔按 👎 或想比對兩個版本,就沒辦法了——原回答已經消失 | |
| B) 保留 + 下方追加 | 原回答保留在畫面上不動,新回答從下方開始串流顯示,前面加上「已根據你的回饋調整,這是更簡潔的版本:」。使用者可以上下滾動比對兩個版本,確認新的真的有改善 | ✅ |
| C) 保留 + 顯示修正過程 | 不只保留原回答,還在中間顯示修正的步驟細節(「偵測到偏好:太長了 → 將 style 改為 concise → 重新產生回答⋯」)。資訊量太多,使用者只想知道結果,不需要看過程 |
CareerWise: (原本的回答)
[👍] [👎]
↓ (使用者按 👎 → 選「太長了」)
已根據你的回饋調整,這是更簡潔的版本:
(新回答串流)
[👍] [👎]
5. 儀表板 — 回饋資料的分析與呈現
選擇 C — 完整儀表板:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 不分析 | 回饋資料只存不用,從不分析。雖然節省開發成本,但也失去了收集回饋的意義——不知道使用者滿意度、不知道哪些地方需要改善 | |
| B) 簡單統計 | 在 /memories 頁面顯示每週 👍 率(例如「本週 85% 使用者給 👍」)和 👎 原因排名(「太長了」佔 40%、「不具體」佔 30%)。可以掌握大致狀況,但無法深入分析 |
|
| C) 完整儀表板 | 除了 👍 率和原因排名,還包含:趨勢圖(這個月 👍 率是上升還是下降)、各 handler 分佈(哪種問題類型最常被 👎)、使用者對比(哪些使用者給 👍 最多、哪些給 👎 最多)。可以回答「這個月 CareerWise 的 👍 率有沒有提升?」「哪種問題類型最常被 👎?」 | ✅ |
選擇原因:回饋資料的價值在於長期趨勢分析,不是只看今天。
P3 — 從修正中學習(Correction Learning)
問題:當使用者說「不對」、「不是這樣」、「我沒說過」時,系統需要判斷這是修正指令,並即時更新記憶和偏好。
設計決策
1. 觸發條件 — 怎麼知道使用者在修正
選擇 C — 關鍵字秒判斷 + LLM 輔助判斷:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 關鍵字偵測 | 用「不對」「不是」「我沒說過」「你錯了」這類關鍵字判斷是否為修正。速度最快(秒判斷、零成本),但可能遺漏——使用者說「其實我是想說⋯」時沒有用關鍵字,但也是修正行為 | |
| B) LLM 判斷 | 每次回答後用 LLM 分析使用者的最後一則訊息,判斷是否包含修正意圖。準確率高、能涵蓋各種表達方式,但每次都要多一次 LLM 呼叫,成本高 | |
| C) 並存 | 先比對關鍵字,命中就直接處理(零成本)。沒有命中關鍵字時再用 LLM 分析做輔助判斷,確保不會遺漏「其實我是想說⋯」這類非關鍵字修正 | ✅ |
2. 回應方式 — 系統更新後怎麼告知使用者
選擇 C — 更新 + 解釋:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 默默更新 | 系統在背景更新記憶和偏好,不讓使用者知道。好處是對話不被打斷,但使用者無法確認修正是否生效——可能說完「不對」後,下次對話 CareerWise 還是用舊資料 | |
| B) 先確認再更新 | 偵測到修正後先回問「我注意到你修正了之前的資料,要幫你更新嗎?」。使用者明確確認後才改。尊重使用者,但多一步確認步驟對已明確表達的修正來說是干擾 | |
| C) 更新 + 解釋 | 直接更新,然後告知使用者改了什麼——「好的,我原本記錄了『想轉管理職』,現在已更新為『加強技術深度』」。使用者看到具體的變更內容,知道修正已生效,信任感更高 | ✅ |
選擇原因:C 讓使用者知道修正已生效——「好的,我原本記錄了『想轉管理職』,現在已更新為『加強技術深度』」。使用者看到具體的變更內容,信任感更高。
3. 影響範圍 — 一次修正要同步更新哪些資料
選擇 C — LLM 判斷影響範圍:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 只更新當前項目 | 使用者說「我沒說過想轉管理職」時,只刪除那筆記憶。但 profile 中的 goals 還留著「轉管理職」,memories 中其他提到管理職的記錄也還在,造成資料不一致——同一個主題,profile 說要轉、記憶說沒說過 | |
| B) 更新所有關聯項目 | 預先定義規則表——修正關鍵字 A 對應更新項目 X/Y/Z。規則明確,但彈性不足:使用者說「我沒說過想轉管理職」和「我其實不喜歡管理職」是不同的修正,但規則可能一視同仁全部更新 | |
| C) LLM 判斷 | 讓 LLM 根據修正內容的語意動態決定影響範圍。使用者說「我沒說過想轉管理職」→ LLM 判斷要刪除相關記憶、移除 goals、更新 profile。使用者說「我其實不是那個意思」→ LLM 判斷修正意圖不明確,先詢問再處理。不需要預先定義規則 | ✅ |
選擇原因:使用者說「我沒說過想轉管理職」可能影響 memories(刪除)、goals(移除)、profile(更新)。C 讓 LLM 根據修正內容動態決定影響範圍,不需要預先定義規則。
P4 — 版本變更日誌
問題:CareerWise 持續更新(知識庫新增、功能改善、prompt 優化),但使用者不知道系統改變了什麼。當回答方式改變時,使用者困惑「它什麼時候變的?為什麼變?」。
設計決策
1. 觸發時機 — 更新日誌在什麼時候顯示給使用者
選擇 C — 可關閉橫幅:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 每次對話開始 | 每次使用者打開 chat 頁面都顯示更新橫幅。優點是不會漏看,缺點是頻率高——如果一週更新三次,使用者每天都要關掉橫幅,久了會麻木甚至反感 | |
| B) 僅重大更新 | 只在新功能上線或大幅改善時顯示,小調整(知識庫新增一篇文章、prompt 微調)不通知。好處是不打擾使用者,但使用者可能發現回答變了卻不知道為什麼 | |
| C) 可關閉橫幅 | 更新後使用者首次開啟 chat 時顯示橫幅,看過後可關閉。關閉後不再顯示,但可從 /memories 頁面查看歷史更新記錄。兼顧通知與不打擾 |
✅ |
2. 儲存位置 — 更新日誌存在哪裡
選擇 A — Firestore 全域集合:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 全域集合 updates | 開一個獨立的 updates 集合,所有使用者共用同一份更新記錄。每次有新更新時只寫入一筆資料,所有使用者都看得到,節省儲存空間又即時 |
✅ |
| B) 使用者集合 | 每則更新寫入每個使用者的 users/{uid}/updates/{id}。如果有一萬個使用者,一則更新就要寫一萬次,浪費 Firestore 寫入次數 |
|
| C) 靜態檔案 | 更新日誌寫在 GitHub 上的靜態 JSON 或 Markdown 檔案,前端直接讀取。不需要後端 API,但無法做到「更新後首次開啟顯示」這類即時通知——使用者必須重新整理才看得到 |
3. 內容格式 — 更新日誌要寫哪些資訊
選擇 B — 標題 + 改善重點:
| 選項 | 內容 | 選擇 |
|---|---|---|
| A) 一句話摘要 | 只寫「CareerWise 已更新」或「Summer 變得更聰明了」。使用者看完只知道有更新,但完全不知道改了什麼,等於沒說 | |
| B) 標題 + 改善重點 | 標題簡短說明更新主題,下方用 bullet points 列出 3–5 項使用者有感的改變。例如「📢 CareerWise 已更新(2026-07-24)• 現在會參考你的個人檔案來回答 • 改善了建議的具體性 • 新增了計劃審查功能」。使用者 10 秒內就能掌握改了什麼 | ✅ |
| C) 完整變更日誌 | 把內部的 GitHub commit log 或技術變更記錄直接列出來,包含 pull request 編號、技術細節、修正的 bug 編號。資訊量太大,對一般使用者沒有意義 |
📢 CareerWise 已更新(2026-07-24)
• 現在會參考你的個人檔案來回答
• 改善了建議的具體性
• 新增了計劃審查功能
Firestore 結構
// updates/{updateId}
{
date: "2026-07-24",
title: "CareerWise 已更新",
items: [
"現在會參考你的個人檔案來回答",
"改善了建議的具體性",
"新增了計劃審查功能"
],
type: "improvement" // "new_feature" | "improvement" | "knowledge"
}
測試方式
測試 1:偏好學習(P1)
在 chat 輸入「太長了」「不喜歡條列式」
→ 打開 /memories
→ 偏好設定區塊應該出現:風格:簡潔、避免:條列式
測試 2:回饋按鈕(P2)
在 chat 輸入「怎麼談薪水」
→ CareerWise 回答後,下方出現 👍/👎 按鈕
→ 按 👎 → 跳出 5 個原因選項
→ 選「太長了」→ 原始回答保留,下方串流新回答
測試 3:計劃持久化(P4)
輸入「該不該轉職去新創」
→ 看到計劃卡片 → Cmd+R 重新整理
→ 計劃卡片還在(Firestore client-side 儲存)
測試 4:/memories 頁面完整功能
打開 http://localhost:3000/memories
→ 個人檔案:可編輯現職、年資、技能
→ 偏好設定:可編輯風格、語氣、具體程度、避免
→ 歷史記憶:可新增、刪除
→ 表現統計:本週 👍 率、最常被 👎 的原因(需有回饋資料)
→ 更新記錄:CareerWise 更新日誌
測試 5:Terminal Log 確認
[Profile] Merged via client SDK ← profile/preferences 有寫入
[Profile] Using client context ← 個人化內容有載入
對 UI/UX 的影響
學習與適應對使用者來說,最直接的感受是CareerWise 愈來愈懂得自己的偏好。
- 即時修正的體驗。 使用者說「太長了」後按 👎 選原因,原回答保留在畫面上,下方立即串流新版本。使用者可以比對前後兩個版本,確認新的真的有改善。這種即時性讓使用者感覺「它真的聽到了」。
- 偏好可視化。 所有學習到的偏好都在
/memories頁面顯示,使用者可以查看、編輯、刪除。如果 CareerWise 學錯了(例如把「一次不喜歡」誤判為「永遠不喜歡」),使用者可以直接修正。 - 更新告知不強迫。 版本變更以可關閉橫幅呈現,使用者知道有更新但不被打斷。想了解詳情可以展開查看,不想看可以關掉。
解法
- 關鍵字 + LLM 雙層判斷。簡單的修正(「不對」)零成本秒判斷,複雜的修正(「其實我是想說⋯」)由 LLM 輔助判斷,兼顧速度和準確性。
- 保留原回答 + 下方追加。使用者按 👎 重新生成時,保留原回答讓使用者可以比較。新回答從下方串流,不會讓使用者覺得原本的回答消失了。
- 全域更新集合。更新日誌只寫入一次 Firestore,所有使用者共用,不需要為每個使用者複製。
總結
這次升級讓 CareerWise 從「被動儲存」變成「主動學習」。
- P1 偏好學習讓 CareerWise 根據使用者的回饋調整回應風格
- P2 回饋機制給使用者表達滿意或不滿意的管道,並即時修正
- P3 修正學習讓 CareerWise 能理解「不對」「不是這樣」這類修正指令
- P4 版本日誌讓使用者知道 CareerWise 什麼時候變了、為什麼變
線上學習的關鍵在於即時性——使用者給出回饋後,下次對話就該有感,而不是等下次系統更新。這套機制讓 CareerWise 愈用愈懂使用者,而不是每次都從陌生人開始。