跟 Claude Code 聊了半小时,工具炸了,全废
你有没有这种经历:跟 AI 聊了半小时,方案越聊越清晰,正准备动手——工具报错了。
那半小时,就这么没了。
上周我就遇到了这个。跟 Claude Code 讨论一个重构方案,聊得很顺,上下文全在,思路也对。结果准备执行的时候,Bash 工具直接抛了个 EINVAL。
排查了一会儿才发现:Windows 的临时路径 C:\Users\sunzh 被某个地方转成了 C–Users-sunzh,冒号和反斜杠全被吃掉了。路径格式不对,文件操作全挂。
这不是第一次了。
MCP 连不上、Skills 加载失败、代理挂了……这些问题有个共同点:我都是在已经开始干活之后才发现的。
有时候是聊了十分钟,有时候是半小时。发现问题的时机越晚,损失越大。
更烦的是,Claude Code 本身不会主动告诉你”你的环境有问题”。它只会在工具调用失败的时候报错,而那个时候你已经在任务中间了。
我开始想:能不能在每次会话开始的时候,就把环境状态摆出来?
Claude Code 有个机制叫 Hook,可以在特定事件触发时自动执行脚本。其中 SessionStart 会在每次新会话开始时运行。
这正好是我需要的时机。
我用 PowerShell 写了一个环境自检脚本,挂在 SessionStart 上。每次 Claude Code 启动,它就跑一遍,把结果打印出来。AI 开局就能看到当前环境是什么状态。
脚本检测 8 项内容:
TEMP 路径(不只是读,是真的写一个文件再删掉,顺便检查路径里有没有 —)、代理连通性(TCP 直连 127.0.0.1:7897)、MCP 服务存活、核心工具是否在 PATH 里、Hook 脚本完整性、磁盘空间、Git 状态、Node 项目健康。
TEMP 路径那段是这样的:
$probe = Join-Path $tempDir (“claude-probe-” + (Get-Random) + “.tmp”) [System.IO.File]::WriteAllText($probe, “ok”) Remove-Item -LiteralPath $probe -Force if ($tempDir -match ‘–‘) { Write-Output “[WARN] TEMP_PATH – contains ‘–‘, may cause issues” } else { Write-Output “[PASS] TEMP_PATH – $tempDir” }
代理检测用的是 TCP 连接,不是 curl,更快也更准:
$tcp = New-Object System.Net.Sockets.TcpClient $tcp.Connect(“127.0.0.1”, 7897) if ($tcp.Connected) { Write-Output “[PASS] PROXY – 127.0.0.1:7897 reachable” } else { Write-Output “[WARN] PROXY – 127.0.0.1:7897 unreachable” }
输出格式很简单,三种状态:
脚本始终 exit 0。
不管检测到什么问题,它都不会阻止会话启动。这是体检报告,不是门禁。
我不想让它变成一个拦路虎。有时候 WARN 是可以接受的,有时候我知道代理今天不用。重要的是信息摆在那里,AI 和我都能看到,然后自己判断要不要处理。
实际用下来,AI 看到 WARN 会主动调整策略。比如代理不通,它就不会去尝试需要网络的操作,而是先问我要不要处理这个问题。
写这个脚本的过程有点讽刺。
我在调查 EINVAL 问题的时候,Claude Code 自己又报了一次 EINVAL。它在帮我排查”为什么工具会报 EINVAL”的时候,亲自演示了一遍这个问题。
就像你去修漏水的厨房,结果修水管的工具掉进了下水道。
那一刻我反而觉得,这个脚本确实有必要写。
用了一段时间之后,工作流变了。
以前是:开始聊 → 聊到一半工具炸 → 排查环境 → 重开会话 → 重新建立上下文。
现在是:开局看报告 → 有问题先修 → 再开始干活。
从”聊半小时白费”到”开局 10 秒知道状态”,这个差距比我预期的大。
200 行 PowerShell,可能比我花在 prompt engineering 上的时间更值。
AI 再聪明,工具链挂了也没辙。就像请了顶级厨师,但厨房在漏水。厨师的水平不是问题,问题是你得先把厨房修好。
环境稳定这件事,比模型能力更基础。
✍️ 我在 X 上分享更多碎片化的开发日常 👉 @HigandS99073
夜雨聆风