Spaces:
Build error
Build error
職涯諮詢個案管理系統 - 架構設計文件
專案目標
打造一個差異化的助人者專業工具,相較於一般的「錄音 → AI 摘要」工具,我們提供:
核心價值主張
- 一鍵整合:錄音 → 逐字稿 → 專業報告 → 個案管理系統
- 專業標準:符合助人專業的報告結構(職游標準框架)
- 累積型檔案:支援個案歷程追蹤、跨次晤談分析
- 智能連動:報告自動與「來訪者歷程」「諮詢策略建議」「回訪提醒」連動
- 專業化 AI:經過專業顧問調教的對話設計(符合助人倫理、督導結構)
- 客製化知識庫:諮詢師可選擇特定文件進行 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 端操作:
- 諮詢師在 App 中錄音
- App 自動轉逐字稿
- 填寫個案基本資料(姓名、年齡、性別等)
- 點擊「生成報告」
API Request:
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 處理流程:
- ✅ 檢查
client_code是否存在- 不存在 → 創建新個案檔案(
clients表) - 存在 → 略過
- 不存在 → 創建新個案檔案(
- ✅ 創建新的 Session 紀錄(
sessions表)- 自動累加
session_number(第 1 次) - 儲存逐字稿
- 自動累加
- ✅ 呼叫 AI 生成報告
- RAG 檢索相關理論(根據 counselor 的 Agent 設定選擇文件)
- 生成結構化報告
- ✅ 儲存報告(
session_reports表) - ✅ 更新個案統計(總晤談次數、最後晤談時間)
**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 端操作:
- 選擇既有個案「小明」
- 錄音 → 轉逐字稿
- 點擊「生成報告」
API Request:
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 處理:
- ✅ 根據
client_code取得既有個案資料 - ✅ 創建第 2 次 Session(
session_number = 2) - ✅ 生成報告時可參考歷次晤談內容(optional,未來功能)
- ✅ 儲存並回傳報告
情境 3:查詢個案歷程 (iOS 或 Web)
API Request:
GET /api/clients/CO_張老師/CL_小明/history
Response:
{
"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:
GET /api/sessions/123/report
Response:
{
"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": "全部完成!"}
處理邏輯:
- 檢查
client_code是否存在於clients表 - 若不存在 → INSERT 新個案
- 若存在 → 取得
client_id - INSERT 新的
session紀錄(自動計算session_number) - 呼叫 AI 生成報告(整合現有的
generate_report_stream) - INSERT
session_reports紀錄 - UPDATE
clients的total_sessions,last_session_date - 回傳完整報告 +
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 端輸入
- 確保在該諮詢師下唯一即可
- 不需要跨諮詢師唯一(未來若需轉介再調整)
資料儲存策略
✅ 儲存的資料
諮詢師基本資料
- counselor_code, name
個案基本資料
- 所有
clients表欄位
- 所有
晤談紀錄
- 逐字稿(
transcript) - 晤談時間、次數、時長
- 逐字稿(
AI 生成報告
- 完整的結構化報告內容
Agent 設定
- 文檔選擇設定
❌ 不儲存的資料
錄音檔
- 由 iOS 本地儲存
- 未來若需要可考慮 S3/Supabase Storage
諮詢師個人設定(暫時)
- system_prompt, temperature 等進階設定
- Phase 2 再實作
RAG 整合策略
現有 RAG 架構
documents → chunks → embeddings
Agent 如何選擇文件
方式 1:選擇特定文檔(Phase 1 實作)
# 從 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:標籤篩選(未來)
# 文檔加上標籤
documents.tags = ["職涯諮詢", "生涯規劃"]
# Agent 設定選擇標籤
agent.selected_tags = ["職涯諮詢"]
# 查詢時過濾
WHERE d.tags && :selected_tags
Phase 1 實作優先順序
今天完成(核心功能)
- ✅ 資料庫 Migration(已完成 SQL)
- ⏳ 執行 Migration
- ⏳ 實作
POST /api/sessions/generate-report- 整合現有的
generate_report_stream - 加入個案創建/更新邏輯
- 加入 Session 儲存邏輯
- 加入 Report 儲存邏輯
- 整合現有的
- ⏳ 實作簡易 Agent 設定 API
POST /api/agents/configGET /api/agents/{counselor_code}/config
- ⏳ 測試 iOS 串接
明天完成(查詢功能)
GET /api/counselors/{counselor_code}/clientsGET /api/clients/{counselor_code}/{client_code}/historyGET /api/sessions/{session_id}/report
後天+(Web 管理介面)
- 諮詢師登入頁面(輸入 counselor_code)
- 個案列表頁面
- 個案詳情 + 歷程時間軸頁面
- 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 錯誤處理
標準錯誤格式
{
"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 狀態: 規劃中 → 準備實作