# 适配器标准:真实/仿真 × API/RPA 四档模式 > 凡是"连接三方系统"(ERP、CRM、SaaS、银行等)的 skill,都应采用本文的 **adapter 四档模式**。这样同一套业务逻辑可以在不同档位间切换:开发用 mock、半集成用 simulator、上线用真实,互不影响。 ## 为什么要分档 对接一个外部系统,工程上无非四种方式的组合: | | API(有接口) | RPA(操作界面) | |---|---|---| | **真实系统** | `real_api` 真实 API | `real_rpa` 真实界面 | | **仿真/离线** | `mock` 纯内存/fixture | `simulator_rpa` 仿真站点/桌面仿真 | ### 四档定义 | 档位 | 含义 | 默认策略 | |------|------|----------| | **`mock`** | 纯内存或 fixture,**默认单测/CI** | 模板 `.env.example` 默认 `OPENCLAW_TEST_TARGET=mock` | | **`simulator_rpa`** | 仿真站点或桌面仿真,可半集成 | 开发联调可选 | | **`real_api`** | 真实 API | **必须** `ALLOW_REAL_API=1` | | **`real_rpa`** | 真实浏览器/真实系统 | **必须** `ALLOW_REAL_RPA=1` | - **mock**:纯离线、不联网,给单测 / CI / 开发自测,**保证可重复**。 - **simulator_rpa**:操作仿真平台(如 `sandbox.jc2009.com`),跑端到端流程但不碰生产。 - **real_api**:有官方接口时**首选**(最稳、最快、最易维护)。 - **real_rpa**:没有 API 只能操作生产界面,**风险最高、放最后**。 > 推荐优先级:**real_api > simulator_rpa > real_rpa**,mock 永远保留做 CI。 ## 权限开关 未显式授权时**不得**落到真实 API/RPA: | 变量 | 作用 | |------|------| | `ALLOW_REAL_API=1` | 允许 `real_api` 访问真实 HTTP | | `ALLOW_REAL_RPA=1` | 允许 `real_rpa` 驱动真实浏览器/RPA | | `ALLOW_WRITE_ACTIONS=1` | 在 `real_*` 下允许**写**操作(提交表单、下单等) | 进程环境变量优先于用户 `.env`(见 `CONFIG.md` 三层优先级)。 ## 目录骨架 ``` scripts/service/_adapter/ __init__.py # dispatch:按档位返回对应 adapter 实例 base.py # 数据契约(dataclass)+ AdapterBase 接口 mock.py # 离线仿真,给 CI/单测 real_api.py # 真实系统 API sim_rpa.py # 仿真平台 RPA real_rpa.py # 真实系统 RPA(占位,谨慎实现) ``` 模板示例:`scripts/service/example_adapter/`(复制改名即用)。 ## 档位 dispatch 由 `OPENCLAW_TEST_TARGET` 统一决定用哪个 adapter: | `OPENCLAW_TEST_TARGET` | adapter | 用途 | |---|---|---| | `unit` / `mock` | `MockAdapter` | 单测 / CI,离线 | | `simulator_rpa` | `SimRpaAdapter` | 开发/演示,操作仿真平台 | | `real_api` | `RealApiAdapter` | 生产,走官方接口 | | `real_rpa` | `RealRpaAdapter` | 生产,操作真实界面 | ```python # __init__.py def get_adapter(): target = (os.environ.get("OPENCLAW_TEST_TARGET") or "mock").lower() if target in ("unit", "mock"): return MockAdapter() if target == "real_api": return RealApiAdapter() if target == "real_rpa": return RealRpaAdapter() return SimRpaAdapter() ``` `get_adapter()` 实现应配合 `tests/adapter_test_utils.py` 的 profile 策略:**未授权时不 silently 开启真实网络/RPA**。 ## contract tests 每个 adapter **必须覆盖同一套契约测试**(复制 `tests/samples/test_service_contract.py.sample`): - 至少覆盖:**timeout**、**unauthorized**、**invalid response**、**empty result** - **mock 不允许真实网络** - 使用 `FakeAdapter` 或等价 stub 模拟异常路径 ## 兄弟依赖 依赖 account-manager 或其他兄弟技能时: 1. 在 `SKILL.md` 的 `metadata.openclaw.dependencies.required` 声明。 2. 调用兄弟技能走统一 **`service.sibling_bridge`**(`call_sibling_json`),**不要**在 service 层散落 `subprocess.run`。 3. **lease 必须 release**(account-manager 租约);进程被 kill 后可能残留 lease,需在运维文档说明排查方式(查 account-manager lease 列表 / 手动释放)。 ```python from service.sibling_bridge import call_sibling_json result = call_sibling_json("account-manager", ["list", "--limit", "10"]) ``` ## 相关文档 - `RPA.md` — 三端 RPA 技术选型与拟人/反反爬范式 - `CONFIG.md` — `.env` 里如何配置运行模式与目标地址 - `TESTING.md` — 测试 target 与隔离体系