iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0
AI 自動化

從 BPM 到 Agentic Workflow:企業 AI 流程的狀態、控制與驗證系列 第 2

Day 02|Reference System:用「企業共享資源協調」取代真實公司系統

  • 分享至 

  • xImage
  •  

昨天我把 Agent 和傳統 Workflow 的分工留在一句話上:模型處理模糊意圖,流程系統負責狀態、規則與可追蹤性。

但這句話還太抽象。如果後面 28 天每天都換一個小 Demo,到最後我會有很多「看起來會動」的程式,卻沒有一套系統真的經過狀態、權限、人工確認、重試、交易衝突與失敗恢復。

所以今天我先不挑 Agent framework,而是先挑一個能一路用到 Day 30 的問題。


這個案例與我的工作內容無關

這套「企業共享資源協調」Reference System 是為了本系列獨立設計的公開測試場景,與我的工作內容、業務流程與實際系統無關。其中的使用者、資源、時間、規則與程式碼都是為實驗從零建立。

我為這個公開案例列了幾個條件:

  • 不用任何真實員工、資源或內部 API。
  • 使用者可以用自然語言提出要求。
  • 流程中要有權限、規則與必要的人工確認。
  • 真正執行時會產生 side effect,而且可能重複或發生衝突。
  • 我可以故意讓它失敗,再觀察是否能恢復。

「企業共享資源預約」剛好滿足這些條件,而且讀者不需要知道特定產業背景就能理解。

一句預約要求,已經包含很多控制問題

我用的第一個要求是:

幫我預約 3 小時、可容納 10 人,而且有投影機的會議空間。

看起來只是查空間後寫入一筆預約,但我真的把步驟拆開後,至少有這些事:

  1. 把時間、人數、設備和時區整理成結構化資料。
  2. 找出容量與設備符合的候選資源。
  3. 檢查同一時段是否已被預約。
  4. 判斷這個使用者有沒有權限。
  5. 三小時是否超過免審核門檻。
  6. 在取得申請人確認與主管核准後,才能真正建立預約。
  7. 重送同一個 request 時,不能多出第二筆預約。

這就是我要的 Reference System:業務情境不複雜,但已經足以把 Agent 和一般軟體工程的邊界全部擺進來。


我先把 LLM 擋在資料庫外面

這套系統中,模型未來可以負責理解「明天下午」、「十個人」或「離大家近一點」這類模糊要求,但它不會取得 raw SQL 或 database connection。

我先固定的控制路徑是:

Natural Language
       │
       ▼
LLM / Intent Extractor          ← 處理模糊輸入
       │
       ▼
Typed BookingIntent             ← Schema validation
       │
       ▼
Workflow State Machine          ← 只允許定義過的狀態轉移
       │
       ├──► Policy / RBAC        ← 權限與業務規則
       ├──► Human Confirmation  ← 必要時暫停
       ▼
Typed Booking Tool              ← 唯一能建立預約的介面
       │
       ▼
SQLite Transaction              ← 衝突檢查與 commit
       │
       └──► Audit Log / Trace

這個安排對我來說很重要。模型可以把時間理解錯,但錯誤的輸出還要先經過 typed contract、policy 和 state machine;「模型說預約成功」也不等於資料庫已經 commit。

本次使用的 intent 是明確、可重現的 synthetic data:

intent = {
    "action": "create_booking",
    "resource_id": "meeting-public-1",
    "resource_type": "meeting_space",
    "start_at": "2031-03-12T14:00:00+08:00",
    "duration_minutes": 180,
    "capacity": 10,
    "requirements": ["projector"],
}

我特別把 start_at 寫成含 timezone 的未來時間,資源與使用者也都是虛構的。如果 duration 不是 15 分鐘的倍數、少了時區或超出允許範圍,程式會在進入工具前就拒絕。

我不用對話紀錄猜流程走到哪裡

這次 180 分鐘的預約超過我設定的 120 分鐘門檻,所以 deterministic policy 會要求主管核准。成功路徑會留下這條狀態鏈:

NEW
 → UNDERSTOOD
 → SEARCHED
 → AWAIT_CONFIRMATION
 → APPROVED
 → EXECUTING
 → SUCCEEDED

我刻意不把這些狀態只放在 prompt 或聊天紀錄裡。如果系統在 AWAIT_CONFIRMATION 中斷,重新啟動後要讀的是持久化 state,不是再叫 LLM 猜一次。

這樣的狀態機也強迫我把一件事寫清楚:申請人確認、主管核准和預約 commit 是三個不同事件,不能因為 Agent 已經回答「好的」就把它們合併。


真的跑一次 Reference System

我用一個暫存 SQLite database 跑這條流程。Runner 會載入 synthetic user 與 resource,完成申請人確認與主管核准,最後輸出 report 與 audit trace。執行完畢後暫存 database 會刪除,全程只在這個獨立測試環境中進行。

PYTHONPATH=src python3 labs/agentic-workflow/run_reference_system.py \
  --results-dir results \
  --experiment-id agentic-workflow-day02-20260916-001

終端輸出如下:

status: success
state: SUCCEEDED
workflow_success_count: 1
state_transition_count: 7
audit_event_count: 13
active_booking_count: 1

第一眼看到 SUCCEEDED 當然是好事,但這五行裡對我最有價值的,其實是 state_transition_count: 7audit_event_count: 13active_booking_count: 1

因為它們分別告訴我:流程不是從開始直接跳到完成;確認、核准與寫入都有事件可以追;最後只有一筆預約真的變成 active。

我再直接讀取 workflow-trace.json

import json
from pathlib import Path

path = Path(
    "results/raw/agentic-workflow-day02-20260916-001/workflow-trace.json"
)
payload = json.loads(path.read_text(encoding="utf-8"))

actions = [event["action"] for event in payload["audit_trace"]]
states = [item["to_state"] for item in payload["state_transitions"]]

print("states=" + " -> ".join(states))
print("actions=" + " -> ".join(actions))
print("final_state=" + payload["run"]["state"])
print("booking_status=" + payload["booking"]["status"])

實際輸出:

states=NEW -> UNDERSTOOD -> SEARCHED -> AWAIT_CONFIRMATION -> APPROVED -> EXECUTING -> SUCCEEDED
actions=workflow_created -> state_transition -> search_resources -> state_transition -> state_transition -> confirmation_requested -> requester_confirmed -> manager_approval -> state_transition -> state_transition -> create_booking -> state_transition -> workflow_completed
final_state=SUCCEEDED
booking_status=active

這條 trace 比 Agent 回答「預約已完成」更有資訊量。我可以看到什麼時候要求確認、什麼時候通過核准,以及 side effect 真正發生在哪一步。

跑通一次之後,我反而有了更多問題

這次成功只能說明我已經有一條可重現的 happy path。但它也讓我可以很具體地問下去:

  • 如果同一個 request 因 timeout 重送,會不會多出一筆 booking?
  • 兩個使用者同時搶同一時段,最後誰會成功?
  • 已經建立 booking,後面的通知卻失敗,要重試還是補償?
  • 沒有權限的使用者,能不能透過 prompt injection 繞過 tool 邊界?
  • 流程停在 AWAIT_CONFIRMATION 後服務重啟,能不能從同一狀態繼續?

這些就是接下來要實際驗證的問題。我不需要再做二十幾個無關的 Demo,而是在同一套資料模型與場景上,一層一層加入 Typed Intent、Policy、RBAC、HITL、Idempotency、Transaction、Saga、Audit、Trace 與 Security。

今天的結論

今天完成的不是一個能自由行動的 Agent,而是一個後面可以持續被破壞、測試與修復的場景。

模型會負責理解「想做什麼」;是否能做、做到哪一步,以及資料是否真的被改變,必須由可驗證的系統來回答。

明天我會回到這條流程,逐步拆開哪些判斷適合交給 LLM,哪些一定要留在 deterministic control plane。

下一篇:Day 03|哪些事交給 LLM,哪些事絕對不要


參考資料

  1. Anthropic, Building Effective Agents
  2. Object Management Group, Business Process Model and Notation 2.0.2
  3. Python Documentation, sqlite3 — Transaction control

本系列的身份、資源、規則與時間均為 synthetic data。


上一篇
Day 01|從 BPM 到 Agentic Workflow:企業流程自動化的下一步,不只是把 LLM 接進來
下一篇
Day 03|哪些事交給 LLM,哪些事不要
系列文
從 BPM 到 Agentic Workflow:企業 AI 流程的狀態、控制與驗證9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言