
把 LLM 接进 GitHub 秘密扫描流程最难的不是写调用脚本也不是让模型识别一两个 token 样本而是在生产前证明它真的能降低误报和漏报而不是把一个 Demo 效果放大到全量仓库。这个问题我最近在整理内部评估方案时又踩了一遍下面按实际落地顺序分享一组经验。适合正在做密钥泄露防护、维护 GitHub 仓库扫描链路的安全工程师和 DevOps。GitHub 原生 Secret Scanning 解决的是“代码仓库里有没有已知格式的密钥被提交”这个基础问题。到了真实生产环境你很快会遇到新的麻烦规则能命中格式但不能判断上下文一个长得很像 AWS Access Key 的测试占位符会触发告警一个被拆行、带注释、藏在配置文件里的真实口令反而可能漏掉。于是很多人想到用 LLM 做二次研判。这个方向可行但在生产前有一个绕不过去的阶段评估。不是跑通几个样例就完事而是要回答清楚漏多少、误多少、花多少钱、跑多久、结果能不能复现。下面直接用评估视角拆解整个流程。1. 用 LLM 做秘密扫描先想清楚它在链路里站在哪1.1 原生扫描擅长“找形态”不擅长“读上下文”GitHub Secret Scanning 靠的是模式匹配和规则库。它能高效识别 GitHub token、云厂商 access key、私钥特征块等固定形态。优点很直接可解释、速度快、成本低。短板也很明显。它很难判断一个字符串到底是不是有效凭据也不容易识别经过编码、拼接、拆行或藏在注释里的变体。真实仓库里大量告警来自示例代码、文档、测试数据。你让规则全量扫结果往往是告警列表很长真正需要处理的比例不高。所以不要一上来否定规则扫描。规则层是必要的它负责把海量代码先过滤一遍让问题集中成“候选告警是否正确”。这比在全量代码里让 LLM 判断要可控得多。1.2 LLM 更合适做告警二次研判而不是全量扫描替代LLM 的价值在语义判断。给一个代码片段它能结合上下文判断这是示例占位符还是疑似真实密钥这条 URL 参数是不是带明文口令这个 private key 片段是真实的还是 mock 的。这种能力正好补规则的短板。但是让 LLM 直接全量扫描仓库并不现实。成本、时延、token 消耗都可能失控。更稳的链路是规则扫描召回候选。LLM 对候选做精排。判断为高风险的结果再进人工复核。这也决定了评估方式。先用规则筛掉明显无关内容再评估 LLM 在候选集合上的表现。如果候选集合本身质量很差LLM 再强也只能在噪音里找信号评估指标会失真。1.3 生产前评估和 Demo 验证要回答的问题完全不同演示环境只要证明“有 secret 时它能识别”。生产评估要回答的问题复杂得多误报率高不高会不会把告警体系淹没。漏报率能否接受尤其是私钥、云厂商密钥这类高风险类型。一个仓库扫描完要多久。跑一个月要消耗多少 token。模型 API 升级后结果会不会突然变化。代码片段传给外部模型是否有隐私和合规问题。这些不是 30 条样例能回答的。必须用贴近生产分布的数据集和可复现的评估流程验证。还有一个容易被忽略的限制如果代码不能离开内网外部模型接口这条路就走不通。这时候只能评估私有化部署模型并额外关注推理精度和显存占用。这个约束要放在最前面确认否则后面指标再好看也落不了地。2. 生产前评估先把责任边界和评估数据定清楚2.1 责任边界原生扫描、规则工具、LLM 各管一段评估之前先把职责拆开。GitHub Secret Scanning 继续负责平台层的自动化扫描和告警聚合。CI 里的规则检查负责提前拦截。LLM 放在规则命中之后作为候选告警的研判层。这样划分有两个好处不需要为每段代码调用模型成本可控各层的失败模式清晰指标不好时能定位问题。这里容易犯的错是真正要评估的是 LLM 研判层而不是从零评估一套全量秘密扫描系统。如果你把所有逻辑混在一起测最后指标差都说不清是哪一层的问题。2.2 评估数据三件套正样本、负样本、干扰样本评估数据不要随便拿几个文件跑。至少要覆盖三类样本正样本模型必须识别为 secret 的片段。例如模拟的 GitHub token、AWS AKIA 开头字符串、带私钥内容的测试文件、配置文件里的明文强口令。生产评估建议用模拟数据避免真实 key 进数据集。负样本长得很像 secret 但不是的片段。例如示例代码里的占位符、已被撤销或过期的测试值、格式正确但明显是教学用途的字符串。干扰样本来自真实仓库上下文的片段。里面混着代码、注释、日志、URL、环境变量。这类样本不是测试模型认不认识 token而是测试它在混杂场景里能不能保持判断。关键在标注。每一条样本至少记录三个字段是否为 secret、secret 类型、难例原因。难例原因可以写“格式疑似但上下文为示例”“secret 被拆成多行”“环境变量引用未赋值”等。这些原因后续会直接告诉你模型错在哪。2.3 数据比例和保留集决定指标可信度数据比例很容易翻车。如果正负样本各一半模型只要倾向输出“是”准确率都不会太难看。但真实环境里规则扫描产生的告警大部分可能并不是有效密钥误报问题往往更严重。所以评估数据集的正负比例要尽量贴近线上真实告警分布。你可以取一段时间内的真实 alerts先人工抽样确定一个基线比例再按比例构造评估数据。还有一点调 prompt 用的数据集和最终打分的评估集必须分开。否则你在同一个测试集上调了几次提示词指标看着一直涨实际是在记住测试集。预留一个全程不看的保留集到最后跑一次才是可信的分数。3. 评估指标不能只看准确率误报和成本才是上线门槛3.1 核心指标精确率、召回率和误报率秘密扫描场景里指标不能只看准确率。准确率在正负样本不均衡时会有很大迷惑性。至少要记录下面几项指标含义在秘密扫描场景里的意义精确率 Precision预测为 secret 中真正是 secret 的比例精确率低说明误报多安全团队会很快麻木开始忽略告警召回率 Recall真正 secret 中被识别出的比例召回率低说明漏报多密钥可能已经进仓库却没人发现误报率误报数量 / 扫描片段总量或每千次告警中的误报比例更贴近告警疲劳直接决定人力消耗F1精确率和召回率的调和平均方便快速对比不同模型版本和 prompt 版本秘密扫描场景里误报率权重往往比召回率更值得关注。漏报可以通过流程弥补比如多工具交叉、历史数据复盘但如果误报太多告警体系会被噪声淹没真的出问题时没人看。反过来如果平台有硬性要求比如行业合规要求对某些泄露零容忍那召回率也不能让步。所以不能只看一个数字要同时记录上面全部指标。另外最好保留模型对每条样本返回的 is_secret、confidence、reason方便逐条分析。3.2 运维指标耗时、并发、Token 消耗和成本生产评估还要加入运维指标。一次评估至少要记录单条样本的调用耗时。每分钟能处理多少片段。总 token 消耗。按测试集规模折算的调用成本。接口调用时的限流、超时、重试次数。本地部署时的显存或内存占用、批量推理吞吐。这里要注意一个细节如果是本地部署模型用 fp16、fp32 还是 bf16 精度可能在结果和速度上都有差异。如果换精度导致评估结果变化必须记录在报告里。否则上线后一旦换精度指标对不上问题会非常难查。运维指标怎么用比如仓库规模有 10 万个文本片段规则扫描后候选告警 5000 个LLM 只需要对 5000 个做研判。那么可以估算 5000 次调用需要多久、多少 token、多少钱。如果候选集合控制不好数量变成 10 万成本就会翻倍。3.3 把指标翻译成“能不能上线”的判断指标要翻译成业务语言而不是停留在“准确率 90%”。我一般会问自己几个问题每天新增告警量是否在团队处理能力内。估计误报数量后团队还愿不愿意继续看这个告警渠道。漏报是否出现在高风险类型比如私钥、云厂商密钥。全量扫描一次的成本和耗时是否符合发布节奏。同一段输入在不同时间运行结果是否稳定。“可以上线”不等于“指标好看”。更稳妥的做法是先小批量灰度拿最近三个月的历史告警跑一遍把 LLM 判定结果和人工复核结果对比。两者差异足够小再放量。4. 评估流程拆开跑从 60 条样本到全仓库4.1 最小样本集先打通调用链不要急着堆规模评估不是一上来就跑全部仓库。先把样本集控制在 60 条左右20 条正样本、20 条负样本、20 条干扰样本。先做一件事把端到端链路跑通读入片段。构造 prompt。调用模型。解析返回结果。计算指标。为什么要先跑 60 条因为链路问题比模型能力问题更隐蔽。模型返回的 JSON 多了一个字段名解析逻辑就可能失败并发一开限流直接打断任务输出目录没有写权限任务跑到一半卡住。这些都不会等到大样本才暴露。跑通之后先看日志和结果文件确认每条样本都有对应输出再考虑批量。4.2 Prompt 和输出格式直接决定评估结果可不可信Prompt 是评估的关键变量。一个用于秘密扫描研判的 prompt 至少包含任务说明、判断标准、输出格式、约束。下面是一个可参考的模板你是一个秘密扫描研判助手。给定一段代码片段判断其中是否存在疑似密钥、口令、私钥或敏感凭据。 判断步骤 1. 先看是否包含常见密钥格式 2. 再看上下文是否表明它是示例、占位符、已过期测试值 3. 注意编码、拼接、拆行、URL query 参数等变体 4. 只有上下文支持是有效凭据时才输出 is_secret 为 true。 输出 JSON {is_secret: true/false, secret_type: 类型, confidence: 0-1, reason: 简要原因}这里有几个参数建议temperature 调到 0避免随机性。max_tokens 不要设太小防止 reason 被截断。解析 JSON 时做容错遇到异常可以重试一次或提取花括号部分再解析。为什么 prompt 里要有判断步骤因为直接问“这是不是密钥”模型容易凭格式直觉给结果。给它步骤输出理由会更稳定也方便逐条看错题。4.3 固定模型、模板、参数和日志确保结果可复现可复现是生产评估的底线。如果同一份评估数据、同一个模型、同一条 prompt今天跑和明天跑结果不一致这个评估就没有参考价值。需要记录至少五样东西数据集版本文件名、hash、标注时间。模型版本接口模型记录 API 版本本地模型记录权重 hash 和推理精度。prompt 版本模板文本本身要纳入版本管理。采样参数temperature、top_p、max_tokens。结果报告每条样本的原始回复、解析结果、耗时、重试次数。我一般会把每次评估输出成一个独立目录里面放 report.json 和 logs。后续模型升级或换参数直接对比两个目录里的指标变化就能知道是哪一步造成的。4.4 全仓库和 Git 历史扫描还要处理边界条件全仓库扫描时很多问题不是模型能力而是边界没处理好。Git 历史里的 secret 往往比当前分支更值得关注。但历史 commit 数量大逐条喂给 LLM 不现实。建议先做前置过滤排除文件名、扩展名、二进制文件、过大文件。排除明显非文本内容。对文本内容做片段化控制单次输入规模。考虑 GitHub API 的速率限制预留分页、sleep 和失败重试。批量任务要求记录每个仓库、每个 commit、每个片段的处理状态。输出命名要可追溯不然跑完一千个仓库后对不上哪条告警来自哪个位置。还要有一个断点续跑的设计失败任务先记录下来下次从失败位置继续而不是全部重跑。5. 常见翻车点误报、漏报、超时和排查顺序5.1 误报爆炸先看负样本和 prompt 判断标准召回率看着不错一放线上误报特别多这是最常见的翻车方式。排查时先看评估数据集。负样本够不够多是不是都是特别容易区分的假 token。如果负样本太简单模型只要看到格式像就判 true线上自然误报爆炸。第二步看 prompt。判断标准是不是只有“格式是否像密钥”没有要求结合上下文。如果是就把判断步骤改成“先确认格式再结合上下文判断是否有效”。第三步看 confidence 阈值。如果打算用 confidence 过滤要先用测试集算一遍。阈值设低等于没过滤设高会损失召回。这里要提醒一句模型返回的 confidence 并不完全等于真实概率。不要盲目信还是要看保留集上的人工复核结果。5.2 漏报严重先确认样本有没有进入模型漏报严重时不要上来就下结论“这个模型不行”。先确认漏报样本是否真的进入了模型。有时候前置规则把片段过滤掉了LLM 根本没看到。有时候输入太长被截断关键上下文丢失。有时候系统提示词覆盖了任务指令模型实际没有按你的 prompt 执行。其次再排查模型本身输入格式是否符合预期。prompt 对“有效凭据”的定义是否被模型误解。样本标注是否准确如果标注有歧义指标差异也不能全怪模型。5.3 超时和成本失控先加去重、缓存和前置过滤扫大仓库超时或者成本承受不住通常不是模型能力问题而是输入控制问题。优先做三件事把重复片段去重。同一个 token 可能出现在多个文件里。建立缓存。高相似片段直接复用结果不重复调用模型。限制单次请求长度代码片段统一截断或分段。还有一个更稳的思路LLM 只跑规则命中后的候选告警而不是全量喂所有代码。这样可以显著降低调用量和成本。如果仍然超时再考虑分批、异步队列、断点续跑。5.4 通用排查顺序我整理了一张排查顺序遇到问题可以按它逐层走看现象先明确是漏报、误报、超时、解析失败还是任务中断。看输入目标片段是否进入模型上下文是否被截断前置规则有没有误过滤。看 prompt 和参数模板版本是否一致temperature 是否变动max_tokens 是否限制了输出。看模型版本和精度接口版本、权重版本、fp16/bf16 差异。看数据集正负样本比例、标注准确性、保留集是否被污染。看调用链路并发、限流、重试、缓存、日志记录。这个顺序不是规定但可以避免一开始就去调模型参数。大部分生产问题在输入和流程上就能找到答案。如果回到最开头的问题我对“生产前评估 LLM 做秘密扫描”这件事的结论其实很简单先让规则扫描顶在前面再让 LLM 过滤候选告警评估阶段不要只看准确率而是盯住误报、成本、可复现性和人工处理链路上线前用一段真实历史告警做灰度把模型版本、prompt 版本、数据集版本都管理起来。秘密扫描的价值不是展示模型有多聪明而是让真正有用的告警能被看见、被处理。LLM 是一个有用的精排层但前提是它经过了贴近生产分布的评估而不是在几个样例上表现良好。