執行記錄
執行記錄是你按下「執行」後產生的可稽核記錄:狀態、階段日誌、人工關卡、最終產物。每一次執行都可重播、可恢復、可分享。
執行的生命週期
每次執行都會走入五種終止狀態之一。狀態機如下:
running → failed
running → cancelled
| 狀態 | 意義 | 你可以做什麼 |
|---|---|---|
pending | 執行已排入佇列但尚未真正開始。通常小於 1 秒。 | 等待。必要時取消。 |
running | 至少一個階段正在進行中。階段日誌正在即時輸出。 | 即時觀看。取消。回應人工關卡。 |
completed | 所有階段都成功完成。所有產物都已儲存。 | 下載產物。分享。用新的輸入重新執行。從後面某個階段恢復以嘗試變動。 |
failed | 某個階段遇到錯誤或逾時。後續階段沒有執行。 | 閱讀錯誤訊息。點擊 "Debug in chat"。重試。或修正應用後重新執行。 |
cancelled | 你(或某人)明確地停止了執行。 | 從頭重新執行,或在已有部分完成階段時從後面階段恢復。 |
一筆執行記錄的結構
平台會將每一次執行持久化到 app_execution,包含以下欄位:
"id": "exec_8f4c2e1b",
"app_id": "app_...",
"user_id": "usr_...",
"status": "completed",
"input": { company_name: "Stripe", ... },
"is_test": false,
"shared_session": false,
"start_from_stage_index": 0,
"prior_execution_id": null,
"duration_ms": 43210,
"error": null,
"created_at": "2026-05-31T09:14:22Z"
}
每個階段也會擁有自己的 app_stage_log 條目:
"execution_id": "exec_8f4c2e1b",
"stage_index": 0,
"stage_type": "agent",
"status": "completed",
"goal_expanded": "Research Stripe and write a brief...",
"session_id": "sess_...", // 如果你點擊 "Debug in chat",這裡會關聯到對應的會話
"duration_ms": 38421,
"error": null
}
goal_expanded 欄位是輸入替換之後的目標,也就是 agent 實際看到的內容。 如果你的表單中 company_name: "Stripe",那麼原始目標中的 {{company_name}} 就會在這裡被解析出來。
即時觀看執行:SSE 串流
在 running 狀態下,應用頁面會訂閱一個以執行記錄 ID 為鍵的 Server-Sent Events 串流。這個串流同時也是對外公開的 API 介面,任何想把執行情況鏡像到其他系統的人都可以使用。 端點如下:
Authorization: Bearer <token>
// 回應標頭
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
五種執行層級事件
每個事件以 event: <name>\n data: <JSON>\n\n 的形式封包。連線時,伺服器 會先重播當前狀態,讓晚到的訂閱者也能看到完整序列,當前執行狀態、迄今為止的每一筆 階段日誌、任何待處理的人工關卡、每一個已儲存的產物,然後再切換到即時廣播。
event | 負載結構 | 觸發時機 |
|---|---|---|
status | { status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled' } | 訂閱時(重播)以及每次執行層級狀態變化時。 |
stage_log | 一整列 AppStageLog 資料,參見上面的結構。 | 訂閱時(每筆現有階段日誌一次)以及每次階段狀態變化時。 |
human_gate | 一整列 AppHumanGate 資料。 | 當 human 階段開啟一個關卡時,以及關卡被解決時再次觸發。 |
artifact | 一整列 AppArtifact 資料,若存在則包含 content。 | 每次階段的輸出被持久化時。 |
done | { status, duration_ms } | 在結尾觸發一次,然後伺服器關閉串流。 |
若你訂閱的是一個已經處於終止狀態的執行,伺服器會重播已儲存的階段日誌與產物,發送一個 done 事件後斷線,不會建立即時連線。如此一來,重播與即時監控使用的是同一個 端點與同一個解析器。
更細粒度的 runner 事件
上面五個執行層級事件是摘要串流。在一個 agent 階段內部,底層的 run-agent 二進位檔會輸出粒度細得多的 JSONL 軌跡,逐 token 文字、工具呼叫、 子任務、思考過程。這些事件位於會話層級串流而非執行層級串流,但它們正是右側推理軌跡面板背後 的資料來源。完整事件目錄請參見runner 協定。
最小 SSE 消費者
const es = new EventSource('/api/app-executions/' + execId + '/stream', {
withCredentials: true,
});
es.addEventListener('status', (e) => console.log('status', JSON.parse(e.data)));
es.addEventListener('stage_log', (e) => console.log('stage', JSON.parse(e.data)));
es.addEventListener('artifact', (e) => console.log('artifact', JSON.parse(e.data)));
es.addEventListener('human_gate', (e) => console.log('gate', JSON.parse(e.data)));
es.addEventListener('done', (e) => { console.log('done', JSON.parse(e.data)); es.close(); });測試執行 vs 正式執行
在執行上設定 is_test: true,它就會被標記為臨時性的。測試執行:
- 不會以正式執行同樣的方式計入你的用量配額。
- 預設會被應用「執行」分頁過濾掉(切換「顯示測試執行」即可看到)。
- 使用獨立的
shared_session 命名空間,這樣隊友的測試執行不會污染你的。 - 除非被釘選,30 天後會自動清除。
當你點擊試一下時,應用編輯器使用的就是測試執行,這正是你在迭代提示詞時 想要的。
人工關卡:暫停以等待核准
human 階段不會執行程式碼。它會暫停執行,顯示目標文字以及先前的產物,等待你 (或另一位有權限的使用者)採取行動。這次暫停會被儲存在 app_human_gate 中:
{
"id": "gate_...",
"execution_id": "exec_...",
"stage_index": 2,
"message": "Review these 47 enriched leads. Remove rows you don't want to email.",
"status": "pending", // pending | approved | rejected
"response": null,
"responded_at": null
}關卡在 UI 中長什麼樣
┌─────────────────────────────── Run #exec_8f4c2 ─────────────────┐
│ Stage 3 of 4 · Review paused │
│ │
│ Review these 47 enriched leads. Remove rows you don't want │
│ to email. │
│ │
│ 📎 enriched_leads.csv (47 rows) [ View ] │
│ │
│ [ Approve & continue ] [ Reject ] [ Edit input first ] │
└──────────────────────────────────────────────────────────────────┘三個按鈕
- Approve & continue(核准並繼續),關卡變為
approved,下一個階段立即開始。 - Reject(拒絕),關卡變為
rejected,執行轉入 failed。 - Edit input first(先編輯輸入),開啟產物以編輯(例如從 CSV 移除列),存檔之後,被編輯的版本就是第 n+1 階段讀取的內容。
找到需要你處理的關卡
從頂部導覽開啟待處理的關卡,或呼叫 GET /api/app-executions/pending-gates。當關卡進入 pending 狀態時, 可以設定透過電子郵件或 Slack 通知你,這對你可能不會盯著看的長任務流程線非常有用。
關卡 API
透過向關卡的解決端點 POST 來核准或拒絕它。請求主體攜帶判定結果,以及可選的自由文字 response,會儲存在關卡列上:
POST /api/app-executions/:execId/gates/:gateId
Content-Type: application/json
Authorization: Bearer <token>
{
"action": "approved" // 或 "rejected",
"response": "Removed 4 lookalikes; lists looks tighter now."
}機制上:伺服器會標記 app_human_gate.status 並寫入 responded_at, 然後解決一個執行器一直在 await 的記憶體 Promise。等待中的階段會立刻從 waiting 切出,流程線要嘛進入第 N+1 階段(核准時),要嘛短路到 failed(拒絕時)。一個攜帶更新後資料列的 human_gate SSE 事件會 送發給所有訂閱者。
當關卡待處理期間,執行始終保持 running。 只有階段日誌會進入 waiting。沙盒會透過 keepAlive 保持運作,這樣 在核准後恢復時不必付冷啟動成本。代價是:一個無限期待處理的關卡會一直霸佔一個熱沙盒,請給審核者一個合理的預期,或者在應用設計裡為關卡設定自動逾時。取消執行
在執行中的執行上點擊取消,或送出:
POST /api/app-executions/:execId/cancel
Authorization: Bearer <your_token>取消會:
- 停止當前正在執行的階段。已完成的階段維持完成狀態,其產物會被保留。
- 關閉沙盒。
- 將執行轉入
cancelled。 - 將尚未花用的預算退還到你的餘額。
稍後你可以從下一個階段恢復:見下文。
從指定階段恢復
一個真正強大的能力:只重跑需要重跑的階段,重用那些已經跑得好的階段產物。在執行請求中傳入 start_from_stage_index 和 prior_execution_id:
POST /api/apps/:appId/run
Content-Type: application/json
{
"input": { ... same shape as the original run ... },
"start_from_stage_index": 2,
"prior_execution_id": "exec_8f4c2e1b"
}執行器實際上做了什麼
- 建立一筆新的
app_execution 列,指向同一個應用版本。對於索引 0 .. start_from_stage_index - 1 的階段日誌,會立即以 status: 'skipped' 寫入,執行歷史會清楚標示哪些階段並未重新執行。 - 透過
dao.listArtifactsByStages(priorExecutionId, [stageIds]) 載入被略過階段 的產物。對於不攜帶內嵌 content 的產物,執行器會以 s3_key 從 S3 下載主體並以 UTF-8 解碼,這樣即使原始列已被卸載,下一階段 的系統提示詞也能看到先前的內容。 - 取得一個全新的沙盒。原執行沙盒上第 0-1 階段寫入的檔案都消失了,只有已被持久化的 產物會跨越邊界。如果後續階段依賴的是中間暫存檔案而非宣告的產物,恢復就無法重現它們。
- 建立第
start_from_stage_index 階段的系統提示詞,把載入到的先前產物以 ## Previous Stage Outputs 的形式注入,然後從那裡一路跑到流程線結尾。
恢復 + shared_session
當原始執行使用了 shared_session: true,且恢復執行也要求它時,執行器會更進一步: 它會在 prior_execution_id 上找出一筆已經有 session_id 的階段日誌, 重用那個會話,繼續同一段 Claude 對話。可見效果:Debug in chat 會顯示一條橫跨原始執行與恢復執行的連續討論串。不要不假思索就啟用,共用 Claude 會話意味著 模型的上下文仍然包含先前的輪次,有時這正是你要的,有時不是。
什麼時候會用到它
- 最後一個階段的草稿不對。第 0-2 階段花了 4 分鐘跑得好好的;第 3 階段的 郵件草稿語氣不對。調整應用,然後從第 3 階段重跑,省下 4 分鐘。
- 階段因為外部原因失敗(Connect 權杖在執行中過期)。修復 Connect,用相同的 輸入從失敗階段重跑。
- 人工拒絕了一個關卡。調整前一個階段的提示詞,從那裡重跑。
恢復不會回復已產生的副作用。如果被恢復的階段已經往你的 CRM 寫入了列、 發送了 Slack 訊息、或推送過一次 git commit,這些工作已經實際發生了。平台不追蹤對外副作用; 恢復只重用已持久化的產物。為了具備冪等性,請讓會觸及 Connect 的階段先檢查 「我們是不是已經做過這件事了?」。在 UI 中:開啟執行,點擊從階段重新執行……,挑選階段。
執行歷史
在應用頁面,執行分頁會以最新優先的順序列出每一次執行。每一列顯示:
欄位 顯示內容 狀態 五個狀態徽章之一(pending / running / completed / failed / cancelled)。 觸發者 你、隊友、排程,或 API。 開始時間 以你工作區時區顯示的時間戳。 耗時 所有階段加總的牆鐘時間。 成本 沙盒秒數 + LLM token 換算成美元。 輸入 所使用的表單值。點擊以展開。 產物 數量,並附帶每個的快速下載。
頂部的篩選條件可以讓你按狀態、日期區間、觸發者與標籤縮小範圍。該列表也可透過 GET /api/app-executions?app_id=... 取得。
偵錯失敗的執行
第 1 步:閱讀錯誤訊息
開啟失敗的執行。頁面最上方第一項就是錯誤訊息與發生錯誤的階段。常見形式:
錯誤 幾乎總是表示 stage_timeout階段耗時超過了 timeout_ms。把它調大。 connect_unauthorized某個 Connect 被撤銷或過期了。重新授權。 required_input_missing某個必填表單欄位是空的。不要把欄位過於激進地標為必填。 artifact_format_mismatch階段產出的格式不對(例如宣告的是 CSV,卻輸出 Markdown)。 sandbox_oom沙盒內記憶體耗盡。資料量太大,拆分階段,或使用腳本階段。 agent_gave_upagent 判斷任務做不下去了。閱讀它的推理,通常是少了某個輸入。
第 2 步:點擊 "Debug in chat"
點擊 Debug in chat。會開啟一個攜帶失敗執行完整脈絡的對話,輸入、部分產物、 agent 推理軌跡、錯誤。直接和 agent 對話:
> Why did this fail? What should I change in the App?agent 會診斷問題、建議修正方案,並(通常會)直接編輯應用以套用修正。然後你就可以從相同位置 重跑。
第 3 步:重試或重新執行
- 重試:相同輸入、相同應用版本、全新沙盒。有時候不穩定的外部 API 只是 需要再試一次。
- 從第 N 階段重跑:保留先前的產物。當只有後段階段壞掉時使用。
- 編輯應用後再執行:用於系統性的 bug(模糊的提示詞、錯誤的格式)。會讓應用升一個新版本。
分享一次執行記錄
你可以把一次執行的唯讀檢視給隊友看,適用於「看看這個應用昨天產出了什麼」之類的情境,又不必 給對方應用本身的寫入權限。
- 開啟執行。
- 點擊分享。
- 設定:要包含哪些產物、有效期、是否允許下載、是否設密碼關卡。
- 取得一個公開連結:
https://app.aitroop.net/s/<token>。
分享記錄會被持久化到 share 表中,附帶 token、解鎖政策與下載處理器。可以隨時 從設定 → 分享撤銷。
透過 API 觸發執行
當你想要從一個 webhook、CI 流程線或另一個 agent 觸發一個應用時很有用。最小呼叫:
curl -X POST https://app.aitroop.net/api/apps/<appId>/run \
-H "Authorization: Bearer $AT_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "input": { "company_name": "Stripe" } }'回應是新的 app_execution,狀態為 status: "pending"。要觀察它:
curl https://app.aitroop.net/api/app-executions/<execId>/stream \
-H "Authorization: Bearer $AT_USER_TOKEN" \
-NSSE 串流會持續輸出直到執行進入終止狀態。或者輪詢 GET /api/app-executions/:execId。
常見問題 & 疑難排解
我的執行卡在 pending 好幾分鐘了。怎麼回事?
可能原因:
- 沙盒供應商冷啟動(罕見;通常小於 1 秒)。
- 你觸到了方案的並行執行配額;執行在排其他執行的佇列。
- agent worker 佇列塞住了(設定 → 工作區的頂部會有狀態橫幅)。
解法:如果超過 2 分鐘,取消並重跑。檢查狀態橫幅。如果一切都正常但仍然卡著, 表示執行在排隊,等待或取消。
為什麼我已完成的執行顯示「0 個產物」?
應用的階段沒有宣告任何 artifact_defs,或者 agent 產出的格式不符合宣告,平台把 它丟掉了。開啟執行,捲到對應的階段,找一找「format mismatch」警告。把目標寫得更明確說明 要產出什麼,或者把宣告的格式改成 file 作為退路。
我取消了一個執行,能「取消取消」嗎?
不行,但你可以從最後一個完成的階段重新執行。先前執行的產物已保留,所以 不會丟掉工作。開啟被取消的執行,點擊從階段重新執行……,挑選最後一個已完成 階段之後的那個階段。
一個人工關卡待處理 3 天了。執行是死了嗎?
沒有。關卡預設無限期等待。執行只是停在那裡,並沒有失敗。要清理它,要嘛回應該關卡,要嘛 取消執行。
如果你希望關卡自動逾期,在階段定義中加入一個逾時: "gate_timeout_ms": 86400000 代表 24 小時。逾時後,關卡會轉入 rejected,執行轉入 failed。
我能看到 agent 當時在想什麼嗎?
可以。在執行的時間軸上點擊任一階段,即可展開它的推理軌跡。軌跡會顯示 agent 的計畫、每一次 工具呼叫(含參數與結果),以及它最後的評註。要看更深的細節,切換「顯示思考過程」,這會 暴露模型內部的推理區塊(在可用時)。
為什麼同一個應用這週比上週慢了一倍?
可能原因:agent 進行了更多次工具呼叫。可能是提示詞改了(看一下版本), 處理的資料變多了,或者某個外部 API 變慢了。把兩次執行並排開啟:執行日誌會顯示每次工具呼叫 的次數與耗時。對比一下就能找到回歸點。
我想 A/B 測試同一個應用的兩個版本。怎麼做?
Fork 這個應用(會建立一份私有副本 v1),編輯副本,然後用相同的輸入執行兩個應用。從各自應用 的「執行」分頁並排比較兩次執行。要做統計層面的深入分析,寫一個排程,每天用相同的輸入執行 兩個版本,並把結果送到一張試算表裡。
我能從 Zapier / n8n / CI 中的 curl 指令觸發執行嗎?
可以,用你的 bearer token 呼叫 POST /api/apps/:appId/run。參考上面的 curl。多數 使用者會把這個呼叫放進一個 webhook 處理器中,再以 GET /api/app-executions/:execId 等待完成。完成時的對外 webhook 也可透過排程的投遞目標來支援。