第一次用 Pi Agent 就踩雷

這篇文章會紀錄我踩雷以及除錯的過程,如果想直接看結論可以直接跳至結論

前言

最近看到很多人在推廣 Pi Coding Agent 趁著週末來玩玩看,在沒有任何背景知識下嘗試來維護我的 Obsidian 的筆記 Index,由於 Index 之前是交給 Claude Code 整理過一次,用 Pi 來測試應該不會出太大問題,但意外總是來的又急又快。

想說應該是不會很難的 Code 就不看直接測試了,結果發現 Error Log 開始狂噴,電腦逐漸卡頓,最後還收到 5 小時 Token 用量到達 limit 的通知,到底發生什麼事?

背景

我的 Obsidian vault 有一個 _metadata 資料夾,裡面放了所有文章的索引、分類以及每日報告。我想讓這些資料自動更新,不用每次手動叫 agent 跑。

我讓 Pi 幫我設計這個自動化流程。它的方案如下:

1
2
3
4
5
6
7
obsidian-notes/
├── .pi/
│ └── extensions/
│ └── metadata-sync.ts
└── scripts/
├── metadata_maintainer.sh
└── metadata_prompt.md

metadata_maintainer.sh — 排程 script,給 launchd 呼叫,負責啟動 agent 執行任務:

1
2
3
4
5
6
if ! (
cd "$WORKSPACE"
pi -p "$prompt" # 啟動 pi agent 執行整理任務
) >"$log_file" 2>&1; then
status="failed"
fi

metadata-sync.ts — Pi 的擴充功能 (extension),讓 Pi 每次啟動時自動執行 script:

1
2
3
4
5
6
7
8
9
10
pi.on("session_start", async (event, ctx) => {
if (event.reason !== "startup") return;

const shouldRun = ctx.hasUI
? await ctx.ui.confirm("更新 _metadata", "要在進入 workspace 時先同步嗎?")
: true; // 非互動模式直接執行

if (!shouldRun) return;
await runSync(pi); // 執行 metadata_maintainer.sh
});

metadata_prompt.md — 告訴 Agent 要執行 task 的細節

這邊的設計是:每次用 CLI 的 Pi 打開 workspace 時,先問你要不要同步;若是自動排程(非互動)就直接執行。

時間線

時間 事件
10:21 Pi 寫好 metadata_maintainer.shmetadata-sync.ts,user reload
10:40 手動跑了一次 metadata_maintainer.sh 測試
10:40:16 第一個遞迴 session 產生,爆炸開始
10:41–11:00 冒出 951 個 process
11:00 打到 Codex API rate limit,報錯 “fetch failed”
13:23 打到 Codex plus plan 用量上限,報錯 “usage limit”
下午 覺得電腦怪怪,然後怎麼會一下就用光 Token!

開始追查

因為 Codex token 燒光了,只好回頭用 Claude Code 一起看。

先看 _metadata/logs

1
2
$ ls _metadata/logs/ | wc -l
2716

我的天啊,我沒寫 retry 機制,這個 script 怎麼會跑了兩千多次?!

接著看一下 Process

1
2
$ pgrep -f metadata_maintainer | wc -l
743

???

原本以為 Pi 都幫我把程式註冊到 launchd 裡面,但是查了之後也沒有,事情更怪了到底怎麼會有殺不完的 Process ?!

好在萬能的 Pi 有提供好用的 Session Log!

pi 會在 ~/.pi/agent/sessions/ 下為每個 workspace 保存完整的對話與 tool call 記錄。我打開爆炸時的 session 目錄看到:

1
2
3
4
5
2026-05-24T02-40-13-328Z_...jsonl
2026-05-24T02-40-16-978Z_...jsonl
2026-05-24T02-40-17-536Z_...jsonl
2026-05-24T02-40-18-097Z_...jsonl
...

每個 session 的開頭都是同一段 prompt——來自 metadata_prompt.md,也就是 metadata_maintainer.shpi -p "$prompt" 傳進去的,這代表總共啟動了上面這麼多個 Pi agent。

正常的執行流程應該是這樣:

1我啟動 Pi workspace
2metadata-sync.ts 被呼叫
3執行 metadata_maintainer.sh
4啟動 Pi agent 去執行 prompt 指令
5結束

最多應該也只有五筆 log,但顯然事實不是這樣,而且後面很多 log 都有 prompt 指令,那就可以合理推測第四步時,Pi agent 跑起來的時候又觸發了 2~4 的過程導致一直有 Pi agent 被開起來 (是不是很像 n+1 query)

簡單的時間軸就是這樣

1
2
3
4
5
6
7
8
pi 啟動,被問是否更新 metadata? -> Yes
└→ metadata_maintainer.sh
└→ pi -p "$prompt" # 啟動 pi
└→ 載入 metadata-sync.ts 擴充功能
└→ session_start
└→ 執行 metadata_maintainer.sh
└→ pi -p "$prompt"
└→ ...

就這樣直接把我的 Codex token 瞬間燒乾了…

要終止這個無限迴圈很簡單,

  1. metadata_maintainer.sh 前面加 exit 0,不要跑到 Pi 指令就退出
  2. 反覆 pkill -9 -f metadata_maintainer 殺光所有的 process(因為 detached,需要跑好幾輪)

結論

Root Cause:Pi 在同一次對話裡做了兩件會互相觸發的事,但它沒有辦法在設計階段模擬兩者同時存在時的執行結果,需要被 review 或是其他機制來發現它的設計有問題。

清掉 process 就結束了。在 reload 或執行之前,還是需要把 agent 寫的東西讀一遍或是交給其他 agent 審查。

Lessons Learned: 如果有寫 extension 且 hook 在 Pi agent 啟動時,就要特別注意遞迴呼叫的問題。

事後想想,其實把 workspace 拆開就能避免這個問題。排程用的 Pi agent 跑在一個沒有掛 extension 的獨立 workspace,它就只是執行任務的 worker,不會觸發任何自動化邏輯。

1
2
3
4
5
6
7
obsidian-notes/             # workspace 1
└── .pi/extensions/
└── metadata-sync.ts
obsidian-notes-scheduler/ # workspace 2
└── scripts/
└── metadata-maintainer.sh

一時想到的解法,也許社群會有其他更好的方法。

這次還好打到五小時 limit 就停了,如果是用 credit 的後果則不堪設想,沒有想到 YOLO 又翻車。


第一次用 Pi Agent 就踩雷
https://weiblog.me/2026-05-24/pi-agent-pitfall/
Author
wei
Posted on
May 24, 2026
Licensed under