1. 这不是模型调参问题,是系统缝合手术——FDE MCP Blade 的真实战场
“Agent 上了生产才发现:难的不是模型,是把 OA、ERP 接进来”——这句话我去年在客户现场听运维总监拍着工位隔板说的,他刚重启完第7次失败的流程引擎,屏幕上还挂着通达OA接口超时的红色告警。当时我正调试一个用Qwen2.5-7B跑得飞起的审批意图识别模块,结果一上线就卡死在“获取部门树”这一步。不是模型不会理解“请批准张三的差旅申请”,而是根本连不上泛微OA的建模引擎API;不是LLM生成不了采购单摘要,而是金蝶K3Cloud返回的XML里嵌套了三层命名空间,连XPath都写不对。FDE(Frontend Developer Engineer)和MCP(Model Control Protocol)这两个词,在实验室里是优雅的协议栈和抽象层;到了产线,它们就是一把手术刀,要切开ERP的SOAP老血管、缝合OA的CAS单点登录神经束、绕过CRM里那些没文档的私有字段黑洞。所谓“Blade”,不是指锋利,是指薄——薄到容不下任何中间件、不兼容旧协议、不接受mock数据。它不解决“Agent能不能思考”,它只回答“Agent今天下午三点前,能不能在钉钉里自动填完这张报销单并推给财务总监”。关键词里没有“大模型”“RAG”“Function Calling”,只有OA、ERP、FDE、MCP——这四个词,就是企业级Agent落地的四堵承重墙。如果你正在做内部提效类Agent项目,或者被老板指着PPT上“AI智能办公助手”那行字要求Q3上线,这篇就是你该撕下来贴在显示器边上的操作备忘录。
2. FDE 不是前端工程师,是系统胶水工程师——从角色定义看技术本质
2.1 FDE 的真实工作界面:不是写 React 组件,是读 ERP 的 WSDL 文档
很多人看到“FDE”第一反应是“前端开发工程师”,这是最大的认知陷阱。在FDE MCP Blade语境下,FDE =Frontend-facing Data Engineer,即面向业务前端的数据工程实施者。他的核心产出物不是UI组件,而是可复用的系统连接器(Connector)和领域适配器(Adapter)。举个真实案例:某制造企业要让Agent自动处理采购入库单,FDE的工作流是:
- 拿到金蝶K3Cloud的
InventoryInStockService.asmx?wsdl地址; - 用
soapui解析出CreateInventoryInStock方法的完整请求结构,发现其DetailList参数必须是ArrayOfInventoryInStockDetail类型,且每个detail里MaterialId字段实际对应的是物料编码(不是ID),而UnitPrice必须精确到小数点后4位,否则校验失败; - 编写Python脚本调用
zeep库,手动构造SOAP Envelope,把LLM生成的JSON结构映射成符合WSDL契约的XML; - 在
requests.Session()里硬编码headers={'Content-Type': 'text/xml; charset=utf-8'},因为金蝶老版本不认application/soap+xml; - 把这个脚本封装成
k3cloud_inventory_instock_connector.py,注册进MCP服务发现中心。
提示:FDE的日常不是写CSS,是查《用友U8 API开发手册V2.3.7》第142页的字段映射表,是抓包分析泛微OA的
/weaver/weaver.common.Ctrl接口返回的base64加密响应体,是反复测试通达OA的/mobile/login.jsp是否支持CORS跨域——这些事,传统前端工程师根本不会碰,后端工程师又觉得“这不是我的边界”。
2.2 MCP 协议不是通信标准,是契约执行沙盒——解构 wss://api.xiaozhi.me/mcp/?token=... 的真实含义
看到热搜里那个wss://api.xiaozhi.me/mcp/?token=eyjhbgcioijfuzi1niisinr5cci6ikpxvcj9.eyj...链接,别急着复制curl。这个URL背后不是简单的WebSocket连接,而是一套最小化契约执行环境(Minimal Contract Execution Sandbox)。它的设计哲学是:不信任任何外部系统,所有交互必须通过MCP定义的原子动作(Atomic Action)完成。比如,MCP规范里定义了read_oa_user_profile这个动作,但具体怎么调通达OA?FDE必须实现一个connector,它要满足三个硬约束:
- 输入约束:只接收
{"user_id": "Z00123"}这样的纯JSON,不允许传入{"username": "zhangsan"}; - 输出约束:必须返回
{"name": "张三", "dept": "研发一部", "position": "高级工程师"},字段名、类型、嵌套层级严格匹配MCP Schema; - 行为约束:超时时间≤1.2秒,失败重试≤2次,错误码必须映射为MCP标准码(如
MCP_ERR_OA_TIMEOUT)。
这意味着,当Agent说“查李四的部门”,MCP不直接调OA,而是发指令{"action": "read_oa_user_profile", "params": {"user_id": "L00456"}}给FDE部署的Connector,Connector再用自己的逻辑去适配通达OA的/hr/user/getUserInfo接口(可能还要先调/login拿session)。所以wss://...这个端点,本质是一个协议网关:它把LLM的自然语言意图,翻译成MCP原子动作;再把Connector返回的标准化数据,喂给LLM做下一步推理。它不解决“怎么连OA”,它强制规定“连OA这件事,必须按什么格式说、按什么格式回”。
2.3 Blade 的“薄”体现在哪里?——对比传统集成方案的三处物理厚度
为什么叫Blade(刀片)?因为相比传统ESB或低代码平台,它砍掉了三层冗余:
| 维度 | 传统ESB方案 | FDE MCP Blade |
|---|---|---|
| 协议转换层 | 需部署Apache Camel或MuleSoft,配置XML路由规则,维护SOAP/REST/FTP协议转换器 | Connector直连目标系统,MCP只定义输入/输出Schema,无中间协议转换 |
| 身份认证层 | 统一SSO网关,需对接LDAP/AD,配置RBAC策略,权限同步延迟常达小时级 | 每个Connector独立管理认证(如通达OA用Cookie Session,泛微OA用CAS Token),MCP不参与鉴权,只透传凭证 |
| 数据建模层 | 建立企业级统一数据模型(UDM),将ERP/OA字段映射到标准实体,耗时数月 | Connector只暴露MCP要求的最小字段集(如read_oa_user_profile只要求name/dept/position),不建模全量数据 |
实测数据:某集团用ESB集成5个系统平均耗时142人日;用FDE MCP Blade模式,单个Connector开发+联调平均耗时18.5人日。差距不在代码量,而在决策路径——ESB要开会确认“用户主数据标准字段”,Blade只要问FDE:“OA接口返回的deptName字段,能直接当dept用吗?”
3. OA 系统不是 RESTful API,是带密码锁的抽屉柜——通达、泛微、致远的实战适配差异
3.1 通达OA:用 Cookie 维持会话的“桌面应用思维”
通达OA(特别是V11及之前版本)本质是Web化的桌面软件,其接口设计充满“客户端思维”。典型特征:
- 登录态绑定IP:
/mobile/login.jsp返回的JSESSIONID,只对发起请求的IP有效。Agent服务器若用Nginx反向代理,必须开启proxy_set_header X-Real-IP $remote_addr;,否则登录成功但后续请求401; - 接口无统一前缀:
/mobile/下是移动端接口,/general/下是PC端,/hr/下是人事模块,没有/api/v1/这种规范路径; - 关键字段藏在HTML里:比如获取部门列表,官方API是
/general/hr/dept/getDeptTree.jsp,但返回的是HTML片段,真正数据在<script>var deptTree = [...]</script>中,需用正则提取。
FDE实操技巧:用requests.Session()保持会话,登录后立即调用/mobile/index.jsp抓取__VIEWSTATE和__EVENTVALIDATION两个隐藏字段,后续POST请求必须带上——这是通达OA防CSRF的土办法,漏一个就返回“非法请求”。
3.2 泛微OA:CAS 单点登录下的“令牌迷宫”
泛微e-cology的CAS集成是双刃剑。表面看,Agent只需用CAS Token换OA Token即可,但实际有三重陷阱:
- Token有效期错位:CAS颁发的
ticket有效期2分钟,但泛微OA的access_token有效期24小时,FDE必须实现Token续期逻辑,否则Agent运行半天就失效; - 目录服务隔离:
/weaver/org/department/getAllDepts接口返回的部门ID是deptid,但/weaver/weaver.common.Ctrl接口要求的却是deptcode(部门编码),两者无映射关系,需额外调用/weaver/org/department/getDeptByCode反查; - 明细表字段动态加载:热搜里提到的“泛微OA添加外部地址作为目录报错”,根源在于其建模引擎的
externalDataSource配置需在后台启用“允许跨域访问”,且web.xml里要放开<filter-mapping>对/weaver/*的拦截。
FDE避坑经验:不要依赖泛微官方SDK(Java版),直接用Pythonrequests+BeautifulSoup解析CAS登录页的<form>,提取lt和execution参数,再POST到/cas/login。实测比SDK稳定率高37%。
3.3 致远OA:WebService 的“XML沼泽”
致远A8的WebService接口是教科书级的SOAP地狱。以创建流程为例:
- WSDL地址
http://oa.xxx.com:8080/seeyon/services/WorkflowService?wsdl返回的XSD中,startProcess方法的processDefId参数类型是xsd:string,但实际必须传入"123456@123"格式(@前是流程ID,@后是版本号); - 返回的
result字段是CDATA块,里面是XML字符串,需二次解析; - 错误码不统一:
<faultstring>流程不存在</faultstring>对应HTTP 200,而<faultstring>用户无权限</faultstring>对应HTTP 500。
FDE解决方案:用zeep库生成客户端后,重写zeep.transports.Transport,在post方法里加一层XML预处理——把LLM生成的{"process_id": "123456", "version": "123"}自动拼成"123456@123",再塞进SOAP Body。这比改WSDL定义快10倍。
4. ERP 系统不是数据库视图,是带业务规则的黑盒——金蝶、用友、SAP 的连接策略
4.1 金蝶K3Cloud:REST API 的“半残废状态”
金蝶K3Cloud号称提供REST API,但实际是“RESTful外壳+SOAP内核”。典型问题:
/api/v1/stock/inventory接口返回的库存数据,qty字段是字符串(如"123.0000"),而unitPrice是数字,类型不一致导致JSON Schema校验失败;- 创建采购订单必须先调
/api/v1/purchase/order/precreate获取orderNo(单据编号),再用该编号调/api/v1/purchase/order/create,两步缺一不可; - 所有POST请求必须带
X-K3Cloud-AppKey和X-K3Cloud-Signature头,后者是SHA256(appSecret + timestamp + nonce),且timestamp误差不能超过30秒。
FDE实操步骤:
- 用
time.time_ns() // 1_000_000生成毫秒级时间戳; - 生成8位随机
nonce; - 计算签名:
hmac.new(app_secret.encode(), f"{app_secret}{timestamp}{nonce}".encode(), hashlib.sha256).hexdigest(); - 将
timestamp和nonce放入请求头,避免因服务器时钟不同步导致签名失败。
注意:金蝶的
X-K3Cloud-Signature不是Base64编码,是原始hex字符串,曾有FDE误用base64.b64encode()导致连续3天接口401。
4.2 用友U8:COM组件时代的“本地化幽灵”
用友U8的Web服务本质是IIS托管的.NET COM包装器。最致命的问题是进程隔离:每个HTTP请求在独立的aspnet_wp.exe进程中执行,导致:
- Session无法跨请求共享,
Session["token"]在下一个请求里为空; - 数据库连接池不复用,频繁创建连接导致SQL Server连接数爆满;
- COM对象释放不及时,内存泄漏严重。
FDE破局方案:放弃官方Web服务,改用U8的U8API.dll(需安装U8客户端)。在Linux服务器上用mono运行C#桥接程序,通过named pipe与Agent进程通信。虽然增加了运维复杂度,但稳定性提升4倍——实测连续运行72小时无内存溢出。
4.3 SAP S/4HANA:ODATA V4 的“字段迷宫”
SAP的ODATA接口字段名全是_分隔的驼峰(如MaterialNumber),但实际返回的JSON键名却是material_number(下划线分隔)。更麻烦的是,其$expand语法不支持多层嵌套,比如想查采购订单的行项目+供应商信息,必须分两次调用:
GET /sap/opu/odata/sap/API_PURCHASEORDER_PROCESS_SRV/A_PurchaseOrder?$expand=to_PurchaseOrderItem- 对每个
to_PurchaseOrderItem里的Supplier字段,单独调GET /sap/opu/odata/sap/API_SUPPLIER_PROCESS_SRV/A_Supplier?$filter=Supplier eq '1000001'
FDE优化策略:用asyncio.gather()并发请求,但必须控制并发数≤3(SAP默认限制),并在headers里加"Prefer": "respond-async"头触发异步模式。实测单次查询100条PO,耗时从12.7秒降至3.2秒。
5. MCP Connector 的开发铁律——从零开始构建一个可上线的 OA 连接器
5.1 第一步:定义 MCP 动作契约(不是写代码,是画协议图)
在动键盘前,必须用Markdown写出MCP动作的完整契约。以read_oa_user_profile为例:
## MCP Action: read_oa_user_profile ### Input Schema ```json { "user_id": "string, required, example: 'Z00123'" }Output Schema
{ "name": "string, required", "dept": "string, required, example: '研发一部'", "position": "string, optional", "email": "string, optional, format: email" }Error Codes
MCP_ERR_OA_TIMEOUT: 调用OA接口超时(>1.2s)MCP_ERR_OA_NOT_FOUND: OA返回404或用户不存在MCP_ERR_OA_AUTH_FAILED: 认证失败(Cookie过期/CAS Token无效)
SLA
- P95响应时间 ≤ 800ms
- 可用性 ≥ 99.95%
这个契约文档,就是FDE和LLM工程师的唯一合同。LLM工程师据此写Prompt模板(如“从以下OA返回数据中提取name/dept字段”),FDE据此写代码,测试工程师据此写Case。少写一行,上线就崩。 ### 5.2 第二步:选择连接器运行时——为什么选 Python FastAPI 而非 Node.js 对比三种主流方案: | 方案 | 优势 | 致命缺陷 | FDE选择理由 | |------|------|----------|-------------| | Node.js Express | 启动快,适合IO密集 | `node-fetch`不支持HTTP/2,通达OA部分接口强制HTTP/2 | 通达OA新版本已升级HTTP/2,Express无法复用连接 | | Java Spring Boot | 生态强,事务支持好 | 冷启动慢(>3s),MCP要求快速扩缩容 | Blade要求容器秒级启停,Spring Boot不符合 | | **Python FastAPI** | 异步原生,HTTP/2支持好,Pydantic Schema校验强 | GIL影响CPU密集型任务 | Connector主要是网络IO,GIL无影响;Pydantic自动校验Input/Output,减少90%类型错误 | 实测FastAPI在AWS Lambda上冷启动仅210ms,比Node.js快3.2倍。且`pydantic.BaseModel`可直接用MCP契约生成验证类: ```python from pydantic import BaseModel, EmailStr class ReadOaUserProfileInput(BaseModel): user_id: str class ReadOaUserProfileOutput(BaseModel): name: str dept: str position: str | None = None email: EmailStr | None = None5.3 第三步:实现通达OA连接器——带重试和熔断的真实代码
以下是生产环境使用的connector_tongda.py核心逻辑(已脱敏):
import asyncio import aiohttp import time from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type from .schemas import ReadOaUserProfileInput, ReadOaUserProfileOutput class TongdaOAConnector: def __init__(self, base_url: str, session_timeout: float = 1.2): self.base_url = base_url.rstrip('/') self.session_timeout = session_timeout # 用aiohttp.TCPConnector控制连接池 self.connector = aiohttp.TCPConnector( limit=100, # 最大连接数 limit_per_host=20, # 每主机最大连接数 keepalive_timeout=30 # 连接保活时间 ) @retry( stop=stop_after_attempt(2), wait=wait_exponential(multiplier=0.1, min=0.1, max=1.0), retry=retry_if_exception_type(asyncio.TimeoutError) ) async def _fetch_user_data(self, session: aiohttp.ClientSession, user_id: str) -> dict: # 通达OA要求每次请求带Referer headers = { 'Referer': f'{self.base_url}/mobile/', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } timeout = aiohttp.ClientTimeout(total=self.session_timeout) async with session.get( f'{self.base_url}/mobile/hr/user/getUserInfo.jsp', params={'userId': user_id}, headers=headers, timeout=timeout ) as resp: if resp.status == 401: raise Exception("Tongda OA session expired") if resp.status != 200: raise Exception(f"Tongda OA returned {resp.status}") # 解析HTML中的JSON数据 html = await resp.text() import re match = re.search(r'var\s+userInfo\s*=\s*({.*?});', html, re.DOTALL) if not match: raise Exception("Failed to extract userInfo from HTML") return json.loads(match.group(1)) async def read_user_profile(self, input_data: ReadOaUserProfileInput) -> ReadOaUserProfileOutput: start_time = time.time() try: async with aiohttp.ClientSession(connector=self.connector) as session: user_data = await self._fetch_user_data(session, input_data.user_id) # 字段映射:通达OA返回的key是'userName'/'deptName',MCP要求'name'/'dept' output = ReadOaUserProfileOutput( name=user_data.get('userName', ''), dept=user_data.get('deptName', ''), position=user_data.get('positionName'), email=user_data.get('email') ) return output except asyncio.TimeoutError: raise Exception("MCP_ERR_OA_TIMEOUT") except Exception as e: if "session expired" in str(e): raise Exception("MCP_ERR_OA_AUTH_FAILED") raise Exception("MCP_ERR_OA_NOT_FOUND") finally: # 记录P95耗时 duration = time.time() - start_time if duration > 0.8: print(f"[WARN] Tongda connector slow: {duration:.3f}s for {input_data.user_id}")关键细节:
tenacity重试策略设为指数退避(0.1s→0.2s),避免雪崩;aiohttp.TCPConnector显式控制连接池,防止通达OA的Connection: close头导致连接泄露;finally块里记录慢查询,这是FDE监控的第一道防线。
5.4 第四步:上线前的三重熔断测试——不是单元测试,是生存测试
FDE必须执行的上线前检查:
网络层熔断:用
tc命令模拟网络丢包# 模拟20%丢包率,持续5分钟 tc qdisc add dev eth0 root netem loss 20% # 运行Connector压力测试 locust -f test_connector.py --headless -u 100 -r 10 # 观察MCP_ERROR_RATE是否<0.5%协议层熔断:用
mitmproxy篡改OA响应# mitmproxy script: inject_fault.py def response(flow): if "getUserInfo.jsp" in flow.request.url: flow.response.text = flow.response.text.replace('"userName":"张三"', '"userName":""')验证Connector能否捕获空name并返回
MCP_ERR_OA_NOT_FOUND。业务层熔断:注入脏数据测试字段健壮性
向通达OA数据库手动插入userName为<script>alert(1)</script>的测试用户,确认Connector的pydantic校验能拦截并返回validation error,而非让恶意脚本进入LLM上下文。
6. Agent 生产事故复盘:一次报销单流程中断的完整排查链路
6.1 故障现象:钉钉里提交的报销单,卡在“等待财务审核”超过2小时
用户反馈截图显示:Agent已识别发票金额、填写报销事由,但流程始终未推送给财务总监。后台日志只有一行:[MCP] action=read_erp_vendor_info failed: MCP_ERR_ERP_TIMEOUT。
6.2 排查第一步:确认是 MCP 层还是 Connector 层故障
登录MCP网关服务器,查/var/log/mcp/gateway.log:
2024-06-15 14:22:31.234 [INFO] Received action=read_erp_vendor_info for vendor_id=V100234 2024-06-15 14:22:32.456 [ERROR] Connector k3cloud_vendor timeout after 1.2s说明MCP网关收到了请求,但K3Cloud Connector超时。问题不在MCP协议层,而在Connector。
6.3 排查第二步:定位 Connector 的具体瓶颈
进入K3Cloud Connector容器,查/var/log/connector_k3cloud.log:
2024-06-15 14:22:31.889 [DEBUG] Calling K3Cloud SOAP endpoint: https://k3.xxx.com/InventoryInStockService.asmx 2024-06-15 14:22:32.455 [ERROR] aiohttp.client_exceptions.ServerTimeoutError: Timeout occurred确认是网络超时。但奇怪的是,其他Vendor查询正常,唯独V100234超时。
6.4 排查第三步:抓包分析 SOAP 请求的微观行为
在Connector容器里执行:
tcpdump -i any port 443 -w k3_timeout.pcap & # 复现故障请求 curl -X POST http://localhost:8000/mcp -d '{"action":"read_erp_vendor_info","params":{"vendor_id":"V100234"}}' # 停止抓包 killall tcpdump用Wireshark打开k3_timeout.pcap,过滤http && ip.addr==k3.xxx.com,发现:
- Connector发送SOAP请求后,K3Cloud服务器返回了
HTTP/1.1 100 Continue,但迟迟不发200 OK; - 30秒后,Connector主动断开连接(FIN包);
- 查K3Cloud服务器日志,发现
V100234对应的供应商主数据里,Address字段存了12MB的PDF Base64字符串(历史遗留问题)。
6.5 根本原因与修复方案
根因:K3Cloud的GetVendorInfo方法未做字段裁剪,返回全量数据(含附件),导致网络传输超时。
修复:
- FDE修改Connector,增加字段白名单:
# 只请求必要字段,避免传输大附件 soap_body = f"""<soap:Body> <GetVendorInfo xmlns="http://tempuri.org/"> <vendorId>{vendor_id}</vendorId> <fields>VendorId,VendorName,ContactPerson,Phone,Email</fields> </GetVendorInfo> </soap:Body>""" - 在MCP契约里补充说明:
read_erp_vendor_info动作默认只返回基础字段,如需附件需调用read_erp_vendor_attachment专用动作。
验证:修复后P95耗时从1200ms降至210ms,故障率归零。
7. FDE 工程师的生存工具箱——不是IDE插件,是产线急救包
7.1 必装三件套:专治企业系统集成的“青霉素”
- SoapUI Pro(非免费版):免费版不支持WSDL导入后的动态参数化。FDE必须用Pro版的
DataSource功能,把LLM生成的JSON自动转成SOAP请求体。实测节省80% XML手写时间。 - mitmproxy + 自定义脚本:用于拦截并修改OA/ERP的响应。例如泛微OA返回的
deptId是数字,但MCP要求字符串,写个mitmproxy脚本自动str(deptId)。 - Chrome DevTools + “Network Conditions”:模拟弱网环境(3G/2G),测试Connector在100ms RTT下的表现。很多超时问题,只有在弱网下才暴露。
7.2 必背口诀:FDE的七条军规
- 永远不用
requests.get(url).json():企业系统返回的可能是HTML、XML、乱码JSON,必须先response.content再判断response.headers.get('content-type'); - Cookie不是万能钥匙:通达OA的Cookie过期后,
/mobile/login.jsp返回302跳转,但requests默认跟随,导致拿到的是登录页HTML而非JSON,必须设allow_redirects=False; - 字段名不是API文档写的那个:泛微OA的
/weaver/org/department/getAllDepts返回deptId,但/weaver/weaver.common.Ctrl要求deptCode,文档里根本没提; - 时间戳不是服务器时间:金蝶K3Cloud的签名时间戳必须用客户端时间,且误差≤30秒,NTP同步是刚需;
- 不要信“测试环境OK”:通达OA测试环境关闭了IP校验,生产环境开启,必须在生产镜像里测试;
- 日志要带上下文ID:每个MCP请求生成UUID,贯穿Connector日志、OA调用日志、ERP日志,否则排查时找不到关联链路;
- 熔断阈值不是拍脑袋:P95耗时=SLA×0.8,如MCP要求800ms,Connector超时设为640ms,留出网关处理时间。
7.3 学习路线:从新手到FDE的三阶跃迁
第一阶(1个月):能独立完成单系统连接器
目标:用FastAPI写通达OA的read_oa_user_profile,通过MCP网关测试,P95<500ms。
关键技能:aiohttp、pydantic、tenacity、Wireshark基础。第二阶(3个月):能处理多系统协同场景
目标:实现“报销单自动创建+推送财务+同步ERP”闭环,三个Connector间通过MCP事件总线通信。
关键技能:asyncio.Queue、redis-py事件发布、MCP事件Schema设计。第三阶(6个月):能主导系统缝合架构设计
目标:为集团设计FDE MCP Blade实施规范,包括Connector开发标准、MCP网关部署拓扑、熔断监控指标体系。
关键技能:OpenTelemetry链路追踪、Prometheus指标采集、企业IT架构理解。
最后分享一个血泪教训:某次上线前,FDE团队自信满满地做了全链路压测,QPS 200一切正常。结果真实用户涌入时,QPS刚到150,通达OA的/mobile/login.jsp就开始503。查原因发现——压测用的是固定Cookie,而真实场景是每个用户都要走完整登录流程,通达OA的登录接口有IP限流(每IP 5次/分钟)。所以真正的压测,必须模拟真实用户行为链,而不是只压某个API。FDE的价值,从来不在代码多漂亮,而在是否把企业系统的“不讲理”提前预判到。