
1. 一次“零报错”的诡异跑偏让我重新审视模型评测这件事模型没有报错日志干干净净指标看起来也正常但任务结果就是不对——这种体验我相信做过模型评测和Agent任务编排的人都遇到过。最近我在实测 Event Horizon 这套网页感知与操作核验方案时就撞上了这么一次典型的“静默走偏”控制台没有任何异常抛出每一步调用都返回了看似合理的结果可最终的任务完成度却和预期差了十万八千里。这件事让我意识到“没有报错”和“任务正确”之间隔着一整套关于感知、核验与状态追踪的工程问题。Event Horizon 这个名字本身就很有意思它指向的是“事件视界”——一个边界越过之后就再也无法回头地观测到真相。放到模型任务编排的语境里它要解决的核心问题是当模型通过网页感知去执行一系列操作时如何确认每一步真的“看到了该看的、点到了该点的、拿到了该拿的”而不是在某个环节悄悄偏离轨道却依然一路绿灯地跑下去。这套思路和 DeepSeek 这类模型在工具调用tool calls场景下的表现强相关尤其是当任务涉及多步网页交互、信息抽取和状态校验时模型很容易在中间某一步产生“幻觉式成功”。这篇文章适合三类人看一是正在做模型评测、Agent 任务编排的工程师二是用 DeepSeek 或其他大模型做网页自动化、信息采集的开发者三是对“模型看起来正常但结果不对”这类问题感到困惑、想搞清楚排查思路的技术人。我会把这次实测的完整过程、踩到的坑、排查手法和最终沉淀下来的核验策略都摊开讲尽量让你能直接抄作业。核心关键词 Event Horizon、模型、网页感知、操作核验、DeepSeek 会自然贯穿全文不堆砌只讲我实际用到的东西。先说结论方向模型不报错不代表任务没走偏真正可靠的评测必须把“感知层”和“核验层”分开设计并且对每一步操作建立可回溯的证据链。下面我从整体设计思路开始拆。2. 整体设计思路为什么“无报错”反而是最危险的信号2.1 从一次真实跑偏说起日志全绿结果全错那次实测的任务本身不复杂让模型通过网页感知去某个信息页面抓取一组结构化数据然后按照既定规则做筛选和汇总。我用的是一套基于 DeepSeek 的工具调用链路模型负责决策“下一步该点哪里、该读哪块内容”Event Horizon 负责把网页状态和操作结果反馈回去。第一次跑完日志里没有任何 errortool calls 的返回也都是 success模型自己还输出了一段看起来很合理的总结。但我拿结果和人工核对时发现模型在第三步就点错了入口进到了一个结构相似但内容完全不同的页面然后基于错误页面的内容继续往下推理一路“顺利”地完成了整个任务。整个过程没有任何异常因为从模型视角看它每一步都拿到了“看起来合理”的返回。这就是典型的静默走偏错误没有被抛出而是被后续步骤“合理化”了。这件事的关键教训是报错是显性的、容易发现的走偏是隐性的、会被正常流程掩盖的。如果你的评测体系只依赖“有没有抛异常”来判断任务是否成功那它天然对这类问题免疫——也就是说它根本检测不出来。2.2 感知层与核验层为什么要拆开很多团队做网页自动化时习惯把“感知”和“执行”揉在一起模型看到页面、决定操作、执行操作、拿到结果一条链路走到底。这种设计在简单任务上没问题但一旦任务步数变多、页面结构变复杂问题就来了——模型对“我看到了什么”的判断和对“我该做什么”的决策会互相污染。Event Horizon 的思路是把这两层拆开。感知层只负责一件事把当前网页的真实状态尽可能无损地转成模型能理解的结构化描述。核验层则负责另一件事在每一步操作之后独立地确认“操作是否真的生效了、页面是否真的变了、拿到的内容是否真的是目标内容”。这两层拆开之后模型不再既当运动员又当裁判走偏的概率会显著下降而且一旦走偏核验层能更早地把它拦下来。我自己的实践体会是拆层的成本主要在前期设计收益在后期排查。前期你得多写一些状态快照和校验逻辑但后期一旦出问题你能快速定位到底是感知错了、决策错了还是执行没生效。这个投入产出比在任务步数超过五步之后会变得非常划算。2.3 DeepSeek 工具调用链路里的“隐性假设”用 DeepSeek 做工具调用时有一个很容易被忽略的点模型对 tool calls 的返回结果默认是“信任”的。也就是说如果你返回的 JSON 里写的是 success模型就会认为这一步真的成功了然后基于这个前提继续往下推理。这个机制本身没问题问题在于很多实现里success 这个字段是“调用没抛异常”就填上的而不是“业务上真的成功”才填的。举个例子你让模型去点一个按钮底层执行器返回了“点击事件已派发”你就填了 success。但实际上按钮可能被遮挡、可能没绑定事件、可能点了之后页面根本没跳转。模型拿到 success就认为跳转完成了下一步直接去读新页面的内容结果读到的还是旧页面。这就是隐性假设带来的走偏。所以在 Event Horizon 这类方案里我强烈建议把 tool calls 的返回设计成“带证据的返回”不只是告诉模型成没成功还要告诉它“你凭什么判断成功”。比如返回里带上操作前后的页面指纹、目标元素的可见性状态、关键区域的内容摘要。模型拿到这些证据才能做出更靠谱的下一步决策。3. 核心细节解析网页感知与操作核验到底在核验什么3.1 网页感知的三种粒度与选择依据网页感知不是“把整个页面丢给模型”就完事了。实际做下来我把它分成三种粒度各有适用场景。第一种是全量 DOM 感知把页面的 DOM 树压缩后整体喂给模型。优点是信息全缺点是噪声大、token 消耗高模型容易被无关元素干扰。适合页面结构简单、目标不明确的探索性任务。第二种是区域感知只把当前视口或者某个容器内的内容提取出来。优点是聚焦、省 token缺点是需要提前知道目标大概在哪个区域。适合流程固定、目标明确的任务。第三种是语义感知不直接给 DOM而是把页面转成“可交互元素列表 关键文本摘要”的形式。这是我在 Event Horizon 实测里用得最多的一种因为它最接近模型决策时真正需要的信息有哪些可点的、可输的、可读的以及它们大概是什么。选择依据其实很简单任务越开放感知粒度越粗任务越确定感知粒度越细。但不管用哪种都要保证感知结果是“可回溯”的——也就是说当后面发现走偏时你能拿出当时模型看到的那个感知快照去复盘它为什么做了那个决策。3.2 操作核验的四个维度存在、可见、可交互、已生效操作核验是 Event Horizon 里最核心的部分。我把它拆成四个递进的维度每一步都比上一步更严格。存在性核验目标元素在 DOM 里到底有没有。这一步最基础但很多走偏就发生在这里——模型以为某个按钮存在实际上选择器匹配到了另一个同名元素。可见性核验元素存在但它是不是真的可见。CSS 里 display:none、visibility:hidden、被其他元素遮挡、在视口外这些都会导致“存在但不可见”。模型如果只看 DOM 存在就认为能点就会走偏。可交互性核验元素可见但它是不是真的能交互。比如被 disabled 的按钮、被 pointer-events:none 禁用的区域、被蒙层盖住的表单。这一步是很多自动化脚本翻车的地方。已生效核验操作发出去了但它是不是真的产生了预期效果。点击后页面有没有变化、输入后值有没有写进去、提交后有没有跳转或提示。这一步最难做也最能拦住静默走偏。我实测下来大部分“无报错走偏”都发生在第三和第四维度之间元素可交互操作也派发了但效果没生效而返回却报了 success。所以核验层一定要把“已生效”作为独立判断不能靠“操作没抛异常”来推断。3.3 状态快照让每一步都可回溯状态快照是我在这次实测里加得最值的一个设计。简单说就是在每一步操作前后都对页面的关键状态做一次轻量记录URL、页面标题、关键区域的内容哈希、可交互元素的数量和摘要。这些快照不需要很大但能在出问题时快速定位“是哪一步开始不对的”。举个例子我那次走偏就是靠对比第三步前后的快照发现的操作前快照里目标入口的文本是“数据查询”操作后快照里页面标题变成了“帮助中心”两者对不上说明点错了。如果没有快照我只能看到一串 success根本不知道从哪一步开始错的。快照的另一个好处是可以做回归对比。同一个任务跑两次如果快照序列不一致说明流程不稳定可能是页面动态加载、可能是模型决策有随机性。这种不稳定性在正式环境里是致命的但在快照对比下会暴露得很明显。提示快照不要存全量 DOM体积大且难对比。存关键区域的文本哈希 可交互元素摘要就够了既轻量又能定位问题。4. 实操过程一次完整的 Event Horizon 核验链路搭建4.1 环境与依赖准备我这次实测的环境比较朴素没有上重型框架主要是为了把核验逻辑本身看清楚。核心依赖就几块一个能跑 DeepSeek 工具调用的运行时、一个网页感知与操作的执行器、一个独立的状态快照存储。运行时我用的就是标准的 tool calls 链路执行器负责把模型决策转成实际的页面操作快照存储用一个轻量的本地结构就行。这里有个选型上的经验执行器最好和模型决策解耦。也就是说模型只输出“我要做什么”的结构化意图执行器负责把它翻译成具体操作并返回证据。这样做的原因是一旦走偏你能清楚地判断是模型意图错了还是执行器翻译错了。如果两者揉在一起排查起来会非常痛苦。依赖版本上我建议把感知库和浏览器内核的版本固定住。网页感知对渲染结果很敏感不同内核版本对同一个页面的解析可能有差异固定版本能减少“同样的代码昨天对今天错”这类问题。4.2 感知模块的接入与参数配置感知模块的接入我分了三个配置项来调。第一项是感知范围。我默认用区域感知把范围限定在主内容容器内避免导航栏、广告位、页脚这些噪声干扰模型判断。配置方式就是给一个容器选择器感知模块只提取这个容器内的内容。第二项是元素过滤规则。不是所有可交互元素都值得给模型看。我一般会过滤掉尺寸过小的、被遮挡的、以及明显是装饰性的元素。过滤规则用一组阈值控制最小宽高、最小可见面积占比、是否在视口内。这些阈值需要根据实际页面调没有万能值。第三项是文本摘要长度。每个元素的文本不能全给太长会挤爆上下文。我一般截断到前若干字符同时保留元素的角色按钮、输入框、链接和状态可用、禁用、选中。这样模型既能知道元素是什么又不会被长文本带偏。配置完之后我会先跑一次“只感知不操作”的 dry run把感知结果打出来人工看一遍。这一步很关键很多走偏的根源其实是感知结果本身就有误导性比如把两个相似元素描述得一模一样模型自然分不清。4.3 核验规则的编写与阈值设定核验规则我是按前面说的四个维度逐层写的。每一层都有明确的通过条件和失败处理。存在性核验用选择器匹配匹配不到就直接判定失败返回“目标不存在”并附带当前感知快照。可见性核验用元素的几何信息和样式信息综合判断宽高为 0、被遮挡、在视口外都算不可见。可交互性核验检查 disabled 属性和 pointer-events 样式。已生效核验最复杂我用的是“操作前后关键状态对比”URL 变了、目标区域内容哈希变了、出现了预期的提示文本满足任意一条就算生效。阈值设定上我踩过一个坑内容哈希的对比不能太严格。有些页面会有动态时间戳、随机 ID 这类每次都变的内容如果直接对整个区域做哈希每次都会判定“变了”核验就失效了。我的做法是先对区域内容做一次归一化把明显的动态部分时间、随机串替换成占位符再做哈希。这样对比才稳定。4.4 完整跑通一次任务并记录快照配置好之后我跑了一次完整的任务并在每一步前后都记录了快照。整个过程大概是模型拿到初始感知结果决定第一步操作执行器执行并返回证据核验层判断是否生效快照存储记录状态模型拿到核验结果和新的感知结果决定下一步。如此循环直到任务完成或核验失败。这次跑通之后我特意做了一次“故障注入”人为把某一步的目标元素选择器改错看核验层能不能拦住。结果是存在性核验在第一步就失败了任务被及时终止没有继续往下走偏。这验证了核验层的价值——它把原本会静默走偏的问题变成了一个显性的、可拦截的失败。下面这张表是我这次实测里核验四维度的通过条件和典型失败表现可以直接参考核验维度通过条件典型失败表现拦截时机存在性选择器匹配到唯一元素匹配不到或匹配到多个操作前可见性元素有非零尺寸且未被遮挡元素存在但不可见操作前可交互性元素未禁用且可接收事件元素可见但点不动操作前已生效操作后关键状态发生变化操作派发但页面无变化操作后5. 常见问题与排查技巧实录5.1 模型不报错但结果错的五类典型场景实测下来我把“无报错走偏”归成五类每一类的排查手法不太一样。第一类是感知误导感知结果把不同元素描述得过于相似模型选错。排查方法是回看感知快照看目标元素和实际选中元素的描述差异。如果差异很小说明感知层需要增加区分度比如补充元素的位置信息或上下文文本。第二类是核验缺失某一步没有做已生效核验操作没生效但被当成成功。排查方法是检查核验规则覆盖度看是不是所有关键操作都有对应的生效判断。第三类是状态污染前一步的残留状态影响了后一步的判断比如弹窗没关、输入框没清空。排查方法是看快照序列里状态是否干净必要时在步骤之间加清理动作。第四类是异步时序页面还在加载模型就基于旧状态做了决策。排查方法是看操作和感知之间的时间间隔必要时加等待条件而不是固定延时。第五类是决策漂移模型在多步之后逐渐偏离原始目标每一步看起来都合理累积起来就错了。排查方法是把任务目标在每一步都重新注入上下文让模型始终对齐目标。5.2 排查走偏的三步定位法遇到走偏我一般用三步定位。第一步找分叉点。对比快照序列找到第一个和预期不一致的步骤。这一步能快速缩小范围避免从头到尾瞎看。第二步看感知快照。在分叉点那一步模型当时看到的感知结果是什么。如果感知结果本身就有问题那问题在感知层如果感知没问题但模型选错了那问题在决策层。第三步看核验记录。那一步的核验结果是什么为什么没拦住。如果核验通过了但实际是错的说明核验规则有漏洞如果核验失败了但任务没停说明失败处理有问题。这三步走下来基本能定位到具体是哪一层的问题。我实测里那次走偏就是靠这三步在十分钟内定位到了感知层的元素区分度不足。5.3 独家避坑技巧汇总几个我踩过坑之后沉淀下来的技巧直接列出来。给每个可交互元素加稳定标识不要只靠文本区分元素文本可能重复。给元素加一个基于位置和角色的稳定标识模型决策和核验都用这个标识能大幅减少选错。核验失败要终止而不是重试很多实现里核验失败会盲目重试结果在错误状态上反复操作越试越乱。我的做法是核验失败先终止记录快照人工确认后再决定是否重试。感知结果里带上“上一步发生了什么”模型需要知道上一步操作的结果才能决定下一步。把上一步的核验结论注入当前感知能显著减少决策漂移。定期做故障注入测试不要等线上出问题才排查主动注入错误看核验层能不能拦住。这是验证核验体系有效性的最好方式。快照存储要能按任务 ID 检索出问题时能快速拉出整个任务的所有快照而不是在一堆日志里翻。注意核验规则不是越多越好。规则太多会导致误拦把正常操作也判成失败。我的经验是只对关键操作做严格核验非关键操作做轻量核验保持整体流程的流畅性。6. 从这次实测延伸出的几点个人体会Event Horizon 这套思路给我最大的启发不是某个具体技术点而是它把“模型任务成功”这件事从“没报错”重新定义成了“每一步都有证据”。这个转变听起来简单但实际做起来会倒逼你把整个链路的可观测性做扎实。以前我判断一个任务成没成功看的是最终输出现在我更愿意看的是每一步的核验记录和快照序列因为最终输出可能是错的但证据链不会骗人。另外一点体会是关于 DeepSeek 这类模型的工具调用。模型本身的能力在快速提升但工具调用的可靠性很大程度上取决于你返回给它的信息质量。你返回的证据越充分、越结构化模型的决策就越稳。反过来如果你只返回一个 success模型就只能靠猜走偏是迟早的事。最后分享一个我最近在用的扩展思路把 Event Horizon 的核验记录做成可视化的任务回放。每一步的感知快照、操作、核验结论按时间轴排开出问题时直接拖到分叉点看现场。这个回放机制在团队协作里特别有用因为排查走偏往往需要多人一起看有个统一的回放视图能省掉大量沟通成本。我目前是用轻量的本地页面做的后续打算把它和任务 ID 绑定做成可检索的历史记录。这个方向我觉得比单纯堆核验规则更有长期价值因为它解决的是“出了问题怎么快速看懂”这件事而这件事在任务越来越复杂的趋势下只会越来越重要。