跳轉到

C4 架構圖 - Time Compass DSPy 系統

本文件使用 C4 Model 四層架構描述 Time Compass DSPy 系統的設計。


C1 System Context(系統上下文)

graph TB
    User["👤 使用者"]

    GoogleAPI["🔵 Google Calendar/Tasks API"]
    MoodleAPI["📚 Moodle API"]

    subgraph System ["🎼 Time Compass Orchestrator"]
        Router["Router"]
        Emotion["EmotionSupport"]
        Summary["Summary"]
        Scheduling["Scheduling"]
    end

    User -->|"user_input<br/>dialog_history"| Router

    Router -->|"pipeline_description"| User

    Emotion -->|"emotion_reply"| User

    Summary -->|"summary_text"| User

    Scheduling -->|"draft_plan / action_description<br/>constraints_and_missing_info<br/>questions<br/>next_steps_suggestion"| User

    System -->|"讀取日程、任務"| GoogleAPI
    System -->|"讀取課程事件"| MoodleAPI

輸出欄位流(使用者接收):

來源模組 輸出欄位 說明
Router pipeline_description 1~3 句話的流程說明
EmotionSupport emotion_reply 溫柔的情緒安撫回應
Summary summary_text 區間回顧的文字總結
Scheduling draft_plan / action_description 方案或可執行行動
constraints_and_missing_info 缺資訊、假設、風險
questions 追問題目
next_steps_suggestion 後續建議步驟

角色與責任:

角色 說明
使用者 提供自然語言輸入(user_input)、對話歷史(dialog_history)
Time Compass Orchestrator 核心容器,管理 Router、EmotionSupport、Summary、Scheduling 的通訊與輸出組裝
Google API 日曆、任務資料來源
Moodle API 課程、作業事件來源

C2 Container(容器分解)

graph TD
    User["👤 使用者"]

    User -->|"user_input<br/>dialog_history"| Orch["🎼 Orchestrator<br/>(主容器)"]

    Orch --> Router["Router<br/>(DSPy Module)"]
    Router -->|"pipeline<br/>pipeline_description"| Orch

    Orch --> Emotion["EmotionSupport<br/>(DSPy Module)"]
    Emotion -->|"emotion_reply"| Orch

    Orch --> Summary["Summary<br/>(DSPy Module)"]
    Summary -->|"summary_text"| Orch

    Orch --> Scheduling["Scheduling<br/>(DSPy Module)"]
    Scheduling -->|"draft_plan / action<br/>questions"| Orch

    Orch -->|"final_reply"| User

    Router -.->|"InteractionContext"| Emotion
    Emotion -.->|"InteractionContext"| Summary
    Summary -.->|"InteractionContext"| Scheduling

容器說明:

容器 型別 職責
Orchestrator DSPy Application 統籌整個對話流程。呼叫 Router 決定 pipeline,依序執行各模組,蒐集結果
Router DSPy Module 判斷使用者意圖、情緒強度,決定後續執行模組(pipeline)
EmotionSupport DSPy Module 情緒安撫與陪伴,自然銜接後續步驟
Summary DSPy Module 時間段回顧與成就總結
Scheduling DSPy Module 複合模組,包含路由、方案生成、追問等子流程

訊息流

Orchestrator.forward(user_input, dialog_history)
  ↓
【第 1 步】Router 決策
  ├─ 輸入: user_input, dialog_history
  ├─ 判斷: 是否進入 EmotionSupport、Summary、Scheduling?
  └─ 輸出: pipeline = ["EmotionSupport", "Summary"], pipeline_description = "..."
  ↓
【第 2 步】組裝 InteractionContext
  ├─ 封裝: user_input, dialog_history, pipeline, ...
  └─ 準備: 按 pipeline 順序依序傳給各模組
  ↓
【第 3 步】依序執行 Pipeline
  ├─ 若 EmotionSupport 在 pipeline:執行並蒐集 emotion_reply
  ├─ 若 Summary 在 pipeline:執行並蒐集 summary_text
  └─ 若 Scheduling 在 pipeline:執行並蒐集草案 / 行動 / 追問
  ↓
【第 4 步】組裝最終回覆
  ├─ 整合各模組輸出
  ├─ 選擇性支援 streaming(逐字推送)
  └─ 回傳 final_reply

C3 Component(組件細節)

Router Module

graph TD
    Input["user_input<br/>dialog_history"]
    Input --> Sig["RouterSignature<br/>(判斷意圖)"]
    Sig --> Decide{"決策節點"}

    Decide -->|"低落"| Em1["Pipeline +=<br/>EmotionSupport<br/>(前置)"]
    Decide -->|"普通/高漲"| NoEm1["不加<br/>前置 Emotion"]

    Decide -->|"需要 Summary"| Sum["Pipeline +=<br/>Summary"]
    Decide -->|"需要 Scheduling"| Sched["Pipeline +=<br/>Scheduling"]
    Decide -->|"都不需"| Empty["Pipeline = []<br/>(無關請求)"]

    Em1 --> Final["Router 输出:<br/>pipeline<br/>pipeline_description"]
    NoEm1 --> Final
    Sum --> Final
    Sched --> Final
    Empty --> Final

簽章: RouterSignature - 輸入: user_input, dialog_history - 輸出: pipeline_description (string), pipeline (List[str])

詳見 USER-DIALOG-FLOW.md → Router 決策流程


Scheduling Module(複合)

graph TD
    Input["InteractionContext"]
    Input --> SchedulingRouter["SchedulingRouter<br/>(判斷任務等級)"]

    SchedulingRouter --> Decide{"是否 L3<br/>(行動級)?"}

    Decide -->|"L3(行動級)"| DraftAction["DraftAction Signature<br/>(生成可執行行動)"]
    Decide -->|"L1/L2(想法/方案級)"| DraftPlan["DraftPlan Signature<br/>(生成草案)"]

    DraftAction --> AskQ["AskQuestion Signature<br/>(若有缺資訊)"]
    DraftPlan --> AskQ

    AskQ --> Output["回傳結果:<br/>questions<br/>next_steps_suggestion"]

子簽章: - SchedulingRouterSignature - 任務等級判斷,決定進入 DraftPlan 或 DraftAction - DraftPlanSignature - L2 級方案生成(含候選時段) - DraftActionSignature - L3 級行動生成(含首步驟指南) - AskQuestionSignature - 資訊不足時追問

詳見 USER-DIALOG-FLOW.md → SchedulingRouter 流程


Orchestrator 內部流通

graph TD
    Start["Orchestrator.forward<br/>(user_input,<br/>dialog_history)"]

    Start --> Ctx["組裝<br/>InteractionContext"]
    Ctx --> CtxData["{\n  user_input: ...,\n  dialog_history: ...,\n  pipeline: [],\n  current_pipeline_index: 0,\n  previous_signature_output: {}\n}"]

    CtxData --> Call_Router["呼叫 Router"]
    Call_Router --> Got_Pipeline["取得 pipeline"]

    Got_Pipeline --> Loop["依 pipeline 順序<br/>逐一執行模組"]

    Loop --> InLoop["for each module in pipeline:"]
    InLoop --> UpdateCtx["更新 InteractionContext<br/>(傳入用戶與前一結果)"]
    UpdateCtx --> CallModule["呼叫 module(ctx)"]
    CallModule --> Collect["蒐集輸出至<br/>previous_signature_output"]
    Collect --> Next["執行下一個模組"]

    Next --> Done{"還有模組<br/>未執行?"}
    Done -->|"是"| InLoop
    Done -->|"否"| Assemble["組裝最終 final_reply"]

    Assemble --> Stream{"需要<br/>Streaming?"}
    Stream -->|"是"| DoStream["dspy.streamify()<br/>逐字推送"]
    Stream -->|"否"| DirectReturn["直接回傳"]

    DoStream --> End["回傳 RouterResponse"]
    DirectReturn --> End

C4 Code(程式碼層級)

Orchestrator 簽章與介面

# 輸入簽章
class OrchestrationInput:
    user_input: str          # 使用者提問
    dialog_history: str      # 對話歷史

# 輸出簽章
class OrchestrationOutput:
    pipeline_description: str    # Router 的流程說明
    final_reply: str            # 最終回覆(整合後)
    streaming_chunks: Optional[AsyncGenerator[str, None]]  # 若支援 streaming

# 主方法
async def orchestrator.forward(
    user_input: str,
    dialog_history: str = ""
) -> OrchestrationOutput:
    """
    主編排入口。管理 Router、模組執行、結果蒐集。
    """
    pass

InteractionContext 資料結構

@dataclass
class InteractionContext:
    """各模組間通訊的標準封裝"""

    # 使用者與對話
    user_input: str                          # 使用者這輪輸入
    dialog_history: str                      # 對話歷史記錄

    # 流程管理
    pipeline: List[str]                      # Router 決定的模組清單
    current_pipeline_index: int               # 當前執行位置
    previous_signature_output: Dict[str, Any] # 前一模組輸出

    # 資源數據
    time_interval_data: Optional[str]        # 可用時間窗(Scheduling 用)

    # 中繼狀態
    emotion_state: Optional[str]             # 情緒評估結果
    task_level: Optional[str]                # 任務等級(L1/L2/L3)

各 Signature 規格

# ========== Router ==========
class RouterSignature(dspy.Signature):
    """判斷使用者意圖、決定後續 pipeline"""

    dialog_history: str = dspy.InputField(description="對話歷史")
    user_input: str = dspy.InputField(description="使用者輸入")

    pipeline_description: str = dspy.OutputField(
        description="1~3 句話描述接下來的步驟"
    )
    pipeline: List[str] = dspy.OutputField(
        description="要執行的模組: ['EmotionSupport', 'Summary', 'Scheduling']"
    )

# ========== EmotionSupport ==========
class EmotionSupportSignature(dspy.Signature):
    """溫柔的情緒安撫"""

    interaction_context: InteractionContext = dspy.InputField()

    emotion_reply: str = dspy.OutputField(
        description="溫柔、正常化感受的回應,自然銜接後續步驟"
    )

# ========== Summary ==========
class SummaryWriterSignature(dspy.Signature):
    """區間回顧"""

    interaction_context: InteractionContext = dspy.InputField()
    time_interval_data: str = dspy.InputField()

    summary_text: str = dspy.OutputField(description="總結文本")

# ========== Scheduling ==========
class SchedulingRouterSignature(dspy.Signature):
    """任務等級判斷"""

    interaction_context: InteractionContext = dspy.InputField()

    catch_and_rephrase: str = dspy.OutputField(description="重述意圖")
    ai_can_do: str = dspy.OutputField(description="AI 可做的動作摘要")
    task_level: str = dspy.OutputField(description="L1/L2/L3")

class DraftPlanSignature(dspy.Signature):
    """L2 方案生成"""

    interaction_context: InteractionContext = dspy.InputField()

    draft_plan: str = dspy.OutputField(description="草案說明(含候選時段)")
    constraints_and_missing_info: str = dspy.OutputField(
        description="缺資訊、假設、風險"
    )

class DraftActionSignature(dspy.Signature):
    """L3 行動生成"""

    interaction_context: InteractionContext = dspy.InputField()

    action_description: str = dspy.OutputField(description="可執行的行動描述")
    start_instructions: str = dspy.OutputField(description="首步驟指南")
    constraints_and_missing_info: str = dspy.OutputField()

class AskQuestionSignature(dspy.Signature):
    """資訊不足時追問"""

    constraints_and_missing_info_from_draft: str = dspy.InputField()
    interaction_context: InteractionContext = dspy.InputField()

    questions: str = dspy.OutputField(description="追問題目")
    next_steps_suggestion: str = dspy.OutputField(description="下一步建議")

實作位置

容器 / 簽章 程式碼路徑
Orchestrator src/time_compass/domain/orchestrator.py
Router src/time_compass/domain/router.py
EmotionSupport src/time_compass/domain/emotion.py
Summary src/time_compass/domain/summary.py
Scheduling src/time_compass/domain/scheduling/
InteractionContext src/time_compass/domain/models/

資料流總結

使用者輸入
  ↓
Orchestrator.forward()
  ↓
Router.forward()
  ├─ 產出: pipeline, pipeline_description
  └─ 寫入 InteractionContext
  ↓
組裝標準 InteractionContext
  ↓
Loop: 依 pipeline 順序執行
  ├─ EmotionSupport (若在 pipeline)
  │   └─ 輸出: emotion_reply
  │
  ├─ Summary (若在 pipeline)
  │   └─ 輸出: summary_text
  │
  └─ Scheduling (若在 pipeline)
      ├─ SchedulingRouter
      │   └─ 輸出: catch_and_rephrase, ai_can_do, task_level
      │
      ├─ DraftPlan 或 DraftAction
      │   └─ 輸出: draft_plan / action_description + constraints
      │
      └─ AskQuestion
          └─ 輸出: questions, next_steps_suggestion
  ↓
Orchestrator 蒐集所有輸出
  ↓
組裝最終 final_reply
  ↓
(可選) 若啟用 streaming,逐字推送
  ↓
回傳給使用者

更多詳節: - USER-DIALOG-FLOW.md - 決策流程詳解 - SIGNATURE-DIRECTORY.md - 完整簽章規格