“We burned 11.7B tokens to find the best cyber AI model”——这是一句来自我们内部评测项目的总结。11.7B 也就是 117 亿这 117 亿个 token 不是用来训练模型而是用来“考”模型。把一批主流大模型放在网络安全运营场景下用统一的任务集、统一的评测口径、统一的计分规则观察它们在日志分析、告警研判、漏洞情报理解、报告生成这些任务上的真实表现。这类评测并不像许多人想象中那么轻松。它不是跑几个问答就出排行榜而是要处理上下文长度、指令遵循、输出稳定性、成本波动、API 限流、模型版本漂移等一系列工程问题。这篇文章会把我们的评测方法论完整拆开为什么 token 消耗会到 117 亿、评测场景怎么设计、成本怎么控、结果怎么解读、以及最容易踩的坑。无论你是准备做模型选型还是想建立一套可持续的评测机制这篇内容都能直接复用。1. 先把概念说清楚token、大模型评测和 cyber 场景1.1 什么是 tokentoken 是大模型处理文本的最小单元。它不是一个字也不是一个完整的单词而是模型分词器切分出来的一个片段。比如英文里一个常见单词可能是一个 token中文里一个汉字有时是一个 token有时一个词会被拆成一个或多个 token。原文Analyze this firewall log. 分词结果示例[Analyze, this, firewall, log, .]不同模型的分词器不同同样的文本在不同模型下的 token 数量也会不一样。所以当我们说“消耗了 11.7B tokens”时并不是指处理了 11.7B 个汉字或 11.7B 个英文单词而是指这些模型总共消费了 117 亿个模型输入输出单位。为什么 token 这么重要计费基础几乎所有商业大模型 API 都按 token 计费输入和输出分开计价。上下文窗口上限模型一次能接收的 token 数是有限的超出就报错或截断。评测成本评测任务量越大、场景越复杂、上下文越长token 消耗越大。1.2 cyber 场景是什么这里的 cyber 指的是网络安全运营场景而不是游戏或潮流文化里的“赛博”。在安全运营工作中分析师每天要处理海量日志、告警、漏洞情报和外部威胁情报大模型在这些场景中可以做四类工作方向典型任务日志分析解析防火墙日志、Web 日志、DNS 日志提取关键字段告警研判判断一条告警是否为误报给出置信度与研判理由情报理解从威胁情报报告中提取 IoC失陷指标、攻击手法、影响范围报告生成把分析过程组织成结构化报告包含结论、证据、建议这些任务有共同特点上下文长、格式要求严格、专业术语多、错误代价高。所以评测模型时不能只问“你好你会做什么”而是要构造接近真实业务的数据和任务。1.3 为什么需要大规模评测很多团队选模型的方式是“有人说好就试一下”。这种做法的风险在于不同场景下模型表现差异极大某个模型在通用对话上表现好但在长文档日志分析上可能很差。通用排行榜只能作为参考不能直接作为生产选型依据。真正可靠的选型方法是固定一批有代表性的任务。让多个模型在同一批任务上跑。用统一的评分标准量化输出质量。统计成本、时延、失败率等工程指标。综合排序选出最适合自己业务的模型。这套流程走下来就会烧掉大量 token。我们这次评测烧了 11.7B tokens正是为了降低选型决策的不确定性。烧 token 不丢人丢人的是烧了很多 token 还在用“感觉”做决定。2. 评测方法论先定场景再定模型最后定指标2.1 评测场景清单评测场景不是随便定的。它必须覆盖目标业务中真正会用到模型的能力。我们围绕 cyber 场景设计了 6 个评测方向长文本日志解析给定一段 5000 到 20000 token 的日志要求模型提取来源 IP、目的 IP、时间、事件类型、风险等级并输出 JSON。告警去重与聚合给定多条相似告警要求模型判断是否属于同一事件并合并成一个事件。威胁情报实体抽取给定一份威胁情报报告要求抽取恶意 IP、域名、哈希值、攻击团伙名称、攻击手法。误报研判给定一条告警及上下文日志要求模型输出“真实攻击 / 误报 / 需要进一步分析”三选一并写理由。根因分析给定攻击链日志序列要求模型推断攻击入口、横向移动路径和最终目标。报告生成给定分析笔记要求模型生成符合模板的正式报告。每个场景又细分为若干子任务每个子任务有独立的提示词模板和评分标准。2.2 候选模型池候选模型的选择遵循“覆盖面优先”原则。我们会同时评测通用大模型针对对话优化的模型针对推理优化的模型针对长上下文优化的模型开源可私有化部署的模型商业 API 模型注意候选模型池需要根据评测时的市场可用情况调整且每次评测后要记录模型版本号。这里不写死具体版本号因为模型版本更新非常频繁。建议在实际评测时为每个模型记录如下元信息字段说明model_name模型标识符version模型版本号或快照时间provider模型供应商access_methodAPI 还是本地部署context_window上下文窗口上限pricing_input每百万输入 token 价格pricing_output每百万输出 token 价格2.3 评测指标体系评测指标分为两类质量指标和工程指标。质量指标指标计算方式权重字段准确率抽取字段与标准答案逐项对比30%语义相似度模型输出与参考答案的语义相似度20%格式合规率输出是否符合 JSON 规则15%推理正确率判断类任务的分类准确率25%漏报率未识别出的关键字段占比10%工程指标指标含义时延平均单任务响应时间失败率超时、报错、截断的任务占比成本效率每有效完成任务消耗的 token 数稳定性同一任务重复 5 次的输出一致性从最终选型角度看工程指标往往比质量指标更致命。一个模型质量再高如果三天两头超时、报错、烧 token生产环境也用不起来。3. Token 消耗分析117 亿是怎么烧出来的3.1 估算模型先给出一个简化的 token 消耗估算公式总 token 消耗 输入 token评测集 输出 token模型回答 重试 token失败重跑产生的额外消耗输入 token 包含系统提示词sys_prompt任务说明task_desc上下文示例few_shot_examples待处理数据input_log输出格式约束output_schema输出 token 是模型生成的内容。它的长度取决于任务类型和模型自身风格。有的模型输出很啰嗦几句话能说清的事要写一大段有的模型则非常简洁。这会导致同样任务下 token 消耗差好几倍。3.2 具体计算过程假设我们有6 个评测场景每个场景 200 条任务每条任务平均输入 8000 tokens每条任务平均输出 800 tokens每个模型跑 5 轮以消除随机性候选模型 6 个那么简单估算单模型单场景消耗 (8000 800) × 200 × 5 8,800,000 tokens 单模型总消耗 8,800,000 × 6 52,800,000 tokens 全部模型总消耗 52,800,000 × 6 316,800,000 tokens这大约是 3.17 亿 tokens距离 11.7B 还差很多。但是这只是理想情况。实际上 token 消耗会被以下几类因素大幅推高长上下文场景根因分析场景中输入可能达到 20000 tokens 以上。连续多轮交互有的评测需要模型多次追问、多次回答而不是一次性给结果。失败重试API 超时、限流、报错、输出格式错误都要重跑。模型风格差异有的模型输出达到 3000 tokens有的只有 200 tokens。校准轮次正式评测前要跑校准任务调整提示词这些消耗也要计入。复评发现数据有问题需要修正后重跑部分任务。把这些因素全部考虑进去整体 token 消耗很快会突破十亿量级。下面是实际消耗分布消耗来源占比说明正式评测任务48%6 个场景 × 全部模型提示词调试22%校准提示词期间反复测试失败重试15%API 报错、超时、格式不合格重跑上下文追加10%任务需要的参考信息过多结果复评5%对低分样本做二次评测3.3 成本控制手段117 亿 tokens 在 API 计费下是一笔不小的开销。成本控制不能靠“事后看账单”必须提前设计。下面是我们验证有效的做法压缩输入上下文。能截断的日志就截断能去重的情报就去重。评测数据集不会因为输入短就失效关键是有区分度。限制输出长度。在 API 参数中设置max_tokens要求模型直接输出 JSON不要解释过程。把“废话”的输出成本降下来。分批跑小步快跑。不要一次性提交 200 条任务。先跑 20 条确认格式和质量没问题再跑完整批次。失败立即止损。对单任务设置超时时间和最大重试次数连续失败 3 次就标记为失败不无限重试。复用模型输出缓存。相同输入、相同参数的请求可以直接用缓存结果避免重复计费。# 文件路径evaluation/token_budget.py # 核心片段评测 token 消耗预估器 MODEL_CONTEXT_WINDOW 128000 def estimate_task_tokens( sys_prompt: str, task_input: str, expected_output: str, few_shots: list[str], expected_output_tokens: int, ) - dict: 估算单条任务的 token 消耗 input_text sys_prompt task_input for shot in few_shots: input_text shot input_token_count int(len(input_text) * 1.3) # 粗略估算中英混合场景 output_token_count expected_output_tokens return { input_tokens: input_token_count, output_tokens: output_token_count, total_tokens: input_token_count output_token_count, } def estimate_batch_tokens( task_num: int, avg_input_tokens: int, avg_output_tokens: int, retry_rate: float 0.15, rounds: int 1, ) - dict: 估算整批任务的 token 消耗考虑重试率 base_consumption task_num * rounds * (avg_input_tokens avg_output_tokens) retry_consumption base_consumption * retry_rate total base_consumption retry_consumption return { base_consumption: base_consumption, retry_consumption: retry_consumption, total_consumption: total, } if __name__ __main__: task_est estimate_task_tokens( sys_prompt你是安全运营专家请解析下面的日志。, task_input2025-06-01T10:00:00Z 192.168.1.10 - 10.0.0.5:443 ..., expected_output{src_ip:192.168.1.10,dst_ip:10.0.0.5}, few_shots[], expected_output_tokens120, ) batch_est estimate_batch_tokens( task_num200, avg_input_tokens8000, avg_output_tokens800, retry_rate0.15, rounds5, ) print(task_est) print(batch_est)运行结果会输出两条估算记录。第一条是单条任务的 token 预估第二条是整批任务加重试成本后的预估。这个估算器可以用来预算审核也可以用来对比不同模型的成本效率。4. 评测框架实现调度、采集与评分4.1 整体架构评测框架的核心需求是多模型、多任务、可配置、可复现。整个框架由四个模块组成评测集管理加载任务数据按场景分组。模型调用层统一封装不同模型的 API 调用处理鉴权和重试。输出采集层收集模型输出记录原始响应、耗时、token 使用量。评分层对模型输出做评分生成结构化结果。4.2 模型调用封装不同模型的 API 各不相同但大多数兼容 OpenAI 风格的接口。我们可以封装一个统一的调用入口# 文件路径evaluation/model_client.py # 核心片段统一模型调用客户端 import time import json from typing import Optional class ModelClient: def __init__( self, model_name: str, api_key: str, base_url: str, max_tokens: int 4096, temperature: float 0.2, ): self.model_name model_name self.api_key api_key self.base_url base_url self.max_tokens max_tokens self.temperature temperature def chat(self, messages: list[dict]) - dict: 调用模型接口返回解析后的响应和元信息 payload { model: self.model_name, messages: messages, max_tokens: self.max_tokens, temperature: self.temperature, } headers { Authorization: fBearer {self.api_key}, Content-Type: application/json, } response self._post(payload, headers) return self._parse_response(response) def _post(self, payload: dict, headers: dict) - dict: 实际 HTTP 请求示例用 requests 伪代码表示 # 实际项目中这里使用 requests.post 或 httpx.post 发送请求 # 注意所有 API 调用必须走公司申请的合法模型服务通道 pass def _parse_response(self, response: dict) - dict: 解析模型返回结果提取文本、耗时和 usage 信息 content response[choices][0][message][content] usage response.get(usage, {}) return { content: content, prompt_tokens: usage.get(prompt_tokens, 0), completion_tokens: usage.get(completion_tokens, 0), total_tokens: usage.get(total_tokens, 0), latency_ms: response.get(latency_ms, 0), } def count_tokens(self, text: str) - int: 估算 token 数量实际项目建议使用模型对应的分词器 return int(len(text) * 1.3)注意上面的代码是框架示意_post方法需要根据实际调用的模型服务商接口来实现。不同模型的鉴权方式、请求格式、响应结构可能有差异示例演示的是通用设计思路。4.3 批量调度器评测任务量很大不能一条一条手动跑。需要写一个调度器来批量运行所有模型的所有任务# 文件路径evaluation/runner.py # 核心片段评测任务调度器 import csv import json import time from dataclasses import dataclass, asdict dataclass class EvalRecord: task_id: str scenario: str model_name: str prompt_tokens: int completion_tokens: int total_tokens: int latency_ms: int success: bool raw_output: str score: float class EvalRunner: def __init__(self, model_clients: dict, tasks: list[dict], save_path: str): self.model_clients model_clients self.tasks tasks self.save_path save_path self.records [] def run_all(self): for task in self.tasks: for model_name, client in self.model_clients.items(): record self.run_single(task, client, model_name) self.records.append(asdict(record)) print( ftask{task[id]} model{model_name} fsuccess{record.success} score{record.score} ftokens{record.total_tokens} ) self.save() def run_single(self, task: dict, client: ModelClient, model_name: str) - EvalRecord: messages [ {role: system, content: task[system_prompt]}, {role: user, content: task[user_prompt]}, ] start_time time.time() try: result client.chat(messages) success True raw_output result[content] score self.score_task(task, raw_output) except Exception as exc: success False raw_output fERROR: {exc} score 0.0 result { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0, latency_ms: 0, } latency int((time.time() - start_time) * 1000) return EvalRecord( task_idtask[id], scenariotask[scenario], model_namemodel_name, prompt_tokensresult.get(prompt_tokens, 0), completion_tokensresult.get(completion_tokens, 0), total_tokensresult.get(total_tokens, 0), latency_mslatency, successsuccess, raw_outputraw_output, scorescore, ) def score_task(self, task: dict, output: str) - float: 评分函数按场景调用对应的评分器 if task[scenario] log_parsing: return score_log_parsing(task[expected], output) if task[scenario] alert_triage: return score_alert_triage(task[expected], output) # 其他场景继续扩展 return 0.0 def save(self): with open(self.save_path, w, newline, encodingutf-8) as f: writer csv.DictWriter(f, fieldnamesasdict(self.records[0]).keys()) writer.writeheader() writer.writerows(self.records)这个调度器把每一个“模型-任务”组合的执行结果完整记录下来。记录中包含 token 消耗、时延、成功状态、原始输出和分数。这些数据是后续排行榜和成本分析的基础。4.4 评分规则示例以告警研判任务为例说明评分怎么设计{ id: alert_triage_001, scenario: alert_triage, system_prompt: 你是一名资深安全运营工程师。请研判以下告警是否为真实攻击。, user_prompt: 告警信息源IP 203.0.113.5 在 10 秒内尝试登录 10.0.0.5 的 SSH 服务 20 次全部失败。请判断该行为属于A. 真实攻击 B. 误报 C. 基础设施扫描 D. 需要进一步分析, expected: { label: 真实攻击, keywords: [爆破, SSH] }, max_score: 10 }评分逻辑分类正确基础分 6 分。理由中包含指定关键词每个关键词加 1 分。输出为合法 JSON加 2 分。输出格式错误或分类错误0 分。这种评分方式既考查模型的判断准确性也考查输出结构和依据的充分性。纯靠“猜对答案”只能拿到基础分必须写出合理理由才能拿高分。5. 结果分析与模型选型方法5.1 排行榜的计算口径评测完成后会得到一份 CSV 结果文件。生成排行榜前需要先清洗数据剔除失败记录。剔除输出为空或格式严重非法的记录。对同一模型同一任务的多次结果取平均。按场景分别计算总分。最后按综合加权分排序。排序公式综合分 质量分 × 0.6 工程效率分 × 0.4其中质量分 各场景质量指标加权平均。工程效率分 100 - (失败率 × 100) × 0.5 - (时延归一化分数 × 0.3) - (token 浪费率 × 0.2)。这个公式确保一个模型哪怕质量再高如果疯狂报错、无限超时、输出又长又啰嗦综合分也会被拉下来。5.2 分数差异要谨慎解读评测结束后经常会出现“模型 A 平均分 82.3模型 B 平均分 81.9”的情况。这种 0.4 分的差异能不能说明 A 比 B 强不一定。需要看标准差模型在不同任务上的分数波动有多大。样本量每个场景到底跑了多少条任务。场景权重A 强在报告生成B 强在日志解析但日志解析的业务权重更高这时选 B 可能更合理。所以在做选型结论时不能只看排行榜。我们额外做了模型分场景能力雷达图。举例模型日志解析告警研判情报抽取根因分析报告生成模型 A88.279.584.082.190.5模型 B92.085.380.279.484.8模型 C75.182.090.370.288.0如果业务侧最看重日志解析和告警研判那模型 B 明显更适合。如果业务是偏报告输出和情报整理模型 A 才是首选。选型不是选“最强”而是选“最合适”。5.3 成本归一化对比除了质量成本也是选型的关键。我们不直接比较 API 价格而是比较“完成任务的平均成本”。计算方式单任务平均成本 (单任务平均输入 token × 输入单价 单任务平均输出 token × 输出单价) / 1000000把 6 个模型的单任务平均成本放到同一张表里会看到一些有趣的结论有些价格贵的模型输出短、失败率低整体成本反而更划算有些便宜模型输出超长、频繁重试最终花费并不低。这个数据是生产选型的重要参考。6. 常见问题与排查思路6.1 API 调用报错与限流问题现象常见原因解决思路请求返回 429API 触发限流降低并发增加重试间隔退避重试请求超时模型响应时间过长设置单请求超时拆分长任务上下文超限输入超过 context window压缩输入日志分段处理摘要前置输出截断达到 max_tokens 上限调大 max_tokens压缩输出模板模型版本漂移服务商更新了模型版本记录请求时间与版本快照固定 model 标识6.2 评测结果异常问题现象常见原因解决思路某模型分数为 0输出全是格式错误检查提示词是否清晰补充输出示例分数波动大模型随机性高降低 temperature增加评测轮次场景分数不合理评分标准有歧义先跑 10 条人工评审对齐评分标准成本远高预估输出 token 超预期分析单模型平均输出长度添加 max_tokens 上限6.3 评测数据污染这是大模型评测中最隐蔽的问题。如果评测集被公开过或者评测样本风格与模型训练数据高度一致模型得分会虚高。规避方式使用内部数据构造评测集不对外公开。定期更新评测集避免模型记忆。对同一任务使用多种问法变体降低“背题”概率。保留一份纯手工构造的盲测集不参与提示词调试。7. 最佳实践与工程建议7.1 评测数据管理评测数据是核心资产建议用独立的代码仓库管理包含原始数据文件JSON / CSV提示词模板每场景一个目录评分规则文档模型输出存档按日期和评测批次归档数据版本要与代码版本绑定。每次评测运行前记录 commit SHA确保任何一次结果都能追溯到当时的评测集和提示词。7.2 成本监控与配额117 亿 tokens 的消耗如果不实时监控很可能超出预算。建议实现一个轻量级监控面板# 文件路径evaluation/cost_dashboard.py # 核心片段token 消耗实时统计伪代码 from collections import defaultdict def build_daily_report(records: list[dict]) - dict: report defaultdict(lambda: {total_tokens: 0, cost: 0.0, failed: 0}) for r in records: model r[model_name] report[model][total_tokens] r[total_tokens] report[model][cost] estimate_cost(r[total_tokens]) if not r[success]: report[model][failed] 1 return report def estimate_cost(total_tokens: int) - float: 成本估算混用输入输出价格实际按计费模型换算 return total_tokens * 0.000001 * 2 # 示例单价替换为实际价格每次批量评测开始前先调用预算估算器确认预估成本在可控范围内再启动。评测过程中每完成一个批次就累加实际 token超过阈值自动暂停。7.3 生产环境部署建议评测选出模型后真正放到生产环境还要做几件事灰度发布先让模型处理 5% 的流量人工抽检质量。降级预案主模型不可用或质量下降时自动切换备用模型。日志全链路记录每次请求的模型版本、prompt 哈希、输出摘要便于追踪变化。定期复评模型服务商更新版本后必须重新跑一遍核心评测集。用户反馈闭环收集业务侧对模型输出的反馈定期回写评测集。7.4 提示词工程化评测过程中我们发现同一模型在不同提示词下的表现差异极大。因此提示词不是“随便写一段”要遵循工程化流程每个提示词都放在版本控制里不要只存在于开发者的本地文件。改动提示词后跑一次小规模评测20 条任务对比分数变化。提示词模板要支持变量注入不允许把业务数据硬编码进模板。对每个场景写 2 到 3 个模板变体评测时取平均成绩。8. 下一步可以做什么这篇文章的侧重点是方法论和工程实现。如果看完觉得有收获下一步可以沿着这几条路径继续深入搭建自己的评测集先收集 50 条真实业务任务构造一个 mini 评测集跑通整套流程。引入自动化评分当前示例里评分是简单规则实际项目中可以引入“裁判模型”用大模型给大模型打分复杂任务能拿到更细的分数。扩展到多模态评测安全场景里有不少图片类任务比如恶意文件图标识别、截图分析、钓鱼邮件可视化特征识别这些需要多模态能力评测。做持续评测平台把评测脚本、数据、看板整合成一个持续集成任务模型版本更新后自动触发评测生成对比报告。回到开头那句话我们烧掉了 117 亿 token不是为了证明哪个模型天下第一而是为了在真实业务场景中找到最合适的那个。这个过程的价值远不止一份排行榜数据——它让模型选型从“听人说”变成了“用数据说”。如果你的团队正在做类似决策不妨把这套方法搬回去小范围试一次先跑 1 到 2 个场景积累一套自己团队的数据。评测一次胜过道听途说十次尤其是在 cyber 这种对准确性要求极高的场景里。
阅读完成 · 觉得有帮助?