1.2 六问诊断法
学习目标
学完这一节,你能:
- 在使用 AI 之前,写出自己的问题规格和初步判断
- 用六问法把一个模糊任务拆成可检查的分析过程
- 判断 AI 输出什么时候可以接受、什么时候必须追问或拒绝
- 把六问法整理成一份"推理收据",留下自己的决策依据
试飞员的清单
2018 年,模拟训练。8000 米高空,600 公里时速,双引擎熄火。
试飞员没有先问"有没有最优方案"。他先跑过一张清单:
- 油量还剩多少?
- 哪个系统报错?
- 能重启吗?
- 最近机场在哪?
- 风向如何?
- 能滑过去吗?
清单不是成功的保证。清单的价值,是让人在压力下仍然有下一步动作。
算法设计也一样。面对一个陌生任务,尤其是一个可以立刻丢给 AI 的任务,你最危险的状态不是"不会写代码",而是还没有形成自己的判断,就已经继承了 AI 的判断。
六问诊断法就是算法设计中的清单。它不替你产出最优算法,而是帮助你在动手之前先建立一个可审查的思考基线。
先想再看:预测锁
使用六问法之前,先做一个更小的动作:预测锁。
预测锁的要求很简单:碰 AI 之前,先写下你的立场,并封存时间。之后可以修正,但不能假装自己一开始就知道。
典型的错误路径是:
拿到问题 -> 立即问 AI -> AI 给出答案 -> 觉得有道理 -> 直接采纳这不是协作,而是继承。你没有形成自己的判断,也就没有能力判断 AI 的答案解决的是不是原问题。
预测锁要求你先写下:
- 我认为问题的输入和输出是什么
- 我认为数据规模和速度要求大概是多少
- 我想到的最简单解法是什么
- 我猜测应该用哪类算法
- 我最担心的边界情况是什么
然后再让 AI 参与。这样,AI 的输出就不再是"标准答案",而是一个可以和你原始判断对照的对象。
预测锁的目的不是证明你比 AI 强,而是暴露你没有想到的盲点。
为什么是六问?
六问不是随意凑出的六个问题。它们对应算法设计中的六个决策层次:
| 层次 | 核心问题 | 本层产出 |
|---|---|---|
| 理解问题 | 我到底在解决什么? | 问题规格 |
| 建立基线 | 最简单的可行办法是什么? | 暴力解和复杂度预算 |
| 检索知识 | 这是不是已知问题? | 问题类型假设 |
| 利用结构 | 有哪些特殊条件可以利用? | 可利用结构清单 |
| 选择范式 | 应该采用哪种设计思想? | 范式选择和理由 |
| 承认边界 | 还有哪些不确定或想不出来? | 风险列表和下一步行动 |
AI 可以参与每一层:它能帮你列可能性、查标准算法、写代码、找反例。但它不能替你承担问题定义和取舍责任。真实约束来自你的场景,最终责任也在你这里。
所以这一节训练的不是"不问 AI",而是训练你带着自己的判断去问 AI。
第一问:我真的理解问题吗?
第一问的产出不是代码,而是一张问题规格卡。
规格卡至少包含五项:
| 项目 | 要回答的问题 | 常见遗漏 |
|---|---|---|
| 输入 | 数据从哪里来?格式是什么?范围多大? | 把自然语言描述当成输入定义 |
| 输出 | 返回一个值、一个列表,还是一个可解释的决策? | 只说"推荐结果",不说 Top-k 还是完整排序 |
| 规模 | n 大概是多少?峰值是多少? | 忽略线上高峰和长期增长 |
| 约束 | 时间、空间、准确率、稳定性有什么要求? | 只关注能不能跑,不关注能不能上线 |
| 例子 | 一个正常例子和一个边界例子分别是什么? | 没有冷启动、空输入、重复值等情况 |
比如"写个推荐算法"不是一个清晰问题。它至少要进一步变成:
输入是用户-商品评分矩阵,约 100 万用户、10 万商品;输出每个用户的 Top-10 推荐;在线请求需要 100ms 内返回;新用户允许退化到热门推荐。
这时才有资格讨论算法选择。
与 AI 协作
这一问最适合让 AI 做"澄清助手",而不是直接做"实现助手"。
可以这样问:
下面是我的问题规格。请帮我找出仍然模糊、可能导致算法选择错误的地方,不要先写代码。
如果 AI 立刻给代码,你也应该先把它拉回规格层面。规格不清,代码越完整越危险。
第二问:简单算法够用吗?
第二问的产出是一个暴力基线和一个复杂度预算。
暴力解不是低水平解法。它有三个作用:
- 作为正确性参照,帮助你测试更复杂的算法
- 作为原型,帮助你确认问题建模是否正确
- 作为预算起点,帮助你判断是否真的需要优化
关键不是问"暴力解是不是高级",而是问"它在当前规模下是否够用"。
一个粗略判断是:
| 数据规模 | O(n) | O(n log n) | O(n^2) | O(2^n) |
|---|---|---|---|---|
| n = 100 | 通常没问题 | 通常没问题 | 通常没问题 | 通常不可接受 |
| n = 10,000 | 通常没问题 | 通常没问题 | 需要谨慎 | 不可接受 |
| n = 1,000,000 | 通常没问题 | 可能可接受 | 通常不可接受 | 不可接受 |
这张表不是硬规则。真实运行时间还取决于常数、语言、硬件、IO、网络、并发和数据分布。但它能防止你在没有规模意识时盲目接受一个复杂度不合适的方案。
与 AI 协作
不要只问:
帮我写最优算法。
更好的问法是:
先给出一个最简单正确的基线算法,并估计它在 n=10^5 时是否可接受。如果不可接受,再说明需要优化到什么复杂度。
这样 AI 的输出会更容易被审查:它必须同时给出解法和复杂度理由。
第三问:有标准解法吗?
第三问的产出是一个问题类型假设。
很多任务表面上是业务需求,底层其实是经典问题。识别类型之后,你不需要重新发明算法,也不需要让 AI 在模糊描述中猜。
识别问题类型时,不要只背算法名字,要看信号:
| 识别信号 | 可能的问题类型 | 追问 |
|---|---|---|
| 有对象和关系 | 点与连接构成的问题 | 连接是否有方向和权重? |
| 要找"最短、最快、最低成本" | 路线或代价最小化问题 | 代价如何计算? |
| 要安排、匹配、分配 | 把资源分给对象的问题 | 是一对一、多对一,还是容量受限? |
| 要从序列中找规律 | 排序、查找或分段问题 | 是否只和相邻元素有关? |
| 要在大量数据中判断是否出现过 | 快速查找或去重问题 | 是否允许概率性错误? |
| 要实时处理连续数据 | 只保留少量状态的数据流问题 | 能否保存全部历史? |
这一步的关键是:先提出假设,再验证假设。
例如"判断一个人能否参加所有会议"看起来是日程管理,其实可以假设为排序问题:把会议按开始时间排序,再检查相邻会议是否重叠。这个假设成立,是因为只要排序后相邻会议不冲突,就不会有跨越更远的冲突。
与 AI 协作
可以让 AI 同时给出多个类型假设:
这个问题可能分别被建模成哪些经典算法问题?请列出每种建模成立需要满足的条件,以及不成立时的反例。
这里你要审查的不是代码,而是"建模条件"。
第四问:能利用特殊结构吗?
第四问的产出是一个可利用结构清单。
通用算法解决的是最一般的问题。但真实任务往往带有特殊条件:
- 数据几乎有序
- 数值范围很小
- 图很稀疏
- 查询很多但更新很少
- 只需要近似答案
- 可以离线预处理
- 输入会持续到达,不能完整保存
这些条件可能彻底改变算法选择。
例如排序整数,如果数值范围只有 0 到 100,计数排序可能比通用比较排序更合适。又如推荐系统,如果离线阶段可以预计算候选集,在线阶段就不应该重新扫描全量商品。
第四问最容易被忽略,因为它要求你不仅理解算法,也理解数据来源和使用场景。
与 AI 协作
让 AI 写通用解之前,先让它读你的结构清单:
我的数据有这些特殊结构:……请判断哪些结构可以降低时间复杂度、空间复杂度或工程成本。每条建议都要说明适用条件。
如果 AI 提出的优化没有利用你的结构,它可能只是给了一个更复杂的通用解。
第五问:哪种范式适合?
第五问的产出是一个范式选择理由。
算法范式不是标签,而是一组证明义务。选择某个范式,就意味着你要回答它最关键的问题:
| 范式 | 先问什么 | 如果答不上来,风险是什么 |
|---|---|---|
| 分治:把问题拆成相互独立的小问题 | 子问题是否独立?合并是否便宜? | 子问题重叠导致重复计算 |
| 局部选择法:每一步都选眼前最好的动作 | 局部最优为什么能推出全局最优? | 得到看似合理但错误的答案 |
| 记表法:把重复子问题的答案存起来 | 状态是什么?转移是否覆盖所有情况? | 状态爆炸或遗漏边界 |
| 试探回退法:尝试一种选择,失败再退回 | 搜索空间是什么?剪枝是否安全? | 枚举失控或剪掉正确答案 |
| 容量分配模型:把限制看作容量 | 容量如何对应现实约束? | 建模错位,算法正确但问题错误 |
| 随机化:允许算法使用随机选择 | 允许什么概率性错误?如何控制失败率? | 把不确定结果误当确定结果 |
| 数据流方法:输入持续到达,只保留少量状态 | 能保存多少状态?是否允许近似? | 用单机批处理思路处理实时流 |
例如,看到"每一步选当前最优"并不能说明这个规则一定正确。你还要说明:为什么这个局部选择不会破坏未来的整体结果?如果说不清,就应该怀疑这个规则。
与 AI 协作
这里不要让 AI 只给算法名称。让它给出选择理由和反例压力测试:
你建议使用这个范式,请说明它成立需要满足的性质;再给一个最可能让该范式失败的反例。
如果 AI 只给出实现,不给出成立条件,你仍然没有完成算法设计。
第六问:还是想不出来?
第六问的产出是一个边界说明。
想不出来不是失败。真正危险的是没有理由地说"做不了",或者没有证据地说"一定可以"。
更好的表达是:
我目前不能直接解决,因为……
我已经排除了……
我还不确定……
下一步我需要……
卡住时可以做四件事:
- 回到第一问,检查问题是否定义错了
- 放宽约束,先解决简化版本
- 搜索相似问题,寻找标准建模
- 请 AI 或专家给出反例、下界、替代建模
第六问把六问法变成循环。卡住不是终点,而是回到更早的问题重新建模。
推理收据:把六问法留下来
在 AI 时代,交付一个答案不够。你还要能交付答案背后的判断过程。
这份记录可以叫推理收据:
问题规格:
- 输入:
- 输出:
- 规模:
- 约束:
- 例子:
暴力基线:
- 思路:
- 时间复杂度:
- 空间复杂度:
- 是否够用:
问题类型假设:
- 我认为它像:
- 成立条件:
- 可能反例:
特殊结构:
- 可利用结构:
- 对复杂度或工程成本的影响:
范式选择:
- 选择:
- 理由:
- 需要证明或测试的点:
AI 对比:
- AI 给出的方案:
- 与我预测不同之处:
- 我接受/修改/拒绝的理由:
剩余风险:
- 未确认的约束:
- 需要补充的测试:
- 下一步行动:推理收据不是形式主义。它训练的是三种能力:
- 你能不能在 AI 之前形成自己的判断
- 你能不能解释为什么接受或拒绝 AI 的建议
- 你能不能在结果出问题时追溯当初的决策依据
这正是未来算法课比过去要求更高的地方。过去学生常常被训练成"能手写实现的人";现在更需要被训练成"能定义问题、审查方案、承担判断的人"。
人与 AI 的分工
六问法不是把人和 AI 分开,而是把协作边界说清楚。
| 层次 | 人的责任 | AI 可以协助 |
|---|---|---|
| 理解问题 | 定义真实目标、约束和验收标准 | 找歧义、补充澄清问题 |
| 建立基线 | 判断复杂度是否够用 | 写基线代码、估算复杂度 |
| 检索知识 | 决定哪种建模最贴近场景 | 列标准算法和类似问题 |
| 利用结构 | 识别数据和业务特殊性 | 提出可能优化方向 |
| 选择范式 | 承担架构选择和证明义务 | 给出实现、反例和测试 |
| 承认边界 | 决定何时放宽、求助或停止 | 提供替代方案和参考材料 |
AI 的价值很大,但它的价值取决于你给它什么问题,以及你如何审查它的回答。
所以,算法课不是因为 AI 会写代码而变得不重要。恰恰相反:当代码生成变便宜,判断错误变得更贵。
本节要点
- 六问法不是求最优解的公式,而是防止思考失控的纪律
- 预测锁要求你在 AI 之前形成自己的判断基线
- 每一问都要有产出:规格、基线、类型假设、结构清单、范式理由、边界说明
- AI 可以参与分析,但不能替你承担问题定义和最终取舍
- 高质量算法学习不再只是写出代码,而是留下可审查的推理收据
课堂练习
练习 1:预测锁训练
问题:给定一个无向图,判断其中是否存在环。
第一步,不使用 AI,写一份预测锁:
- 你如何定义输入和输出?
- 你想到的最简单解法是什么?
- 你预测的时间复杂度和空间复杂度是多少?
- 你认为这个问题像哪类经典问题?
- 你担心哪些边界情况?
第二步,让 AI 给出两种不同解法,并要求它说明复杂度和边界情况。
第三步,提交一张对比表:
| 项目 | 我的预测 | AI 输出 | 我最终接受的判断 |
|---|---|---|---|
| 问题建模 | |||
| 算法思路 | |||
| 复杂度 | |||
| 边界情况 |
评分重点不是谁先想到标准解,而是谁能清楚说明自己为什么修改判断。
练习 2:六问法应用
用六问法分析下面的问题:
给定 n 个会议的起始和结束时间,判断一个人能否参加所有会议。
你的提交必须包含:
- 问题规格卡
- 暴力基线和复杂度
- 标准解法假设
- 至少两个边界例子
- 最终给 AI 的提示词
- 你会用哪些测试判断 AI 的实现是否正确
练习 3:审查 AI 输出
问题仍然是会议安排。假设 AI 给出如下判断:
先按会议开始时间排序。然后检查每个会议的开始时间是否大于前一个会议的结束时间。如果都大于,就可以参加所有会议。
请审查这段答案:
- 它的算法思想是否合理?
- "大于"是否一定正确?如果一个会议 10:00 结束,下一个会议 10:00 开始,算不算冲突?
- 这个答案缺少哪些输入约定?
- 你会如何修改提示词,让 AI 先问清楚边界再写代码?
练习 4:推理收据
任选一个你最近见过的编程任务,按本节模板写一份推理收据。要求:
- 先写自己的预测锁
- 再附上 AI 输出摘要
- 最后写出你接受、修改或拒绝 AI 建议的理由
课后测验
📝 课后测验
上一节:1.1 你面对的是一个什么问题
下一节:1.3 如何验证正确性