GitHub工程师分享在真实secret扫描场景中评估LLM的踩坑经验,包括评估指标设计、prompt稳定性测试与模型选型思路。
语言模型可以在干净的基准测试中表现良好,但在生产环境中真正重要的场景上仍可能遇到困难。
基准测试和精选数据集在构建基于 LLM 的系统原型时很有用。它们帮助团队比较模型、测试初始 prompt,并判断一个想法在技术层面是否可行。
但随着系统越来越接近生产环境,评估问题也在发生变化。
实际输入往往模糊不清。标签可能不一致。重要的上下文可能缺失或被截断。评估集可能无法反映生产环境的分布。很少出现在基准测试中的边缘情况可能成为常见的失败来源。即使离线指标有所改善,这些结果也可能无法干净地转化为生产环境的行为。
在评估一个旨在减少 GitHub secret scanning 误报的系统时,我们遇到了这些挑战。
Secret scanning 识别可能被提交到仓库中的凭证(如 token 和密钥)。由于某些候选字符串看起来像 secrets,但实际上并不代表真正的凭证,开发者可能会浪费时间调查不需要修复的告警。
我们需要的不是确定 LLM 能否正确分类字符串,而是理解该系统能否在保持足够召回率以确保安全工作流安全的同时减少干扰告警。
在这篇文章中,我们分享了帮助我们从有前景的原型结果过渡到生产环境的实践。这些经验教训广泛适用于代码分析、开发工具、安全、数据分析等依赖 LLM 的生产工作流。

当 LLM 系统表现不及预期时,第一反应往往是调整其技术组件。
团队可能会重写 prompt、添加上下文、引入另一个推理步骤、调整周围的管道,或切换模型。在进行任何这些更改之前,他们应该明确评估旨在支持的产品决策。
对于我们的 secret scanning 工作,我们提出了以下问题:
该系统能否在保持足够召回率以确保生产安全工作流安全的同时减少误报?
要回答这个问题,团队必须决定哪些错误是可接受的,哪些指标应该驱动产品决策,以及哪些护栏必须保持在定义的阈值内。
在 secret scanning 中,错误地压制一个真实凭证可能比让开发者审查额外的告警更具后果性。因此,我们没有将精确率和召回率视为同等可互换的指标。
我们的主要目标是减少误报并提高精确率。召回率作为安全约束:只有当任何下降保持在预定义的可接受范围内时,实验才能推进。这为我们提供了评估权衡的明确方法。我们选择了在满足召回率要求并达到运营护栏的前提下,实现最强误报减少的配置。
我们将评估标准组织为三个层级:
这是我们试图改善的用户利益衡量标准:
误报减少
这防止了明显的改进引入不可接受的安全风险:
运营护栏
这些决定了结果是否实际可部署:
生产兼容性
这种区分防止我们将每个指标视为可互换的。减少误报但显著降低召回率的更改并非自动就是改进。提高质量但使系统变慢、变贵或难以集成的更改也不是改进。
考虑两个假设的实验结果:
| 实验 | 精确率 | 召回率 | 延迟 | 决策 |
|---|---|---|---|---|
| 实验 A | 大幅提升 | 低于安全护栏 | 可接受 | 不推进 |
| 实验 B | 中等提升 | 仍在护栏内 | 可接受 | 继续测试 |
如果孤立地看精确率,实验 A 可能看起来更有说服力。实验 B 更符合产品目标,因为它在不影响召回率护栏的前提下改善了开发者体验。
在评估 LLM 系统之前,先决定什么对用户来说是成功,以及系统必须尊重哪些护栏。我们希望生成支持产品决策的证据。
基于 LLM 的系统在首次成功评估后仍会持续变化,因此评估不应是一次性的活动。团队会修改 prompt、采用新模型、改变输入和上下文的构建方式,并优化周围的业务逻辑。
其中任何更改都可能改进系统、引入回归,或导致意外的行为变化。
因此,我们将离线评估等同于端到端集成测试。每当对 prompt、模型、输入构建或更广泛的系统逻辑进行有意义的更改时,我们都会重新运行评估。
评估还需要足够的可重复性,以便每个新结果都能与已知基准进行比较。每次运行我们都记录 prompt 版本、模型版本、数据集版本和系统配置。
这使得回答以下问题成为可能:
新的 prompt 是否在不影响召回率的前提下提升了精确率?
模型升级是在整个数据集上都有帮助,还是仅在某些类别内?
对输入或上下文的更改是修复了一种错误模式,还是同时引入了另一种?
对周围逻辑的更改是持续改善了结果,还是仅仅将错误出现的位置发生了转移?
如果没有这种纪律,团队很容易比较在不同条件下生成的结果,并将改进归因于错误的更改。
一次只改变一个主要变量
仅靠可重复性是不够的。实验还需要设计得使结果的原因清晰。
我们一次只改变一个主要变量,并将每次运行与已知基准进行比较。例如,我们分别评估 prompt 修订和模型升级,然后才一起测试。
这很重要,因为即使微小的 prompt 更改也可能改变模型行为,而模型升级可能影响质量、成本、延迟或输出一致性。如果两个变量在同一实验中同时改变,我们就不会知道是哪一个导致了改进或回归。
我们将 prompt 和评估配置视为代码进行管理。我们对它们进行版本控制、记录更改内容、保持先前配置可复现,并使回滚成为可能。
| Run ID | Prompt 版本 | 模型版本 | 精确率 | 召回率 | 延迟 | 备注 |
|---|---|---|---|---|---|---|
| R-001 | v1 | Model A | 0.71 | 0.78 | 1.2s | 基准 |
| R-002 | v2 | Model A | 0.75 | 0.77 | 1.2s | 仅 prompt 变更 |
| R-003 | v1 | Model B | 0.74 | 0.80 | 1.0s | 仅模型变更 |
上表中评估运行跟踪表里的值为假设值,仅用于说明如何跟踪和比较评估运行。
定期测试模型升级
当 LLM 系统表现不佳时,开发者通常会向 prompt 添加更多指令。有时这有帮助,但并非总是如此。例如,prompt 可能背负了来自模型本身的复杂性。
更强的模型可能用更简单的 prompt 就能表现得比旧模型配合大量调优更好。更简单的 prompt 也更容易理解、测试和维护。
模型升级仍需仔细评估。新模型可能在一个类别改善性能,同时在其他类别引入回归。它还可能影响成本、延迟、输出格式化或与现有管道的兼容性。
评估过程应该足够廉价和可重复,使测试新模型成为常规操作。对 prompt、模型或管道的任何有意义的更改都应在进入生产环境前经过离线评估。
离线评估只有在类似于系统将在生产环境中执行的任务时才有价值。
在 secret scanning 工作流中,模型很少只评估一个干净、孤立的值。它可能需要评估特定候选项以及周围代码和其他可能相关、不完整或潜在分散注意力的信息。这些信息的呈现方式差异会实质性影响结果。
因此,我们的离线评估需要保留生产任务的重要特征,包括:
被评估的候选项
模型可用的周围上下文
相关支持信息
输入格式化和约束的方式
模型周围的更广泛系统逻辑
即便微小的差异也可能扭曲结果。更干净的数据集可能排除了歧义案例,提供了更完整的上下文,或去除了可能分散模型注意力的相邻值。
看一个简化的例子:
example_token = "sample_value_for_documentation"
production_api_key = get_secret_from_environment()
candidate_value = "flagged_value"
假设 candidate_value 是系统应该评估的值。但模型可能转而关注 example_token,因为它的变量名看起来更与安全相关,从而对错误的值产生了看似合理的解释。
这类失败很容易被忽视,因为评估样本只包含一个明显的候选对象时不易察觉。它浮出水面是因为离线评估保留了一些真实 secret 扫描工作流中存在的歧义和干扰因素。
离线流水线越接近生产流水线,评估就越有价值。当两者存在差异时,良好的离线分数可能只是反映了一个比实际部署场景更简单的问题。
生产数据可以使评估更具代表性,但它的标签往往捕获的是工作流结果,而非可靠的 ground truth。例如,一个被忽略或已解决的 secret 扫描警报不一定代表误报。
开发者解决一个警报可能是因为:
这些结果在产品数据中可能看起来相似,却代表了不同的 ground truth 状态。
在使用生产标签之前,问自己:
对于重要或模糊的子集,你可能需要完成人工审查。你不需要消除每一个不完美的标签,但需要确保评估数据足够准确,以支持所做出的决策。
有代表性的生产数据可能在开发早期就十分有限、敏感或无法获取。合成样本、学术基准测试和开放数据集可以帮助开发者启动评估并扩展覆盖范围,但这些样本应该作为补充,而不是取代类生产数据。
也就是说,合成样本可以极大地帮助填补那些稀有或难以收集的测试用例的空白,例如歧义输入、缺失上下文、不同寻常的格式以及代表性不足的失败模式。例如,一串凭证字符串列表可以测试模型是否识别常见格式,但它无法完全评估模型如何在真实代码中对候选对象进行推理。
我们调整了外部样本来匹配我们的任务,并审查了与产品定义不一致的标签。我们还使用现实istic 的失败模式来创建针对性的合成案例,涉及相邻的类凭证值、测试代码、占位符、间接引用和缺失上下文。
聚合指标告诉你系统整体是否改善了。错误分析告诉你下一步该改什么。
更高的精确率分数并不能揭示剩余错误是来自歧义输入、糟糕的提示词框架、缺失上下文、噪声标签,还是来自狭窄的数据集。
要理解这些问题,需要检查失败案例。
我们审查了误报和漏报的样本,并按其可能来源分组:模型、提示词、输入、流水线、数据集或标签。反复出现的问题包括前面已经讨论过的一些,例如推理了错误的候选对象、缺失上下文,以及与评估定义不匹配的标签。
每个类别都指向不同的应对方式。推理了错误的值指向提示词或输入框架问题,缺失证据指向上下文构建,而错误的标签则需要数据清理。反复出现的领域特定歧义可能表明需要更清晰的产品策略或专门的评估类别。
手动审查数十或数百个样本需要时间,但这通常能带来更快的进展。一旦反复出现的失败模式清晰了,团队就可以进行有针对性的修改,并衡量它是否解决了问题。
对于每个错误,一个有用的问题是:这次失败是来自模型、提示词、输入、流水线、数据集,还是标签?
这种分类将一个模糊的质量问题转化为具体的工程任务。
手动审查每一个评估样本可能无法扩展。LLM-as-judge 可以通过以下方式减轻负担:对明确案例进行分类、识别可能被错误标注的样本、并优先将歧义案例交给人工审查。因为评判模型也可能犯错或因为错误的原因与其他模型达成一致,其输出应该被视为另一种预测,而非 ground truth。
更安全的模式是使用评判模型进行分诊:
以这种方式使用,评判模型将人工注意力集中在最有可能改变结果的案例上。

我们的目标是在保持敏感安全工作流召回率的同时减少误报。离线评估为我们提供了一种受控方式,可以在开始在线实验之前比较提示词、模型、输入和流水线的变化。
通过反复评估和有针对性的错误分析,我们在保持召回率符合既定护栏的同时,在评估的离线数据集上达到了误报减少 95% 的效果。更重要的是,我们理解了结果是如何产生的:评估更紧密地反映了生产任务,变更是在可重现的基准上测量的,剩余的失败模式已被记录在案。
离线评估并不能证明系统在每个生产场景中的行为。它提供了足够的结构化证据来证明以明确理解的风险和护栏进入在线实验是合理的。
清单:将 LLM 系统推向生产之前
使用此清单来评估你的评估是否提供了足够的证据来推动系统前进。逐节梳理,确认目标、数据、实验和剩余的生产风险已被清晰理解。
错误分析与生产就绪
在信任之前先评估
随着基于 LLM 的系统进入生产,评估应该成为常规工程工作流的一部分。强有力的离线评估可以显示产品目标在代表性条件下是否已达到、不确定性在哪里、以及系统是否准备好进行受控的生产推广。
生产中的不确定性是不可避免的。评估使其可见、可衡量和可管理。
探索 secret 扫描文档 >
Mariko 是 Microsoft 的一位首席应用科学家,负责领导网络安全运营的 AI 智能体工作流开发。她目前的兴趣集中在基于 LLM 的系统、AI 智能体工作流,以及将前沿 AI 研究应用于现实世界的产品和运营。
Zixiao 是微软的一位高级应用科学家,工作重点是密钥检测和智能体安全系统,重点是将研究进展转化为大规模的实际安全能力。他还从事 LLM 微调以及 token 高效 AI 系统的研究,致力于提高基础模型的效率、可扩展性和实际部署能力。
GitHub Copilot 新手入门:管理工作
如果你同时在处理多个 Copilot 会话,可以使用"My work"窗格来跟踪正在进行、已完成和接下来的工作。
画布如何让智能体工作流变得可见、可控且成本高效
Chat 适合表达意图,但智能体工作在滚动中容易丢失。以下是我如何在智能体工作流中使用画布——以及为什么你的工作流也值得一个画布。
如何借助智能体应用将你的软件交付工作流引入 GitHub
了解四个 GitHub 智能体应用如何帮助你跨 SDLC 范围、安全、推广和发布功能——全部在 GitHub 内完成,无需离开。