ChatGPT 本地知识库维护链路故障排查
按本地 MCP、Tunnel 控制面、ChatGPT App、Skill、Workspace Agent 和合并校验分层定位知识库维护链路故障。
[!abstract] 快速原则 从最靠近数据的本地层向外检查:MCP 测试 → Tunnel access/doctor → daemon → App 工具快照 → Agent 挂载与审批 → 具体提案校验。不要看到 404 就直接重建全部配置。
[!info] related notes
- 相关 howto: 构建本地 MCP, 连接 Secure MCP Tunnel, 配置 App、Skill 与 Agent
- 相关 MOC: ChatGPT MOC
- 实践记录: Thought Forest 与 ChatGPT 知识库集成实践
ChatGPT 本地知识库维护链路故障排查
现象
常见症状:
- Tunnel API 返回 404;
- doctor 失败或 tunnel-client 不在线;
- ChatGPT 创建 App 时看不到 Tunnel;
- App 只发现 11 个旧工具;
- 只读工具被标成 WRITE/DESTRUCTIVE;
- Workspace Agent 找不到 App 或 Skill;
- Agent 跳过第一次/第二次确认;
- 提案存在但合并被拒绝;
- 已合并但搜索仍返回旧索引。
- 自启动注册报 `tunnel-client not found on PATH`;
- 自启动注册报 `MSFT_TaskLogonTrigger is not a valid value for the Trigger variable`;
- 修正脚本后注册计划任务仍报“拒绝访问”。
快速分层
flowchart TD
A[故障] --> B{npm run kb:mcp:test}
B -- 失败 --> L[修本地 Server]
B -- 通过 --> C{tunnel access/doctor}
C -- 失败 --> T[查 ID/组织/RBAC/网络]
C -- 通过 --> D{daemon ready}
D -- 否 --> R[重启单实例 tunnel-client]
D -- 是 --> E{普通聊天 App 只读调用}
E -- 失败 --> P[查 App/Tunnel/工具快照]
E -- 成功 --> F{Draft Agent Preview}
F -- 失败 --> G[查 App/Skill/审批/指令]
F -- 成功 --> H{提案或合并失败}
H -- 是 --> I[查 proposal hash/base hash/path]
排查过程
第一层:本地 MCP
Set-Location D:\home\thought-forest
npx tsc --noEmit --pretty false
npm run kb:mcp:test
npm run kb:inbox:list
如果这里失败,Tunnel 和 ChatGPT 不可能修复它。先处理工具 schema、路径、索引或测试问题。
第二层:Tunnel 身份和权限
npm run kb:mcp:tunnel:access
npm run kb:mcp:tunnel:doctor
`404 Tunnel not found` 有多种可能:
- Tunnel ID 抄错;
- key 属于另一个 Platform Organization;
- principal 缺 Read/Use,控制面隐藏资源;
- Tunnel 已删除或重建;
- 本机 profile 与 `.env` 使用不同 ID。
先逐字符核对 ID,再查组织和权限。不要仅凭“我是管理员”推断当前 runtime key 具备 Tunnel 权限;ChatGPT Workspace Admin、Project Owner 和 Platform Organization Owner 是不同角色边界。
记录响应中的 request ID,必要时提交给 OpenAI Support。
第三层:daemon 与网络
检查:
- 是否只运行一个目标 tunnel-client;
- healthz 是否 live;
- readyz 是否 ready;
- 日志是否持续 polling;
- 代理、自定义 CA 或 mTLS 是否阻断;
- 任务计划是否以正确用户和工作目录运行。
Doctor 成功但 daemon 未常驻,ChatGPT 仍会在实际调用时失败。
Windows 登录自启动的三类失败
1. `tunnel-client not found on PATH`
先区分“程序不存在”和“按名称找不到”。`PATH` 只是 Windows 搜索可执行文件的目录列表;如果 `run-tunnel.cmd` 使用 `D:\tools\tunnel-client\tunnel-client.exe` 绝对路径,手动启动可以成功,而仅执行 `Get-Command tunnel-client` 的注册前检查仍会失败。
修复原则是让注册检查与实际 launcher 使用同一个安装事实。当前脚本同时接受 PATH 中的命令和已知安装路径,不需要把 runtime key 写入计划任务参数。
2. `MSFT_TaskLogonTrigger` 无法赋给 `Trigger`
PowerShell 变量名不区分大小写。脚本参数 `$Trigger` 带有 `ValidateSet(‘LogOn’, ‘Startup’)` 时,局部变量 `$trigger = New-ScheduledTaskTrigger …` 实际是在给同一个变量赋一个 CIM 对象,因此参数验证器拒绝 `MSFT_TaskLogonTrigger`。
修复是把对象变量改成语义不同的名称,例如 `$taskTrigger`:
$taskTrigger = New-ScheduledTaskTrigger -AtLogOn -User $currentUser
Register-ScheduledTask -Trigger $taskTrigger
3. `Register-ScheduledTask: 拒绝访问`
不要立即把任务升级为 SYSTEM 或最高权限。先显式创建当前用户、交互式登录、最低权限的 principal,并让 Logon trigger 绑定同一用户:
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$principal = New-ScheduledTaskPrincipal `
-UserId $currentUser `
-LogonType Interactive `
-RunLevel Limited
$taskTrigger = New-ScheduledTaskTrigger -AtLogOn -User $currentUser
Register-ScheduledTask `
-TaskName ThoughtForestKbTunnel `
-Action $action `
-Trigger $taskTrigger `
-Principal $principal `
-Settings $settings
这个配置与知识库的用户级路径、用户配置和登录后运行模型一致。只有确实需要“无人登录也运行”时,才应评估 Windows Service 或系统级 Startup trigger,以及随之而来的凭据存储与权限问题。
第四层:ChatGPT App
普通新聊天中只启用 App,发送只读概况请求。若失败:
- App 是否指向正确 Tunnel;
- 是否误选 `Thought Forest KB (legacy)`;
- App 的连接是否仍有效;
- 工具快照是否为 12 个;
- 工具标注是否与当前 Server 一致;
- 工作区是否允许自定义 MCP。
服务端新增工具后,已发布 App 不一定自动更新。根据套餐使用 Refresh/重新审核,或新建 App 并明确标记旧版。
第五层:Skill 与 Workspace Agent
App 普通聊天可用而 Agent 不可用时,检查 Draft config:
- connector ID 是否为新版 App;
- allowed tools 是否包含完整 12 个;
- Skill 是否出现在 `skills`;
- 三个写工具是否 Always ask;
- Agent 指令是否明确两次停止;
- Preview 是否运行当前 Draft;
- Agent 是否错误地使用已发布旧版本。
“Add skill”按钮存在不代表没有挂载;应寻找已挂载 Skill 卡片或读取 Draft config。
第六层:提案合并
按错误类型处理:
| 错误 | 根因 | 处理 |
|---|---|---|
| proposal not found | ID 错误、已消费或归档 | 调用 `list_proposals`,不要猜 ID |
| proposal hash mismatch | 提案正文被修改 | 重新生成提案 |
| target already exists | 新建期间出现同名文件 | 查重后改为 patch 或选择新边界 |
| base hash mismatch | 目标在提案后被修改 | 重新读取目标并生成 patch |
| target outside z | 路径不在批准目录 | 修正知识架构,不扩大白名单 |
| symlink/path traversal rejected | 真实路径逃逸 | 保持拒绝,检查输入和文件结构 |
| index failed after apply | 写入已成功,索引失败 | 只运行 `npm run kb:index` |
典型误诊:404 被当成纯 RBAC
如果同一个账号在网页中是 Owner,但脚本返回 404,不应立即断言是 RBAC。最小证据链:
- 从 Tunnel 管理页复制真实 ID;
- 与 `.env` 和 profile 逐字符比较;
- 使用 runtime key 发起精确 GET;
- 确认组织;
- 最后再检查角色权限。
Thought Forest 的实际案例中,根因是 Tunnel ID 中多个字符抄错,而不是缺权限。这个案例说明错误码只能缩小范围,不能替代输入核对。
解决方案
遵循“只修当前失败层”:
- 本地测试失败:修 Server;
- access 失败:修 ID、组织或 key;
- doctor 失败:修 profile、命令或网络;
- App 失败:修连接或工具快照;
- Agent 失败:修挂载、指令或审批;
- proposal 失败:重新生成精确提案;
- index 失败:重建索引。
不要同时重建 Tunnel、App、Skill 和 Agent,否则会丢失诊断对照。
回归验证
修复后从失败层向外重新验证:
- MCP tests
- Tunnel access
- Tunnel doctor
- daemon health/ready
- 普通聊天只读 App
- Draft Agent 只读 Preview
- 第一次批准只暂存
- 第二次批准合并
- 拒绝/冲突路径
- `ThoughtForestKbTunnel` 为 Enabled,principal 是当前用户且 RunLevel 为 Limited
- 重新登录后只出现一个 tunnel-client,`healthz` 和 `readyz` 均返回 200
预防
- ID 复制后用脚本验证,不手工重输;
- profile、`.env` 和文档使用占位符或单一来源;
- 旧 App 重命名为 `legacy`;
- 服务端版本和工具数量进入 smoke test;
- Skill 源目录与生成 ZIP 做 hash 比较;
- Agent 发布前固定运行四个验收场景;
- 日志不输出 key、token 或完整敏感 header。