青雲的博客

Claude Code 的 /btw:不打断主任务的“顺口一问”,源码里是怎么做隔离的?

· 7 分钟阅读

最近 Claude Code 传出新增了 /btw 功能,由 Anthropic 工程师 Eric Schluntz 作为内部 side project 做出来的,3 月 11 日前后开始在社区广泛传播。官方文档也已经上线:Interactive mode - Claude Code Docs

简单说,/btw 就是用来问”顺手的小问题”的,不会打乱正在进行的对话。我去扒了一下源码,看看它具体是怎么实现的。


先说它解决了什么问题

用 Claude Code 的时候,Claude 正在帮你重构一段代码,这时你脑子里突然冒出一个问题:“这个 API 的文档在哪?“或者”Python 里 sortedlist.sort() 有什么区别?”

如果你直接把问题打进去,Claude 会把它当成主对话的一部分——它可能打断当前任务去回答你,而这个问答过程会写进对话历史,占用 context,影响后续的代码工作。

/btw 的设计目的就是处理这类”随口一问”:问完就算,答案给你看,但什么都不留下。


怎么验证的

把包装好的 Claude Code 装上,去 node_modules 里翻:

npm install -g @anthropic-ai/claude-code
grep -n "btw\|marble_whisper" ~/.nvm/versions/node/v22.22.0/lib/node_modules/@anthropic-ai/claude-code/cli.js

版本是 v2.1.74,这个命令在这个版本里存在,但默认是关闭的。


Feature Flag

第一个关键点:命令受 Feature Flag 控制,默认不开。

function k96() {
  return P8("tengu_marble_whisper2", false)
}

P8 是读 Feature Flag 的函数,"tengu_marble_whisper2" 是 flag 名,默认值 false。也就是说,除非 Anthropic 在服务端把这个 flag 开给你,这个命令在 UI 上是隐藏的——帮助菜单里不显示,快捷键面板里也不出现。

对应的 UI 渲染逻辑:

V6 = k96() && createElement(Text, { dimColor: K }, "/btw for side question")

只有 flag 开了,这行提示才会出现在界面上。

Spinner 里也有一段:如果你用了超过 30 秒没用过 /btw,它会显示一条 Tip:

let n = o && s > 30000 && k96() && !D1().btwUseCount
// ...
"Use /btw to ask a quick side question without interrupting Claude's current work"

核心实现:怎么做到不影响主对话的

这是最关键的部分。找到 IW4 函数(就是处理 /btw 问题的函数):

async function IW4({ question, cacheSafeParams }) {
  const prompt = `<system-reminder>This is a side question from the user. You must answer this question directly in a single response.\n${question}`
  
  const result = await GR({
    promptMessages: [UserMessage({ content: prompt })],
    cacheSafeParams,
    canUseTool: async () => ({
      behavior: "deny",
      message: "Side questions cannot use tools",
      decisionReason: { type: "other", reason: "side_question" }
    }),
    querySource: "side_question",
    forkLabel: "side_question",
    maxTurns: 1,
    skipCacheWrite: true   // ← 关键
  })
  
  return { response: parseResponse(result.messages), usage: result.totalUsage }
}

两个关键参数:

maxTurns: 1这次对话只允许一轮。Claude 回答你,结束,不来回。避免 /btw 演变成一个子任务.

skipCacheWrite: true这是核心。LLM API 有 Prompt Cache 机制——系统会缓存你的对话 context,下次调用时命中缓存可以节省 token 消耗、降低延迟。skipCacheWrite 设为 true 意味着:这次调用不往 cache 里写任何东西。

实际效果:

  • /btw 的问题和 Claude 的回答不会出现在主对话的 cache 里
  • 下一次主对话的 API 调用,cache 状态和没发生过 /btw 一样
  • 主对话的 context 窗口没有被污染

还有一个细节:

canUseTool: async () => ({
  behavior: "deny",
  message: "Side questions cannot use tools",
})

/btw 的回答不能调用任何工具。你问的问题只能靠模型自己的知识回答,不能触发文件读写、命令执行等操作,进一步保证了隔离性。


System Prompt 的处理

注意 prompt 里有一段 <system-reminder> 标签:

<system-reminder>This is a side question from the user. You must answer this question directly in a single response.

这不是普通的 system prompt,而是注入到 user message 里的”提醒”。作用是告诉模型:这是个独立的小问题,不要试图调用工具,不要问追问,直接给答案。

对比一下 /btw 和普通消息的区别:

普通消息/btw
写入对话历史
写入 Prompt Cache否(skipCacheWrite)
允许调用工具
最大轮次无限制1
影响后续 context

正则匹配

命令的触发是通过正则匹配输入:

var F6Y = /^\/btw\b/gi

匹配以 /btw 开头、后面跟词边界的输入(大小写不敏感)。所以 /btw 这是什么 会触发,/btws 不会。

高亮处理函数:

function CW4(A) {
  if (!k96()) return []
  let matches = []
  for (let Y of A.matchAll(F6Y))
    if (Y.index !== undefined)
      matches.push({ word: Y[0], start: Y.index, end: Y.index + Y[0].length })
  return matches
}

flag 关闭时直接返回空数组,连高亮都不做。


总结

/btw 的实现思路本质上是一个受控的旁路请求

  1. 触发条件受 Feature Flag 控制,默认隐藏
  2. 请求走独立的 API 调用路径(forkLabel: "side_question"
  3. skipCacheWrite: true 确保不污染主会话的 Prompt Cache
  4. maxTurns: 1 + 禁止工具调用,保证它是轻量的一次性问答
  5. 问答结果展示给用户,但不写入主对话历史

这个思路对设计 AI 编程助手其实有参考价值——当用户需要”插嘴问一句”时,不应该让这个问题破坏当前工作流的 context。隔离不是难事,难的是把隔离做得足够彻底:cache 不写、history 不记、工具不调。

目前这个命令还在 flag 后面,大多数用户看不到。不过既然代码里已经有了,应该是快放出来了。

相关文章

评论