资讯动态

一次会话算不算通过:多轮对话的评测单元

发布时间:2026/10/25 9:35:15 来源:尧图企业网站定制
说明本文讨论的是一段多轮会话怎么作为一个评测样本属于评测工程话题不涉及具体模型版本与价格。AI 领域版本迭代极快凡涉及版本号、价格、可用性请以你阅读时的官方页面为准。文中代码为结构示意请按自己的技术栈调整后再上生产。一、单轮评测跑到多轮就失效单轮评测集的形状几乎固定一行一条样本三列——输入、期望、判定函数。跑一遍得到一张表按类别聚合。这套东西搬到多轮产品上第一次跑出来的结果通常和体感对不上不是偏低是偏高。原因不在判定函数写得松在评测单元选错了。后一轮的题目由前一轮的答案决定用户第一轮说「把上个月的销售表按区域汇总」第二轮说「再按季度拆一下」。拆的是什么取决第一轮给的表长什么样交上来的是「区域×月份」宽表第二轮该把月份列并成季度列交上来的是「区域×明细行」长表第二轮该做一次分组聚合。同一句输入正确答案是两套操作。把第二轮单独喂给模型它照样给出一个像样的答复判定器看这句话合不合理也会判通过。但会话里它答的是另一份表——题目的一半在上文里。用户会改口上下文也会变长十轮会话里出现一两次改口是常态说错币种要更正方向不对要换目标答案太长要换形式。改口把「正确」的定义在会话中途换掉了。单轮样本的期望写死会话的期望在第 6 轮变成另一个东西前 5 轮在新期望下看全错可它们在产出当时是对的。判定器不知道第 6 轮发生了什么只会把「当时正确、后来被推翻」记成失败。另一头是上下文长度。同一句话在第 2 轮问和第 12 轮问行为不一样早期约束被后来的内容稀释工具返回越堆越多模型开始总结前文而不是回答当前问题或者把三轮前的临时结论当定论用。这不是知识问题是策略漂移只在长上下文里出现单轮评测测不到。为什么「每轮都判一次」会得到虚高的分一是分母变了。按轮次算一条 20 轮的会话提供 20 个判定点一条 2 轮的只提供 2 个长会话在总分里的分量被自动放大。二是判定点重复。确认币种、确认格式、确认口径同一份信息在 8 轮里被确认 8 次算 8 个通过。三是关键判定点被平均掉。一条会话的成败往往只在最后两轮前面九轮都是铺垫。终局失败被前九轮的成功摊薄看起来像一次局部失误。二、评测单元怎么定单元定错后面的断言、权重、分母全都跟着错。三种单元的适用面轮次级单元是「一问一答」不是会话。它适合验证单点能力格式是否守住、该拒的是否拒了、工具是否选对。前提是这一轮不依赖上文所以它在多轮产品里只能覆盖一小部分样本。任务级单元是「一段连续、目标不变的交互」适合绝大多数产品评测因为用户自己就是按任务记账的这件事办成了没有。一条会话里有三个目标就产出三个任务级样本。会话级单元是「从打开到关闭」。它只在评测跨任务能力时必要上一件事的偏好要不要带到下一件事、多任务切换时上下文会不会串。这类样本少判定也最软。单元边界适合评什么不适合评什么计数单位轮次级一问一答格式、拒答、工具选择任何有上文依赖的行为轮任务级目标不变的一段交付是否达成、约束是否守住跨任务记忆目标会话级打开到关闭偏好延续、多任务隔离单点能力会话一个会话里有多个任务按目标切不按话题切切分用两个判据作用不同。目标是否变了有没有产生新的交付物、新的对象。用户在改一份报价单中途问「你们支持哪些导出格式」这是新目标问完回来继续改还是原来那个目标。上下文是否需要重放把这段单独拿出来不带前文能不能得到同样的正确答案。这条决定「能不能切」。两条冲突时以第二条为准。上面那个例子里导出格式的问答可以切成一个轮次级样本报价单那一段跨过插问必须带前文才能重放仍然合成一个任务级样本只是轮次不连续。这一点直接决定样本结构turn_index必须是索引数组不能写成[start, end]。写成区间插问那几轮会被卷进来切成两段后半段就丢了上文。样本结构⚠️ 代码待验证{sample_id:ss_20261021_0417#g2,session_ref:ss_20261021_0417,unit_type:task,turn_index:[3,4,5,6,9],goal:把报价单改成含税口径并导出表格,state_expect:[{key:currency,mode:eq,value:CNY,from_turn:3},{key:tax_mode,mode:persist,value:inclusive,from_turn:4},{key:extra_tax_line,mode:absent,value:true,from_turn:6}],final_expect:{artifact_type:sheet,must_have_columns:[含税单价,含税合计],must_not_have_columns:[未税单价],answer_must_contain:[含税]},replay:{tool_fixture:fx_20261018_a,config_snapshot:cfg_7f3c,seed:20261018,grader_version:r5},labels:{turns:5,goal_changes:1,corrections:2,has_artifact:true}}sample_id用「会话标识 目标序号」拼不要用自增号切分规则改一次自增号就整体错位。labels里的三个数是第七章分层的依据corrections为 0 的样本和大于 0 的通过率差得很远。三、状态依赖后一轮的正确答案取决于前一轮多轮里能写死的只有状态写不死的是回答。记状态不记期望回答期望回答是一个字符串同一个状态在会话里的说法有几十种——「改成含税价」「按含税算」「价格里把税包含进去」说的是同一件事。判定器对字符串做模糊匹配误差方向不可控既会把对的判错也会把错的判对。期望状态是一个键值对可以精确比较。所以多轮样本的主体不是expected_answer是state_expect。三类状态类别典型例子谁写入能否被覆盖断言方式事实币种、客户名、单据编号用户提供或工具返回能属于更正要留痕终局等值约束行数上限、必含字段、不得改动的列用户提出不能只能显式撤销逐轮保持决定模板、口径、处理路径在候选里选定能但要能追溯是哪一轮改的候选集合内三类的差别不在重要程度在被覆盖的合法性。事实被新事实覆盖是正常的约束被悄悄覆盖是缺陷用户说「不要动 B 列」模型第 7 轮为了凑格式把 B 列重排了决定被覆盖要看有没有说明。三类都用「终局等值」去判约束类会全部漏判。断言怎么写⚠️ 代码待验证defcheck_state(trace,expects):trace: 每轮结束后的状态快照expects: 样本里的 state_expect。out[]foreinexpects:key,mode,starte[key],e[mode],e.get(from_turn,0)got[t.get(key)fortintrace]ifmodein(eq,one_of):want[e[value]]ifmodeeqelsee[values]okgot[-1]inwant badnext((iforiinrange(len(got)-1,-1,-1)ifgot[i]notinwant),None)elifmodepersist:okall(got[i]e[value]foriinrange(start,len(got)))badnext((iforiinrange(start,len(got))ifgot[i]!e[value]),None)elifmodeabsent:okall(got[i]!e[value]foriinrange(start,len(got)))badnext((iforiinrange(start,len(got))ifgot[i]e[value]),None)else:raiseValueError(f未知断言模式{mode})out.append({key:key,mode:mode,ok:ok,bad_turn:bad})returnoutpersist和eq的差别是这段代码的重点。eq只看最后一轮persist从from_turn开始逐轮看。很多会话终局是对的中间有三四轮产出是错的——约束在第 5 轮被丢掉第 8 轮又想起来了。用eq判这条通过用persist判bad_turn指到第 5 轮排查的人直接去看那一轮不用从第一轮读起。两个实现细节。absent和「字段缺失」不是一回事前者是这个值不该出现后者说明抽取器漏了。缺字段的样本记undetermined当成absent通过等于把抽取器的 bug 记成模型的成绩。抽取器自己也要评人工标一批状态算键级准确率低于阈值先修它。四、中途改口与自我修正改口不是噪声是一等公民。把改口从样本里剔掉评出来的是一个不存在的产品。三种形态三种处理形态典型说法判分基准样本怎么处理常见错判纠正事实「币种是美元不是人民币」以最后一次更正为准同一样本改状态值把更正前的轮次记成失败改目标「算了改成按客户拆」旧目标按旧期望判新目标另立样本切两条共享前文用新目标去判旧产出改形式「太长了列个表」终局按新形式判同一样本加形式断言旧形式被判成格式错误三种里只有「改目标」需要切样本。这个区分不做最常见的后果是一条会话被判两次失败旧产出用新目标衡量怎么都不对。判终局还是判每轮以终局为主配三个过程量。响应延迟改口发生在第 6 轮模型从第几轮开始按新要求做。第 6 轮就转了延迟为 0拖到第 8 轮中间两轮产出是废的。改对是必然要求转得慢才是缺陷。旧状态残留改口前的值有没有继续出现在后续输出里。用户说币种是美元第 7 轮合计还按人民币算——表面上接受了更正实际只改措辞没改计算。冲突提示新要求与既有约束冲突时有没有指出来。前面说「不要动 B 列」后面说「B 列也汇总进去」两句不能同时满足。直接照做是一种处理先问一句「B 列之前要求不动这次要一起改吗」是另一种后者记conflict_flagged。「改对了」要不要给分不给。改对是被要求的行为不是加分项。给改对加分等于承认「先做错再改对」和「一次做对」同价长期会训出一个反复试探的产品。该记的是错了几轮从改口那轮到行为真正转向隔了几轮这个数进labels进过程分。有例外新要求与既有约束直接冲突模型没有闷头执行而是指出冲突并等确认这不是「改对」是避免了一批无用功记正分合理。自我修正另算一类。模型自己发现前一轮说错并纠正记self_correction标签不单独加分。它说明过程不稳标签用来分析哪类任务容易反复不能抵掉终局失败。五、评分终局判定、过程判定与两者混用评分要回答两件事办成了没有过程有没有问题。前者决定通过与否后者决定往哪儿改。终局判定的三种实现规则判定的检查项是具体的有没有那两列、有没有不该出现的列、数值合计对不对、答复里有没有结论。它稳定、可复现、便宜缺点是只覆盖可判的部分。覆盖率要算出来——被规则覆盖的断言条数除以总条数低于阈值时整条记undetermined别让半套规则判出通过。裁判模型补开放部分。rubric 只问三件事目标是否达成、有没有承诺了没做的事、有没有引入用户没要求的东西。要求输出结构化结果并带证据——第几轮哪句话支撑这个结论不带证据的判定直接丢弃。它最容易出的错是宽容话说得客气、结构清楚就判通过所以 rubric 要写成可反驳的形式不问「是否回答了问题」问「有没有给出具体处理结果」。人工只用两处建基线处理争议样本。它不进常规回路成本撑不住也没必要——绝大多数判定是重复的。过程判定看什么只看三个点多了没人看。工具选择该调的调了没有判据落在 trace 上。追问时机信息不足时有没有发起一次澄清且只问缺的那一项。问了三件只缺一件浪费用户一轮该问没问、直接猜一个值问题更大——猜错要花更多轮修。重复动作同一工具同参数连续调两次以上或把上一轮问过的问题再问一遍。这在长会话里频率更高是上下文管理失效的直接信号。混用时的权重与失效条件⚠️ 代码待验证unit_type:taskgrader_version:r5final:rule_set:quote_rules_v3weights:state_expect:0.5final_expect:0.5coverage_gate:0.8# 规则覆盖的断言占比低于此值整条记 undeterminedprocess:checks:tool_choice:{weight:0.4}clarify_timing:{weight:0.3}repeat_action:{weight:0.3}min_turns:4# 少于 4 轮的样本不参与过程判定guard:veto:-unrequested_write# 未经确认的写操作-stale_state_used# 拿改口前的旧值继续执行blend:final:0.6process:0.3guard:0.1fallback:undetermined这么分有前提终局占大头用户只认结果过程占三成它是唯一能指向改法的信号护栏是否决项越过一次直接失败不进加权。失效条件要写进配置不能靠人记。coverage_gate没满足时终局分不可信整条记undetermined。min_turns以下不判过程「追问时机」在两轮会话里没有观察窗口。裁判模型的版本必须和结果一起存判定器升级后重跑分数会变要能区分「产品变了」和「尺子变了」。两个方向的错要分开记。终局对、过程错工具调三次才拿到结果按终局算通过过程分要扣——通过率没动而过程分掉了说明结果还稳但成本在涨。终局错、过程对工具都选对了最后汇总算错最值得看改一处提示就能修把它们和「工具乱选」混在一起团队会去调工具路由调完发现没效果。完整版资料清单本文用到的会话样本模板、状态断言脚本和评分配置都在里面扫码即可获取六、复现同一条会话怎么重跑一条会话的失败如果重跑不出来就没法修。复现要存的东西比单轮多。四样东西第四样最容易漏输入序列每轮用户的原始文本按turn_index取。别存拼接后的大字符串那样定位不到是哪一轮出错。工具返回每次调用的返回体按「轮次 : 调用序号」索引。同一轮调了两次就存两个只存最后一个会把问题掩盖掉。配置快照提示版本、工具注册表、参数默认值、开关状态。少一样行为不同就说不清是谁的问题。判定器版本样本没变、产品没变判定器从 r4 换到 r5结论变了历史曲线出现台阶然后有人开始查产品。工具返回与随机性录制回放固定返回用于回归失败一定能复现。代价是它把「上游变了」挡在门外——回放里工具永远返回三个月前那份数据接口改字段永远测不出来。真实调用不固定用于定期体检。跑得少、成本高但能发现环境漂移。两层之间要有一个判据重跑失败时先比工具返回。返回体和录制时不同这条失败不算模型回归记env_drift不进主分母。少这个判据一次上游字段改名会让整批样本集体失败。随机性也是同一类问题。固定种子不等于结果确定服务端可能有多副本、并发批次会影响数值、超时重试会改变路径。做法是同一会话跑三次两次通过算通过结论不一致记flaky。flaky单列不进主分母但要单独看比例和分布——它集中在某类任务上说明那类任务本身不稳比通过率下降更值得处理。重放器与不一致的定论重放器本身不长难在两处取舍。⚠️ 代码待验证defreplay(sample,gen,fixtures):只固定输入与工具返回不固定模型输出。msgs,trace[],[]forturninsample[turn_index]:msgs.append({role:user,content:sample[user_text][turn]})forstepinrange(sample[max_steps]):respgen(msgs,seedsample[replay][seed],turnturn,stepstep)ifresp.tool_calls:fork,callinenumerate(resp.tool_calls):keyf{turn}:{k}ifkeynotinfixtures:return{status:incomplete,missing:key}msgs.append({role:assistant,tool_call:call})msgs.append({role:tool,content:fixtures[key]})continuemsgs.append({role:assistant,content:resp.text})trace.append({turn:turn,text:resp.text,state:resp.state})breakelse:return{status:incomplete,missing:f{turn}:max_steps}return{status:done,trace:trace}两处细节决定它对不对。每一轮都把本次生成的输出写回msgs。图省事把当年录下的模型输出写回去重放就变成放录像测的是一个不存在的系统。fixture 缺了就停不回落真实调用。回落看起来健壮实际会让结果一半来自录制、一半来自线上出问题无法归因。缺就记incomplete补录制再跑。max_steps的兜底同理某轮模型进入反复调工具的状态没有上限的重放会跑很久最后超时退出看起来像基础设施问题。重跑结果不一致时三种原因按顺序排除先固定判定器把同一份输出判两次结论不同是判定器不稳跟产品无关再固定种子重放结论仍然飘是模型不确定最后比工具返回返回体变了是输入漂移。顺序不能反先怀疑模型是本能反应而模型往往是最无辜的那一环。要素存什么不存的后果归档粒度输入序列每轮原始文本定位不到是哪一轮出问题按样本工具返回返回体按轮次与调用序号索引同轮多次调用互相覆盖按调用配置快照提示、工具注册、默认值、开关行为不同却查不出原因按版本判定器版本标识与关键参数分数变化归错因按版本随机种子每次运行的种子无法区分不确定与漂移按次七、通过率怎么算与落地顺序分母与判不了会话数作分母最省事一条算一个问题是长短会话等权二十轮改了三次需求的和两轮的确认类权重一样。任务数作分母贴近用户感知用户记的是「那件事办成没」。主口径建议任务级会话级只在评测跨任务能力时用。轮次数作分母只用于定位它回答「哪一轮最容易断」回答不了「有多少事办成了」。undetermined不能算失败也不能算通过。算失败通过率被「判不了」拉低团队去优化判定器算通过问题被藏起来。做法是分母排除、单列上报并把它的占比当成独立指标——这个数上升说明规则覆盖或状态抽取出了问题。加权与分层加权用固定的一组分层权重不要按样本量自动加权那会让最容易采样的那一层支配总分而那一层往往最简单。分层的目的是定位三个维度够用——会话长度、改口次数、是否跨任务。混在一起看的通过率没有信息量分开看才知道是哪一类在掉。⚠️ 代码待验证WITHunitAS(SELECTs.sample_id,(s.labels-turns)::intASturns,(s.labels-corrections)::intAScorrections,r.verdictFROMeval_sample sJOINeval_result rUSING(sample_id)WHEREr.run_id:run_idANDr.grader_version:grader_version)SELECTCASEWHENturns3THEN1-3WHENturns8THEN4-8ELSE9ENDASturns_bucket,count(*)FILTER(WHEREverdictpass)ASpassed,count(*)FILTER(WHEREverdictfail)ASfailed,count(*)FILTER(WHEREverdictundetermined)ASundetermined,round(count(*)FILTER(WHEREverdictpass)::numeric/nullif(count(*)FILTER(WHEREverdictundetermined),0),3)ASpass_rateFROMunitGROUPBY1ORDERBY1;查询里有两点要守住。grader_version必须进WHERE否则不同版本的判定结果会被混在一起算undetermined必须从分母排除同时单独输出。分层权重落到代码是这样⚠️ 代码待验证STRATA[(1-3,0.2),(4-8,0.5),(9,0.3)]defpass_rate(rows):acc_w,total_w,undet,per0.0,0.0,0,{}forname,winSTRATA:seg[rforrinrowsifr[turns_bucket]name]oksum(1forrinsegifr[verdict]pass)badsum(1forrinsegifr[verdict]fail)undetsum(1forrinsegifr[verdict]undetermined)ifokbad0:# 整层都判不了这一层不进加权continueper[name]ok/(okbad)acc_ww*per[name]total_wwreturn{rate:acc_w/total_wiftotal_welseNone,strata:per,undetermined:undet}total_w不是固定的 1。某一层全部undetermined时它被跳过剩下权重重新归一否则那一层会把总分拉低。归一之后不同批次的权重构成可能不同strata要一起输出。落地顺序与遗留问题第一批做目标明确、轮次在三到八之间、有可检查产物的任务级样本。这类样本状态好写、终局好判、重放稳定先跑通能验证整条链路切分、断言、重放、判定、聚合每一环都会在这里暴露问题。第二批加改口样本挑corrections大于 0 的会话补状态断言和过程量。这批上来之后通过率通常会掉一截不是退步是前面没测到。第三批才做跨任务会话和纯咨询类前者依赖偏好延续后者判据最软两批都会把判定器和人工拖进长时间对齐。跨会话的记忆也用这套结构表达不了。用户隔天回来接着上次的事做样本边界不在一个会话里turn_index直接失效。要评这一类得把单元提到「用户 × 主题」判定要能区分「记得」和「猜对」。另一件是判定器版本变更后的可比性变更时整批重跑、留一份基线但两套判定器的差异来自 rubric 的哪一条没有系统性的拆法。完整版资料清单会话切分规则、状态断言模板和通过率聚合脚本都整理在里面了扫码即可获取附表 A关键取舍一览取舍本文结论判断依据位置评测单元用轮次还是会话主口径用任务级用户按任务记账轮次放大长会话第二章会话内多目标怎么切按目标切冲突时以能否重放为准不能重放的片段必须带前文第二章期望写回答还是写状态写状态同一状态说法太多字符串匹配不可控第三章约束类状态怎么断言逐轮保持不看终局中间轮次的错误会被终局掩盖第三章状态缺失怎么算记判不了当成通过等于把抽取器的错记成成绩第三章改目标要不要切样本要用新目标判旧产出必然全错第四章改对了给不给分不给记改口后延迟给分等于承认先错后对与一次做对同价第四章规则覆盖不足怎么办整条记判不了半套规则判出的通过分不可信第五章工具返回固定不固定回放固定体检不固定回放挡不住上游漂移第六章重放是否复用当年输出不复用复用等于放录像测不到当前系统第六章重跑不一致先查谁判定器、模型、工具返回倒序排查会把模型当替罪羊第六章通过率的分母任务数为主会话数让长短会话等权第七章判不了的样本怎么算分母排除单列上报算失败会让人去修判定器第七章分层权重怎么定固定权重不按样本量按样本量加权会让简单任务支配总分第七章附表 B术语速查表术语含义评测单元一条样本覆盖的交互范围分会话级、任务级、轮次级任务级样本会话内目标不变的一段交互本文主口径轮次级样本一问一答只用于不依赖上文的单点能力样本切分按目标变化与能否重放两个判据拆会话期望状态会话结束时应当成立的状态键值替代期望回答事实状态用户提供或工具返回的客观值可被更正约束状态用户提出的限制只能显式撤销决定状态候选里选定的方案变更要可追溯保持断言从某一轮起每轮都要满足的检查不看单点旧状态残留改口前的值继续出现在后续输出里响应延迟改口发生到行为真正转向之间的轮数冲突提示新要求与既有约束矛盾时主动指出并等确认终局判定只看会话结束时的结果是否达成过程判定看工具选择、追问时机、重复动作等轨迹特征规则覆盖率被规则覆盖的断言占比低于阈值整条记判不了判不了判定条件不满足的第三种结论既不算通过也不算失败会话重放用录制的输入与工具返回重跑模型输出重新生成工具夹具按轮次与调用序号索引的工具返回录制环境漂移上游返回变化导致的失败不计入模型回归写在最后这篇用到的资料写这篇文章时我把几个模型的官方文档、参数表和实测记录都对了一遍顺手整理成几份配套的东西大模型学习路线图从 LLM 基础到 Agent 开发各阶段该学什么、用什么资料大模型全套教程按主题分好的视频与文档清单大模型实战好书24 本附每本适合的阶段资料是我自己整理的放在下面这个码上扫码即可获取添加时备注「大模型」优先通过。拿到之后建议先看学习路线图那一份先定位自己在哪个阶段再决定学什么比一上来就啃框架效率高得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑