CareerWise 的目標設定與監控:從設計到實作

CareerWise 的目標設定與監控:從設計到實作

CareerWise 是一個以 LLM 為核心的職涯諮詢網站,提供履歷健檢、職涯建議與預約諮詢。使用者可以詢問轉職、面試、薪資談判等問題,系統透過知識庫搭配 Groq 的 LLM 來提供 grounded 的建議。在上一篇中,我們從概念面拆解了目標設定與監控模式。這一篇則記錄如何把這些概念真正落實到 CareerWise 中。

現狀:純被動回應

目前 CareerWise 的 Summer 是純被動回應系統:

使用者 → 發問 → Summer → 回答 → 結束

具體問題有六個:

  1. 無目標概念 — 使用者問什麼就答什麼,不知道「這次想達成什麼」
  2. 無達成確認 — 對話結束時不知道問題是否被解決
  3. 無跨對話連續性 — 三天後 Summer 完全忘了之前聊過什麼
  4. 球員兼裁判 — review agent 跟 Summer 用同一模型,難以發現自身盲點
  5. 無長期規劃結構 — 「五年內成為 CTO」這類目標只能得到一次性建議
  6. 無目標可視化 — 使用者的目標分散在對話歷史中,無法一覽

整體架構

新架構在既有的對話流程中嵌入目標相關的環節:

initChat()
  ├─ 載入最近 2 個 chat
  ├─ 檢查前一個 chat 是否有未完成 goal → 顯示 proactive prompt
  └─ 檢查當前 chat 是否有 goal → 無則顯示 goal input

POST /api/chat
  ├─ classifyIntent()
  ├─ classifyTier()
  │   ├─ simple → SSE streaming
  │   ├─ medium → career chain
  │   ├─ planned → plan review
  │   ├─ planning → goal decomposition chain (新增)
  │   └─ complex → 平行化
  └─ 注入 goal context → system prompt

回答後
  ├─ 顯示 achievement prompt(若存在 goal)
  ├─ 使用者按 👍 → goal.achieved = true
  └─ 使用者按「還要問」→ 繼續

決策項目

共六項設計決策,從基礎的模型配置到上層的 UI 呈現。

Review 模型獨立

問題reflect.tsreviewAgent()rewriteAgent() 都用 llama-3.1-8b-instant。同一模型同時負責生成和審查,難以發現自身盲點與幻覺。

選項 內容 選擇
A) 維持同一模型 review + rewrite 都用 llama-3.1-8b-instant  
B) 不同 prompt 同模型 review 用更嚴格的 system prompt  
C) 不同模型做 review review 換成 mixtral-8x7b-32768

選擇 C。B 只能改善語氣差異,無法解決模型本身的盲點。C 讓 review 與 generate 使用不同架構的模型(Mixtral MoE vs Llama dense),兩者的知識邊界與幻覺模式不同,能更有效發現問題。

const REVIEW_MODEL = "mixtral-8x7b-32768"   // 不同模型
const REWRITE_MODEL = "llama-3.1-8b-instant"  // 維持原模型

Session Goal 設定與儲存

問題:使用者每次對話都從零開始,Summer 不知道「這次想達成什麼」。

選項 內容 選擇
A) 只存對話歷史 依賴 LLM 從歷史推斷目標  
B) 獨立 goals 集合 users/{uid}/goals/ 獨立於 chat  
C) 擴充 chat document users/{uid}/chats/{chatId} 加入 goal 欄位

選擇 C。goal 與對話生命週期一致:chat 建立時可設 goal,chat 結束時 goal 自然 archive,不需要獨立管理。

// users/{uid}/chats/{chatId} — 新增欄位
{
  goal?: {
    text: string,
    achieved: boolean,
    achievedAt?: Timestamp,
    createdAt: Timestamp,
    smartGoal?: {
      specific: string,
      measurable: string,
      achievable: string,
      relevant: string,
      timeBound: string
    }
  },
  followUpFrom?: {
    chatId: string,
    achieved: boolean
  }
}

注入後的 system prompt 會包含目標資訊:

你是 Summer — 一位擁有豐富經驗的前端工程師與職涯顧問。
...
使用者的個人檔案:現職:TSMC Principal Engineer,年資:15 年
使用者的偏好:喜歡簡潔回答
使用者的目標:幫我評估該不該轉職

跨 Session 主動追蹤

問題:使用者今天問了「該不該離職」,三天後 Summer 完全忘了。

選項 內容 選擇
A) 不追蹤 每次從零開始  
B) 被動顯示歷史 頁面側邊欄顯示過往目標  
C) 主動問候 偵測未完成目標時主動關心

選擇 CinitChat() 時,檢查前一個 chat 是否有未完成的 goal。若存在,顯示 proactive prompt:「上次聊到…後來有進展嗎?」使用者可回應「有進展」或「還沒」。

SMART 目標框架

問題:使用者常說模糊的目標(「我想變強」),Summer 直接回應,沒有幫助使用者把目標具體化。

選項 內容 選擇
A) 不處理 直接回答  
B) 被動提供 SMART 模板 使用者自行點開  
C) 主動偵測 + 引導 Summer 主動引導 SMARTify

選擇 C。偵測到模糊目標時,Summer 以結構化提問引導:

使用者:「我想學前端」
  → Summer:「我來幫你把這個目標具體化:
     - Specific:你想學到什麼程度?(找工作 / 轉職 / 純興趣)
     - Measurable:怎樣算學會?(完成專案 / 拿到 offer)
     - Time-bound:希望多久達成?」

長期目標分解(Goal Decomposition Chain)

問題:使用者說「五年內成為 CTO」—— Summer 只能給一次性建議,無法分解為可執行的子目標。

選項 內容 選擇
A) 單次回答 一次 LLM 呼叫  
B) 提示鏈 3-step 背景分析 → KB 比對 → 報告  
C) 提示鏈 4-step SMARTify → 分解 → 排序 → 報告

選擇 C。在 classifyTier() 中新增 "planning" tier,觸發 4-step chain:

Step 1: SMARTify Goal          — 模糊目標具體化
Step 2: Decompose Sub-goals    — 拆成 4-8 個子目標(含依賴關係)
Step 3: Priority & Timeline    — 安排 3-5 個階段與時程
Step 4: Generate Report        — 產出自然語言 roadmap

classifyTier 擴充邏輯:

const PLANNING_KEYWORDS = [
  "規劃", "長期", "五年", "十年", "路線", "藍圖",
  "目標", "願景", "生涯規劃", "職涯規劃"
]

export function classifyTier(message: string): "simple" | "medium" | "planned" | "planning" | "complex" {
  const hasPlanningKeywords = PLANNING_KEYWORDS.some(kw => message.includes(kw))
  const isLong = message.length > 30
  if (hasPlanningKeywords && isLong) return "planning"
  // ... 其餘 tier 邏輯維持不變
}

目標進度儀表板

問題:目標分解完後,使用者沒有地方可以持續追蹤進度。

選項 內容 選擇
A) 不顯示 只存在後端  
B) 整合進 /memories memories 頁面加入 goals 區塊  
C) 獨立頁面 + memories 區塊 新增 /goals 頁面

選擇 C/goals 有完整的目標管理(目標卡片 + 進度條 + 子目標列表),/memories 只放摘要與連結。目標建立後,Summer 在回應中引導使用者前往 /goals 查看完整儀表板,讓使用者知道目標已經被記錄且可以隨時追蹤。

使用者旅程

情境 A:短期目標

Day 1 — Alice 第一次打開 CareerWise:

┌─────────────────────────────────────────────────────┐
│ 🎯 這次想討論什麼?                                    │
│ [我想確定該不該轉職]          [開始對話] [跳過]         │
└─────────────────────────────────────────────────────┘

Alice:「該不該從金融業轉職到前端工程師?」
→ Summer 回答(system prompt 已注入目標,回答針對轉職評估)

┌─────────────────────────────────────────────────────┐
│ 這個回答有幫助到你嗎?                [有 👍] [還要問]  │
└─────────────────────────────────────────────────────┘

Alice 按「還要問」→ 繼續對話,直到按「有 👍」完成目標。

情境 B:跨 Session 追蹤

Day 3 — Alice 再次打開 CareerWise:

┌─────────────────────────────────────────────────────┐
│ 上次我們聊到「該不該轉職」,後來有進展嗎?               │
│          [有進展]                    [還沒]           │
└─────────────────────────────────────────────────────┘

Alice 按「有進展」:
→ Summer:「太好了!學 HTML/CSS 是很好的開始。今天想聊什麼?」
→ 前一個目標標記為已完成

情境 C:長期目標分解

Bob:「我想五年內成為 CTO」
→ classifyTier → "planning"
→ Summer 先 SMARTify,引導 Bob 把目標具體化
→ Bob 回答後 → 4-step decomposition chain
→ 產出 roadmap 報告(願景目標 → 階段里程碑 → 具體行動 → 時間線)
→ 儲存到 Firestore → /goals 可查看進度

CareerWise 目標儀表板

對 UI/UX 的影響

這項設計對 CareerWise 使用者來說,最直接的感受是 Summer 從被動回答變成主動關心。

改變了什麼

對話開始時,使用者看到的不再是空白輸入框,而是一個目標設定卡片:「🎯 這次想討論什麼?」。使用者可以設定這次想達成的目標,或點「跳過」保持原本的自由模式。

每次 Summer 回答後,如果存在目標,下方會出現「這個回答有幫助到你嗎?」的提示。使用者按 👍 表示目標達成,按「還要問」則繼續對話。這個反饋讓 Summer 知道問題是否被解決。

如果使用者沒按 👍 就關閉對話,下次回來時會看到:「上次聊到⋯後來有進展嗎?」。這種跨 session 的關心讓 Summer 感覺有記憶,不只是每次從零開始的陌生人。

目標建立後,Summer 會在回應結尾引導使用者前往 /goals 儀表板查看完整的目標路線圖,讓使用者知道目標已經被記錄且可以隨時追蹤進度。

對長期規劃的支援

當使用者提到「我想五年內成為 CTO」這類模糊目標時,Summer 不再直接給一次性建議,而是先引導使用者把目標具體化(SMART 提問),然後產出結構化的 roadmap。使用者可以在 /goals 頁面看到自己的目標卡片與進度條,隨時追蹤。

使用者的控制權

所有目標相關的 UI 都是 opt-in:goal input 可以跳過、achievement prompt 可以忽略、proactive follow-up 只發生在有未完成目標時。使用者不會被強迫設定目標,但當需要時,Summer 會引導而非直接回答。

已知 UX 風險與解法

風險 問題 解法
Achievement prompt 疲乏 每次回答後都出現,長期目標(20+ 輪)從關心變干擾 連續按 3 次「還要問」後自動隱藏;或偵測密集對話時延後顯示
Goal input 疲乏 每次新對話都顯示,連續跳過的使用者覺得多餘 跳過次數累計 3 次後自動隱藏,使用者可在 /memories 設定重新開啟
SMART 引導打斷節奏 使用者說「我想學前端」,Summer 不回答先問三題 引導結尾加一句「先隨便聊聊也行,之後隨時可以設定目標」,讓自由探索不被堵死

總結

這次設計將 CareerWise 從純被動回應升級為具備目標設定與監控能力的主動教練系統。對照原本的六個問題:

原本問題 對應解法
無目標概念 Session Goal
無達成確認 Achievement Prompt
無跨對話連續性 跨 Session 追蹤
球員兼裁判 Review 模型獨立
無長期規劃結構 Goal Decomposition Chain
無目標可視化 目標儀表板

讓 Summer 不只是回答問題,而是陪使用者一起設定目標、追蹤進度、達成結果。

參考資料


CareerWise Agentic AI Goal Setting Design Pattern Architecture AI Engineering