返回课程首页

附录 H

故障排查手册

模型、工具、会话、Skills、Extensions、SDK 与 RPC。

源码基线:Pi v0.82.0 · commit 518855d

先判断错误属于哪一层,再读对应日志和源码。不要把所有问题都归因于“模型不稳定”。

1. 模型没有回答

检查:

  1. Model/Provider 是否存在;
  2. Auth Resolution 是否成功;
  3. Context 是否超限;
  4. AbortSignal 是否已触发;
  5. Provider Stream 是否发 Error/Done;
  6. Extension input/Command 是否已经 Handled;
  7. UI 是否错误地等待一个不会出现的 Settled。

源码入口:pi-ai providersagent-session.tsagent-loop.ts

2. 流式文本重复或缺失

  • 是否把完整 Message 当 Delta Append;
  • 是否按 message.role 分支;
  • 是否只让 Assistant 使用 message_update
  • 是否在 message_end 用最终 Message Reconcile;
  • Reconnect 是否缺 Snapshot Barrier;
  • Provisional 是否已用 Entry ID 对账。

3. UI 一直显示运行中

  • 是否只监听 agent_end 或漏了 agent_settled
  • 是否有 Retry/Compaction;
  • Follow-up 是否继续同一个 Run;
  • 是否存在 Pending Approval;
  • Extension Command/Handled Input 是否被错误地等待 Settled;
  • RPC Worker 是否已退出但 Store 未切换 Generation。

4. Tool 没有执行

  • Tool Name 是否注册;
  • tools Allowlist 是否过滤了 Custom Tool;
  • Arguments 是否通过 Schema;
  • tool_call Handler 是否 Block/Throw;
  • Approval 是否拒绝/超时;
  • Abort 是否已触发;
  • Backend Final Policy 是否拒绝;
  • 是否混淆宿主直接 Shell 与模型 Bash Tool 路径。

5. Tool 执行了两次

  • RPC Response 丢失后是否重发 Prompt;
  • Retry 是否错误包住副作用;
  • Idempotency Key 是否稳定;
  • Extension 是否动态重复 pi.on()
  • EventBus Listener 是否 Reload 后未 Unsubscribe;
  • 多窗口是否都认为自己是 Owner;
  • Worker 崩溃结果是否本应标为 Indeterminate。

6. 审批显示的参数和实际执行不同

  • 是否审批 Raw Args 而不是 Canonical Args;
  • 批准后是否仍允许 Argument Transform;
  • Capability 是否绑定 argsHash/toolCallId/sessionId;
  • Backend 是否最终重检;
  • RPC Confirm 是否只有显示文本、缺少安全映射;
  • 是否存在 Edit/Bash 旁路。

7. Skill 找不到

  • SKILL.md 路径/大小写;
  • Frontmatter;
  • Description;
  • Resource Scope;
  • Project Trust;
  • Package 是否安装/固定;
  • getSkills().diagnostics
  • 同名冲突;
  • Dynamic Resource 是否返回绝对路径。

8. Skill 被发现但没有遵循

  • 模型是否读取完整 SKILL.md
  • 是否提供 Read Tool;
  • Skill 是否要求不存在的 Tool;
  • Workflow 是否过长/矛盾;
  • 相关 Reference 是否读取;
  • ToolResult 是否让模型偏离;
  • Golden Task 是否覆盖该模型。

9. Extension 加载失败

  • Module Import/Default Export;
  • Factory Throw;
  • Node Runtime/Dependency;
  • Project Trust;
  • Extension Path;
  • Loader Error;
  • Provider/Flag 冲突;
  • 是否把长期资源放在 Factory,失败后无法 Cleanup。

默认 Loader 继续加载其他 Extension;安全关键扩展缺失应由宿主阻止高风险运行。

10. Extension Reload 后重复行为

  • Timer/Watcher/Socket 是否在 Shutdown 清理;
  • EventBus Unsubscribe;
  • Module Singleton;
  • 同一实例是否重复注册 Handler;
  • 旧 Async Callback 是否检查 Generation;
  • pi/ctx 是否仍被使用;
  • Host Bridge 是否在 Invalidate 前拆除。

11. Provider 动态模型为空

  • 使用的是 Legacy Config、完整 Provider 还是 createProvider;
  • allowNetwork=false 时是否有 Cache/Static Models;
  • 是否把 Promise<void> 与“返回模型列表”契约混用;
  • 完整 Model<Api> 是否含 provider/api/baseUrl;
  • Credential/Store/Signal 是否正确;
  • 注册时离线 Refresh 是否被无条件网络请求破坏。

12. Session 恢复后历史变少

很可能把 get_messages 当成完整历史。Compaction 后它是当前 Agent Context。使用 get_entries、稳定 Entry ID、leafId 和 Cursor 恢复完整 Branch/UI History。

13. Session 恢复后消息重复

  • 是否先订阅 Buffer;
  • get_entries Response 是否建立 Snapshot Barrier;
  • Barrier 前无 ID Message Event 是否丢弃/对账;
  • 是否只 Replay Barrier 后 Event;
  • Entry ID 是否去重;
  • Provisional 是否替换而不是 Append。

14. 切 Session 后旧事件出现

  • setBeforeSessionInvalidate() 是否拆旧 Bridge;
  • setRebindSession() 是否订阅新 Session;
  • Generation 是否增加;
  • Event Envelope 是否含 Runtime/Session;
  • Pending Approval 是否 Cancel;
  • 是否直接缓存了旧 AgentSession/Context。

15. SDK Extension 没有 session_start

createAgentSession() 后是否调用 session.bindExtensions(...)?订阅应先建立,再 Bind,以捕获 Extension 处理生命周期期间产生的公开 Session Event。Replacement 后重新执行绑定。

16. SDK 退出时 Extension 没清理

拥有 Runtime 时应 await runtime.dispose()。直接 session.dispose() 不发 session_shutdown,会跳过 Extension Shutdown Handler。

17. RPC 没有响应

  • 是否按 LF 而非通用 Unicode Line Split;
  • JSON 是否每条一行;
  • Command ID 是否唯一;
  • Response 是否乱序但被错误队列消费;
  • stdin 是否等待 drain
  • stdout 是否持续读取;
  • Worker stderr/Exit;
  • Protocol Version 是否匹配。

18. RPC Extension Dialog 不工作

v0.82.0 内置 RpcClient 没有完整的 extension_ui_response API,且会把 UI Request 强转普通 Event。生产桌面 Client 需要扩展或自建 JSONL Client。

19. Worker 崩溃后怎样恢复

reject pending commands
→ cancel dialogs/queues
→ mark running tool indeterminate
→ generation + 1
→ restart fixed version worker
→ open session
→ state/messages/entries snapshot
→ barrier reconcile
→ audit/backend query

不要恢复为“仍 Pending”,也不要盲目重发高风险 Prompt。

20. 最小诊断包

提交 Bug 时保留:

  • Pi/Node/App 版本;
  • OS/Architecture;
  • CWD/Trust 状态(脱敏);
  • Provider/Model 名称;
  • Extension/Skill 来源与版本;
  • Session/Run/Tool Correlation ID;
  • Error Stack(宿主有采集时);
  • Event Timeline;
  • 最小复现;
  • 是否可用 Faux/Fixture 复现。

不要附带 Token、完整 Environment 或用户文件正文。