训练一个 Deep Research Agent,数据里通常不只有用户问题和模型答案。
模型会发起 Search、Visit 或计算调用,工具环境再返回网页片段、错误信息和结构化结果。把整条记录拼成一个序列后,一个容易被忽略的问题出现了:这些字是不是都应该让模型学习预测?
答案是否定的。
模型应该学会什么时候调用工具、参数怎样填写、拿到结果后怎样继续以及最终如何回答。工具返回却是环境产生的,不是模型应该凭空生成的内容。
如果训练时不区分两者,模型可能在没有真正调用工具时,直接续写一段像搜索结果的文字。看起来信息丰富,实际上把“使用工具”学成了“模仿工具”。
所以面试官真正想问的是:
Observation Loss Mask 到底遮住什么,为什么只改 attention mask 不够,怎样把角色边界映射到 token,如何处理模板、截断、工具错误和多轮调用,又怎样证明 Mask 没有串位?
先分清三个概念:输入、目标与可见性
用户问题是模型做决策的前提。
工具 observation 也是前提。模型必须看见搜索结果,才能判断下一步访问什么或怎样回答。
工具调用与最终答案则是模型要学会生成的输出。
因此,“不让 observation 参与 loss”不等于“不让模型看见 observation”。前者控制监督目标,后者控制注意力可见范围,完全不是一件事。
如果把工具返回从上下文删掉,后续回答失去依据。如果用 attention mask 屏蔽它,模型同样无法利用环境结果。正确做法是保留 observation 在输入中,让后续 token 可以关注它,只把对应位置的训练 label 忽略。

工具返回要被模型看见,但不要求模型把它重新生成一遍。
不做 Observation Mask,模型会学坏什么?
最直接的问题是目标错位。
训练目标要求模型预测一段网页正文,实际上线上运行时,这段正文应该由 Search 或 Visit 返回。模型把容量花在记忆环境文本,而不是学习行动策略。
第二个问题是伪工具调用。
若训练序列中模型输出后总跟着一段 observation,模型可能学会直接续写这段模式。线上控制器还没执行工具,它已经自己生成了“工具结果”。
第三个问题是来源混淆。
工具返回里可能包含事实、广告、导航、错误页和不可信文本。把它们都当模型正确输出,会弱化“环境内容只是证据候选”的边界。
第四个问题是损失被长返回主导。
Deep Research 的网页片段往往远长于一个工具调用。即使每个 token 权重相同,大量 observation token 也会在总 loss 中占据主要部分,真正要学的工具参数和答案反而信号更弱。
第五个问题是评估错觉。
训练 loss 下降,可能只是模型更会复述重复出现的工具返回,并不代表工具选择、停止条件和答案证据有改善。
Loss Mask 具体遮住什么?
一个常用的原则是按“线上究竟由谁产生这段内容”划分。
用户消息由用户提供,不是模型预测目标。
系统指令由应用提供,也通常不作为当前 Agent 行为的监督目标。
工具 observation 由环境提供,必须 mask。
模型生成的结构化 tool call 是目标,因为线上需要模型决定工具与参数。
模型最终回答是目标,因为它需要综合证据完成任务。
对于状态摘要、计划或中间说明,要根据线上架构判断。如果它由模型生成并会在推理时复现,可以纳入目标;如果由控制器或外部压缩器写入,就应当作为条件而不是目标。
不要依赖字段名字猜。某些数据把工具返回错误标成 assistant,某些框架又把模型的 tool call 拆成专用角色。真正边界来自生产协议与消息血缘。
为什么不是 Attention Mask?
Attention mask 主要回答“某个 token 在计算表示时能看见哪些位置”。
Loss mask 回答“这个位置预测错了是否产生训练损失”。
Agent 后续决策必须读取 observation,所以它在注意力上通常是可见的;但 observation 不是模型负责生成的,所以 label 应当忽略。
常见实现是在完成模板渲染和 tokenize 后,复制 input ids 为 labels,再把不参与监督的位置设为训练框架约定的 ignore index。损失函数跳过这些位置,输入序列仍保持完整。
若误用 attention mask,模型可能看不到工具结果;若只在原始字符串上删除 observation,消息结构与位置也会改变。两种做法都改变了真实推理条件。
为什么必须在 Chat Template 之后确定 token 边界?
原始数据里的消息边界不一定等于最终 token 边界。
目标模型的 chat template 会插入角色控制符、起止标记、换行和工具调用包装。不同 tokenizer 还可能把相同字符切成不同 token。
如果先按字符位置计算 mask,再套模板,偏移很容易错。结果可能把工具调用的一部分遮掉,或者让 observation 的开头和结尾漏进 loss。
更稳妥的方式有两类。
一种是逐段渲染并记录累计 token 长度。每加入一条消息,就比较模板前后 token 序列,得到新片段边界。
另一种是使用框架提供的 assistant token mask 或角色级标注能力,但仍要验证它是否正确识别 tool call 与 tool observation。
无论用哪种方式,都要针对实际模型模板写测试,不能假设换一个模型后边界仍然成立。
一条多轮轨迹怎样生成 Labels?
第一步,先校验消息协议。每个工具返回必须能通过 call ID 找到对应工具调用,不能出现孤立 observation。
第二步,按目标模型模板渲染完整对话,保留用户、模型调用、工具返回和最终回答的顺序。
第三步,tokenize 时获得 input ids,并建立每个 token 对应的消息角色或生成来源。
第四步,将用户、系统、工具 observation 与控制器生成片段设为 ignore index。
第五步,保留模型需要学习的 tool call 与 final answer 标签。是否训练模型生成额外计划,应由线上协议决定。
第六步,处理末尾控制符。有些结束标记是模型必须学会生成的停止信号,应与对应 assistant 段一起保留;有些模板分隔符只是输入包装,需要按框架定义处理。
第七步,输出有效监督 token 数。若一条样本被 mask 后没有任何目标 token,应该拒绝或单独处理,而不是进入训练制造空梯度。

先确定消息血缘,再经过模板和 tokenizer 映射到 token 级 labels。
工具错误返回也要 Mask 吗?
要。
超时、权限拒绝、空结果、参数错误和解析失败都由环境产生,不是模型应当背出来的文本。
但错误 observation 对后续行为很有价值。模型需要看见错误类型,再学习重试、修改参数、切换来源或降级回答。
所以错误返回仍保留在上下文并 mask,其后的恢复行动继续作为模型目标。
这里有个前提:错误必须真的来自工具环境,不能由 Teacher 为了补齐轨迹自由编写。否则即使 mask 正确,后续恢复策略仍在回应虚构条件。
同样,网页中的不可信指令也属于 observation。模型可以读取但不应把它视为系统命令,训练数据还要在角色与安全策略上明确优先级。
连续多个 Tool Call 怎样避免串位?
Agent 可能一次发出多个并行调用,也可能在一轮里连续调用不同工具。
只靠“assistant 后面的下一段都是 tool”这种位置规则不够。必须使用 call ID 或等价关联键,将每个 observation 绑定到具体调用。
并行返回顺序还可能与发起顺序不同。训练格式应按照控制器真实提供给模型的顺序记录,不能为了排版整齐重新排序后又丢失关联。
工具返回内部若嵌有类似 assistant 标签的字符串,也不能触发角色切换。边界必须来自结构化消息,不来自内容正则。
规范化时还要检查重复 ID、缺失 ID、一个返回对应多个调用和调用未返回等异常。能够解析不代表关联正确。
截断时最容易发生什么错误?
长轨迹超过最大长度时,简单从尾部截断可能留下工具调用,却删掉对应 observation 和答案;从头部截断又可能删除任务与早期证据。
Mask 本身无法修复不完整语义。
数据管道应先按消息或步骤边界裁剪,不能在一个 JSON tool call 中间截断。若丢失了后续回答所依赖的 observation,这条样本的答案监督也不再可靠。
可以对轨迹做结构化摘要或选择完整子轨迹,但摘要由谁生成、哪些事实被保留必须有明确协议。外部摘要作为条件时也应 mask。
若样本最终没有有效模型目标,或者最后一个调用没有闭合,应该标记为截断未完成,而不是自动补一个答案。
相关教程在强化学习部分还提醒,未完成长轨迹若直接作为错误负样本,可能让模型学会为了避免截断而仓促作答。SFT 数据阶段就应保留这个失败类型。
Mask 正确不等于数据正确
一条轨迹可以完美区分角色,却仍然选择错工具、访问错页面、重复搜索或给出无证据结论。
Loss mask 只保证监督目标没有要求模型生成环境文本。
轨迹仍需经过结构、行为和答案质量门:工具参数是否合法,步骤是否推进,异常是否真实,关键主张是否有证据,停止是否合理。
同样,Mask 不能解决训练分布问题。如果绝大多数目标 token 都来自 Search 调用,模型仍可能形成默认搜索偏好。
因此应同时统计样本数、总 token、有效监督 token、不同目标类型 token 和被 mask token。只看文件行数或序列长度,会误判真实训练信号。

Mask 解决目标归属,策略、证据、分布和安全仍要分别验收。
多个数据来源怎样统一,才不会越洗越乱?
真实项目的轨迹可能来自不同 Teacher、不同工具框架和不同时间版本。
有的来源把工具调用放在 assistant 的结构化字段里,有的写成文本标签;有的 observation 使用 tool 角色,有的嵌在普通消息中;还有的数据已经把用户、工具和模型文本拼成一整段。
不能先全部拼接,再用一个正则寻找标签。只要网页正文里恰好出现相同字符串,角色边界就会被误判。
更稳妥的顺序是先为每个来源编写解析适配器,将原始记录转换成统一中间结构。中间结构保留消息来源、call ID、工具名、参数、返回状态和原始偏移,再由同一个模板渲染与 label 构造器生成训练样本。
无法可靠恢复血缘的数据,即使文本看起来完整,也不应自动进入高质量训练集。可以留作无监督语料或人工复原候选,但不能假装它已经具备准确 mask。
规范化后要保留原始样本 ID 与转换版本。以后更换 tokenizer 或 chat template 时,可以从中间结构重新构造,而不是在旧 token 序列上继续修补。
这也是为什么“格式清洗”不能只看最终 JSON 能否解析。真正重要的是每个 token 的生产责任仍然可追溯。
怎样发现批量 Mask 漏标或误标?
单条测试通过后,批处理仍可能因为某个数据源或模板版本出现系统性偏移。
可以按数据来源统计 observation token 占比、有效监督 token 占比、tool call 与 final answer 的监督长度。这里不需要预设一个通用正确比例,而是观察同类任务和相邻版本是否发生无法解释的突变。
若某批样本的有效监督 token 突然接近整段序列,优先检查 observation 是否被误标成模型输出。若有效监督几乎为零,则检查 assistant 段是否被整体遮住。
还可以抽取若干样本生成颜色化 token 报告:被 mask 的位置使用灰色,监督位置使用蓝色,并在旁边标出角色和 call ID。它比只看布尔数组更容易发现模板控制符和边界 token 泄漏。
训练日志也能提供线索。如果 loss 很快下降,但推理时模型频繁自行输出网页片段,优先检查 observation 是否曾经参与监督,不要先归因于模型“记忆力强”。若模型不会闭合 tool call 或生成 final answer,则可能对应目标 token 被错误 mask。
这些现象只能提示排查方向,不能单独定因。最终仍要回到具体样本的消息血缘、labels 和推理控制器重放。
怎样验证 Mask 没有做错?
第一层是结构单测。
构造一条只有用户、一次 tool call、一次 observation 和 final answer 的最小轨迹,逐 token 打印文本、角色和 label 状态。人眼应能确认工具调用与答案参与监督,用户和 observation 被忽略。
第二层是边界用例。
覆盖空 observation、中文与英文混排、多字节字符、工具错误、并行调用、连续调用、引用标记、模板控制符和刚好发生截断的位置。
第三层是反解抽查。
把所有未 mask token 解码出来,检查它是否只包含模型在线上应该生成的片段。再解码 mask 片段,确认 observation 没有漏出。
第四层是统计验收。
按角色统计 token 与有效 label 数,观察不同数据来源和版本是否突然变化。某批数据有效监督比例异常高,可能是 observation 漏标;异常低则可能把 assistant 输出遮掉。
第五层是极小批过拟合测试。
用少量已人工确认样本检查训练能否降低目标位置 loss,并在给定同样 observation 时复现合法 tool call 或答案。它不能证明泛化,却能暴露全 mask、边界错位和模板不兼容。
第六层是推理回放。
模型生成 tool call 后,必须由真实控制器执行,再把 observation 注入。若它经常在工具返回前自行生成结果,说明训练格式、停止控制或历史数据仍有串位。
面试官继续追问,怎么接?
追问一:为什么用户问题也通常不参与 loss?
它是任务条件,不是模型在线上要生成的内容。训练目标是条件给定后产生的工具行动与回答。
追问二:把 observation 从 input 删除不行吗?
不行。后续决策需要读取工具结果。它应当可见但不计入预测损失。
追问三:Mask 后模型还能学会利用工具结果吗?
可以。后续 tool call 与答案的损失会通过注意力依赖 observation,模型学习的是“基于这个输入怎样行动”,不是“生成这个输入”。
追问四:所有 assistant token 都应该参与 loss 吗?
不一定。要看线上由谁生成。控制器注入的摘要即使存成 assistant 角色,也不应仅凭角色名当作目标。
追问五:怎样证明 observation 没有漏进 loss?
做 token 级可视化、反解抽查、角色统计、边界单测和极小批过拟合,并在推理回放里确认工具返回前不会自写结果。
怎样把 Observation Mask 讲到工程细节
Observation 是工具环境提供给模型的条件,不是模型应该生成的目标。训练时我会保留它在 input 中,让后续行动可以关注,但把对应 label 设为 ignore index。不能用 attention mask 代替,因为那会让模型看不到工具结果。
边界要来自结构化消息血缘和生产协议,经过目标模型 chat template 与 tokenizer 后映射到 token,不能只按字符或角色名字猜。用户、系统、工具返回与控制器注入片段通常 mask,模型生成的 tool call、必要停止符和 final answer保留监督。工具错误也要 mask,但其后的重试与降级行动仍是目标。
验收上我会覆盖并行调用、空返回、错误返回、模板控制符和截断,做 token 可视化、反解、角色统计、极小批过拟合与推理回放。最后强调,Mask 只修正“由谁生成”的训练目标,不能替代工具选择、证据准确、轨迹进展和数据分布质检。

Mask 管道要过哪些验证
拿一条多轮工具轨迹对照 token、角色边界与 labels,确认训练目标没有把环境返回误当成模型答案。
- Observation 是否保留在输入中,同时从 labels 中忽略?
- Mask 边界是否在真实 chat template 与 tokenizer 后验证?
- 工具错误、并行调用、控制器摘要和截断是否有独立用例?
- 是否统计有效监督 token,而不只看样本数和总长度?
- 是否用真实控制器回放,确认模型不会自行生成工具返回?
- 是否把 Mask 正确性与轨迹策略、证据质量分开验收?