上一篇我列了用 Claude Desktop 踩到的 6 个坑。写完之后我挨个去碰了碰,结果不算乐观:真正填上的只有 1 个(沙箱),剩下 5 个要么无解、要么只定位到原因却改不动。
太长不看版
已解决:
- 坑 6 · 沙箱(
npm run dev跑不起来)✅:推荐开启 Preview,用 preview 工具起 dev server 直接绕开沙箱;不开 Preview 的话,也可以用sandbox.excludedCommands把npm run dev、curl放到沙箱外跑。
无解:
- 坑 5 · 插件只能在 CLI 装 ❌:登录官方账号后 Claude Desktop 倒是能装插件,但我日常走中转站,那种状态下照样装不了——对我等于没用。
- 坑 1 ·
Claude in Chrome关不掉 ❌:为找开关特地登录了官方账号,翻遍设置仍无处可关。
已定位、暂时改不动:
- 坑 4 · 回复语言不稳 🔍:网关抓包确认系统提示词里明明写着「全程用中文回复」,配置没问题,只能认定是 Opus 4.8 自己抽风。
- 坑 3 · 会话标题大多生成不出来 🔍:标题请求开着超大的 thinking 预算、生成偏慢,撞上 Claude Desktop 约 10 秒的超时窗口——超时标题就被丢掉,会话保持
Untitled。 - 坑 2 · 工具调用失败 / 任务静默停止 🔍:失败请求的
messages数组最后一条消息的 role 是assistant(本应是user),中转站对这种请求时好时坏(偶尔回 400),于是工具调用接不下去、或任务静默停住。
坑 6:沙箱——解决了
这是上一篇里对我影响最大的坑——Claude Desktop 把 Claude Code 跑在沙箱里,npm run dev 直接起不来。前端开发离不开 dev server,所以这条必须先填。
现象
跑 npm run dev,报的是:
listen EPERM: operation not permitted
EPERM 是关键。沙箱默认禁止进程 bind/listen 本地端口,而 dev server 恰恰要起一个端口对外提供服务,于是被沙箱挡在门外。
推荐解法:开启 Preview
最省事的路子是:设置 → Claude Code → 开启 Preview。
开启后,Claude Desktop 会注入一组 Preview 工具。通过 Preview 工具去启动 npm run dev,dev server 不在 bash 沙箱里跑,自然也就不会撞上「禁止监听端口」这道墙——下面那一整套 sandbox.excludedCommands 配置都可以省了。而且 Preview 工具本身还自带访问页面、截图、读 console / 网络请求等能力,验证渲染比手动 curl 顺手不少。
如果你也是用 Claude Desktop 做前端开发,我建议先走这条:开 Preview,用 Preview 工具起 dev server,基本不用再碰沙箱配置。
备选解法:sandbox.excludedCommands
如果不想开 Preview、坚持用 bash 直接跑 dev server,那就得自己动手把命令放出沙箱。我最早填这个坑时走的就是这条路,记录在这里备查。
第一个误区:只放行命令是不够的
我最开始想当然,以为在 permissions.allow 里把 npm run dev 放行就行了。结果加完照样报 EPERM。
后来才搞明白:permissions.allow 解决的是「允许执行这条命令」,但沙箱限制的是「这条命令能不能出沙箱去监听端口」——这是两回事。命令是被允许跑了,可它一跑起来就想监听端口,又被沙箱拦下来。放行权限并没有触及沙箱这一层。
真正管用的:sandbox.excludedCommands
真正管用的是 sandbox.excludedCommands——把命令加进这个列表,它就会在沙箱外运行,自然也就不受「禁止监听端口」的限制了。而且即便处在严格沙箱模式下,excludedCommands 依然生效,加完不用重启会话。
curl 也得一起放进去
dev server 起来之后,我想用 curl 访问它确认页面正常,结果又踩一个坑:
curl http://localhost:4321
# Exit 7
Exit 7 是连不上。原因是沙箱内的 curl 走的是隔离的回环,而 dev server 是在沙箱外起的——两边的 localhost 根本不是同一个,沙箱里的 curl 自然访问不到沙箱外的端口。
所以 curl 也得加进 excludedCommands,让它和 dev server 待在沙箱外的同一个网络环境里,才能访问得到。
给 curl 收个口
不过 curl 出了沙箱就能访问外网了,全量放行 curl 不太放心。我的做法是只放行指向 dev server 端口的 curl,把暴露面缩到最小。
本项目是 Astro,dev server 监听 4321,所以只放行 4321 这个端口的前缀(如果你的框架是别的端口,比如常见的 3000,换成对应端口即可)。
最终 .claude/settings.local.json 里和沙箱相关的部分长这样:
{
"permissions": {
"allow": [
"Bash(npm run dev:*)",
"Bash(curl http://localhost:4321:*)",
"Bash(curl http://127.0.0.1:4321:*)"
]
},
"sandbox": {
"excludedCommands": [
"npm run dev",
"npm run dev *",
"npm run preview",
"npm run preview *",
"curl http://localhost:4321*",
"curl http://127.0.0.1:4321*"
]
}
}
两块是配套的:excludedCommands 负责让命令出沙箱,permissions.allow 负责免去每次执行的确认。curl 我特意只放行 4321,没有放行所有 curl。
配好之后验证闭环就通了:后台跑 npm run dev → curl http://localhost:4321/ 能拿到页面 HTML → 比对内容确认渲染正常。这条配置路线也能让 dev server 在 Claude Desktop 里跑起来。
坑 1:Claude in Chrome 关不掉,登录官方账号也没用
上一篇说过,Claude Desktop 自带的一批内置 MCP 工具白占了大约 15k 上下文,其中 Claude in Chrome 占得最多,偏偏我又用不上,还关不掉,挺难受。
我猜测:会不会是某些管理、设置入口要登录官方账号才会出现?于是我专门在 Claude Desktop 里登录了自己的 Claude 账号试了一把。结果是:
- 没有付费订阅,Cowork 和 Claude Code 这些功能都用不了——登进去也是个半残状态。
- 登录后倒是能装插件了——这给上一篇的坑 5 找到了原因:「插件只能在 CLI 装、Claude Desktop 只能启停」其实跟账号状态有关,登录官方账号后 Claude Desktop 自己就能装。但对我没什么用——我日常走的是中转站,那种状态下照样装不了。所以坑 5 对我仍是无解,只是总算知道卡在哪。
- 但翻遍设置,依然没有任何地方能关掉
Claude in Chrome。我本来就是冲着这个去登录的,结果它纹丝不动。
所以这个坑目前的结论是:无解。该占的 15k 上下文还是占着,只能继续忍。如果以后发现关闭的入口,再回来更新。
剩下三个坑——回复语言、会话标题、工具调用失败——我都没真正修好,但借着手头的网关把请求抓下来逐字段看,倒是都摸到了原因。
坑 4:回复语言不稳——定位到了,但锅不在配置
上一篇里我提过,中文配置下 Claude 偶尔会蹦英文甚至日文。这回我顺手查了一下,结论有点出乎意料。
我手头有个网关,能把 Claude Desktop 实际发出去的 API 请求原样抓下来。于是直接看它发的请求体——重点是系统提示词里到底有没有交代语言。结果是写得明明白白:
Always respond in Chinese. Use Chinese for all explanations, comments, and
communications with the user. Technical terms and code identifiers should
remain in their original form.
Maintain full orthographic correctness for Chinese, including all required
diacritical marks, accents, and special characters.
也就是说,「全程用中文回复」这条指令确确实实发到了模型那一侧,配置层面没有任何问题:该带的系统提示词都带上了。
那既然指令到位了还蹦英文,问题就只能往模型自己身上找了。结合网络上其他人的反馈(例如 V2EX 的这篇帖子),我只能认定是 Opus 4.8 自己抽风——指令收到了、也不是没看见,就是偶尔不照做。这种事配置上没得修,只能等模型本身稳定。
坑 3:会话标题大多生成不出来——卡在一个超时窗口
上一篇说会话标题基本生成不出来,新建会话一直挂着 Untitled(即未命名状态)。这回顺手用网关查了查,也查到了很可能的原因。
先看 Claude Desktop 怎么起标题:每次在新会话里第一次发消息后,它会并发发两个标题生成请求——一个用我当前选的模型(我一般是 Opus 4.8),另一个固定用 claude-haiku-4-5。最终采用的是 Haiku 那个(Opus 那路就算生成了、还按我的中文偏好给了中文标题,Claude Desktop 也不用)。
反直觉的地方:响应其实都是正常的
我把「显示成功」和「没显示」两种情况的请求、响应都抓下来逐字段对比,结论是——不管标题最后显不显示,模型都正确返回了符合格式的标题。没显示那次,Haiku 也老老实实给了 <title>Chinese response instability</title>,格式、内容都没毛病。所以锅不在模型,在 Claude Desktop 拿到响应之后。
真正的线索:跟耗时强相关
对比几次之后发现,决定标题显不显示的,是这次标题请求花了多久:
- 显示成功那次:从发出到响应完成 8.5 秒;
- 没显示那次:13.1 秒。
差不多卡在 10 秒这条线的两侧。看样子 Claude Desktop 给标题生成留了个约 10 秒的窗口,超过就把标题丢掉,会话保持 Untitled。有了这个怀疑,我在新开会话发出第一条消息之后,盯着 Claude Desktop 标题的 loading 状态数了一下,果然在 10 秒后就从 loading 状态变成了 Untitled。
Haiku 为什么慢到 13 秒:thinking 预算开太大了
翻请求体就明白了——这个「起 2~5 个词标题」的小活儿,居然开着 thinking:
"model": "claude-haiku-4-5-20251001",
"thinking": { "budget_tokens": 31999, "type": "enabled" }
3 万多的思考预算配给一个起标题的任务。于是 Haiku 经常要先吭哧吭哧想上几百上千 token 才吐出 <title>,耗时很容易破 10 秒。没显示那次它想了 871 个 thinking token,显示成功那次只想了 637 个——会话内容越复杂想得越久,也就越容易超时。
这也解释了为什么是「大部分」都失败:带 thinking 的标题请求天生就慢,多数会话的耗时本就压在 10 秒线之上,只有内容够简单、Haiku 想得够快的才偶尔赶上窗口。(比如我在让 Claude Desktop 分析网关日志的会话,第一句就是 @qu.md 阅读这个文件并解答我的问题,标题 qu.md questions 几乎秒出,就正常显示了。)
锅在哪
不在我的配置,也不在会话内容,而是官方这边两个设定撞一起了:给标题生成开了过大的 thinking 预算(拖慢它),又配了偏短的超时窗口(把慢的直接淘汰)。这俩我都改不了,都是 Claude Desktop 内置的。真要修得靠官方——给标题生成关掉 thinking、或放宽超时,再不然干脆采用先返回的 Opus 标题(那一路是 JSON 输出、没开 thinking,几乎总是更快)。
坑 2:偶发工具调用失败 / 任务静默停止——请求结尾混进了一条 assistant
上一篇还剩两个偶发的坑:工具调用偶尔失败、任务偶尔静默停止(不报错就不动了)。这回借着网关也顺手查了查,发现这俩很可能是同一个原因。
线索:messages 数组的最后一条是 assistant
把失败那几次的请求体抓下来一看,里头有个不该出现的东西——messages 数组的最后一条消息,role 是 assistant,而不是 user。
正常情况下,Messages API 的对话是 user / assistant 交替的;尤其在工具调用这个回合里,流程是:
user(发起) → assistant(tool_use) → user(tool_result) → assistant(继续) → …
也就是说,每次「请模型接着干活」的请求,最后一条都应该是 user(带着上一步的 tool_result)。可失败那几次,最后一条偏偏是 assistant——等于把一条本该由 user 收尾的请求,硬生生用 assistant 收了尾。
后果:中转站偶尔回 400
我走的是中转站转发。这种以 assistant 结尾的请求发过去,中转站那侧的表现很不稳定:偶尔能正常返回,偶尔直接回 400。
一旦撞上 400,这一轮的工具调用就接不下去了——要么表现为「工具调用失败」,要么干脆静默停止:没有红色报错,任务就停在那不动了。这正好对上了上一篇描述的那两个现象。
锅在哪:还不能完全确定
按理说,最后一条是 assistant 这种请求压根不该由客户端发出来——正常流程下最后一条一定是 user。所以我也不敢百分百断定这就是 Claude Desktop 自己发歪了,目前两种可能都没法证死:
- 一种是 Claude Desktop 在某些时序下,把 assistant 的中间态当成完整一轮发了出去;
- 另一种是中转站这侧校验太严——对一个 Anthropic 官方接口本来能容忍的请求(assistant 结尾相当于 prefill,让模型接着往下写)做了更严格的检查,才回了 400。
能确定的只有:失败的请求确实以 assistant 结尾,且中转站对这类请求的响应不稳定。后续要么换直连官方接口再抓一轮对比,要么盯着 Claude Desktop 看它到底在什么情况下会发出这种请求,再回来更新。
小结
到这儿,上一篇那 6 个坑算是过了一遍:坑 6(沙箱)填上了(推荐开 Preview,也可以用 excludedCommands 配置兜底),坑 5(插件)登录官方账号后才行,坑 1(Claude in Chrome)翻遍设置仍无解;剩下坑 4(语言)、坑 3(标题)、坑 2(工具调用)都借网关定位到了原因,但症结都在官方那侧、自己改不动。能修的修了,改不动的至少知道卡在哪——后面有进展再回来更新。