Harness 工程 全部章节

第12章 观测与评测——系统是否真的有效

一项任务留下了产物,仍可能没有达到目标;一次调用被拒绝,也可能已经留下不允许的效果。要判断系统是否有效,既要解释这一次发生了什么,也要检查同一种实现面对不同输入时是否仍守住约定。前者需要关联证据,后者需要稳定的任务与比较方法。两者最终服务于一个决定:这项改动是否值得交给真实任务使用。

本章从任务证据进入评测,不另造一套脱离执行的评分系统。我们要建设的是从观察到判断的路径:先确认事实及缺口,再分别评价任务效果与约束,定位失败,组织比较,最后作发布决定。日志条数、测试数量和较低的 token 用量都不能独自完成这条路径。

12.1Trace 的关联范围

任务轨迹(trace)是按因果关系关联一次任务的请求、决定、动作与观察的记录。它不是把终端输出、所有消息和所有载荷按时间堆在一起。最小形态是一组能回答以下问题的事件:哪次请求提出哪个动作,依据哪个目标与许可版本,动作是否被提交,哪个对象在什么边界接受了验收,最终为什么停止。

因果关系需要不同层级的身份。run_id 标识一次运行;request_id 标识一次模型请求;action_id 标识一项业务动作;attempt_id 标识对这项动作的一次提交尝试;tool_call_id 配对模型提出的调用与返回结果。同一动作若允许重试,各次尝试仍属于原动作;重新向模型请求另一种方案,则产生新的请求。一次请求还可能提出多个调用,不能把请求次数当成动作次数。

模型提供的调用编号也不是全系统唯一的业务身份。关联时至少要保留它属于哪个运行和请求。若同一业务动作后来通过核对工具取得结果,核对本身有自己的调用编号,但观察要指向被核对的动作和尝试。否则,新调用报告“找到对象”时,读者无法判断它找到了原提交的结果,还是一个相似的新对象。

第3章的代码已经区分运行、模型请求、创建动作和调用编号,但不支持自动重试,没有完整的尝试身份与接手协议。这里提出的关联规则不是声称代码已经拥有这些能力。串行、未知即停的小系统可以保持原有最小形态;只有新增尝试时,才需要把新的层级真正落到提交、查询与记录中。

记录点应放在改变判断的边界。请求发出前,绑定目标、许可、材料、工具契约与输入;响应返回后,分别记录收到、持久保存、解析和确认;有副作用时,关联提交意图、实际提交、外部受理和效果核对;结束时,保留停止原因与验收范围。任意一处缺失都应成为可见缺口,而不是用后来一句“成功”填平。

12.2记录的时间、来源与权力边界

有了关联,还必须知道每条记录究竟证明什么。观察(observation)是某个组件在某个边界取得的结果;证据来源(provenance)说明它由谁、通过哪个接口、针对哪个对象与版本取得。观察不是对整个环境的全知描述。最小记录应同时给出观察对象、状态、取得方式、版本与观察时间。

时间至少区分本地观察时间与外部声明时间。observed_at 可以表示宿主收到响应或完成读取的时间;服务响应里的生成时间、受理时间或对象更新时间,则注明来源。请求发送时间不等于外部执行时间,接收时间也不等于效果开始时间。需要测量本地经过时长时使用单调时钟;跨机器比较先说明时钟误差,不能仅按两台机器的系统时间排列因果顺序。

每个步骤都要留下它知道的事实,而不只留下一个状态词。收到创建回执,能证明接口返回了什么;重新读取绑定对象的指定版本,能证明那次读取观察到了什么。响应丢失时,已提交和未提交之间可能仍无从区分。此时状态为 unknown,并注明缺的是受理回执、对象版本、完整载荷还是可靠记录,而不是笼统说“系统异常”。

第3章把最新响应的接收状态与协议确认状态分开,这是必要的区别。persisted 不表示响应已经合法,accepted 也不表示文件已经创建。读取摘要时还要分开 status、verified_at_stop、当前授权和已知未知项。保留了旧验收,不等于旧结果在停止边界仍可作为当前任务完成结果。

载荷证据还要注明表示。book/v2/harness.py 的 Harness.snapshot 保存经过脱敏的字节,并为这份快照计算 hash;请求意图另有发送前原载荷的 hash。两者不能混称“请求 hash”。响应快照的 hash 同样绑定脱敏后的保存内容,不是未经处理的原始响应。发生脱敏时,原载荷与诊断副本可能不同,读者必须能看出哪个字段绑定哪份字节。

据此应把三件事分开:实际发送或收到的载荷、诊断保存的表示、后来允许发送的表示。诊断人员获准查看脱敏副本,不表示模型、评测人员或文档读者都获准查看原文。若某字段未保存,便不能从副本反推出原值;若只有 hash,便不能据此重建内容或判断语义。

记录本身也有边界,能解释行为不等于能扩大权限。可观测性(observability)是通过受控记录与查询解释运行行为的能力。它不是恢复机制,也不是新的授权来源。最小形态是能够从停止摘要找到相关事件、对象及证据,并指出仍不能确认的地方。把一条 trace 重新读入模型,不会使旧调用再次取得执行资格。

日志应先定义字段允许清单,而不是先原样 dump 再寄希望于脱敏。通常需要运行与动作身份、版本、受理状态、停止原因、用量和受限证据引用;是否需要材料正文、调用参数中的业务字段或错误堆栈,应逐项说明。凭证、个人信息、业务秘密和不必要的原始响应不因“方便排错”自动进入记录。错误信息也可能包含路径、请求片段和令牌,不能只过滤正常响应。

脱敏规则要覆盖记录入口,并给出已知范围。第3章使用无敏感信息的练习材料和固定工具,保存脱敏快照有助于检查本地闭环;它不构成任意业务数据的通用保密方案。增加新工具或新字段时,应重新检查允许清单、异常路径及输出表示,不能沿用原先的密钥替换规则便宣称全部隐私已经处理。

记录还需要访问与保留规则。任务执行者、诊断人员和评测人员不一定具有相同权限。摘要可以广泛可见,材料副本和精确资源位置则可能受限。明确保留期限、删除责任和证据引用失效后的行为;删除诊断正文之后,仍可保留许可允许的小型统计,但不能继续声称原文证据可查。

内容 hash 可以帮助比较字节与绑定对象,不提供防篡改审计证明。能够改文件和账本的主体,也可能重算 hash。若业务要求独立审计,需要另建独立记录边界、访问控制和校验责任;不能给普通 JSONL 文件加一个摘要字段便冒充已经满足。没有这类要求的小系统,不必为了“可观测”先建设独立审计平台。

诊断工具也不能直接重放 trace 中的动作。定位到一个未知提交,只获得核对对象的线索。是否等待、查询、重试或补偿,仍由当前许可、原契约和动作事实决定。把“观察记录完整”解释为“可以自动续跑”,正是把证据与继续权混在一起。

12.3效果、约束与失败定位

任务效果验收检查约定的结果是否成立;约束验证检查声明的操作、发送和资源边界是否满足。它们是两个评价轴,不是同一分数的加减项。最小结果分别记录效果为通过、未通过或未知,约束为检查通过、发现违反或证据不足,并附上各自对象和证据。

一份摘录文件可以内容正确,却创建在未获准的位置;也可以严格停在许可范围内,却没有完成摘录。前一种不能靠内容分数抵消越权,后一种也不能因边界守住就宣称任务成功。两个轴都应保留未知:产物无法重新读取时,不能把它当作效果通过;只有工具拒绝文字而未核对执行路径时,也不能把约束当作已经证明。

内容正确的产物不证明越权从未发生。验收只读到最终对象,可能没有覆盖其他文件、后台工作或远端转交。工具返回 reject 也不证明实际效果已被阻止:要确认拒绝发生在效果前,并检查受保护对象及相关执行通道。验证范围应随执行边界变化,不能只看调用返回值。

反向用例需要写出预期禁止效果。对于固定工具,可以检查附加路径字段被拒绝且未创建其他目标。若新增任意命令能力,则需要针对实际权限上界检查相关资源与后代,原固定工具测试不能替它作证。若采用组织平台扩展,再检查工作区权限串用、连接凭证串用和撤权后继续提交;个人系统没有这些能力,就不必被迫建设相应平台用例。

有限测试提高的是对已声明路径的信心,不证明所有攻击均已覆盖。报告应说哪些对象、故障和输入已检查,哪些依赖可信组件或外部服务契约。即使本轮没有发现违反,也不能把检查结果升级为无条件的“安全”。

效果与约束结果分开之后,才有条件定位失败。失败定位是用可核对的观察,把未达成结果缩小到某个责任边界。它不是看到错误便归咎于模型。最小诊断应说明最后成立的事实、下一项缺失条件、支持这一判断的证据,以及还不能排除的原因。

至少区分输入、检索、模型选择、契约、执行、验收和版本。输入层检查目标与用户纠正是否进入有效请求;检索层检查来源是否取得、版本是否合适、缺口是否已告知模型;模型选择层检查模型在已给信息下提出了什么。模型没有见到材料,不应被描述为“忽视材料”;取得材料但未放入创建请求,则是输入与发送链的问题。

契约层检查参数、缺失值、调用配对和工具映射;执行层检查提交、受理及实际效果;验收层检查判据是否正确落到对象。最后单独检查版本:请求是否合法,可能取决于目标、许可、工具或对象是否已变化。旧请求本来合格,返回时版本失效,不等于原模型选择错误。

定位未知时要克制。超时不能确定失败于模型推理还是通信,更不能确定远端没有计算。写后记录失败不能确定对象未创建。诊断可以把范围缩到两个边界之间,保留尚需的查询或人工核对;不需要为了报表每行都有原因而编造一个确定分类。

失败也有非零成本。请求没有得到可用回答,仍可能产生模型费用;拒绝和反复读取仍占延迟与工具额度;未知提交还可能需要人工核对。把这些运行排除出成本统计,会让最不稳定的策略看起来最便宜。需要改进的是具体缺口,不是把困难样本从报告中删除。

12.4评测任务集与故障矩阵

评测任务集是一组版本固定、许可明确、预期结果可判断的任务。它不是临时找几条提示词看模型表现。最小任务条目包括任务身份、fixture 版本、目标、读取与发送许可、允许效果、预期验收、预算和故障注入点。没有预期验收的输入,只能用于探索,不能直接进入成功率。

fixture 是可重复使用的固定输入材料,不是复制真实私密数据的理由。任务修改后要形成新版本;同一个名字下悄悄更换材料,旧结果便无法比较。故障注入则是在明确边界制造受控失败,例如在效果前拒绝记录、在提交后丢失回执。它不是模拟一段事故故事,而是检查已声明的处理条件。

检查位置固定条件或注入点要观察的结果
输入与发送来源已读,但未进入创建请求创建拒绝,且无创建效果
契约解释参数缺失、空值或额外字段按绑定契约处理,不猜默认值
提交前写前记录失败不启动对应效果
效果之后回执或结果记录失败保留未知,不自动重提
验收边界对象内容或版本变化旧验收不替当前对象作证
控制边界当前许可撤回旧响应不启动新动作

矩阵列的是建设方法,并非这些扩展全部已经运行。真正报告时,逐项绑定实际测试、运行记录与断言。测试方法数、执行次数、参数组合数和检查的责任边界也要分开统计:一个方法可以只测一个分支,也可以包含多个固定组合。数量说明执行规模,不直接说明深度。

随书本地实践的测试方法按批次分开报告:

批次测试方法数与结果证据范围
原第3章基础测试首次请求12项、harness 98项,既有记录合计110项通过本轮未重跑,原基础实现本轮未改;不是新扩展的回归结果
本轮局部实践 book/v2/test_practices.py39项通过窄契约转换、内存原文引用、压缩候选结构与版本、只读对账、scope/account 纯函数及策略文本等局部检查;包含 Unicode JSONL 分隔字符用例
本轮接入实践 book/v2/test_capability_lab.py18项通过固定 MCP 协议子集、方法依赖与阶段资源、来源字节绑定、原循环创建及反向拒绝路径

三批合计167个测试方法,是已有基础110项与本轮新增39+18项的汇总,不是本轮一次执行了167项。方法数也不是断言数、独立任务数或故障组合数;数量不能保证覆盖深度,更不能证明全部历史格式或不透明接续项都已支持。全书配套实践用于检验局部机制,不是以这167项为主体的模型实验。

原脚本化 demo 产生过748字节的真实产物。本轮接入实践另经过真实子进程 stdio MCP 通信、3次脚本模型请求和3次工具调用,沿原 Harness 创建并验收真实产物。工具通信与产物不是模拟的,模型选择仍由 ScriptedTransport 给出,没有真实模型 API 联调;这不提供模型成功率、缓存命中率或服务费用。

执行边界证据另列。实际 Seatbelt 能力检查返回 capability_unavailable,sandbox-exec 报 Operation not permitted,退出码71;能力未建立,后续执行约束套件没有运行,也没有降级为无沙箱执行。策略文本的纯函数测试通过,不能代替内核约束实测。这里的约束评价只能是“证据不足”,不能记为检查通过。

可从项目根目录运行下面的局部实践入口。practices.py --demo 只输出合成示意;capability_lab.py --demo 会在随书包内新建证据目录与文件。测试入口也会留下本地证据,不请求付费模型;这些命令不包括原110项回归或 Seatbelt 约束套件。

python3 -I -B book/v2/practices.py --demo
python3 -I -B book/v2/test_practices.py
python3 -I -B book/v2/capability_lab.py --demo
python3 -I -B book/v2/test_capability_lab.py

结果须回到各批次记录与对应断言核对,不能以汇总数量填补缺失证据。

后续新增能力先补对应任务与故障点,再补实际结果。尚未运行的 benchmark,即用于版本比较的固定评测基准,应标为待运行设计;不能从用例存在推断用例通过,更不能把脚本化 token 数当作真实用量。付费联调必须由使用者明确选择,评测入口不能因为发现凭证就自动请求模型。

12.5对照条件、成本与发布判断

比较的对象应当是一项明确改动。对照评测是在尽量相同的任务与外部条件下比较新旧策略。它不是让新版本做容易任务、旧版本做困难任务,再比较平均分。最小对照固定任务集版本、服务接入、模型配置、工具包、验收与预算,只改变准备评价的策略。

例如要评价结果折叠,就固定来源、工具与验收,比较两种输入表示;要评价检索路由,就固定可用来源与目标,不同时换模型和材料。模型调用名背后的实际版本可能变化,应记录可获得的响应版本信息,缺失时写未知。若接入服务或模型配置同时变化,结果只能评价这组联合变化,不能归功于其中一个组件。

随机性不会因写了 seed 就消失。接口可能不支持 seed,也可能只提供尽力复现;外部状态、缓存和模型版本仍会变化。评测需按任务差异安排重复样本,并公开独立任务数、各任务重复次数及运行条件;次数应由实际比较需要决定。本书尚未运行这类模型对照评测,没有可报告的随机样本结果,不能把预设规模当作已评测数量。

运行顺序同样属于条件。连续跑完旧策略再跑新策略,可能把服务负载和缓存差异带进比较。按任务配对并交错顺序,记录冷启动、已有缓存与重取条件,有助于解释差异;仍不能把无法控制的外部因素假装消除了。样本较少时逐项报告差异,比给出精确但没有依据的显著性结论更诚实。

成功率要有可计数的分母。评测批次应保留计划、实际启动、未启动原因与每个样本的结果;以事先约定的已启动有效任务为分母时,未知和预算停止不能悄悄剔除。有效条件在运行前确定,不能按结果筛掉失败样本;重复样本与独立任务数分开报告。成功分子来自绑定的效果验收与约束检查,不来自模型自报完成;由此得到的是限定任务集和检查范围内的通过率。

结果通过率相近,仍不能只比较 token。总成本包括模型用量、工具与服务支出,以及重试、重取和人工介入。延迟既包括模型等待,也包括执行、核对和人工等待。计数先说明单位:重试是动作尝试,重取是再次获取材料,人工介入是一次需要人作决定或核对的事件,不与模型请求合并。

费用记录要区分观测、假设与未知。完整 usage 可以给出实际报告的输入、输出及缓存细分;只有输入输出总量时,按全部输入未命中估算可以作为保守假设,但不能写成观测到零命中;整份 usage 缺失时,总费用仍为未知,已知请求费用只是一部分。book/v2/harness.py 的 Usage.record 与 Usage.summary 正是保留这些口径,而不是把未知请求补成零。

本书使用 2026 年 11 月 1 日的 DeepSeek deepseek-flash 基线,单位为人民币元/百万 tokens:高峰命中输入 0.04、未命中输入 2、输出 8;空闲时段分别为 0.02、1、4。计算是各次命中输入、未命中输入和输出分别乘对应单价,再除以一百万。相同历史再次发送仍计入输入,不能只数新增文字。

这份日期化基线用于统一比较,不是供应商账单。现有代码由显式 tariff 选择基线,不查询实际价格,也不自动判断适用时段。实际账单估算另需调用时间、当时价格与计费规则,并与账户记录核对。本地请求时间只是线索,不是服务确认的计费时间。不能把基线投影与当时消费相加或混称实际支出。

汇总时保留分布和尾部。平均延迟不能显示少数任务长期等待;平均费用也可能掩盖反复重取。至少列出中位数、可支持的分位数、最大值及超预算数量,注明样本量与计算口径。样本少到不足以稳定描述尾部时,展示逐项结果,不用漂亮的百分位数字掩盖不足。未知用量的数量必须与费用一起显示。

降低 token 若增加失败、信息重取或人工核对,未必降低任务总成本。反过来,稍多输入若减少错误动作与返工,也可能值得采用。判断依据是任务效果、约束、成本与负担的共同变化,不能把某一个易采集指标当作全部改善。

这些比较最后汇成一个决定。发布门槛(gate)是新版本进入真实任务前必须满足的明确条件。它不是评测报告末尾一个综合分数。最小门槛说明任务范围、效果要求、不可接受的约束违反、资源预算、回归结果、人工核对结果和决定责任人。涉及业务结果的判断,由理解目标与许可的业务负责人确认,不能全部交给技术指标代签。

门槛随新增能力变化。增加 shell、后台运行、恢复或新连接,会改变执行与发送边界;即使原任务通过率不降,也须补新能力的验证。未采用组织平台时,不强制引入工作区与凭证隔离模块;采用之后,这些范围便成为发布条件,不能继续只引用个人摘录任务的检查。

发布决定还应说明如何停止扩大使用,以及未知由谁处理。人工确认不能修复已经缺失的强制边界,但可以判断证据不足时是否维持有限使用。某些结果适合继续小范围试用,另一些约束违反应阻止发布。把这些区别写清楚,比把所有风险折算成一个可抵消分数更有作用。

12.6本章判据

  • ☐能沿运行、请求、动作、尝试和调用关系找到事实,并区分本地观察时间、外部声明时间与证据来源。
  • ☐每个未知都指出缺失条件;原载荷、脱敏副本及各自 hash 不混用,记录不取得恢复或执行权。
  • ☐日志有字段允许清单、访问与保留规则,不原样倾倒敏感内容,不把 hash 当作防篡改审计证明。
  • ☐效果验收与约束验证分别报告;拒绝返回和正确产物不被扩大为禁止效果从未发生的证明。
  • ☐任务、fixture、许可、验收和故障点有版本;实际执行数量与覆盖边界、脚本化与 live 证据分开。
  • ☐对照保留相同任务与配置、重复样本数及可计数分母,待运行设计不冒充实测。
  • ☐成本、延迟、重试、重取与人工介入保留分布和未知;日期化基线不混称实际账单。
  • ☐发布门槛绑定业务负责人、新增能力边界及回归和人工结果,没有用平均分抵消约束违反。

本章没有回答什么

本章没有给出适用于所有业务的质量评分,也没有证明有限测试能够覆盖全部攻击、服务变化或文件系统故障。语义质量需要任务自身的判据;实际执行边界需要对应资源与通道的机制和证据,不能由观测记录补成保证。

本章没有新增真实模型 benchmark、真实缓存数据或供应商账单,也没有把现有本地测试升级为所有扩展的验证。读者需要按所采用的能力补任务、运行和人工结果。Trace 提供的是诊断与判断依据;可靠接续仍须满足动作事实、当前许可与原契约,不能从一份记录直接取得继续权。