关于 ultrathink-protocol
用于先诊断、再修复复杂技术问题的协议 Skill。它通过基于证据的调查步骤,定位实际行为偏离预期的位置。
主要功能
- 01分离诊断与实施
- 02假设—行动—观察循环
- 03分层诊断步骤
- 04修复前验证证据
- 05处理调查陷入停滞
适用场景
- 01追踪跨系统层的问题
- 02检查运行时配置和进程状态
- 03以定向调查取代反复尝试修复
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bmad-labs/ skills --skill ultrathink-protocol安装后在 Claude Code 中输入/ultrathink-protocol确认已加载。
详细介绍
Ultrathink Protocol
此协议的用途
复杂技术问题常以一种特定模式告终:匹配一个看似合理的修复方案,应用它,发现并未奏效,再换一种方案重复尝试。每次迭代都让人觉得有所进展,却没有一次真正带来理解。这个循环可能持续数小时。
此协议通过将两种绝不能混为一谈的模式分开,打破这个循环:
- 诊断模式 — 构建经过验证的模型,弄清实际发生了什么
- 实施模式 — 确定原因后再应用修复方案
在诊断模式得出一个经过验证的原因之前,不能进入实施模式——这意味着你掌握了能够解释症状的直接证据(日志行、端口号、源代码函数、网络跟踪记录,或从运行中的进程读取的配置值)。“可能是 X”是一个假设,不是经过验证的证据。“运行中的进程从路径 Y 读取配置,而不是路径 Z,因为启动脚本在执行程序前覆盖了环境变量”才是经过验证的证据。
执行周期
复杂调查中的每一步都遵循以下三部分结构。 明确写出,不要压缩成一个段落。
THOUGHT: What hypothesis am I testing? What do I expect to find?
What would this result mean for my current model of the problem?
ACTION: The single most informative thing I can do right now —
a command, a source read, a log grep, a process inspection.
One action per cycle. Pick the action that would most change
your model if the result is unexpected.
OBSERVATION: What actually happened. Quote the relevant output directly.
Does this confirm or refute the hypothesis?
How does it change the model?
理解是在 OBSERVATION 步骤中建立的。如果观察结果只说“这证实了我的理论”,却没有解释为什么,那就是一个危险信号——这意味着你可能是在让证据符合预先形成的结论,而不是据此更新自己的模型。
诊断阶梯
从上往下逐级排查。在找到经过验证的证据时停止。排查得过多会浪费时间;过早停止则会得出错误诊断。
Level 1 — 精确描述症状
采取任何行动之前,先用尽可能具体、可观察的方式重述症状:
- 较弱:“不工作”
- 较强:“根据进程 A 自身的日志,它以 1 Hz 写入输出,但 30 秒后消费者 B 仍未收到任何内容,尽管双方都声称连接到了同一个通道”
观察结果与预期结果之间的差距,决定了问题的轮廓。每项诊断操作都应针对性地解释这一差距,而不是探索相邻的可能性。
Level 2 — 排除显而易见的问题
检查那些无需成本就能检查、且一旦出错就能解释所有问题的事项:
- 进程是否实际在运行?
- 运行中的进程是否确实能看到你认为它应该看到的配置/环境变量? (**关键:**检查进程自身的环境,而不是 shell 或配置文件——它们经常并不相同)
- 部署的代码/二进制文件是否为正确版本?
- 进程是否连接到了正确的端点、接口或地址?
**进程环境陷阱。**这是所有技术栈中非常常见的故障模式:你在启动器、compose 文件或包装脚本中配置了变量,但进程会在启动时、变量生效前覆盖它。务必验证运行中的进程实际看到的内容,而不是你让启动器传入的内容。在 Linux 上:/proc/<pid>/environ。在其他平台上:使用等效的进程检查工具。
Level 3 — 跟踪实际数据路径
确定预期的数据流,然后验证它在实际运行的系统中的每个步骤:
- 实际行为从哪一步开始偏离预期行为?
- 链条中最后一个行为正常的组件是什么?
- 第一个行为异常的组件是什么?
根本原因几乎总是恰好出现在一个偏离点——可能是层边界、被静默覆盖的配置值,或代码绑定到的接口与预期不同。“最后一个正常”与“第一个异常”之间的差距,就是需要排查的地方。
具体而言:不要推测可能出现什么问题,而要检查运行状态——打开的文件描述符、绑定的地址、活动连接、正在处理的实际值——并将它们与你的预期进行比较。
第 4 级 — 阅读源代码
当组件的行为与文档或配置不符时,阅读处理配置或负责相关路径的代码。听起来很慢,但与猜测各种配置变体相比,这种方法始终更快。
源代码访问优先级:
- 搜索已安装的头文件或打包脚本——它们通常随已安装的软件包提供,并能揭示函数签名、常量值、环境变量名称
- 在二进制文件中搜索字符串字面量——找到代码在运行时实际读取的环境变量名称、配置键、特殊值
- 阅读上游源代码(GitHub、软件包注册表)——这是最权威的依据;只需查看一个函数的实现,就能省去数小时的配置尝试
- 在文档和问题跟踪器中搜索你遇到的确切行为
源代码阅读之所以如此有价值,关键就在于:如果某个函数读取的是 CONFIG_VAR_B,而不是你一直在设置的 CONFIG_VAR_A,调查就能立即结束。无论你尝试多少种变体,对 CONFIG_VAR_A 进行任何配置更改都不会奏效。
第 5 级 — 受控实验
当无法获取源代码,或代码路径过于复杂、无法静态追踪时,运行受控实验,准确隔离一个变量:
- 将系统缩减到仍能复现故障的最小情况
- 只更改一项,然后观察效果
- 设计实验来证伪你当前的假设,而不是证实它
好的实验应当有可能证明你错了。如果它只能证实你已有的想法,那就不具备诊断价值——这只是多绕了几步的确认偏误。
卡住时的门槛
出现以下任一情况,就说明你卡住了:
- 在没有新的、经过验证的证据表明根本原因已经改变的情况下,你对同一类修复方法尝试了两次以上(不同的配置值、同一补丁的不同版本、不同的重启顺序)
- 最近三个观察步骤都没有改变你对问题的判断
- 你正在考虑采用某种已失败方案的更复杂版本
- 你的推理中出现了“也许”,却没有测试计划
卡住时:停下来。不要再尝试其他修复变体。
改为:
-
明确说明情况:
“我卡住了。我目前对问题的判断是 [X]。我掌握的证据是 [Y]。我无法解释的部分是 [Z]。”
-
沿诊断阶梯继续深入——说明你还没有查得足够深入。卡住最常见的原因是:没有直接检查某一层的实际行为;某个假设取代了观察。
-
如果所有可用的诊断工具都已用尽,就升级到外部研究(见下文)。
用户说“停止在不了解根本原因的情况下反复试错”,这是一个必须立即停止的信号。它意味着违反了流程——无论当前的修复尝试看起来离成功有多近,都要立即返回诊断模式。
升级:何时以及如何开展研究
在以下情况下,应升级到网络搜索、查阅文档或研究源代码:
- 根本原因需要理解你无法直接检查的系统(闭源二进制文件、第三方中间件、未记录的协议行为)
- 你已经得出了清晰、具体且可以回答的问题
- 如果不获取更多信息就继续诊断,只会沦为猜测
可供研究的问题应足够具体,能够通过搜索直接回答:
“[库 X] 的 [函数 Y] 在运行时实际读取哪个环境变量?”
无法供研究的问题,是你卡住时写下、希望靠研究来解围的问题:
“[技术 A] 如何与 [技术 B] 配合使用?”
如果你无法写出一个具体问题,就说明诊断还不够深入。此时正确的做法是继续诊断,而不是继续研究。
调查期间的沟通
要说什么
- 每次执行 ACTION 前,用一句话说明正在验证的假设
- 每次 OBSERVATION 后,说明你的模型发生了什么变化——即使答案是“没有变化,而这本身也缩小了可能性范围”
- 确认根因后,提出任何修复方案之前,先完整、准确地说明根因:
“根因已确认:[组件 A] 使用 [值 X],因为 [机制 Y] 在启动时覆盖了已配置的 [值 Z]。证据:[日志/源代码/进程状态中的直接引文]。”
不要说什么
- 不要把工具调用描述成进展(“我来查看日志……”不是发现——报告发现,而不是意图)
- 不要在确认原因之前宣布修复方案
- 不要说“我觉得问题可能是 X”,然后立刻针对 X 应用修复——“可能是”代表假设;先验证
- 不要把 THOUGHT/ACTION/OBSERVATION 压缩成一个段落——明确的结构正是为了避免跳过验证步骤
多层分解
当系统包含多个层(任何技术栈:硬件 → 驱动程序 → 操作系统 → 运行时 → 中间件 → 应用程序 → 配置)时,故障几乎总是发生在某一层边界上。定位方法如下:
-
找出最后一个正常工作的层。 链路中的哪一处行为符合预期?从输入端开始,沿链路向前检查。
-
找出第一个发生故障的层。 行为最先从哪一处开始偏离预期?
-
根因就在该边界上。 现在你有了一个精确的单层问题,而不是一个整个系统的问题。只调查该边界。
这种分解能将“整个流程都无法正常工作”转化为一个单层问题,只需一两个诊断操作即可解答。
避免调查尚未检查的层。 表层尚未彻底检查时,很容易对更深层提出假设。实际的偏离点几乎总比预想的更浅。
本协议可避免的反模式
| 反模式 | 信号 | 正确做法 |
|---|---|---|
| 配置反复尝试 | 对同一项配置更改尝试第三种变体 | 停下。查看正在运行的进程实际加载了什么配置。 |
| 重启循环 | 重新构建 → 重启 → 检查,但没有获得新的诊断信息 | 停下。代码没有变化。再次重启前先检查状态。 |
| 假设漂移 | 尚未验证原因 X,就针对 X 编写修复方案 | 将 X 视为假设。编写修复方案前先找到直接证据。 |
| 复杂度升级 | 每次修复尝试失败后,都增加更多层或间接步骤 | 运用奥卡姆剃刀。更简单的解释往往更正确。在正确位置修改 3 行,胜过在错误位置添加 50 行变通方案。 |
| 确认式阅读 | 阅读诊断输出是为了印证已有观点,而不是检验观点 | 思考:如果我的假设是错的,我会看到什么?有针对性地寻找这些迹象。 |
| Shell ≠ 进程环境 | 假设进程看到的就是启动器被告知要传入的内容 | 在运行时检查进程自身的环境,而不是启动配置。 |
| 跳过层级 | 未检查表层,就推测更深层的问题 | 从输入到输出逐层检查。第一次出现偏离的位置就是根因。 |
通用诊断工具包
# What environment does the running process actually see?
# Linux:
cat /proc/<pid>/environ | tr '\0' '\n'
# Or filter for a specific variable:
cat /proc/<pid>/environ | tr '\0' '\n' | grep VAR_NAME
# Which network sockets does a process own? (Linux)
# Map process file descriptors to UDP/TCP ports:
python3 -c "
import os, re
pid = <pid>
inodes = {}
for fd in os.listdir(f'/proc/{pid}/fd'):
try:
m = re.match(r'socket:\[(\d+)\]', os.readlink(f'/proc/{pid}/fd/{fd}'))
if m: inodes[int(m.group(1))] = fd
except: pass
for proto in ['udp', 'tcp']:
try:
with open(f'/proc/net/{proto}') as f:
for line in f:
p = line.split()
if len(p) >= 10:
try:
i = int(p[9])
if i in inodes:
port = int(p[1].split(':')[1], 16)
print(f'{proto.upper()} fd{inodes[i]} port={port}')
except: pass
except: pass
"
# What string literals (env var names, config keys) does a binary contain?
grep -oa '[A-Z_][A-Z0-9_]\{3,\}' /path/to/binary | sort -u | head -50
# Read source from a public GitHub repo without cloning:
gh api repos/<org>/<repo>/contents/<path/to/file> --jq '.content' | base64 -d
# Which file is a process actually reading? (Linux, requires strace)
strace -p <pid> -e trace=openat 2>&1 | grep -v ENOENT
# What is the process's working directory and open files?
ls -la /proc/<pid>/fd
readlink /proc/<pid>/cwd
完成检查清单
只有在检查完每一项后,才能宣布修复完成:
- 用一句话说明根本原因,并附上直接证据引用
- 修复针对根本原因,而非下游症状
- 没有为绕过原因不明的行为而增加复杂性
- 修复是解决已验证原因的最简单改动
- 应用修复前,已作出具体预测:“修复后,我预计会观察到 [X]”
- 应用修复后,已通过观察验证该预测
- 在故障发生的层级测试系统,而不只是进行端到端测试