先问对问题,再找答案——hl-research 的完整探索记录

1 阅读8分钟

一个关于"不知道自己不知道什么"的问题

在用 Claude Code 开发的过程中,我经常遇到同一个问题:需要在陌生领域做技术选型,但不知道从哪里问起,因为我不知道这个领域有哪些维度需要考虑。

比如我想在 Claude Code 里生成图表,我知道有 Mermaid、HTML、drawio XML 这些选项。但我不知道它们之间的选择背后,还有"渲染环境"、"工具链依赖"、"语法校验"这些维度——我是做完调研之后才知道这些维度的存在的。

在开发语言智能助手的时候,我还遇到过另一个问题:我想让 AI 调用意图理解后直接发 HTTP 请求,我知道大模型有结构化输出,于是我就顺着这个方向去调研了。调研工具也帮我出了一份"用结构化输出拼接 HTTP 调用"的方案。

但是实现后我才发现,这个问题早就被工具调用(Function Calling)和 MCP 协议解决了。我造了一个轮子,一个很差的轮子。

这不只是信息不足的问题,在陌生领域,我们很可能连方向都是错的。

调研工具的集体盲区

市面上已经有各种 AI 调研工具,Claude Code 也自带了 deep-research。它们的工作流高度一致:

用户提出明确问题 → 搜索 → 综合 → 输出答案

但这里有一个隐晦的假设:用户已经提出了正确的问题。

如果用户的问题本身就是基于错误认知拼凑出来的呢?如果用户描述的"需求"其实是一个伪装成需求的、错误的解决方案呢?

结果就是:用户说不清,AI 问不对,两边都卡住了。AI 直接按用户的问题去调研,只是在给一个错误的问题寻找完美的答案。

传统调研工具帮你在一张已知的地图上找最短路径。但它们不会告诉你——你可能连地图都拿错了。

我需要一个能帮我先确认问题本身是否正确的调研工具。于是 hl-research 诞生了。

把"问对问题"变成一个工作流

解决这个问题,需要的不只是一次性问答,而是一个有中间交互的工作流。我把整个调研过程拆成两个阶段:

flowchart TB

    Start["Research Workflow"]

    Start --> P0
    Start --> P1

    subgraph SG0["Phase 0 — 盲探与澄清"]
        P0["开始"]

        A["盲搜:了解技术全景"]
        B["识别独立决策维度"]
        C["翻译成需求导向问题"]
        D["用户回答"]
        E["确认调研计划"]

        P0 --> A --> B --> C --> D --> E
    end

    subgraph SG1["Phase 1 — 定向深研"]
        P1["开始"]

        F["定向深研"]
        G["并行搜索所有维度"]
        H["每维度给出默认推荐"]
        I["跨维度一致性校验"]
        J["输出完整报告"]

        P1 --> F --> G --> H --> I --> J
    end

Phase 0 不做方案调研。它只做一件事:帮用户发现自己不知道的维度,然后翻译成不需要领域知识就能回答的问题。

这里有一条规则:Phase 0 的所有问题必须是需求导向的,不能是技术导向的。

  • 错误问法:「应该用 Mermaid 还是 HTML?」
  • 正确问法:「你希望图表最终在哪里查看——浏览器?终端?还是提交到 Git 的文件?」

区别在于:用户来做调研,就是因为不懂这个领域。如果问题需要领域知识才能回答,那这个问题本身就是错的。

回到之前那个"用结构化输出发 HTTP"的例子。Phase 0 不会直接开始调研怎么拼接 HTTP 请求。它会先盲搜整个"AI 调用外部服务"的技术全景,然后识别出用户可能不知道的维度。比如"是否希望 AI 自动选择调用时机?""需要调用的目标系统有没有现成的 API 描述规范?"。然后反过来问用户。在这些问题的答案出来之前,不会开始任何方案调研。

另一个关键设计是调研计划确认门:Phase 0 结束后,会把即将研究的维度和方向列出来,等用户确认再进入 Phase 1。这个停顿不是摩擦。调研一旦跑偏,花掉的时间就回不来了。确认门之前改方向,什么都不损失;过了门再改,前面的时间就白花了。这可以让我读完计划,对照自己的理解,决定要不要追问。

至于第二个阶段,反而和其他的调研工具差不多,因为问对问题确定方向才是最重要的!

第一次实战:Claude Code 画图方案

hl-research 写完后的第一个实战:

/hl-research Claude Code 生成图片方案(流程图、架构图、时序图等)怎么做比较好?用什么语言?Markdown?HTML?Mermaid?用 agent 还是 skills?

Phase 0 识别出三个独立决策轴:

  • 输出落点:终端内联 / 浏览器预览 / 磁盘文件
  • 触发方式:Skill(方法论) vs MCP Server(能力扩展)vs Agent
  • 图表语言:Mermaid / D2 / HTML+SVG / PlantUML

然后问了我两个需求导向的问题:图表最终在哪里看?这个方案想做成可复用的 Skill 还是临时用法?

我的回答让方向瞬间清晰:需要 PNG/SVG 文件可提交 Git、需要浏览器预览、要做成 dotfiles 里的 /hl-diagram Skill。

Phase 1 的答案收敛得很干净:

维度选择理由
图表语言Mermaid覆盖所有图类型,Claude 理解最深
文件生成mmdc + Kroki API fallback本地优先,无依赖时自动降级
浏览器预览生成 HTML →/tmp/open零依赖,macOS 原生
验证机制mmdc 校验循环,最多 3 次重试Claude 生成 Mermaid 有约 20% 语法错误率
Skill 架构PureSKILL.md + references/ 子目录不依赖 MCP,便携

从调研到工具:/hl-diagram Skill

基于这份报告,/hl-diagram 实现了:

skills/hl-diagram/
├── SKILL.md          # 主流程:类型推断、生成、校验循环、输出
└── references/
    ├── flowchart.md      # 从 mermaid.js.org 裁剪的语法参考
    ├── sequence.md
    ├── architecture.md
    ├── class.md
    ├── er.md
    └── common-errors.md  # 常见语法错误速查

两个设计细节:

按需加载 reference。 每次调用只读入对应图类型的参考文件,而不是把所有语法文档一次性塞进 context。实测发现,如果五种图类型的语法全部加载,无关内容会干扰 Claude,反而更容易把不同图类型的语法混淆。

语法验证是强制循环。 Claude 生成的 Mermaid 代码大约有 20% 的语法错误率,不是不懂语法,而是长 context 下容易漏掉细节。所以 Skill 硬编码了:生成 → 验证 → 修复 → 再验证,最多 3 次,失败则停止并暴露错误,不允许无限重试。

实现完成后的第一个任务,是让它给自己画一张工具全景图,以免将来忘记包括它自己在内的工具。

flowchart TB
    subgraph CONFIG["Claude Code 全局配置 — ~/.claude"]
        subgraph SKILLS["Skills(/命令名 触发)"]
            subgraph RES["调研"]
                s1[&#34;/hl-research<br/>通用调研,两阶段工作流&#34;]
                s2[&#34;/hl-dev-research<br/>项目内开发调研&#34;]
            end
            subgraph CODE[&#34;编码&#34;]
                s3[&#34;/hl-commit<br/>规范 Git 提交&#34;]
                s4[&#34;/hl-test<br/>编写并运行测试&#34;]
                s5[&#34;/hl-diagram<br/>Mermaid 图表生成&#34;]
            end
            subgraph FESK[&#34;前端&#34;]
                s6[&#34;/hl-fe-design<br/>前端设计简报&#34;]
                s7[&#34;/hl-fe-proto<br/>Vue 3 组件原型&#34;]
            end
            subgraph RVSK[&#34;评审&#34;]
                s8[&#34;/hl-be-review<br/>企业级 Java 代码评审&#34;]
            end
        end
        subgraph AG[&#34;Agents(子代理)&#34;]
            a1[&#34;hl-backend<br/>后端实现专家&#34;]
            a2[&#34;hl-frontend<br/>Vue 3 前端专家&#34;]
        end
        subgraph RU[&#34;Rules(路径匹配后自动注入)&#34;]
            r1[&#34;java.md — Java 工程规范&#34;]
            r2[&#34;java-style.md — Java 格式规范&#34;]
        end
    end
    s6 -.->|&#34;输出 design-brief.md&#34;| s7

    classDef sk fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
    classDef ag fill:#dcfce7,stroke:#22c55e,color:#14532d
    classDef ru fill:#fef9c3,stroke:#eab308,color:#713f12
    class s1,s2,s3,s4,s5,s6,s7,s8 sk
    class a1,a2 ag
    class r1,r2 ru

图出来了,但调研过程本身也值得复盘。

最后通过调研工具本身评估本次 skills 调研的质量,从而形成闭环。

用结果反观过程

整个链条走完后,回头看,发现了几个值得记录的问题。

研究计划里出现了一个假问题。 Phase 1 的调研计划列了五个维度,其中"图表语言选型"被当成了一个需要研究的问题。但实际上,Mermaid 在盲探阶段就已经是压倒性答案——社区生态最全、Claude 理解最深、所有目标图类型全覆盖。它不应该被列为"需要研究的维度",而应该直接作为前提约束写在计划开头。这个发现让我在 hl-research 的规则里加了一条:如果盲探后某个维度已有压倒性答案,直接声明为"前提约束",不再列为研究维度。

确认门的价值比预想的更重要。 在确认调研计划时,我只是简单说了"go",没有做任何修改。这看起来像是纯粹的摩擦。但这个停顿必须要有,它给了我读完计划、对照自己的理解、决定是否追问的机会。对于一个调研工具来说,确认门之前改方向,什么都不损失;过了门再改,前面的时间就白花了。

总结

每次调研后,可以留下调研过程让调研工具评估本次调研的质量,最终形成一个完美的闭环:一个工具被调研工具找到、实现,然后用来证明调研工具的质量。

如果要用一句话总结:理论上完美的设计,第一次运行就会暴露问题;但那些问题,正是让设计变得更好的原材料。

hl-claude/context/research-workflow.md 里现在有完整的设计决策记录和这次执行 trace,下次改动 hl-research 的人(包括几个月后的我自己)能看到每一个决策背后的理由,从而推动下一次的迭代。。

工具代码开源在 dotfiles 仓库hl-researchhl-diagram 以及其他 Skill 的 SKILL.md 都在 claude/skills/ 目录下。


更多思考

感谢你读到这儿。这篇文章记录了我解决“不知道自己不知道什么”这个问题的完整过程,包括 hl-research 的两阶段工作流设计、第一次实战的完整 trace,以及后来提炼出的 /hl-diagram Skill。

如果你想获取最新版本、参与讨论,或者只是想看一个更干净、可随时更新的版本,欢迎来我的博客做客:

博客里没有额外的广告,只有持续的迭代。