langchain-ai/langchain#38904 · test_stream_error_callback 被 xfail 长期掩盖:错误断言让"流式错误回调"验证名存实亡 · 2026-07-26
test_stream_error_callback
(langchain-core,chat_models/test_base.py)被标记为
@pytest.mark.xfail(reason="failing due to a bug in the testing code")。
真实根因不是产品代码,而是测试断言写错了:断言
generations == [],
但 generations 是"每个 prompt 一个列表"的嵌套结构,空结果应是
[[]]。
修正断言即可通过。问题的严重性在于:这条 xfail 让"流式错误回调"这一关键可靠性路径长期处于零覆盖状态。
xfail 存在期间,每一次测试运行都跳过对流式错误回调的实际断言,绿色 CI 掩盖了验证缺口。
xfail 在测试报告中显示为"预期失败/已知问题",不触发红灯。维护者与用户都会默认"这块有测试保护"——实际上保护为零。
被掩盖的正是流式过程中的错误回调路径——即"流到一半失败时,on_llm_error 是否被正确触发、generations 状态是否正确"。这恰是生产 Agent 最依赖、也最容易静默吞错的环节(参见 ARK 对 #38892/#39039 的流式静默丢弃诊断)。
真相:LLMResult.generations 的类型是 list[list[Generation]]——外层每个元素对应一个 prompt。单 prompt 的空生成是 [[]],不是 []。
根因是"测试断言与被测类型契约不符",而处置方式(挂 xfail 而非修断言)把一个 5 秒可修的笔误,升级成了长期的覆盖盲区。
报告者与 @Tanmay9223 均已定位到同一处断言,并在 #38901 提交修复:修正断言为 [[]] 并移除 xfail 标记。
这是一个"根因无争议、修复一行、却依赖上游合入节奏"的典型案例——与 ARK 此前诊断的 #38779(7 个 PR 被自动关闭)同属维护带宽瓶颈族。
xfail 是把双刃剑:它让 CI 保持绿色、避免 flaky 阻塞合并,但一旦 reason 写成"测试代码的 bug"却无人回收,它就从"临时豁免"退化为"永久掩盖"。
场景:团队复用上游测试模式作为自家回归基线
许多团队直接照搬 langchain-core 的回调测试范式来验证自家 Agent 的流式错误处理。若照搬了同款错误断言或"遇错就 xfail"的习惯——
→ CI 全绿,但流式失败路径从未被真正断言过
→ 生产中一旦"流到一半失败",on_error 未触发、部分结果被当成成功返回,直到用户投诉才暴露。
问题本质
这是"静默失败"从产品代码蔓延到验证层的镜像:不是 Agent 骗了你,而是"证明 Agent 没骗你的那套测试"本身失效了。安全网破了个洞,而洞口贴着"预期之内"的绿色标签。
① OutputValidator — 运行时断言流式终止状态
② TrustLoop — xfail / skip 审计闸门
③ OTel Bridge — 流式错误路径全链路留痕
即使上游测试仍被 xfail,ARK 也能在真实流量上验证该路径行为符合契约。
#38904 的价值不在这个一行断言笔误,而在它示范了"静默失败如何潜入验证层"。当测试用 xfail 掩盖自己的 bug,绿色 CI 就成了最危险的谎言——因为它给出的是"有保护"的假象。
被掩盖的恰是流式错误回调路径——生产 Agent 中最容易"流到一半悄悄吞错"的环节,与 ARK 反复诊断的 #38892/#39039 同源。
修复只需一行、根因毫无争议,却要等上游合入 #38901——再次印证:可靠性防线必须建在自己这一侧,不能把安全网的完整性外包给上游的合并队列。
ARK 的运行时输出校验 + xfail/skip 审计闸门 + OTel 留痕,把"被掩盖的测试缺口"转化为显式的运行时断言、有时限的技术债与可观测的生产证据——让安全网重新真正兜底。