讓 CareerWise 愈用愈懂你:學習與適應

CareerWise 是一個職涯諮詢 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 愈來愈懂得自己的偏好

解法

總結

這次升級讓 CareerWise 從「被動儲存」變成「主動學習」。

線上學習的關鍵在於即時性——使用者給出回饋後,下次對話就該有感,而不是等下次系統更新。這套機制讓 CareerWise 愈用愈懂使用者,而不是每次都從陌生人開始。


CareerWise Learning and Adaptation Agentic AI AI UX Architecture Design Pattern AI Engineering Agentic Design Pattern Agentic AI 401

Summer Tang
Sponsored
Summer Tang 一對一諮詢
Summer|TSMC 主任工程師|擁有 15 年資深 Web 架構經驗,職涯歷經跨國頂尖企業與新創。專精於高流量企業級應用開發,核心技術涵蓋微前端、效能優化、測試自動化與 SEO。曾出版多本技術著作,並多次擔任 MOPCON、WebConf 等大型技術年會講者。
了解更多 →