Skip to content

测试、调试与代码重构

本节信息

讲师 Elie Schoppik(Anthropic)· 时长 12:30 · ▶ 原视频

🎧 听本节
0:00 / 0:00

现在这个代码库缺少测试,没法评估聊天机器人的 RAG 流程。这一节我们就来写这些测试,并用它们去调试一个聊天机器人处理查询时出的错;最后,再重构它处理工具调用的方式。开始吧。

出 bug 了,但别急着「截图丢给 Claude」

假设距离上次动这个应用已经过了一阵子,我们回来想再用它。问一句「第 5 课讲了什么」,本来该返回信息,结果——出错了。

这时候很容易忍不住:把报错复制、丢给 Claude,盼着它一把解决。但我们要换种做法。与其把 Claude 带上一条瞎折腾的弯路,不如更有章法地来:我们知道应用出了毛病,但也知道这儿几乎没有测试能去验证问题到底在哪。

所以我们写的提示词,不只说错误是什么,还指明该在哪里写测试

锁定嫌疑文件,让 Claude 先写测试

这个错可能来自好几个 Python 文件:

  • AIGenerator:处理与 Anthropic API 的交互。
  • rag_system.py:整个 RAG(检索增强生成)的总指挥。
  • search_tools:定义底层的工具。

我们先让 Claude 给这几个特定文件写测试,再让它跑这些测试,借此查出哪里不工作、做出恰当的修复。先从测试入手,就能给「继续盖楼」打下一个稳固的地基。

因为这事稍微有点难,我们还让 Claude 多想想——这会触发它的扩展思考(extended thinking) 能力,多分配一些 token 给思考过程。下面这段回放,还原了「先写测试 → 跑测试 → 揪出真凶」的全过程:

claude code · 先测试后调试0 / 9

点「下一步」开始这段会话回放 ↓

它似乎已经定位到一个关键的配置问题、可能就是这个 bug,但写这些测试能给我们百分百的把握——确认这确实是问题、确认这就是正确的修复。

真凶:MAX_RESULTS 是 0

根据测试的发现,问题出在做向量搜索时返回的块数量上。我们去看看 MAX_RESULTS——果然印证了问题:不知什么原因,它居然是 0,所以向量检索一条都不返回。把它改掉后,测试如期通过,结果也完整了。

我们不只修好了 bug,还给自己造了一套强大的基础设施:以后再做新改动时,能确保「东西坏了却不知道为什么」这种情况不再发生。

重构:让工具能多轮调用

应用跑通了。现在聊一个我想做的重构/clear,从新功能开始。

ai_generator.py 里,我们规定每次查询最多搜一次。对相对简单的查询,这没问题。但当我们想做更复杂的查询——比如对比不同课程、对比它们的大纲——就需要不止一次工具调用了。所以我们需要一种机制:迭代地递归地走完所有需要的工具。

那就重构它。我这条提示词挺长,所以新建一个 markdown 文件 backend-tool-refactor.md,把当前行为期望行为都描述清楚,还给了一个示例流程(比如「搜索一门和另一门课讨论同一主题的课程」),并要求:写测试要验证外部行为,而不是纠结内部状态的细节

我还让 Claude 做一件特别的事:先别写代码,派出两个子代理(subagent)去并行头脑风暴可能的方案。这种场景下我自己也不确定最优重构是什么,与其让它只定一个方案,不如给它机会并行地琢磨出多个。

结果两个 agent 各自读文件、给出两套思路:一套偏迭代、一套更全面。Claude 让我二选一。第一眼看方案 A 简单些,那就打开计划模式、选方案 A,确保拿到完整计划、认可后再改。

实现时它会:更新方法签名加上最大轮数、更新系统提示词,而核心重构在 handle tool execution 里。可以看到它向后兼容:没改内部的 RAG 系统、也没动任何 API 端点。更重要的是——它在更新测试并运行测试,验证实现是对的,还专门加一个测试验证顺序工具调用没问题。

在浏览器里验收

到浏览器验证。先问某门课某节课的细节,能如期拿到标题——这之所以特别,是因为单次工具调用是拿不到的:第一次工具调用只给课程大纲,第二次才给某节课的细节。

再来点更复杂的:「有没有别的课程,和 MCP 这门课第 5 课讲同一个主题?」要回答这个,就得多次工具调用。结果看起来没有别的课程讲「构建 MCP 客户端」——这结果确实准确。

下一节,我们会用工作树(Git worktree)同时跑多个 Claude Code 会话来提升效率,并确保它们之间不会重叠或互相覆盖。