接口跑通了我为什么还要打开页面看一眼前言这是「把业务系统接进 Agent」系列的第六篇。前面几篇一直在讲怎么把接口包成工具、怎么管权限、怎么接 MCP。这篇讲一个很容易被跳过、但跳过之后一定出事的问题接口成功之后怎么确认事情真的办成了。先说一次改活动价的经历。当时我让 Agent 改一个商品的活动价从 99 改成 79。工具调完接口返回 200日志里一串 SuccessAgent 也很干脆地回了一句「已经改好了」。结果业务打开商品页一看还是 99。查了半天才明白接口写的是主库商品页读的是缓存缓存要过几分钟才失效。接口没错页面也没错错的是我们把「接口成功」当成了「事情办成」。从那以后我给写操作都加了一步接口跑完打开页面看一眼。一、接口返回 200只是服务端说它收到了一次改价请求大概会经过这些地方Agent → 工具层 → 业务服务 → 数据库 → 缓存 → BFF → 前端 → 用户接口的 200只代表业务服务这一层处理完了。后面的缓存有没有刷新、BFF 有没有拿到新数据、前端有没有重新渲染它都不知道。Agent 更不知道。它能看到的只有工具返回的那段结果。工具说成功它就认为成功工具返回一个订单对象它就认为订单变了。它没有眼睛不会自己去页面确认。但业务验收的从来不是 HTTP 状态码是页面上那个结果。用户不会去看你的接口日志他只看价格对不对、状态对不对、列表里有没有。所以「接口成功」和「事情办成」之间隔着一整条链路。这条链路上任何一环出问题接口都是 200页面都是错的。二、页面能看出三类接口看不出的问题我把这类问题分成三类都是接口断言测不出来的。第一类是渲染。接口返回1234.5页面显示成1234.5还是¥1,234.50接口返回 20 条前端分页只渲染了 10 条字段是空的时候页面显示null还是一个空白日期少了一天可能是时区没处理对。这些都不影响接口返回但用户一眼就能看见。第二类是权限和状态。接口按权限过滤了数据但页面缓存了上一个用户的列表提交成功了页面还显示旧状态异步任务还在跑页面先显示了「已完成」前端做了乐观更新接口其实失败了页面看起来却是成功的。第三类是跨系统。订单接口成功了但履约页面没同步审批接口通过了但待办列表里还在支付成功了但账单页还是未支付。这类问题最麻烦因为两个系统各自都对只有站在用户视角把流程走完才能发现中间断了一截。这三类问题有一个共同点它们都不是「接口错了」而是「接口对了但用户看到的不对」。你盯着接口日志查一天也查不出来。三、执行走接口验证走页面有人听到这里会说那干脆全用浏览器操作算了。不行。全用页面操作慢、脆、贵而且权限和审计都很难做。第九篇讲浏览器自动化的时候就说过那是没有 API 时的兜底不是有 API 时的首选。我的做法是分开执行走接口验证走页面。执行用领域工具。改价就调update_price退款就调refund_order。这类工具稳定、快、参数清楚出了事能审计到具体动作。验证用浏览器但只读。打开用户会看的那个页面检查关键文本、关键元素、关键状态。不点击不填表不提交。它只负责回答一个问题用户现在看到的是不是对的。验收工具不要做成通用的click/fill。那种工具动作空间太大模型很容易在验收的时候又改了什么。应该做成窄接口比如read_page_text、assert_page_contains、assert_element_state。参数是页面地址和断言条件不是一串自由操作。权限也要注意。验收必须用当前用户的会话不能用管理员账号。否则你看到的是管理员视角用户看不到的东西你都能看到验收就失去意义了。四、验收点怎么选不是每个动作都要配页面验收。全配一遍成本高也没必要。我的判断标准只有一句这个动作如果失败用户会在哪个页面发现那个页面就是验收点。改价验收点是商品详情页或活动页。退款是订单详情页和退款记录页。审批是待办列表和详情页。发布文章是前台的文章页。这些页面是流程的最后一公里用户真正看结果的地方。读接口可以抽查。比如查询订单接口返回了什么页面大概率也显示什么抽一两个关键字段看看就行。写接口和跨系统流程必须过页面因为这两类最容易出现「接口成功、页面没变」。还有一个细节验收要等。异步任务、缓存刷新、消息同步都需要时间。但不能用固定的sleep等三秒还是等三十秒应该用条件轮询等到页面出现预期状态或者超时失败。五、代码怎么写我把验收拆成三层断言、验收点、验收工具。先定义断言。断言只读页面快照不操作页面。publicinterfaceAssertion{booleantest(PageSnapshotpage);Stringdescribe();}publicrecordTextContains(Stringtext)implementsAssertion{publicbooleantest(PageSnapshotpage){returnpage.text().contains(text);}publicStringdescribe(){return页面应包含: text;}}publicrecordElementAbsent(Stringselector)implementsAssertion{publicbooleantest(PageSnapshotpage){return!page.exists(selector);}publicStringdescribe(){return页面不应出现: selector;}}然后是验收点。一个动作对应一个页面和一个断言列表。publicrecordAcceptanceCheck(Stringaction,StringurlTemplate,ListAssertionassertions){}publicfinalclassAcceptanceRegistry{privatefinalMapString,AcceptanceCheckchecks;publicAcceptanceCheckget(Stringaction){AcceptanceCheckcheckchecks.get(action);if(checknull){thrownewToolException(没有配置验收点: action);}returncheck;}}最后是验收工具。模型只需要说「验一下改价业务 ID 是多少」具体打开哪个页面、断言什么都在注册表里。publicrecordVerifyInput(NotBlankStringaction,NotBlankStringbusinessId){}publicrecordVerifyOutput(booleanpassed,ListStringfailures,StringpageSummary){}publicfinalclassVerifyActionToolimplementsAgentToolVerifyInput,VerifyOutput{privatefinalAcceptanceRegistryregistry;privatefinalBrowserClientbrowser;OverridepublicStringname(){returnverify_action;}OverridepublicStringdescription(){return只读验收打开业务页面检查动作执行后的最终状态。不会点击、不会提交。写操作执行后应调用一次。;}OverridepublicVerifyOutputexecute(VerifyInputin,ToolContextctx){AcceptanceCheckcheckregistry.get(in.action());Stringurlcheck.urlTemplate().replace({id},in.businessId());PageSnapshotpagebrowser.openReadOnly(url,ctx.sessionId());ListStringfailurescheck.assertions().stream().filter(a-!a.test(page)).map(Assertion::describe).toList();returnnewVerifyOutput(failures.isEmpty(),failures,page.summary());}}browser.openReadOnly用当前用户会话打开页面等 DOM 稳定后拍一个快照不做任何写操作。断言只在这个快照上跑。这样验收和操作是两条独立的路径不会因为共用同一个缓存或者同一个连接而自欺欺人。六、Agent 什么时候才算「完成」加了验收之后Agent 的完成标准要改。以前是工具返回成功就算完成。现在应该是执行成功并且验收通过才算完成。伪代码大概是这样result call_tool(action, params) if not result.ok: return 执行失败: result.error verify verify_action(action, businessId) if not verify.passed: return 执行成功但页面验收失败: verify.failures return 已完成页面状态已确认验收失败之后不要让它盲目重试。先分类是异步还没跑完等一会儿再验是缓存没刷新换个读路径或者等失效是权限不对检查会话是跨系统没同步看消息有没有发出去还是真的改错了回滚。分类清楚再动作。最怕的是验收失败之后模型又调一遍写接口把已经成功的事情做了第二次。还有一点验收失败时要把证据带回来。页面上看到了什么、哪个断言没过、快照摘要是什么。不要只说「验收失败」。人排查的时候这些证据比一句失败有用得多。七、几个我踩过的坑第一个坑用接口返回的数据去构造验收断言。接口说价格是 79你就断言页面应该有 79。这不叫验收这叫自己证明自己。验收的数据必须来自页面本身或者来自一条独立的读路径。第二个坑验收和操作共用缓存。改完之后马上验读到的还是旧缓存怎么验都不过。要么等缓存失效要么在验收时加一个绕过缓存的读参数。第三个坑只验文本不验状态。页面上有「79」这个数字不代表价格改对了可能只是推荐位里的另一个商品。要验具体元素里的值不是全页搜文本。第四个坑验收点选太多。每个动作都配三四个页面跑一轮下来又慢又贵。选用户最后真正看的那个页面一个就够。第五个坑用管理员账号验收。管理员能看到所有数据用户看不到的它也能看到验收全过用户一打开还是不对。验收必须用当前用户的会话。八、下一篇执行和验收都有了下一篇把这个系列串起来拿订单查询这个场景从接口选择、工具封装、权限透传到最后的页面验收完整走一遍。参考资料Playwright 断言与等待Chrome DevTools Protocol本系列第九篇浏览器自动化 Agent 详解
企业数字化 ERP 产品动态
相关推荐
别再手动打标签!一维助手三类标签组,自动搭好客户画像 私域客户越来越多,靠销售、运营手动打标签,几乎是很多团队的通病。不仅耗时耗力,还容易出现标准不一、漏标错标的问题:同一个客户,不同销售标记的意向完全不一样,后续做定向群发、跟进盘活,精准… · 2026/11/4 2:37:16
精于检验 · 诚于服务|阿尔法检验,品质全域护航 · 认证一站通达 我们怀着谦虚和恭敬,以合作共赢的意愿,携手与您共同发展ALPHA阿尔法检验——精于检验,诚于服务。扎根深圳的第三方专业检验检测机构,为您的贸易与品质保驾护航。关于我们ALPHA阿尔法检验深耕检测认证行业近20年,2005年… · 2026/11/4 2:37:16
Python 多模态手势交互技术报告:融合手部骨骼、眼动与语音的无接触交互原型 多模态手势交互的目标,是让人不再依赖手柄、鼠标或触屏,而是通过自然手势、视线落点和语音指令共同表达意图。手部骨骼追踪负责捕捉动作形态,眼动追踪提供“用户在看哪里”的空间锚点,语音指令补充明确语义,三者结合可… · 2026/11/4 2:37:16
物联网异常检测算法对比与工程实践 1. 项目背景与核心价值物联网设备正在以惊人的速度渗透到我们生活的每个角落。从智能家居的温度传感器到工业生产线上的振动监测仪,这些设备每时每刻都在产生海量数据。但随之而来的问题是:如何从这些数据洪流中识别出真正值得关注的异常信号?… · 2026/11/4 3:26:24
VMware VMnet1/VMnet8消失的四大根因与根治方案 1. 问题本质与真实场景还原VMware安装后缺失VMnet1、VMnet8虚拟网卡,或设备管理器中这两个适配器显示黄色感叹号——这不是小概率偶发故障,而是我过去三年在某高校实验室、某外包技术支援团队、以及多个远程交付项目中反复遇到的高频顽疾。它直接导致&am… · 2026/11/4 3:26:24
STM32F407+OV2640+ESP8266图像传输实战:从采集到上云 简介:这份资源面向嵌入式与物联网方向的开发者及学习者,围绕STM32F407驱动OV2640摄像头采集图像、经ESP8266 Wi-Fi模块上传服务器并同步串口送往上位机显示这一完整链路,提供可编译运行的工程代码,适合用来练习微控制器编程、传感… · 2026/11/4 3:26:24
大语言模型动态决策在多视图聚类中的应用与优化 1. 项目概述:当大语言模型遇上多视图聚类去年我在处理一组跨模态医疗数据时,发现传统多视图聚类方法在面对异构特征时表现乏力。正当我纠结于特征对齐的阈值设置时,团队里新来的实习生随口说了句:"要是能让模型自己判断不同视… · 2026/11/4 3:26:24
电力电子大作业答辩通关:Boost参数计算、整流波形与PID整定核心考点 简介:这份电力电子技术课程大作业文档面向电气工程、自动化等专业学生及电力电子初学者,围绕基于PID控制的Boost型开关电源与可控整流电路设计展开,可帮助读者完成从理论计算到Simulink仿真的完整闭环。文档重点讲解Boost升压变换器中电感与滤… · 2026/11/4 3:26:24
渗透测试工程师成长指南:从基础到实战 1. 渗透测试行业的真实挑战作为一名从业多年的网络安全工程师,我见过太多怀揣黑客梦想的年轻人,在接触渗透测试后迅速被现实击垮。这个行业远没有影视作品中那么光鲜亮丽,背后是无数个熬夜研究漏洞的夜晚和持续不断的学习压力。1.1 技术门槛&… · 2026/11/4 3:25:24
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46