{"schema_version":1,"id":"article:eval-driven-deep-research","kind":"article","slug":"eval-driven-deep-research","title":"用评测驱动迭代 Deep Research，我学到了什么","author":"晨旭","url":"https://chenxu.xin/writing/eval-driven-deep-research","date":"2026-08-10","updated":"2026-08-10","description":"第一次比较完整地独立跑完一轮评测驱动迭代。五课记录：不要急着相信分数、评测会否定你的方案、评测器自己也会犯错、真正有价值的是定位错误层级、以及总分不是目标。","position":null,"group":null,"series":"入门系列文章","tags":["evaluation","agent","ai-pm","deep-research"],"publication_status":"public","maturity":"evergreen","body_sha256":"3975e304f956d3f503761e460527f3b7f6b5eb57aa7df70d3504cb50f1f29b4f","paragraph_rule":"src/lib/paragraphs.mjs@1","paragraphs":[{"id":"p1","kind":"paragraph","text":"做 AI 应用，大概都听过一句话：要做评测驱动。","raw":"做 AI 应用，大概都听过一句话：要做评测驱动。"},{"id":"p2","kind":"paragraph","text":"模型输出不稳定，不能只凭感觉判断效果；每次修改提示词、模型或者工作流，都应该通过评测确认它到底有没有变好。","raw":"模型输出不稳定，不能只凭感觉判断效果；每次修改提示词、模型或者工作流，都应该通过评测确认它到底有没有变好。"},{"id":"p3","kind":"paragraph","text":"这周，我借着自己正在做的 Deep Research 项目，第一次比较完整独立地尝试了评测驱动的迭代。","raw":"这周，我借着自己正在做的 Deep Research 项目，第一次比较完整独立地尝试了评测驱动的迭代。"},{"id":"p4","kind":"paragraph","text":"这是一个会搜索公开信息、阅读公司年报，并生成股票研究报告的 AI 应用。因为金融报告里有大量数字、时间和会计口径，它很适合做评测：一个结论写得是否流畅可能很主观，但营收是多少、引用是否支持原文、报告期有没有写错，至少有一部分是可以核实的。","raw":"这是一个会搜索公开信息、阅读公司年报，并生成股票研究报告的 AI 应用。因为金融报告里有大量数字、时间和会计口径，它很适合做评测：一个结论写得是否流畅可能很主观，但营收是多少、引用是否支持原文、报告期有没有写错，至少有一部分是可以核实的。"},{"id":"p5","kind":"paragraph","text":"在真正做完这一轮评测迭代之后，我最大的收获是：","raw":"在真正做完这一轮评测迭代之后，我最大的收获是："},{"id":"p6","kind":"quote","text":"评测驱动并不只是给模型做一场考试，还是在开发过程中不断校准自己判断的过程。","raw":"> 评测驱动并不只是给模型做一场考试，还是在开发过程中不断校准自己判断的过程。"},{"id":"p7","kind":"heading","text":"把「好不好」，拆成几个可观察的问题","raw":"## 把「好不好」，拆成几个可观察的问题"},{"id":"p8","kind":"paragraph","text":"开始做评测时，我做的第一件事不是设计一个总分，而是问自己：一份 Deep Research 报告失败，可能失败在哪里？","raw":"开始做评测时，我做的第一件事不是设计一个总分，而是问自己：一份 Deep Research 报告失败，可能失败在哪里？"},{"id":"p9","kind":"paragraph","text":"于是我查找整合了一些业界论文与技术博客，把它粗略拆成了几层：","raw":"于是我查找整合了一些业界论文与技术博客，把它粗略拆成了几层："},{"id":"p10","kind":"list","text":"1. 有没有找到材料：搜索和抓取是否拿到了需要的信息？\n2. 有没有选对材料：正确资料已经存在时，系统有没有选择更可靠、时间更合适的那一份？\n3. 有没有写对：证据里有正确数字，写进报告时有没有转述错误？\n4. 引用是否成立：报告标注的来源，是否真的支持前面的论断？\n5. 整体是否有研究价值：结构、深度、风险分析和投资结论是否合理？","raw":"1. **有没有找到材料**：搜索和抓取是否拿到了需要的信息？\n2. **有没有选对材料**：正确资料已经存在时，系统有没有选择更可靠、时间更合适的那一份？\n3. **有没有写对**：证据里有正确数字，写进报告时有没有转述错误？\n4. **引用是否成立**：报告标注的来源，是否真的支持前面的论断？\n5. **整体是否有研究价值**：结构、深度、风险分析和投资结论是否合理？"},{"id":"p11","kind":"paragraph","text":"然后，我为一些公司整理了人工核实的关键事实，例如某年的营收、归母净利润、现金流和重要事件；保存每次运行使用的证据、生成的报告、耗时和调用成本；再让不同评测器分别检查事实覆盖、数字准确性和引用情况。","raw":"然后，我为一些公司整理了人工核实的关键事实，例如某年的营收、归母净利润、现金流和重要事件；保存每次运行使用的证据、生成的报告、耗时和调用成本；再让不同评测器分别检查事实覆盖、数字准确性和引用情况。"},{"id":"p12","kind":"paragraph","text":"这一步给我的最大帮助，是让我不再把所有问题都叫作「模型效果不好」。以前看到报告漏掉一个重要数字，我第一反应可能是修改写作提示词。现在我会先看：这个数字有没有进入证据池？","raw":"这一步给我的最大帮助，是让我不再把所有问题都叫作「模型效果不好」。以前看到报告漏掉一个重要数字，我第一反应可能是修改写作提示词。现在我会先看：这个数字有没有进入证据池？"},{"id":"p13","kind":"list","text":"- 如果根本没搜到，应该修检索\n- 如果搜到了却没被保留，应该修证据筛选\n- 如果已经交给写作模型却没有写出来，才是生成问题\n- 如果写出来了但期次错了，则可能是摘要阶段已经损坏了信息","raw":"- 如果根本没搜到，应该修检索\n- 如果搜到了却没被保留，应该修证据筛选\n- 如果已经交给写作模型却没有写出来，才是生成问题\n- 如果写出来了但期次错了，则可能是摘要阶段已经损坏了信息"},{"id":"p14","kind":"paragraph","text":"问题一旦被分层，迭代才真正有了方向。","raw":"**问题一旦被分层，迭代才真正有了方向。**"},{"id":"p15","kind":"heading","text":"第一课：先不要急着相信分数","raw":"## 第一课：先不要急着相信分数"},{"id":"p16","kind":"paragraph","text":"刚开始有评测结果时，我非常自然地犯了一个错误：把分数变化理解成改动效果。","raw":"刚开始有评测结果时，我非常自然地犯了一个错误：把分数变化理解成改动效果。"},{"id":"p17","kind":"paragraph","text":"某次调整之后，事实覆盖率提高了，我就认为提示词有效；下一轮又降低了，我又开始寻找新的解释。","raw":"某次调整之后，事实覆盖率提高了，我就认为提示词有效；下一轮又降低了，我又开始寻找新的解释。"},{"id":"p18","kind":"paragraph","text":"后来我用相同代码、相同问题重新运行，才发现结果本身就会波动：搜索结果会变化，网页有时抓不到，模型对相关性的判断也不是完全稳定的。Deep Research 又是一条很长的链路，前面一个很小的变化，可能让后面使用完全不同的证据。","raw":"后来我用相同代码、相同问题重新运行，才发现结果本身就会波动：搜索结果会变化，网页有时抓不到，模型对相关性的判断也不是完全稳定的。Deep Research 又是一条很长的链路，前面一个很小的变化，可能让后面使用完全不同的证据。"},{"id":"p19","kind":"paragraph","text":"这意味着：","raw":"这意味着："},{"id":"p20","kind":"quote","text":"有分数，不等于有结论。","raw":"> 有分数，不等于有结论。"},{"id":"p21","kind":"paragraph","text":"于是我开始尝试保存搜索和抓取结果，让不同版本尽量使用同一批资料（控制变量法）；对重要实验重复运行；不再根据单个案例做全局判断；如果变化没有明显超过正常波动，就把结论写成「暂时无法证明有效」，而不是「略有提升」。","raw":"于是我开始尝试保存搜索和抓取结果，让不同版本尽量使用同一批资料（控制变量法）；对重要实验重复运行；不再根据单个案例做全局判断；如果变化没有明显超过正常波动，就把结论写成「暂时无法证明有效」，而不是「略有提升」。"},{"id":"p22","kind":"paragraph","text":"这一系列操作是不是听起来很像传统的软件测试？但 AI 应用有一个额外困难：即使输入相同，结果也未必完全相同。因此评测不是简单地判断通过或失败，还要先理解自己的噪声有多大。","raw":"这一系列操作是不是听起来很像传统的软件测试？但 AI 应用有一个额外困难：即使输入相同，结果也未必完全相同。因此评测不是简单地判断通过或失败，还要先理解自己的噪声有多大。"},{"id":"p23","kind":"heading","text":"第二课：评测不只会否定模型，也会否定方案","raw":"## 第二课：评测不只会否定模型，也会否定方案"},{"id":"p24","kind":"paragraph","text":"有一段时间，报告经常漏掉事实。我当时很自然地就想到：是不是给模型的证据太少了呢？","raw":"有一段时间，报告经常漏掉事实。我当时很自然地就想到：是不是给模型的证据太少了呢？"},{"id":"p25","kind":"paragraph","text":"于是我把报告生成阶段能够看到的证据数量扩大了一倍。","raw":"于是我把报告生成阶段能够看到的证据数量扩大了一倍。"},{"id":"p26","kind":"paragraph","text":"结果事实覆盖没有明显提升，数字准确性反而下降了。","raw":"结果事实覆盖没有明显提升，数字准确性反而下降了。"},{"id":"p27","kind":"paragraph","text":"原因是，更多证据不等于更多有效信息。不同网页可能使用不同报告期、不同统计口径，转载文章还可能省略关键限定。模型一次看到更多内容，也就有更多机会把相似数字混在一起。","raw":"原因是，**更多证据不等于更多有效信息**。不同网页可能使用不同报告期、不同统计口径，转载文章还可能省略关键限定。模型一次看到更多内容，也就有更多机会把相似数字混在一起。"},{"id":"p28","kind":"paragraph","text":"如果没有评测，我很可能会因为报告变得更长、引用变得更多，而认为这次改动是有效的。","raw":"如果没有评测，我很可能会因为报告变得更长、引用变得更多，而认为这次改动是有效的。"},{"id":"p29","kind":"paragraph","text":"但评测告诉我，这个方向并不成立。我最终回退了改动，并记录下「增加证据数量不等于提高研究质量」。","raw":"但评测告诉我，这个方向并不成立。我最终回退了改动，并记录下「增加证据数量不等于提高研究质量」。"},{"id":"p30","kind":"paragraph","text":"这里，评测不是在帮助我证明自己的方案是对的，而是让我更快承认自己的方案可能是错的。","raw":"这里，评测不是在帮助我证明自己的方案是对的，而是让我更快承认自己的方案可能是错的。"},{"id":"p31","kind":"heading","text":"第三课：评测器本身也会犯错","raw":"## 第三课：评测器本身也会犯错"},{"id":"p32","kind":"paragraph","text":"为了检查报告里更多数字，我做了一个基于结构化财务数据的规则评测器。它会识别报告中的财务指标，再与数据库里的数值比较。","raw":"为了检查报告里更多数字，我做了一个基于结构化财务数据的规则评测器。它会识别报告中的财务指标，再与数据库里的数值比较。"},{"id":"p33","kind":"paragraph","text":"第一版跑出来的结果很差，大量数字被判错。看到结果时，我的第一反应就是：报告中的数字质量远比想象中糟糕。","raw":"第一版跑出来的结果很差，大量数字被判错。看到结果时，我的第一反应就是：报告中的数字质量远比想象中糟糕。"},{"id":"p34","kind":"paragraph","text":"但逐条查看后，我发现错的很多不是报告，而是评测器：","raw":"但逐条查看后，我发现错的很多不是报告，而是评测器："},{"id":"p35","kind":"list","text":"- 它把年份当成金额\n- 把增长率当成营业收入\n- 把分部营收和公司总营收比较\n- 把单季度数字和半年累计数字比较\n- 把报告引用并反驳的外部观点，当成报告自己的结论","raw":"- 它把年份当成金额\n- 把增长率当成营业收入\n- 把分部营收和公司总营收比较\n- 把单季度数字和半年累计数字比较\n- 把报告引用并反驳的外部观点，当成报告自己的结论"},{"id":"p36","kind":"paragraph","text":"后来我不断缩小评测器的判断范围。遇到不能高置信判断的表达，就选择不评分。它能检查的数字变少了，但留下来的判定更可信。","raw":"后来我不断缩小评测器的判断范围。遇到不能高置信判断的表达，就选择不评分。它能检查的数字变少了，但留下来的判定更可信。"},{"id":"p37","kind":"paragraph","text":"扩充到小盘股和 ST 公司后，我又遇到一个更糟糕的情况。评测结果一度显示，小盘股报告的数字质量明显差于大盘股。这个结论非常符合直觉：公开资料越少，AI 越容易出错。","raw":"扩充到小盘股和 ST 公司后，我又遇到一个更糟糕的情况。评测结果一度显示，小盘股报告的数字质量明显差于大盘股。这个结论非常符合直觉：公开资料越少，AI 越容易出错。"},{"id":"p38","kind":"paragraph","text":"但复核以后才发现，大部分差异仍然来自评测器没有见过的新表达方式。修正误报后，两组之间的差距基本消失。","raw":"但复核以后才发现，大部分差异仍然来自评测器没有见过的新表达方式。修正误报后，两组之间的差距基本消失。"},{"id":"p39","kind":"paragraph","text":"这两次的结果，让我逐渐明白：","raw":"这两次的结果，让我逐渐明白："},{"id":"p40","kind":"quote","text":"越符合预期的评测结果，越容易未经检查就被相信。","raw":"> 越符合预期的评测结果，越容易未经检查就被相信。"},{"id":"p41","kind":"paragraph","text":"评测器并不是天然客观的。人工编写的标准答案可能有错，规则可能覆盖不全，LLM 裁判也可能有偏好。评测体系本身同样需要测试、抽查和迭代。","raw":"评测器并不是天然客观的。人工编写的标准答案可能有错，规则可能覆盖不全，LLM 裁判也可能有偏好。**评测体系本身同样需要测试、抽查和迭代。**"},{"id":"p42","kind":"heading","text":"第四课：真正有价值的是定位错误发生在哪一层","raw":"## 第四课：真正有价值的是定位错误发生在哪一层"},{"id":"p43","kind":"paragraph","text":"这次实践中有一个让我印象很深的例子。","raw":"这次实践中有一个让我印象很深的例子。"},{"id":"p44","kind":"paragraph","text":"某篇报告引用了一条旧新闻中的历史营收数字，却把它写成了最近一年的数据。顺着整条链路检查后，发现：正确的最新年报其实已经在证据池里，错误的旧新闻片段也在。系统不是没有找到答案，而是在两个答案之间选择了错误的那个。","raw":"某篇报告引用了一条旧新闻中的历史营收数字，却把它写成了最近一年的数据。顺着整条链路检查后，发现：正确的最新年报其实已经在证据池里，错误的旧新闻片段也在。系统不是没有找到答案，而是在两个答案之间选择了错误的那个。"},{"id":"p45","kind":"paragraph","text":"这不是检索失败，而是取信失败。","raw":"**这不是检索失败，而是取信失败。**"},{"id":"p46","kind":"paragraph","text":"更早的一步中，摘要模型还给一条原本没有年份的新闻片段补上了错误年份。到了写作阶段，错误已经被包装成了一条看起来完整的证据。","raw":"更早的一步中，摘要模型还给一条原本没有年份的新闻片段补上了错误年份。到了写作阶段，错误已经被包装成了一条看起来完整的证据。"},{"id":"p47","kind":"paragraph","text":"我尝试过在最终报告阶段增加规则，拦截这类数字，但每一种规则都会误伤到大量正常内容。最后才意识到，问题是发生在了更上游：年报经过自然语言摘要后，原本清晰的「指标、报告期、数值」关系丢失了。","raw":"我尝试过在最终报告阶段增加规则，拦截这类数字，但每一种规则都会误伤到大量正常内容。最后才意识到，问题是发生在了更上游：年报经过自然语言摘要后，原本清晰的「指标、报告期、数值」关系丢失了。"},{"id":"p48","kind":"paragraph","text":"所以更合理的方案，不是继续在最后增加补丁，而是在处理年报时保留结构化信息和原文位置。（这一点也印证了之前在从 PDF 到向量检索的代码拆解里的判断：切分阶段真正的产出是元数据，不是文本块。）","raw":"所以更合理的方案，不是继续在最后增加补丁，而是在处理年报时保留结构化信息和原文位置。（这一点也印证了之前在[从 PDF 到向量检索的代码拆解](/writing/pdf-to-vector-retrieval)里的判断：切分阶段真正的产出是元数据，不是文本块。）"},{"id":"p49","kind":"paragraph","text":"这个例子改变了我对 AI 工作流的理解。以前我很关注最后一个写作模型够不够强；现在我更关注信息在哪一步开始丢失。","raw":"这个例子改变了我对 AI 工作流的理解。以前我很关注最后一个写作模型够不够强；现在我更关注信息在哪一步开始丢失。"},{"id":"p50","kind":"paragraph","text":"越早发生的信息损坏，越不应该依赖下游模型把它猜回来。","raw":"**越早发生的信息损坏，越不应该依赖下游模型把它猜回来。**"},{"id":"p51","kind":"heading","text":"第五课：评测驱动不等于追求一个更高的总分","raw":"## 第五课：评测驱动不等于追求一个更高的总分"},{"id":"p52","kind":"paragraph","text":"做了一段时间后，我发现自己很容易陷入「让指标上涨」的心态。","raw":"做了一段时间后，我发现自己很容易陷入「让指标上涨」的心态。"},{"id":"p53","kind":"paragraph","text":"但不同指标可能互相冲突：","raw":"但不同指标可能互相冲突："},{"id":"p54","kind":"list","text":"- 写得更多，事实覆盖可能提高，错误数字也可能增加\n- 引用更多，不代表引用真的支持结论\n- 结构更完整，可能只是报告更长\n- 规则检查得更严格，可能同时制造更多误报","raw":"- 写得更多，事实覆盖可能提高，错误数字也可能增加\n- 引用更多，不代表引用真的支持结论\n- 结构更完整，可能只是报告更长\n- 规则检查得更严格，可能同时制造更多误报"},{"id":"p55","kind":"paragraph","text":"如果把所有东西压缩成一个总分，就会很容易为了优化分数而优化分数。","raw":"如果把所有东西压缩成一个总分，就会很容易为了优化分数而优化分数。"},{"id":"p56","kind":"paragraph","text":"要把评测看成一组仪表，而不是一个排行榜。一次修改之后，需要去弄明白的是：","raw":"要把评测看成一组仪表，而不是一个排行榜。一次修改之后，需要去弄明白的是："},{"id":"p57","kind":"list","text":"- 它改变了哪一层？\n- 它解决了原本针对的问题吗？\n- 有没有让其他地方变差？\n- 这个变化是否足够大，能够排除随机波动？\n- 评测器是否有能力判断这件事？","raw":"- 它改变了哪一层？\n- 它解决了原本针对的问题吗？\n- 有没有让其他地方变差？\n- 这个变化是否足够大，能够排除随机波动？\n- 评测器是否有能力判断这件事？"},{"id":"p58","kind":"paragraph","text":"有些改动只修复了一个很具体的问题，整体分数几乎不动，但仍然值得保留；有些改动让总分提高，却只是让报告写了更多容易命中的头部数字，并没有提高研究深度。","raw":"有些改动只修复了一个很具体的问题，整体分数几乎不动，但仍然值得保留；有些改动让总分提高，却只是让报告写了更多容易命中的头部数字，并没有提高研究深度。"},{"id":"p59","kind":"paragraph","text":"所以，评测驱动并不是「每次提交都要涨分」，而是「每次提交都尽量有可以被证伪的理由」。","raw":"所以，评测驱动并不是「每次提交都要涨分」，而是「每次提交都尽量有可以被证伪的理由」。"},{"id":"p60","kind":"heading","text":"最后","raw":"## 最后"},{"id":"p61","kind":"paragraph","text":"在实践之前，我以为评测驱动就是：准备一批问题，计算几个分数，然后用分数指导优化。","raw":"在实践之前，我以为评测驱动就是：准备一批问题，计算几个分数，然后用分数指导优化。"},{"id":"p62","kind":"paragraph","text":"真正做过一次之后，我觉得它更像是一种约束自己思考的方式。","raw":"真正做过一次之后，我觉得它更像是一种约束自己思考的方式。"},{"id":"p63","kind":"paragraph","text":"它要求我区分事实和直觉，区分相关和因果，区分「没有发现问题」和「有能力证明没有问题」。它也要求我面对一些不太舒服的结果：精心设计的方案可能无效，指标上涨可能只是噪声，甚至负责评判模型的评测器本身可能才是错的。","raw":"它要求我区分事实和直觉，区分相关和因果，区分「没有发现问题」和「有能力证明没有问题」。它也要求我面对一些不太舒服的结果：精心设计的方案可能无效，指标上涨可能只是噪声，甚至负责评判模型的评测器本身可能才是错的。"},{"id":"p64","kind":"paragraph","text":"评测驱动可能不会让每次决策都变得确定。但它能让不确定性变得更可见，让试错更有积累。","raw":"评测驱动可能不会让每次决策都变得确定。但它能让不确定性变得更可见，让试错更有积累。"},{"id":"p65","kind":"quote","text":"从一个真实失败出发，判断它发生在哪一层，提出一个可以被推翻的假设，做尽可能小的改动，在相对固定的条件下复跑，然后决定保留、回退，或者承认暂时无法判断。","raw":"> 从一个真实失败出发，判断它发生在哪一层，提出一个可以被推翻的假设，做尽可能小的改动，在相对固定的条件下复跑，然后决定保留、回退，或者承认暂时无法判断。"},{"id":"p66","kind":"paragraph","text":"它不是让迭代过程从此变得精确，而是让我不再轻易地凭感觉做事。","raw":"它不是让迭代过程从此变得精确，而是让我不再轻易地凭感觉做事。"}],"authored_claims":[{"id":"score-is-not-conclusion","text":"有分数，不等于有结论。用相同代码、相同问题重跑，结果本身就会波动——搜索结果会变、网页有时抓不到、模型对相关性的判断也不稳定。评测不是简单判断通过或失败，还要先理解自己的噪声有多大。","stance":"judgment","confidence":"high","supersedes":null,"note":null,"formed_at":"2026-08-10"},{"id":"eval-falsifies-your-own-plan","text":"评测不只会否定模型，也会否定你自己的方案。把证据数量扩大一倍后，事实覆盖没提升，数字准确性反而下降——更多证据不等于更多有效信息，不同报告期和口径混在一起反而制造了错误。","stance":"fact","confidence":"high","supersedes":null,"note":null,"formed_at":"2026-08-10"},{"id":"evaluators-make-mistakes-too","text":"评测器本身也会犯错，而且越符合预期的评测结果越容易未经检查就被相信。规则评测器曾把年份当金额、把分部营收和总营收比较；小盘股「质量更差」这个符合直觉的结论，复核后发现差异几乎全来自评测器没见过的表达方式。","stance":"fact","confidence":"high","supersedes":null,"note":null,"formed_at":"2026-08-10"},{"id":"locate-the-layer-not-the-symptom","text":"真正有价值的是定位错误发生在哪一层。报告把旧新闻的历史营收写成最新数据，正确年报其实就在证据池里——这不是检索失败，而是取信失败。越早发生的信息损坏，越不应该依赖下游模型把它猜回来。","stance":"judgment","confidence":"high","supersedes":null,"note":null,"formed_at":"2026-08-10"},{"id":"eval-driven-means-falsifiable-reasons","text":"评测驱动并不是「每次提交都要涨分」，而是「每次提交都尽量有可以被证伪的理由」。要把评测看成一组仪表，而不是一个排行榜——压缩成单一总分，就很容易为了优化分数而优化分数。","stance":"judgment","confidence":"high","supersedes":null,"note":null,"formed_at":"2026-08-10"}],"claim_ids":["score-is-not-conclusion","eval-falsifies-your-own-plan","evaluators-make-mistakes-too","locate-the-layer-not-the-symptom","eval-driven-means-falsifiable-reasons"],"revision":"094db3a230822c8287e1817f8d2e8acf4b20bdeb8aa5856c23de7ad5f301ecd0"}