先把观察和解读分开放,再问 Agent
把原话和事实放在 BaseHalf 画布一侧,把团队以为它们意味着什么放在另一侧。只有该留下的证据才连上指定的压力测试,再把那一次跳跃选给 Claude Code 或 Codex。
周末一堆搜索工单砸进频道:「search is broken」、一张空面板截图、一条后来又能搜出三则笔记的查询。人很容易把这一堆贴进 Claude Code 或 Codex,问搜索到底哪里坏了。模型会很流畅地把堆里的每一个猜测都当成事实。更便宜的功夫在更前面,而且是视觉上的:先把你真正观察到的放在板子一侧,把团队以为这些观察意味着什么放在另一侧,然后再请任何人(人或 Agent)起跳。
这和把一团雾摊开、直到能给问题起名字,不是同一步;也和把选项并排放好不同。这里的问题已经有了个半成品。风险在于:一次跳跃已经被夹带进来,看起来就像证据的一部分。
一个搜索变空的周末
假设产品是一款本地优先的桌面笔记应用。周末你手里攒下了这些:
- 一条支持回复:「我把昨天用过的笔记标题打进去,搜索是空的。我知道文件还在,我从侧边栏打开过。」
- 周日晚上搜索面板的截图。查询是
invoice Q3。输入框下面是一片空白。没有「0 results」,没有提示,裁切范围内也没有转圈或进度。 - 周一重新打开后的调试日志:同一查询在 09:02:11 返回 0 条、耗时 1840 ms,09:02:48 返回 3 条、耗时 62 ms,中间没有错误行。
- 秒表计时:打开文件夹后的第一次搜索大约 1.8 秒;同一次会话里后来的搜索是 40–80 ms。
这些是观察。它们还没说为什么。旁边,团队已经有了几跳:
- 索引过期了:第一次结果是空的、第一次搜索又慢,说明重新打开后索引还没就绪。
- 查询解析把标题弄丢了:
invoice Q3被拆开或打分,以至于用户记得的标题对不上。 - 空状态太安静:人们报「search is broken」,是因为分不清第一次搜索只是慢、真的没有结果,还是面板卡住了。
索引过期的故事很整齐。它也可能是错的。面板太安静,同样能催生这些工单,索引本身可以没问题。
两堆,不要一团
用 BaseHalf 打开项目文件夹。每个文件都会变成一张卡片。写短笔记,一张只放一个想法:
context.md:这个周末的工单,此外什么都不写。- 观察:
obs-support-quote.md、obs-empty-results-screenshot-note.md、obs-query-log.md、obs-timing.md。只放事实和原话。这些卡片上不要写「所以索引过期了」。 - 解读:
interp-index-stale.md、interp-query-parser.md、interp-ui-too-quiet.md。每一张都明确写明:这是一跳。 pressure-test.md:你终于愿意提出的那个问题,比如:「第一次结果为空、重新打开后第一次搜索又慢,真的能推出索引过期吗?还是一个太安静的空状态本身就能解释这些工单?」
像白板上的纸条那样拖开。情境放上面。观察堆在左边。解读堆在右边。压力测试放底部,坐在可能支持或推翻那一跳的事实下面。这套摆法是给你看的。卡片位置和尺寸写在 .bh/ 下,通过 BaseHalf 自己的忽略文件不进 git(它不会去改你的 .gitignore),所以你可以继续挪这两堆,而不把一个座位表变成合并冲突。

眼睛现在能看见粘贴进 prompt 时会被盖住的东西:三则解读坐在四条事实对面,而这些事实里只有一部分跟第一跳有关。
一堆不是一条连接,选中也不是
板子一旦看起来像图,三种动作很容易混在一起。
| 动作 | 它是什么 | 它用来干什么 |
|---|---|---|
| 空间分堆 | 卡片坐在哪、有多大,一般记在 .bh/ 下 | 让眼睛把原话和事实,与团队以为它们意味着什么分开 |
| Upstream 连接 | 文件里的纯文本列表:Markdown frontmatter 的 upstream:,或其他文件在 .bh/mirror/<path>/upstream.yaml | 该留下、并流入一次点名的压力测试的证据 |
| 选中 | 你为这次提问高亮的卡片,单击、Shift-单击,或拖出一个框 | 此刻 Claude Code 或 Codex 在 Agent Area 里该看到的东西 |
坐在一起是一种看的办法。它不是语义关系,不是自动生成的图,也不等于左边每一张都在证明右边每一张。BaseHalf 不会替你把观察和解读分开。你自己挪,直到这两种句子不再占同一块地方。
只有 A 确实该持续喂给 B 的时候才连线。一旦有了 pressure-test.md,如果空面板那张笔记和计时那张下周还该跟着这个问题走,就把它们连进去。Markdown 笔记把这份名单写在 frontmatter 的 upstream: 里。支持回复和「查询解析」那一跳,如果不是这次压力测试要谈的,就别连。坐在左堆里,是直觉上它们属于观察。一条线是在声称:上下文从这里流到那里。
选中这一跳,不要整块板
板子现在把问题收小了。你不是在问「搜索哪里坏了」,而是在问:两次观察(第一次结果为空,以及重新打开后第一次搜索变慢)是否真能推出索引过期,还是太安静的空状态本身就能解释这些工单。
选中这张压力测试卡,加上属于它的观察卡。如果你希望 Agent 去攻打某一跳,再把那一张解读(索引过期)加进去,查询解析的猜测和剩下的原话先别选。拖一个框,或按住 Shift 点选,就能组成这一组;板上其余部分可以继续给你看,而不必倒进 prompt。选中内容是 Claude Code 或 Codex 在 Agent Area 里这次提问能看到的东西。BaseHalf 本身不是 Agent。

然后再问。不要问「诊断搜索」。请模型拿这些观察去压一压那一跳。
有了回答之后留什么
留下点过名的压力测试、真正起作用的观察,以及一则短笔记:这一跳是否站得住。如果它们该继续同行,就保留或改一改 upstream 列表。没站住的解读可以留在板上当提醒,也可以删。别因为事实曾经坐在一起,就把整个左堆升级成永久连接。
边界
把两堆分开,并不会让观察自动变成真的。如果截图裁掉了一行其实存在的「0 results」,或者计时量到的是慢磁盘而不是搜索本身,你会整齐地去压一条错误的跳跃,模型也会流畅地回答它。画布让这一跳看得见。落地之后信不信,仍然是你的事。
先把观察放一边、解读放另一边,然后再问。只有该跟着这次点名测试走的证据才写进 upstream。选中那一块,再去问 Agent。