146 lines
11 KiB
Markdown
146 lines
11 KiB
Markdown
# AI 使用體驗
|
||
|
||
[← 回到 README](../README.zh-TW.md)
|
||
|
||
這份文件記錄 LazyBoy 怎麼讓「AI 用電腦」這件事變得跟人一樣順,以及背後的取捨。
|
||
三個主題其實是同一件事:系統如果把 AI 使用電腦當成一系列無狀態的請求,AI 就必須每輪重新
|
||
交代自己在哪裡、在做什麼,界面也只能用輪詢去猜現在發生了什麼。
|
||
|
||
| 主題 | 一句話 | 細節 |
|
||
| --- | --- | --- |
|
||
| 任務長度 | 沒有輪數額度,只有偵測鬼打牆的保險絲 | [輪次政策](./operations.md#任務跑多久輪次政策) |
|
||
| 容器內終端機 | 一台活的 tmux,人和 AI 看同一個 shell | [終端機](./operations.md#容器內終端機) |
|
||
| 聊天即時性 | 事件推送,輪詢只是兜底 | 本文件下面 |
|
||
|
||
## 輪數不是額度,是偵錯工具
|
||
|
||
### 交代一次,持續執行
|
||
|
||
清楚的工作指令直接開工,不預設要求使用者確認計畫。模型請求不設 60 秒總時限,也不定時發送等待提示。首次動作最多補上一句開工說明,之後只在重要階段、改變方法或遇到阻礙時簡短回報;一般工具呼叫不逐一播報。實際發生模型重試時更新同一個狀態位置,新的輸出會清除提示。
|
||
|
||
Worker 在模型與工具等待期間,每 10 秒更新背景心跳並延長執行租約,不產生聊天訊息。綠點以最近 30 秒內的心跳為依據,失去心跳時前端不能用舊的串流文字覆蓋失聯狀態。綠點表示 worker 存活,不聲稱任務已有進展。真實的供應商錯誤仍會進入恢復流程;使用者仍能停止或接管。
|
||
|
||
一般任務也採用 goal 的交付原則:完成子步驟或說「做好了」不會直接結束,必須核對完整目標後明確宣告完成。普通的「做不到/無法完成」會進入自行診斷,而非直接要求使用者接手。模型須自行選擇除錯方法,說明實際嘗試與結果後繼續;登入、2FA、拼圖驗證、缺少必要資訊或授權才交給使用者。
|
||
|
||
偵測到方法打轉時,系統先要求換方法,保留原目標和工具歷史。同一段沒有進展的恢復最多提供兩次改道機會,相同失敗不能重新算一次;新的成功狀態變更才結束這段恢復。最後的保險上限仍有效。恢復耗盡會記為失敗並說明具體障礙,不標成完成。成功工具操作會重設連續空談次數,避免長任務累積幾次進度說明就被停止。執行中補充訊息會併入原任務,不必使用 `/goal`,也不另開一個工作搶同一台電腦。
|
||
|
||
以前一個 run 固定 40 輪,等於假設所有任務一樣長:洗資料這種事情做不完,但也不會因此變成
|
||
錯誤,只是被腰斬。現在的正常結局是**把事情做完**(模型提出驗證,或明白說它卡在哪裡),會
|
||
被停下來的只有鬼打牆:同一個會改變狀態的動作連做六次、同一個錯誤連錯八次、連續十四個動作
|
||
全部失敗。觀察、等待、輪詢不算重複動作,所以等一個長 build、等下載、輪詢佇列都不會被打斷。
|
||
|
||
設計上要記住兩件事:
|
||
|
||
- 提示(「你已經做同一件事三次了」)永远不會停掉任務,只有重複到像故障才會暫停,暫停也是停在
|
||
現況、按「繼續」接下去,不重來。
|
||
- 保險絲(`budget_exhausted`)代表迴圈失控,是故障不是成績;它照樣可以續跑,但值得去看執行記錄。
|
||
|
||
純聊天仍然是 4 輪上限:那是避免模型在閒聊裡燒額度,跟任務長度無關。
|
||
|
||
## 任務狀態與交付
|
||
|
||
一般工作以 `report_task` 記錄重要進展、改採的方法、必要資訊與完成結果。回覆中提到
|
||
captcha 或說「做好了」不會改變工作狀態。完成回報必須列出已完成項目、驗證依據、空的
|
||
待辦清單與全部交付檔案;後端會檢查檔案範圍、存在、大小及讀取權限。這能驗證交付物
|
||
可取得,內容是否充分符合目標仍依賴模型提供的核對證據,並非自動判定所有事實正確。
|
||
|
||
`GET /api/sessions/{id}/task` 回傳該對話各助理最新任務、回報與心跳到期時間,沿用對話
|
||
權限檢查。狀態列區分排隊、處理、恢復、等人、完成、未完成與停止。綠點表示有效心跳;
|
||
電腦是否開機另行呈現。心跳、模型重試和逐次工具動作不新增聊天訊息;重要回報才進對話,
|
||
技術紀錄留在執行詳情。排隊及舊串流文字不能把助理冒充成在線。
|
||
交付回報通過後直接完成,不額外等待一輪模型回覆;完整核對證據留在可展開的詳情。
|
||
|
||
`request_takeover` 可指定登入、驗證或授權原因。介入卡只要求當下的人類步驟,交還後以
|
||
原 run 接續,重新取得畫面並附上先前工作紀錄,不要求再打一遍「繼續」。
|
||
成果卡沿用工作區預覽與下載;舊回覆仍可閱讀,未驗證的舊路徑不會補標成已交付。
|
||
|
||
一般介面以對話、成果及助理設定為主。助理設定最上方直接呈現完整頭像編輯器,
|
||
下方可編輯工作內容與工作指示。記憶、帳號與服務集中在設定,環境選擇、套件安裝及技能匯入收進進階入口。
|
||
既有會議模式偏好及獨立電腦設定保留,不搬動帳號或工作區資料。
|
||
|
||
回歸驗證:`tests/task-experience.test.mjs` 在獨立 API、資料庫及模擬模型下驗證一次交辦、
|
||
失敗改道與接手後原任務接續;不能拿它當作第三方網站或真實模型的成功率保證。
|
||
|
||
## 終端機是一台活的 tmux
|
||
|
||
`shell` 透過 Cua 在共用 VNC 桌面上開啟有名稱的終端機。相同 `session` 保留工作目錄、
|
||
環境變數與背景工作;`keys: "C-c"` 會在該終端機送出中斷,`reset` 會換成乾淨的登入 shell。
|
||
|
||
輸出以桌面截圖回傳。模型必須確認提示字元已回來才能輸入下一條命令;省略 `command`
|
||
即可再次查看,長輸出可以透過 Cua 捲動終端機。`wait_ms` 預設 1000、上限 10000,
|
||
等待結束不會終止命令。終端機若被關閉,下次呼叫會重新開啟,已關閉 shell 的環境不會還原。
|
||
|
||
檔案列出、分頁讀取與寫入也使用這個可見終端機。所有這些工具都需要視覺模型與桌面控制鎖。
|
||
|
||
## 聊天是推送,不是輪詢
|
||
|
||
事件早就寫進 `events` 表,也有 SSE 端點,但兩端都在猜:伺服器每 750 ms 掃一次資料庫,瀏覽器
|
||
每 2 秒重刷一次全部狀態(訊息、電腦狀態、螢幕、技能、心跳一起打)。所以一個回覆最快也要兩輪
|
||
輪詢才被看見。
|
||
|
||
現在的管線:
|
||
|
||
1. 寫事件的事實不變——`events` 表仍然是順序與重放的依據(游標是 `threads.next_event_seq`,
|
||
斷線重連用 `Last-Event-ID` 從資料庫重放,不會漏也不會重複)。
|
||
2. 提交之後往進程內的 wake channel 敲一下(`WakeBus`)。SSE 端點不再固定間隔輪詢,而是等敲;
|
||
敲不到時(多副本、讀者落後)以 5 秒兜底輪詢補上。
|
||
3. 瀏覽器用 `EventSource` 訂閱 `/api/sessions/{id}/events`,事件在 120 ms 的窗口裡合流,
|
||
一回合變動只刷新一次。
|
||
|
||
實測(本機 loopback、丟棄式資料庫、同一台機器):
|
||
|
||
| 事件 | 以前 | 現在 |
|
||
| --- | --- | --- |
|
||
| 自己發的訊息出現在畫面 | 最多 2 秒 | 送出去後約 25 ms |
|
||
| 「思考中」指示出現 | 最多 2 秒 | 約 32 ms(worker 也被敲醒,不再等 200 ms 定時器) |
|
||
| 模型回覆出現 | 寫入後最多 2.75 秒 | 寫入後約 25 ms(模型本身要幾秒是另一回事) |
|
||
|
||
順帶把浪費掉的工作拿掉:分頁藏在後面時不再刷新(回到前景立刻補一次),心跳從 2 秒改成
|
||
60 秒——一次心跳買的是 15 分鐘控制租約、避免 10 分鐘閒置暫停,60 秒是很寬的餘裕。
|
||
|
||
**壞了會怎樣。** SSE 被 proxy 擋住或斷線,瀏覽器察覺後自動回到 2 秒輪詢,等於退回以前的行為,
|
||
不會變成不更新;伺服器端事件順序仍然只以資料庫為準,wake 不見得可靠,只是慢。
|
||
|
||
自己量一次:
|
||
|
||
```bash
|
||
curl -N -b cookies.txt http://127.0.0.1:3101/api/sessions/<id>/events
|
||
# 另開一個終端機送訊息,看事件幾毫秒後出現在這條串流裡
|
||
```
|
||
|
||
長任務還有一層上下文保險絲:舊的網頁快照會收成摘要,最新畫面保持完整。這不是另開一個模型做壓縮,而是避免 70 輪 DOM 把 128k 窗口塞爆。細節見 [模型上下文](./operations.md#模型上下文)。
|
||
|
||
## 已知取捨
|
||
|
||
- 一般聊天可串流文字;工作任務採安靜執行,只顯示重要進展與最終交付。狀態與心跳獨立更新,
|
||
不以逐字輸出或工具播報充當進度。
|
||
- 電腦狀態(執行中/暫停、誰在控制)沒有自己的事件,只能靠兜底輪詢更新,`LIVE_POLL_MS` 目前是 4 秒;
|
||
桌面畫面本身是即時串流,只有狀態列會慢幾秒。要真正事件化得把 `computers` 的狀態變更也寫進
|
||
`events`(狀態是 bot 層、事件是執行緒層,要先決定寫到哪條執行緒)。
|
||
- 滑鼠停在頭像上看到的執行記錄泡泡,開啟時仍是輪詢(它只在滑鼠停留時開啟,量很小)。
|
||
- wake channel 是單進程的。多副本部署時,其他副本靠 5 秒安全輪詢追上;真要横向擴充應改用
|
||
Postgres `LISTEN/NOTIFY`。
|
||
- 持久終端機需要桌面映像檔裡的 `tmux`;舊映像檔會退回一次性 shell,`docker compose build computer`
|
||
之後就有了。
|
||
- 容器執行檔仍以 uid 1000、限制環境變數的方式進入容器,持久化的是 shell 狀態,不是憑證。
|
||
|
||
## 不用手動管理長對話
|
||
|
||
聊天原文保留在同一段對話。助理使用最近 32 則訊息與對話摘要;累積超過工作窗口時,
|
||
背景整理較舊內容為目標、限制、決策、完成項目、待辦與原文索引。摘要整理不新增聊天訊息,
|
||
也不阻塞新任務。失敗不推進摘要位置,後續自動重試;`read_conversation` 可在同一對話內
|
||
搜尋及分頁取回原文,不需要使用者重述。清除對話會更新 generation,防止背景舊摘要復活。
|
||
|
||
最新交辦優先:補充或修正套用到當前工作;新的任務則優先執行,舊待辦暫存,不拿來阻擋
|
||
新任務交付,也不在交付後擅自恢復舊工作。已送出的工具動作不會被倒轉,下一個模型決策會
|
||
接收新指示。執行中的原始交辦、最新指示與工作回報另放在工作上下文,避免被大量畫面輸出擠掉。
|
||
|
||
摘要是可回查的工作筆記,不是完整記憶保證,也不自動寫成跨對話的個人偏好。
|
||
附件原檔仍受既有保存期限限制;保留聊天文字不代表永久保存附件位元組。
|
||
|
||
## MCP HTTPS
|
||
|
||
電腦內 MCP 客戶端的 rmcp 必須同時啟用 `reqwest`(TLS)和 HTTP 傳輸功能。
|
||
單有 `transport-streamable-http-client-reqwest` 只能通過 HTTP fixture,無法連接 HTTPS 服務。
|
||
TLS ClientHello 回歸測試不依賴外部網站;修正另以 Context7 的唯讀工具發現流程實際驗證。
|