# 職涯諮詢個案管理系統 - 架構設計文件 ## 專案目標 打造一個**差異化的助人者專業工具**,相較於一般的「錄音 → AI 摘要」工具,我們提供: ### 核心價值主張 1. **一鍵整合**:錄音 → 逐字稿 → 專業報告 → 個案管理系統 2. **專業標準**:符合助人專業的報告結構(職游標準框架) 3. **累積型檔案**:支援個案歷程追蹤、跨次晤談分析 4. **智能連動**:報告自動與「來訪者歷程」「諮詢策略建議」「回訪提醒」連動 5. **專業化 AI**:經過專業顧問調教的對話設計(符合助人倫理、督導結構) 6. **客製化知識庫**:諮詢師可選擇特定文件進行 RAG 檢索 --- ## 系統架構概覽 ``` ┌─────────────┐ │ iOS App │ 錄音 → 轉逐字稿 └──────┬──────┘ │ API Call ↓ ┌─────────────────────────────────────────┐ │ Backend API Server │ │ ┌────────────────────────────────────┐ │ │ │ Session Management (個案管理) │ │ │ │ - 自動創建/更新個案檔案 │ │ │ │ - 晤談次數累計 │ │ │ │ - 歷程追蹤 │ │ │ └────────────────────────────────────┘ │ │ ┌────────────────────────────────────┐ │ │ │ AI Report Generation (報告生成) │ │ │ │ - RAG 知識檢索 │ │ │ │ - 結構化報告生成 │ │ │ │ - 對話節錄提取 │ │ │ └────────────────────────────────────┘ │ │ ┌────────────────────────────────────┐ │ │ │ Counselor Agent (客製化 AI) │ │ │ │ - 文件選擇 │ │ │ │ - 知識庫過濾 │ │ │ └────────────────────────────────────┘ │ └─────────────────────────────────────────┘ │ ↓ ┌─────────────────────────────────────────┐ │ Supabase Database │ │ - clients (個案基本資料) │ │ - sessions (晤談紀錄) │ │ - session_reports (AI 生成報告) │ │ - counselor_agents (諮詢師 AI 設定) │ │ - documents + chunks + embeddings (RAG) │ └─────────────────────────────────────────┘ ``` --- ## 核心使用情境 ### 情境 1:首次晤談 (iOS → Backend) **iOS 端操作**: 1. 諮詢師在 App 中錄音 2. App 自動轉逐字稿 3. 填寫個案基本資料(姓名、年齡、性別等) 4. 點擊「生成報告」 **API Request**: ```json POST /api/sessions/generate-report { "counselor_code": "CO_張老師", "client": { "code": "CL_小明", "name": "小明", "age": 25, "gender": "男", "occupation": "軟體工程師", "education": "大學", "location": "台北" }, "session": { "transcript": "Co: 你好,今天想聊什麼?\nCl: 我最近對工作感到很困惑...", "num_participants": 2, "session_date": "2025-01-15T10:00:00" } } ``` **Backend 處理流程**: 1. ✅ 檢查 `client_code` 是否存在 - 不存在 → 創建新個案檔案(`clients` 表) - 存在 → 略過 2. ✅ 創建新的 Session 紀錄(`sessions` 表) - 自動累加 `session_number` (第 1 次) - 儲存逐字稿 3. ✅ 呼叫 AI 生成報告 - RAG 檢索相關理論(根據 counselor 的 Agent 設定選擇文件) - 生成結構化報告 4. ✅ 儲存報告(`session_reports` 表) 5. ✅ 更新個案統計(總晤談次數、最後晤談時間) **API Response (SSE Stream)**: ``` data: {"step": 1, "status": "processing", "message": "正在分析逐字稿結構..."} data: {"step": 2, "status": "completed", "message": "識別到 2 個關鍵議題"} data: {"step": 3, "status": "processing", "message": "正在檢索相關理論..."} ... data: {"step": 5, "status": "completed", "data": {"report": {...}}} ``` 最終回傳完整報告 JSON --- ### 情境 2:第二次晤談 (簡化流程) **iOS 端操作**: 1. 選擇既有個案「小明」 2. 錄音 → 轉逐字稿 3. 點擊「生成報告」 **API Request**: ```json POST /api/sessions/generate-report { "counselor_code": "CO_張老師", "client": { "code": "CL_小明" // 不需要再傳基本資料,後端自動取得 }, "session": { "transcript": "Co: 上次我們聊到職涯困擾...", "num_participants": 2, "session_date": "2025-01-22T10:00:00" } } ``` **Backend 處理**: 1. ✅ 根據 `client_code` 取得既有個案資料 2. ✅ 創建第 2 次 Session(`session_number = 2`) 3. ✅ 生成報告時可參考歷次晤談內容(optional,未來功能) 4. ✅ 儲存並回傳報告 --- ### 情境 3:查詢個案歷程 (iOS 或 Web) **API Request**: ```json GET /api/clients/CO_張老師/CL_小明/history ``` **Response**: ```json { "client": { "code": "CL_小明", "name": "小明", "age": 25, "gender": "男", "total_sessions": 2, "first_session_date": "2025-01-15T10:00:00", "last_session_date": "2025-01-22T10:00:00", "status": "active" }, "sessions": [ { "session_id": 123, "session_number": 1, "session_date": "2025-01-15T10:00:00", "summary": "初次晤談,探索職涯困擾,使用生涯卡牌", "main_concerns": ["職涯轉換", "工作壓力"] }, { "session_id": 124, "session_number": 2, "session_date": "2025-01-22T10:00:00", "summary": "深入探索價值觀,進行興趣測驗", "main_concerns": ["自我探索", "決策困難"] } ] } ``` --- ### 情境 4:取得特定報告詳情 **API Request**: ```json GET /api/sessions/123/report ``` **Response**: ```json { "session_id": 123, "client_info": { "name": "小明", "age": 25, "gender": "男" }, "session_summary": { "content": "個案表達想要轉換跑道的想法...", "self_evaluation": "初次晤談,建立良好關係" }, "conceptualization": "【主訴問題】\n個案表達對目前軟體工程師工作感到倦怠...", "main_concerns": ["職涯轉換", "工作生活平衡"], "counseling_goals": ["釐清職涯方向", "改善工作壓力"], "techniques": ["同理心回應", "生涯卡探索"], "theories": [ { "text": "Super 的生涯發展理論指出...", "document": "生涯發展理論", "score": 0.85 } ], "dialogue_excerpts": [ {"speaker": "speaker1", "order": 1, "text": "聽起來你對目前的工作感到一些困擾?"}, {"speaker": "speaker2", "order": 2, "text": "是的,我覺得每天寫程式很累"} ] } ``` --- ## 資料庫設計 ### 1. `clients` - 個案基本資料 | 欄位 | 型別 | 說明 | |------|------|------| | id | SERIAL | Primary Key | | client_code | VARCHAR(100) | 唯一識別碼,格式:`{counselor_code}_{alias}` | | counselor_code | VARCHAR(100) | 所屬諮詢師 | | name | VARCHAR(200) | 化名 | | gender | VARCHAR(50) | 性別 | | age | INTEGER | 年齡 | | occupation | VARCHAR(200) | 職業 | | education | VARCHAR(200) | 學歷 | | location | VARCHAR(200) | 居住地 | | economic_status | VARCHAR(200) | 經濟狀況 | | family_relations | TEXT | 家庭關係 | | status | VARCHAR(50) | active/inactive/completed | | first_session_date | TIMESTAMP | 首次晤談時間 | | last_session_date | TIMESTAMP | 最後晤談時間 | | total_sessions | INTEGER | 總晤談次數 | | notes | TEXT | 諮詢師備註 | | tags | TEXT[] | 標籤 | | created_at | TIMESTAMP | 建檔時間 | | updated_at | TIMESTAMP | 更新時間 | ### 2. `sessions` - 晤談紀錄 | 欄位 | 型別 | 說明 | |------|------|------| | id | SERIAL | Primary Key | | client_id | INTEGER | FK → clients.id | | counselor_code | VARCHAR(100) | 諮詢師代碼 | | session_number | INTEGER | 第幾次晤談 | | session_date | TIMESTAMP | 晤談日期 | | duration_minutes | INTEGER | 時長(分鐘) | | session_type | VARCHAR(50) | individual/group/online/offline | | transcript | TEXT | 原始逐字稿 | | num_participants | INTEGER | 會談人數(default 2) | | status | VARCHAR(50) | draft/completed/reviewed | | created_at | TIMESTAMP | 建立時間 | | updated_at | TIMESTAMP | 更新時間 | **Unique Constraint**: `(client_id, session_number)` ### 3. `session_reports` - AI 生成報告 | 欄位 | 型別 | 說明 | |------|------|------| | id | SERIAL | Primary Key | | session_id | INTEGER | FK → sessions.id | | client_info | JSONB | 個案基本資訊 | | session_summary | JSONB | 晤談摘要 | | conceptualization | TEXT | 概念化分析(完整文字) | | main_concerns | TEXT[] | 主訴問題列表 | | counseling_goals | TEXT[] | 諮詢目標列表 | | techniques | TEXT[] | 使用技巧列表 | | dialogue_excerpts | JSONB | 對話節錄 | | theories | JSONB | 相關理論文獻 | | client_progress | TEXT | 個案進展(未來功能) | | next_steps | TEXT | 後續建議 | | follow_up_date | TIMESTAMP | 回訪日期(未來功能) | | supervision_notes | TEXT | 督導討論內容(未來功能) | | generated_at | TIMESTAMP | 報告生成時間 | | updated_at | TIMESTAMP | 更新時間 | ### 4. `counselor_agents` - 諮詢師客製化 AI | 欄位 | 型別 | 說明 | |------|------|------| | id | SERIAL | Primary Key | | counselor_code | VARCHAR(100) | 諮詢師代碼(Unique) | | agent_name | VARCHAR(200) | Agent 名稱 | | selected_document_ids | INTEGER[] | 選擇的文檔 IDs | | selected_tags | TEXT[] | 或按標籤篩選(未來) | | system_prompt | TEXT | 客製化 prompt(未來) | | temperature | FLOAT | 溫度參數(未來) | | top_k | INTEGER | RAG top_k(default 5) | | similarity_threshold | FLOAT | 相似度門檻(default 0.5) | | specialties | TEXT[] | 專長領域(未來) | | approach | TEXT | 諮詢取向(未來) | | total_sessions | INTEGER | 使用次數 | | last_used_at | TIMESTAMP | 最後使用時間 | | created_at | TIMESTAMP | 建立時間 | | updated_at | TIMESTAMP | 更新時間 | ### 5. `client_progress_timeline` - 個案進展時間軸(未來功能) | 欄位 | 型別 | 說明 | |------|------|------| | id | SERIAL | Primary Key | | client_id | INTEGER | FK → clients.id | | session_id | INTEGER | FK → sessions.id | | stage | VARCHAR(100) | 階段(探索期/工作期/結束期) | | progress_score | INTEGER | 進展評分 1-10 | | mood_score | INTEGER | 情緒狀態 1-10 | | milestones | TEXT[] | 里程碑 | | breakthroughs | TEXT | 突破點 | | challenges | TEXT | 挑戰 | | counselor_notes | TEXT | 諮詢師觀察 | | created_at | TIMESTAMP | 建立時間 | --- ## API 設計規格 ### 核心 API(Phase 1 - 優先實作) #### 1. 生成並儲存報告 ``` POST /api/sessions/generate-report Content-Type: application/json Request Body: { "counselor_code": "CO_張老師", "client": { "code": "CL_小明", "name": "小明", // 首次必填 "age": 25, // 首次必填 "gender": "男", // 首次必填 "occupation": "軟體工程師", // 選填 "education": "大學", // 選填 "location": "台北", // 選填 "economic_status": "穩定", // 選填 "family_relations": "已婚" // 選填 }, "session": { "transcript": "Co: 你好...", "num_participants": 2, "session_date": "2025-01-15T10:00:00", "duration_minutes": 60 // 選填 } } Response: SSE Stream Content-Type: text/event-stream data: {"step": 1, "status": "processing", "message": "正在分析逐字稿結構..."} data: {"step": 1, "status": "completed", "message": "逐字稿分析完成", "data": {...}} data: {"step": 2, "status": "processing", "message": "正在識別關鍵議題..."} ... data: {"step": 5, "status": "completed", "message": "個案報告生成完成", "data": {"report": {...}, "session_id": 123}} data: {"step": 6, "status": "completed", "message": "全部完成!"} ``` **處理邏輯**: 1. 檢查 `client_code` 是否存在於 `clients` 表 2. 若不存在 → INSERT 新個案 3. 若存在 → 取得 `client_id` 4. INSERT 新的 `session` 紀錄(自動計算 `session_number`) 5. 呼叫 AI 生成報告(整合現有的 `generate_report_stream`) 6. INSERT `session_reports` 紀錄 7. UPDATE `clients` 的 `total_sessions`, `last_session_date` 8. 回傳完整報告 + `session_id` --- #### 2. 查詢諮詢師的個案列表 ``` GET /api/counselors/{counselor_code}/clients Query Parameters: - status: active/inactive/completed (選填) - limit: 20 (選填) - offset: 0 (選填) Response: { "total": 15, "clients": [ { "code": "CL_小明", "name": "小明", "age": 25, "gender": "男", "total_sessions": 3, "last_session_date": "2025-01-22T10:00:00", "status": "active", "tags": ["職涯困擾", "焦慮"] }, ... ] } ``` --- #### 3. 查詢個案歷程 ``` GET /api/clients/{counselor_code}/{client_code}/history Response: { "client": { "code": "CL_小明", "name": "小明", "age": 25, "gender": "男", "occupation": "軟體工程師", "total_sessions": 3, "first_session_date": "2025-01-15T10:00:00", "last_session_date": "2025-01-22T10:00:00", "status": "active" }, "sessions": [ { "session_id": 123, "session_number": 1, "session_date": "2025-01-15T10:00:00", "duration_minutes": 60, "summary": "初次晤談,探索職涯困擾", "main_concerns": ["職涯轉換", "工作壓力"] }, ... ] } ``` --- #### 4. 取得特定報告 ``` GET /api/sessions/{session_id}/report Response: { "session_id": 123, "session_number": 1, "session_date": "2025-01-15T10:00:00", "client_info": { ... }, "session_summary": { ... }, "conceptualization": "...", "main_concerns": [...], "counseling_goals": [...], "techniques": [...], "theories": [...], "dialogue_excerpts": [...] } ``` --- ### Agent 設定 API(Phase 1 - 簡化版) #### 5. 設定諮詢師的 Agent ``` POST /api/agents/config Request: { "counselor_code": "CO_張老師", "agent_name": "職涯諮詢專用 AI", "selected_document_ids": [1, 3, 5, 7] // 選擇特定文檔 } Response: { "success": true, "message": "Agent 設定已更新", "agent": { "id": 1, "counselor_code": "CO_張老師", "agent_name": "職涯諮詢專用 AI", "selected_document_ids": [1, 3, 5, 7], "top_k": 5, "similarity_threshold": 0.5 } } ``` --- #### 6. 取得諮詢師的 Agent 設定 ``` GET /api/agents/{counselor_code}/config Response: { "agent": { "id": 1, "counselor_code": "CO_張老師", "agent_name": "職涯諮詢專用 AI", "selected_document_ids": [1, 3, 5, 7], "top_k": 5, "similarity_threshold": 0.5, "total_sessions": 15, "last_used_at": "2025-01-22T10:00:00" } } ``` --- ## 身份識別策略 ### 諮詢師識別(Counselor Code) **格式建議**: ``` CO_{姓名/暱稱} 例如:CO_張老師、CO_李心理師 ``` **特性**: - 不需要密碼(暫時) - 由 iOS 端儲存並自動帶入 - 未來可考慮裝置綁定或簡易 PIN 碼 ### 個案識別(Client Code) **格式建議**: ``` CL_{化名/代號} 或 {counselor_code}_CL_{化名} 例如: - CL_小明 - CO_張老師_CL_小明 ``` **特性**: - 由諮詢師在 iOS 端輸入 - 確保在該諮詢師下唯一即可 - 不需要跨諮詢師唯一(未來若需轉介再調整) --- ## 資料儲存策略 ### ✅ 儲存的資料 1. **諮詢師基本資料** - counselor_code, name 2. **個案基本資料** - 所有 `clients` 表欄位 3. **晤談紀錄** - 逐字稿(`transcript`) - 晤談時間、次數、時長 4. **AI 生成報告** - 完整的結構化報告內容 5. **Agent 設定** - 文檔選擇設定 ### ❌ 不儲存的資料 1. **錄音檔** - 由 iOS 本地儲存 - 未來若需要可考慮 S3/Supabase Storage 2. **諮詢師個人設定**(暫時) - system_prompt, temperature 等進階設定 - Phase 2 再實作 --- ## RAG 整合策略 ### 現有 RAG 架構 ``` documents → chunks → embeddings ``` ### Agent 如何選擇文件 **方式 1:選擇特定文檔**(Phase 1 實作) ```python # 從 counselor_agents 取得 selected_document_ids agent = get_counselor_agent(counselor_code) selected_doc_ids = agent.selected_document_ids # [1, 3, 5, 7] # RAG 查詢時過濾 WHERE c.doc_id IN :selected_doc_ids ``` **方式 2:標籤篩選**(未來) ```python # 文檔加上標籤 documents.tags = ["職涯諮詢", "生涯規劃"] # Agent 設定選擇標籤 agent.selected_tags = ["職涯諮詢"] # 查詢時過濾 WHERE d.tags && :selected_tags ``` --- ## Phase 1 實作優先順序 ### 今天完成(核心功能) 1. ✅ 資料庫 Migration(已完成 SQL) 2. ⏳ 執行 Migration 3. ⏳ 實作 `POST /api/sessions/generate-report` - 整合現有的 `generate_report_stream` - 加入個案創建/更新邏輯 - 加入 Session 儲存邏輯 - 加入 Report 儲存邏輯 4. ⏳ 實作簡易 Agent 設定 API - `POST /api/agents/config` - `GET /api/agents/{counselor_code}/config` 5. ⏳ 測試 iOS 串接 ### 明天完成(查詢功能) 6. `GET /api/counselors/{counselor_code}/clients` 7. `GET /api/clients/{counselor_code}/{client_code}/history` 8. `GET /api/sessions/{session_id}/report` ### 後天+(Web 管理介面) 9. 諮詢師登入頁面(輸入 counselor_code) 10. 個案列表頁面 11. 個案詳情 + 歷程時間軸頁面 12. Agent 設定頁面(選擇文檔) --- ## 未來擴充功能(Phase 2+) ### 進階 CRM 功能 - 回訪提醒(`follow_up_date`) - 個案進度評分(`client_progress_timeline`) - 階段分析(探索期/工作期/結束期) ### 協作功能 - 跨諮詢師轉介 - 督導討論功能(`supervision_notes`) - 團隊協作 ### 進階 Agent 功能 - 自訂 system_prompt - 調整 temperature - 專長領域標籤 ### 資料分析 - 諮詢師統計儀表板 - 個案改善率分析 - 熱門議題追蹤 --- ## 技術棧 - **Backend**: FastAPI + Python 3.10+ - **Database**: Supabase (PostgreSQL + pgvector) - **AI**: OpenAI GPT-4o-mini + text-embedding-3-small - **Frontend**: Next.js 14 + React + TypeScript - **iOS**: Swift (由團隊其他成員開發) --- ## 資料隱私與安全 ### 現階段(MVP) - 不儲存錄音檔 - 逐字稿和報告儲存在 Supabase(已加密傳輸) - 簡易代碼識別(counselor_code) ### 未來規劃 - 端對端加密(E2EE) - 符合 GDPR/HIPAA 規範 - 資料匿名化選項 - 定期資料備份 - 資料刪除權(Right to be forgotten) --- ## API 錯誤處理 ### 標準錯誤格式 ```json { "error": { "code": "CLIENT_NOT_FOUND", "message": "找不到該個案資料", "details": { "client_code": "CL_小明", "counselor_code": "CO_張老師" } } } ``` ### 常見錯誤碼 - `CLIENT_NOT_FOUND`: 個案不存在 - `COUNSELOR_NOT_FOUND`: 諮詢師不存在 - `SESSION_NOT_FOUND`: 晤談紀錄不存在 - `INVALID_TRANSCRIPT`: 逐字稿格式錯誤 - `AGENT_NOT_CONFIGURED`: Agent 未設定 - `DOCUMENT_NOT_FOUND`: 文檔不存在 --- ## 測試策略 ### 單元測試 - 個案創建/更新邏輯 - Session 編號自動累加 - Report 資料解析 ### 整合測試 - iOS → API → Database 完整流程 - RAG 文檔過濾功能 - SSE 串流測試 ### E2E 測試 - 首次晤談完整流程 - 後續晤談流程 - 歷程查詢功能 --- ## 部署架構(未來) ``` ┌──────────┐ │ iOS App │ └────┬─────┘ │ ↓ ┌──────────────────┐ │ Cloudflare / CDN │ └────┬─────────────┘ │ ↓ ┌──────────────────┐ │ FastAPI Server │ (Railway / Render / AWS) │ (Load Balanced) │ └────┬─────────────┘ │ ↓ ┌──────────────────┐ │ Supabase │ │ (PostgreSQL + │ │ pgvector) │ └──────────────────┘ ``` --- ## 變更歷史 | 日期 | 版本 | 變更內容 | |------|------|----------| | 2025-01-XX | 0.1 | 初版架構設計 | --- **文件作者**: Claude + Young **最後更新**: 2025-01-XX **狀態**: 規劃中 → 準備實作