AI代理总抓不住真正瓶颈?JetBrains Rider现在能修复了
一个值得思考的场景:你的应用卡死了十秒钟,然后你问 AI 代理出了什么问题。它实际做了什么?长期以来,诚实的回答是:它翻遍你的代码,然后胡乱猜测。
分析器工具拍摄的快照是运行时证据。它确切知道 CPU 去了哪里。但一个没有分析工具访问权限的代理无法读取它。所以它只能做唯一能做的事:扫描项目,找到一些看起来可疑的低效点,然后自信地把它们当作瓶颈呈现。有时它会碰巧猜对。但在真正的死机场景下,通常不会。
我们一直在 Rider 中构建解决这个问题的功能:一个基于 dotTrace 的分析技能,供 AI Assistant 中的代理使用,名为 dottrace-analyze。思路非常直接。你把已经用 dotTrace(通过独立分析器、命令行工具或 Rider 内的 dotTrace)捕获的 .dtp 快照交给代理,它不再漫游你的源代码,而是先读取分析数据。它找到时间实际耗费在哪里,顺着热点路径回溯到你的代码,然后解释什么慢了、为什么慢,并给出接下来该看什么的建议。
我们跑了评估。为了避免评分变成个人主观判断,每个答案都对照一个已知的根本原因,使用固定的 LLM-as-judge 标准进行评分:代理是否识别了主要热点、解释了机制、避免了误导性绕路,并提出了基于证据的修复建议?结果超出预期,所以我们不妨从最戏剧性的案例开始:
dotTrace 支持的性能分析评估
当代理能读取运行时证据时,准确率上升,猜测减少。
基于 dotTrace 的技能在更广泛的评估批次中改善了结果,而在对代理轨迹的近距离观察中也显示了相同模式。
平均准确率分数:有技能 8.15 vs 基线 4.71
完美根本原因匹配数:48/80 vs 基线 20/80
关闭场景评估中正确目标率:仅源码 0/10 → 加分析器 10/10
轨迹评估中平均时间:无技能 373 秒 → 有技能 206 秒
分数根据已知参考根本原因判定;轨迹数据显示代理如何得出答案。
案例研究:没有 dotTrace 代理发现不了的 UI 死机
我们的一个测试场景是早期版本的 Avalonia,它在关闭时会挂起。这个问题甚至两年前渗透进了 Rider 本身(见 YouTrack 问题),这说明了来自流行开源项目的性能退化是多么容易影响你的应用。
为澄清我们的方法:我们故意测试了修复之前的一个 Avalonia 版本(修复见 AvaloniaUI/Avalonia#16633)。使用一个已知且已解决的 bug 对我们至关重要,因为它为评估提供了清晰的参考答案。
我们将同一个代理对同一个问题运行了十次(带技能)和十次(不带技能),然后让一个 LLM 评判员根据已知根本原因对每个诊断按 0 到 10 分评分。
不带技能时,代理平均得分 1.6/10。它去翻渲染代码,列出一些通用建议,从未触及真正问题。
带技能时,它十次运行每次都得 10/10。
Avalonia 长线死机:技能将失误转为完美诊断
相同代理运行十次,根据已知根本原因评判。
无分析技能:1.6/10 宽泛的渲染猜测
带 dotTrace 技能:10/10 十次全部完美
热点路径:UI 线程布局→ 文本格式化和 Unicode 双向处理。
CPU 线索:约 88% 的 CPU 占用位于双向规则处理下方的切片索引访问。
修复方案:在规则循环之前将运行物化为连续的 Span<T>。
这就是“这段代码看起来可疑”和“快照显示死机在这里”之间的区别。
结果不是“稍微好一点”:代理从可靠地迷失方向变为可靠地正确,且没有方差。
而且它发现的东西是那种单靠读代码很难发现的(即使你有几小时空闲)。死机并不在任何一个明显的位置。它来自文本布局路径深处的一个逐字符操作,单个操作并不昂贵,但执行次数太多,消耗了大部分 CPU。这种代价只有在你能看到时间实际花在哪里时才会显现。代理顺着快照直接找到了它,解释了为什么如此昂贵,并指出了可以修复的更改。
完整基准测试:八个场景,80 次运行
上述 Avalonia 场景只是我们评估的一部分。在检查了该案例的重复运行后,我们将批次扩大到来自不同项目的八个 .NET 性能调查场景,并比较了同一代理在有无分析器访问权限下的表现。以下是技能在每个场景下对平均准确率分数的影响(满分为 10):
批次结果:更有用的诊断,更多完美根本原因匹配
在 80 次运行中,该技能提高了平均质量和一致性。
平均准确率分数:8.15 基线:4.71
得分 8+ 的运行数:59/80 基线:29/80
完美根本原因匹配数:48/80 基线:20/80
最大的提升出现在答案真正存在于运行时证据中的场景。持平或略微负面的案例也很有用:它们显示了产品应避免调用较重分析工作流的场景。
在所有 80 次运行中,平均准确率分数从 4.71 升至 8.15。得分 8 或以上的运行数大致翻倍,从 29 增加到 59。精确击中根本原因(满分 10)的运行数翻了一倍多,从 20 增加到 48。
关于表中两点我们想坦诚说明。
第一点是技能发挥价值的地方:基线毫无希望的那些场景。任何答案真正存在于运行时中的地方(Avalonia 死机、Cyclops 工作负载),基线得分在 1 到 2 之间,而技能将其拉到 9 或 10。代理不再将注意力分散到通用优化想法上,而是牢牢锚定在实际上慢的东西上。
第二点是表格底部,我们故意保留它。game-of-life、checkers-copy 和 checkers-update 在没有分析器工具时已经处理得很好,而在两个 checkers 案例中,技能使分数略微下降了零点几分。教训不是技能损害了结果,而是有些任务不需要它。有时,当快速查看代码就能解决问题时,调用完整的分析器工作流只是浪费 token。
实际成本是多少
我们像追踪准确率一样仔细追踪了成本,因为一个产生更好答案但代价不合理的技能我们是不会发布的。先讲直接部分:读取快照是实实在在的工作。代理加载分析数据、遍历调用树、在开始推理之前将证据关联回你的源代码。在上述 80 次运行批次中,这体现在账单上:不带技能时每次运行成本约为 1.91 美元,带技能时约为 2.61 美元。批次总成本不带技能约为 153 美元,带技能约为 209 美元。考虑到诊断改进幅度,我们认为这是个不错的交易,但确实是真实增加,我们宁愿由我们告诉你。
不过还有第二个效果,方向相反。在另一个 Avalonia 测试案例中(一个关闭缓慢的应用),不带技能的代理从未找到真正原因。十次运行中,它不断构建看似合理但错误的理论,广泛搜索并沿途读取一个又一个文件,每次都得 0 分。带技能后,它先测量,顺着分析器直接找到负责的代码路径,每次都得 10 分。跳过所有漫游还使运行更便宜、更快:每次运行 2.58 美元而不是 3.74 美元,206 秒而不是 373 秒。
所以公平的总结是:技能改变了钱花在哪里。它花更多时间读取证据,花更少时间探索死胡同。有时净成本更高,有时更低,但两种情况下,你都在为一个基于应用实际行为的答案付费,我们认为这值得。
成本:更多证据,更少错误转弯
分析器分析有成本,但也能减少广泛且无结果的代码搜索。
范围:80 次运行评估批次 上述所有场景
无技能:1.91 美元/次,总计 153 美元
有技能:2.61 美元/次,总计 209 美元
每次运行约多 0.70 美元
快照分析增加了每次运行成本,但准确率大幅提升。
范围:Avalonia 关闭评估 每臂 10 次运行
无技能:3.74 美元/次,平均 373 秒
有技能:2.58 美元/次,平均 206 秒
这里更便宜、更快
分析器证据减少了漫游,直接将代理引向负责的代码路径。
该技能默认并不更便宜。它改变了工作发生的地方:更多证据读取,更少死胡同探索。
你在 Rider 中会看到什么
工作流非常简单:用 dotTrace 捕获一个 .dtp 快照——无论是从 Rider 内部、从 dotTrace 独立版 还是用 dotTrace 命令行工具。然后在 AI Assistant 工具窗口中选择你的代理,通过在提示中引用快照目录来调查该快照。
底层它会加载 dottrace-analyze 技能,并使用 dotTrace SDK 读取分析数据;返回的是一份聚焦的报告:
- 主要瓶颈的简短摘要;
- 占用运行时的方法、源代码位置和调用路径;
- 用开发者语言表述的根本原因,而不仅仅是方法名;
- 接下来该看什么的建议。
对于更深入的调查,它可以将其渲染成一份简洁的 HTML 报告,你可以在标签页中打开并与团队分享。性能工作通常是协作性的,当不止一个开发人员解决问题时,清晰的工件非常有用。
代理搜索轨迹的变化
第二次评估中最强的信号是轨迹:代理通过工具和文件的实际路径。无技能运行失败并不是因为懒惰或语无伦次。它们广泛搜索,发现了一个看似真实的计时器问题,并在错误的子系统周围构建了一个自信的解释。有技能运行从测量开始,所以在开始读源码之前,搜索空间已经围绕热点路径收缩。
代表性轨迹:广泛搜索 vs 分析器优先路径
相同关闭任务,相同模型,相同代码库。区别在于第一条有用的证据。
无技能:19 次调用
2 次子代理搜索,13 次读取,2 次 glob,2 次 grep。没有测量,只有推理。
- 探索关闭路径——分散到 dispose、shutdown、dispatcher 和 timer 代码。
- 读取渲染和 dispatcher 文件——遍历 MediaContext、render timers、application lifetime 和 dispatcher 循环。
- 搜索阻塞模式——寻找 waits、joins、sleeps 和 render-thread 模式。
- 锚定在 Win32DispatcherImpl.cs——注意到
UpdateTimer中的Now - dueTime,并将其视为决定性线索。 - 证实计时器理论——读取 dispatcher 接口和队列来支持一个看似合理但错误的诊断。
错误目标:所有 10 次无技能运行都收敛到了错误区域。答案听起来有根有据,但从未触及 teardown 热点。
带 dotTrace 技能:10 次调用
1 次技能调用,5 次分析器调用,1 次 grep,1 次 glob,2 次读取。先测量,再读取。
- 调用
dottrace-analyze——进入结构化快照工作流。 - 读取快照和时间线——发现 7.3 秒捕获,一个核心被占用约 5.5 秒,GC 可忽略。
- 检查运行调用树——最大的自耗叶子是
List<T>.Remove,通过Classes.RemoveListener到达。 - 跳转到相关源代码——grep
RemoveListener,读取Classes.cs,然后定位SafeEnumerableList.cs。 - 确认根本原因——深入递归 detach,识别 O(n²) 的监听器移除。
正确目标:所有 10 次有技能运行都指出了确切的根本原因。源代码阅读确认了测量证据,而不是凭空编造怀疑名单。
在这个关闭评估中,有技能的那一队平均完成得更快、更便宜:206 秒和每次 2.58 美元,相比之下无技能为 373 秒和 3.74 美元。
证据胜于猜测
整个结果可以用一个对比来总结。没有快照时,代理最多能提供“这里有些可能慢的代码异味”。有了快照,代理可以说“这个快照显示 88% 的时间花在了这里,原因是……”第二句话就是全部意义所在。
猜测 vs 知晓
纯代码代理 vs 分析器代理决定先看哪里的并排对比。
纯代码代理
- 广泛扫描源码
- 找到看起来可能慢的代码
- 在没有运行时证据的情况下对问题排序
- 可能错过实际瓶颈
分析器代理 - 先读取快照
- 顺着热点路径进入源码
- 区分症状和原因
- 推荐基于证据的修复
性能工作有一个大多数编码任务没有的苛刻要求:答案必须匹配程序实际做了什么,而不是它看起来可能会做什么。我们评估中得分高的运行都有相同的模式:它们不仅命名了方法,还解释了调用路径,量化了热点区域,区分了根本原因和症状,并提出了直接来自分析数据的修复方案。这就是专家调查的形状,并且只有当代理从专家会使用的相同证据开始时才可能实现。
dotTrace 已经知道运行时发生了什么。AI Assistant 已经可以将证据转化为解释和下一步行动。该技能就是两者之间的桥梁,而在那些最关键的案例中,它正是区分“猜测的代理”和“知晓的代理”的关键。
现已在 Rider 2026.2 EAP 8 中提供
关于许可的说明: 在 Rider 2026.2 早期访问计划期间,你可以在 EAP 构建中免费试用此工作流。对于正式产品许可,此功能的性能分析部分依赖于 dotTrace。Rider 中的 dotTrace 和 dotMemory 插件可通过 dotUltimate 或 All Products Pack 订阅获得;仅 Rider 订阅不包含 dotTrace 分析功能。
这仍然是早期访问计划中的实验性实现,我们还有很多工作要做。因此你的反馈极其重要。请告诉我们你认为该报告有多有用,或者哪些地方可能不完全可靠。下载最新的公开构建来尝试一下。
下载 Rider EAP