1. 从“能聊”到“会做事”:Hermes Agent不是聊天机器人,而是可调度的智能体单元
你有没有遇到过这样的场景:在某个内部系统里,点开一个对话框,输入“把上周销售数据导出成Excel发给市场组”,几秒后,文件就生成、附带邮件草稿,连附件命名都按公司规范加了日期前缀;又或者,在调试一个嵌入式设备时,直接说“检查串口0的波特率是否匹配固件要求”,Agent自动调用串口检测工具、比对配置表、高亮不一致项——整个过程没有人工介入,也没有打开任何新窗口。
这已经不是科幻片里的桥段。Hermes Agent 正是这样一类正在落地的新型智能体架构,它的核心价值不在“聊得多像人”,而在于“能不能被精准调度去完成确定性任务”。很多人第一眼看到“Agent”就默认是升级版Chatbot,这是最大的认知偏差。我参与过三个不同行业的Hermes落地项目,最深的体会是:它本质上是一个可编排、可验证、可审计的执行单元,对话只是它的入口和反馈通道,不是它的目的。
关键词里没写,但实际项目中反复出现的四个支柱是:会话(Conversation)、工具(Tool)、MCP(Multi-Component Protocol)、记忆(Memory)。它们不是并列的功能模块,而是一套环环相扣的运行契约。比如,“会话”不是指支持多轮闲聊,而是定义了一套状态机协议——当用户说“再查一遍昨天的库存”,系统必须能准确识别这是对上一轮“查询库存”动作的重试指令,而非新发起一次查询;“工具”也不是简单挂载几个API,而是要求每个工具必须声明输入约束、副作用范围、失败回滚方式;“MCP”是让这些组件能彼此“听懂对方说话”的底层语言;而“记忆”更不是缓存聊天记录,它是带时间戳、带权限标签、带版本号的状态快照库,用于支撑审计追溯与状态恢复。
这个架构特别适合那些对确定性、可追溯、低容错有硬性要求的场景:工业设备远程诊断、金融合规文档初审、医疗影像报告辅助生成、政务审批材料预检。在某高校实验室做的模拟项目X中,我们用Hermes Agent替代了原来由三个人轮班盯守的实验设备监控脚本。旧脚本只能发告警邮件,新Agent收到“温度超限”告警后,会自动执行:① 调用PLC控制接口降低加热功率;② 启动本地录像并打上时间水印;③ 将操作日志、当前温控曲线图、历史5分钟趋势打包生成PDF;④ 按预设规则推送至值班工程师企业微信,并同步存入审计数据库。整个链路耗时2.3秒,全程留痕,且每一步操作均可被独立验证与复现。
提示:判断一个系统是否真正具备Hermes Agent能力,不要看它能不能回答“今天天气怎么样”,而要看它面对“把A服务器的nginx日志中错误码502的请求IP,按出现频次排序取前10,生成表格发到运维群”这条指令时,能否拆解为“登录A服务器→执行grep命令→解析输出→排序→生成表格→调用群消息API”这一串原子动作,并在任意环节失败时提供明确的错误定位与重试建议。
2. 会话层:不是理解语义,而是解析意图状态机
很多团队在实现Hermes Agent时,第一道坎就卡在“会话”设计上。他们花大量精力优化大模型的prompt,试图让模型“更懂人话”,结果上线后发现:用户说“把刚才那个报表再发我一次”,系统要么重复发送原始报表(忽略了“刚才”这个时间锚点),要么干脆报错。问题根源不在模型不够强,而在会话层缺失一套显式的状态管理机制。
Hermes的会话层本质是一个轻量级状态机(State Machine),它不负责生成回复文本,只做三件事:识别当前指令类型、绑定上下文实体、更新会话状态栈。我们以“查询库存”为例,完整状态流转如下:
| 状态节点 | 触发条件 | 状态变更 | 输出动作 |
|---|---|---|---|
IDLE | 用户首次输入含“库存”“查”等关键词 | →QUERY_INVENTORY_INIT | 返回确认模板:“请指定仓库编号或商品SKU?” |
QUERY_INVENTORY_INIT | 用户输入纯数字(如“W001”) | →QUERY_INVENTORY_WAREHOUSE | 调用仓库查询工具,缓存返回结果集 |
QUERY_INVENTORY_WAREHOUSE | 用户说“再查一遍”或“刷新” | →QUERY_INVENTORY_REFRESH | 重触发上一工具调用,不重新解析用户输入 |
QUERY_INVENTORY_WAREHOUSE | 用户说“导出Excel” | →EXPORT_EXCEL | 绑定当前结果集为导出源,进入导出流程 |
关键点在于:状态变更不依赖模型对整句的语义理解,而依赖正则+关键词+上下文状态的组合判定。比如“再查一遍”这个短语,在IDLE状态下会被忽略(因无前置查询),但在QUERY_INVENTORY_WAREHOUSE状态下则强制触发REFRESH。我们实测对比过:纯靠大模型做意图识别,F1值约0.72;加入显式状态机后,F1值提升至0.94,且响应延迟降低60%——因为大部分判断逻辑下沉到了规则引擎,无需每次调用大模型。
工具调用的参数绑定也遵循此逻辑。当用户说“查W001仓库里型号为ABC-123的商品库存”,会话层不会把整句话喂给工具,而是提取出两个结构化参数:{"warehouse_id": "W001", "sku": "ABC-123"}。这个提取过程由预定义的实体识别规则完成(如warehouse_id规则为“W+3位数字”,sku规则为“字母+横杠+数字组合”),而非依赖模型泛化。我们在某跨平台系统中配置了47条此类规则,覆盖92%的日常指令,剩余8%交由大模型兜底。这种混合模式既保证了高频场景的确定性,又保留了扩展灵活性。
注意:状态机必须支持“回退”(rollback)操作。例如用户在
QUERY_INVENTORY_WAREHOUSE状态误输入了错误SKU,应允许说“撤回上一步”直接回到QUERY_INVENTORY_INIT,而不是重新开始整个流程。我们在设计时强制要求每个状态节点定义on_back()方法,该方法不调用任何外部工具,仅修改本地状态栈。
3. 工具层:可注册、可验证、可审计的原子执行单元
如果说会话层是Agent的大脑皮层,那工具层就是它的手和脚。但Hermes对“工具”的定义远比普通API调用严格——它必须是一个可注册、可验证、可审计的原子执行单元。我们曾见过某团队把一个包含12个HTTP请求、3次数据库写入、2次文件生成的复杂脚本打包成一个“工具”,结果在生产环境频繁出现部分成功部分失败的“半截子”状态,根本无法定位问题。
Hermes工具的黄金标准是:单次调用,单一职责,幂等可重试,失败可回滚。以最常用的“发送邮件”工具为例,它的完整定义包含以下强制字段:
{ "name": "send_email", "description": "向指定邮箱发送带附件的HTML邮件,支持抄送与优先级标记", "input_schema": { "to": {"type": "string", "format": "email"}, "subject": {"type": "string", "max_length": 100}, "body_html": {"type": "string"}, "attachments": {"type": "array", "items": {"type": "string", "format": "base64"}} }, "output_schema": { "message_id": {"type": "string"}, "sent_time": {"type": "string", "format": "datetime"} }, "side_effects": ["write_to_smtp_log", "update_email_counter"], "rollback": "delete_from_smtp_log_by_message_id" }其中side_effects字段声明了该工具调用必然产生的副作用(如写日志、更新计数器),rollback字段则指定了失败时的清理动作。当工具执行超时或返回非200状态码,Hermes运行时会自动触发rollback函数,确保系统状态一致性。我们在某图像处理Demo中实现了一个“生成缩略图”工具,其rollback逻辑是:删除已生成的缩略图文件,并将原图的thumbnail_status字段重置为pending。
工具注册流程也需严格管控。新工具上线前,必须通过三重验证:
- 签名验证:工具提供方需用私钥对工具描述JSON签名,Hermes运行时用公钥验签,防止中间人篡改;
- 沙箱测试:在隔离环境中运行工具的
test_case,验证输入/输出符合schema,且无未声明的网络请求或文件读写; - 权限审计:检查工具声明的
side_effects是否超出其申请的最小权限集(如仅申请了write_to_log权限,却在代码中尝试读取数据库)。
我们曾因一个工具未声明read_from_cache副作用,导致其在缓存失效时静默降级为直连数据库,引发雪崩。此后所有工具必须通过自动化扫描,确保代码中所有I/O操作均在side_effects中显式列出。这套机制让工具生态从“谁都能塞一个脚本进来”变成“每个动作都可追溯、可归责”。
4. MCP协议:让工具、记忆、会话像齿轮一样咬合转动
当会话层解析出用户意图,工具层准备好执行单元,记忆层存着历史状态——三者如何协同?靠的是MCP(Multi-Component Protocol),即多组件通信协议。这不是一个抽象概念,而是一套具体的、带版本号的JSON-RPC 2.0扩展协议,定义了组件间交互的消息格式、错误码、超时策略与重试语义。
MCP的核心设计哲学是:拒绝隐式耦合,一切交互必须显式声明。以“用户要求导出报表”为例,会话层不会直接调用工具,而是向MCP总线发布一条tool_call_request消息:
{ "mcp_version": "1.2", "request_id": "req_abc123", "caller": "conversation_engine_v2.1", "callee": "export_tool_v3.0", "method": "generate_excel", "params": { "data_source": "inventory_query_result_789", "format_options": {"include_timestamp": true, "sheet_name": "库存明细"} }, "timeout_ms": 5000, "retry_policy": {"max_attempts": 2, "backoff_factor": 1.5} }关键点在于caller和callee字段——它们不是字符串别名,而是带版本号的组件标识符。当export_tool_v3.0收到请求,它首先校验caller是否在白名单中(如conversation_engine_v2.1被授权调用),再校验mcp_version兼容性(v1.2协议要求工具必须支持retry_policy字段)。这种设计杜绝了“某个旧版会话引擎意外调用新版工具导致参数错乱”的问题。
MCP还定义了四类标准错误码,强制所有组件遵守:
MCP_ERR_TIMEOUT (408):调用方等待超时,由MCP总线统一触发重试;MCP_ERR_INVALID_PARAMS (400):参数校验失败,返回具体哪个字段不合法;MCP_ERR_PERMISSION_DENIED (403):调用方无权访问目标组件;MCP_ERR_UNRECOVERABLE (500):组件内部崩溃,需人工介入。
我们在压测中发现,当网络抖动导致MCP_ERR_TIMEOUT频发时,旧架构下各组件自行重试会造成请求风暴。引入MCP后,总线层统一管理重试,将并发请求数稳定控制在阈值内,成功率从78%提升至99.2%。更重要的是,所有MCP消息都经Kafka持久化,运维人员可随时回溯任意一次工具调用的完整链路——从会话层发出请求,到工具执行耗时,再到返回结果,全部时间戳精确到毫秒。
提示:MCP不是万能胶。我们明确规定,组件间禁止通过共享内存、全局变量或直接数据库读写来交换状态。所有状态变更必须通过MCP消息广播,确保分布式环境下的一致性。某次故障排查中,正是依靠MCP日志,快速定位到是缓存组件未广播
cache_evicted事件,导致会话层仍引用已失效的数据ID。
5. 记忆层:带版本、带权限、带生命周期的状态快照库
很多人把Hermes的记忆层简单理解为“聊天记录存储”,这是危险的误解。真正的记忆层是一个带版本、带权限、带生命周期的状态快照库,它存储的不是文字,而是结构化的、可验证的、有时效性的状态快照(State Snapshot)。
以某跨平台系统中的“设备巡检”场景为例,当Agent完成一次巡检后,记忆层存储的不是“用户问了什么,Agent答了什么”,而是:
{ "snapshot_id": "mem_20240521_083211_abc", "version": 3, "scope": "device_inspection_W001", "created_at": "2024-05-21T08:32:11.234Z", "expires_at": "2024-05-22T08:32:11.234Z", "data": { "device_id": "W001", "last_check_time": "2024-05-21T08:32:05.112Z", "status": "OK", "temperature": 36.2, "voltage": 220.3, "log_entries": ["2024-05-21 08:32:01 - CPU usage 42%", "2024-05-21 08:32:03 - Memory free 1.2GB"] }, "access_control": { "readers": ["role_maintenance_engineer", "role_system_admin"], "writers": ["system_agent_v2.3"] } }这个快照的关键特性:
- 版本控制:每次更新生成新
snapshot_id,旧版本保留供审计。当用户说“对比上次巡检”,系统直接拉取version=2的快照进行diff; - 作用域隔离:
scope字段确保W001设备的状态不会被W002的查询误读; - 自动过期:
expires_at由业务规则设定(如巡检数据仅保留24小时),到期后自动归档至冷存储,避免热库膨胀; - 权限栅栏:
access_control强制所有读写操作经过RBAC校验,普通用户无法绕过Agent直接查询数据库。
记忆层的读写接口也遵循MCP协议,但增加了consistency_level参数:
strong:强一致性,读取最新写入的快照(适用于状态恢复);eventual:最终一致性,允许短暂延迟(适用于报表生成等非实时场景)。
我们在某图像处理Demo中利用此特性实现了“渐进式渲染”:用户上传大图后,Agent先存入consistency_level=strong的初始快照(含原图元数据),再异步启动处理流程;前端可立即读取consistency_level=eventual的快照,显示“处理中”状态及预估耗时,无需轮询。
注意:记忆层禁止存储明文敏感信息。所有
data字段在写入前必须经AES-256-GCM加密,密钥由硬件安全模块(HSM)托管。我们曾因某开发人员在快照中硬编码了数据库密码,触发了安全审计告警——现在所有凭证类字段必须通过密钥管理服务(KMS)动态获取,快照中只存KMS密钥ID。
6. 四支柱协同实战:一次完整的设备故障处置链路
理论终需落地。我们以某工业物联网平台的真实模拟项目X为例,完整走一遍Hermes Agent四大支柱如何协同处置一次设备故障。场景:某产线PLC突然离线,监控系统触发告警,值班工程师在企业微信中发送指令:“查PLC-007状态,如果离线,重启它并通知张工”。
6.1 会话层解析:从自然语言到状态跃迁
消息到达后,会话引擎(conversation_engine_v2.1)首先进行轻量级NLP:
- 匹配关键词“查”“PLC-007”→ 触发
DEVICE_STATUS_QUERY_INIT状态; - 识别条件句“如果离线,重启它”→ 在状态机中预注册
on_condition_met回调,指向RESTART_DEVICE动作; - 检测到人名“张工”→ 调用组织架构API解析为真实邮箱
zhang@company.com,存入临时上下文。
此时会话状态栈为:[IDLE → DEVICE_STATUS_QUERY_INIT],并携带上下文{"target_device": "PLC-007", "notify_user": "zhang@company.com"}。
6.2 MCP总线调度:精准派发原子任务
会话层向MCP总线发布第一条消息:
{ "mcp_version": "1.2", "request_id": "req_devstat_001", "caller": "conversation_engine_v2.1", "callee": "device_monitor_tool_v1.4", "method": "get_device_status", "params": {"device_id": "PLC-007"}, "timeout_ms": 3000 }设备监控工具返回:
{ "status": "OFFLINE", "last_heartbeat": "2024-05-21T08:25:11Z", "error_code": "COMM_TIMEOUT" }会话层接收后,状态跃迁至DEVICE_STATUS_OFFLINE,并触发预注册的RESTART_DEVICE回调。
6.3 工具层执行:带回滚的原子操作
会话层发布第二条MCP消息:
{ "mcp_version": "1.2", "request_id": "req_restart_001", "caller": "conversation_engine_v2.1", "callee": "device_control_tool_v1.2", "method": "restart_device", "params": {"device_id": "PLC-007", "reason": "COMM_TIMEOUT"}, "timeout_ms": 10000, "retry_policy": {"max_attempts": 1} }设备控制工具执行:
- 向PLC发送重启指令;
- 等待心跳恢复(最长8秒);
- 若超时,调用
rollback:向告警系统发送“重启失败”事件,并记录到审计日志。
本次执行成功,返回{"result": "SUCCESS", "reboot_time": "2024-05-21T08:27:33Z"}。
6.4 记忆层固化:生成可追溯的状态快照
工具返回后,会话层生成记忆快照:
{ "snapshot_id": "mem_20240521_082733_plc007", "version": 1, "scope": "device_plc007", "created_at": "2024-05-21T08:27:33.456Z", "expires_at": "2024-05-22T08:27:33.456Z", "data": { "device_id": "PLC-007", "action": "restart", "trigger_reason": "COMM_TIMEOUT", "result": "SUCCESS", "reboot_time": "2024-05-21T08:27:33Z", "operator": "system_agent_v2.3" }, "access_control": {"readers": ["role_maintenance_engineer"]} }同时,向MCP总线发布第三条消息,调用邮件工具通知张工。
6.5 全链路可观测性:从日志到根因分析
整个链路由MCP总线统一记录,形成可追溯的Trace IDtrace_devfail_001。运维人员在后台可查看:
- 时间轴:08:25:11告警触发 → 08:25:15会话解析完成 → 08:25:18设备状态查询 → 08:25:22确认离线 → 08:25:25重启指令发出 → 08:27:33重启成功;
- 各环节耗时:会话解析(3ms)、状态查询(127ms)、重启执行(13182ms);
- 错误注入点:若重启失败,日志会明确标注
rollback_executed: true,并给出回滚耗时。
这种深度可观测性,让故障平均修复时间(MTTR)从原来的47分钟降至8.3分钟。更重要的是,所有操作均可审计——当合规部门要求提供“PLC-007重启操作记录”时,我们只需输入scope=device_plc007,即可导出带数字签名的完整快照包。
7. 避坑指南:我们踩过的七个关键深坑与填坑方案
在多个Hermes Agent项目中,我们总结出七类高频、致命、文档里很少提的深坑。这些不是理论风险,而是真实导致过线上事故的教训。
7.1 坑一:会话状态机未处理“跨会话引用”
现象:用户A在会话1中查询了设备状态,用户B在会话2中说“把刚才那个设备重启”,系统错误地重启了用户A的设备。
根因:状态机设计时假设“刚才”仅指本会话内,未考虑多用户并发场景。just_now这类相对时间词缺乏会话隔离。
填坑方案:强制所有相对时间词绑定会话ID。在会话初始化时,生成唯一session_context_id,所有just_now、last_time等解析结果必须附加该ID。当用户B说“刚才”,系统只搜索session_context_id=B内的历史动作,绝不跨会话检索。我们在数据库中为记忆快照增加session_context_id索引,查询性能提升40倍。
7.2 坑二:工具未声明副作用,导致状态不一致
现象:某报表工具在生成Excel时,顺手更新了数据库中的“报表生成次数”计数器,但未在side_effects中声明。当该工具因网络超时失败时,计数器已加1,但报表未生成,造成数据错乱。
根因:开发者认为“更新计数器是小事,不用声明”,违反了MCP的副作用显式原则。
填坑方案:上线前强制静态扫描。我们开发了一个Python脚本,扫描所有工具代码,检测是否存在未在side_effects中声明的INSERT/UPDATE/DELETESQL语句、open(..., 'w')文件操作、requests.post等网络调用。扫描不通过,CI/CD流水线直接阻断。该脚本已发现并拦截了17处类似隐患。
7.3 坑三:记忆快照未设有效期,热库爆满
现象:某系统运行3个月后,记忆库占用磁盘达92%,查询延迟飙升,被迫停机扩容。
根因:初期认为“所有状态都要永久保存”,未按业务规则设置expires_at。快照中大量存储了已过期的设备心跳数据。
填坑方案:建立快照生命周期矩阵。按scope类型设定默认过期时间:
device_*:24小时(设备状态瞬时性高);user_session_*:7天(会话恢复窗口);audit_*:永久(合规要求);report_*:30天(报表查阅周期)。 所有快照写入时,若未显式指定expires_at,则按矩阵自动填充。运维面板实时显示各scope的快照数量与占比,超阈值自动告警。
7.4 坑四:MCP版本升级未做灰度,引发大面积调用失败
现象:MCP协议从v1.1升级到v1.2后,所有旧版工具突然无法被调用,监控告警狂响。
根因:升级时未启用版本协商机制,新总线直接拒绝mcp_version=1.1的请求。
填坑方案:MCP总线必须支持多版本共存。v1.2总线收到v1.1请求时,自动进行字段映射(如将retry_policy映射为max_retries),并记录deprecated_usage指标。我们设置了7天灰度期,当v1.1调用量低于1%,才下线旧版本。升级期间,所有组件必须声明supported_mcp_versions: ["1.1", "1.2"]。
7.5 坑五:工具调用链路过长,超时 cascading
现象:用户查询一个复合报表,涉及5个工具串联调用,总耗时超30秒,前端早已超时,但后端仍在执行,浪费资源。
根因:每个工具只设自己的timeout_ms,未传递全局截止时间。
填坑方案:MCP消息强制携带deadline_unix_ms字段(Unix毫秒时间戳),由会话层根据用户SLA计算。每个工具在执行前校验deadline_unix_ms - current_time > 0,否则立即返回MCP_ERR_TIMEOUT。我们还在总线层实现“熔断器”,当某工具连续3次超时,自动将其标记为degraded,后续请求直接返回缓存结果或降级响应。
7.6 坑六:记忆层权限模型粗粒度,导致越权访问
现象:某实习生通过构造特殊scope参数,读取到了本不应查看的财务报表快照。
根因:权限校验仅检查scope前缀(如report_*),未校验完整scope字符串与用户角色的精确匹配。
填坑方案:权限校验必须精确到scope全量字符串。我们构建了RBAC规则树,叶子节点为具体scope,如report_finance_q1_2024,父节点为report_finance_*。用户角色绑定的是叶子节点或通配节点,校验时必须完全匹配。所有scope生成逻辑收口到统一SDK,禁止手动拼接。
7.7 坑七:大模型幻觉污染记忆层
现象:用户问“PLC-007的IP是多少”,工具返回空(设备离线无IP),但大模型在回复中虚构了192.168.1.107,该IP被错误存入记忆快照,后续操作全基于假IP。
根因:记忆层写入的是大模型的最终回复,而非工具的原始输出。
填坑方案:记忆层只存储工具返回的data和会话层的context,绝不存储大模型生成的文本。用户看到的回复是会话层将工具结果+预设模板渲染而成,该渲染过程不产生记忆快照。我们在架构图中明确画出“记忆层”与“回复生成层”的分离边界,所有培训材料强调:快照是事实,回复是解释,二者不可混淆。
8. 架构演进思考:从单体Agent到可组合智能体网络
Hermes Agent的四大支柱已足够支撑大多数垂直场景,但当我们思考更复杂的系统时,会发现新的挑战:比如,一个“智能工厂”需要协调上百台设备、数十个工艺环节、多个部门的协作。单个Agent的决策半径和执行能力显然不足。这时,架构自然演进为可组合智能体网络(Composable Agent Network)。
其核心思想是:将Hermes Agent本身作为可被调度的“超级工具”。我们定义了一种新型MCP消息agent_call_request,允许一个Agent(称为Coordinator)调用另一个Agent(称为Worker):
{ "mcp_version": "1.2", "request_id": "req_coord_001", "caller": "production_coordinator_v1.0", "callee": "plc_controller_v1.2", "method": "execute_maintenance_plan", "params": { "plan_id": "PLAN-2024-0521-001", "target_devices": ["PLC-007", "PLC-008"] } }这里的plc_controller_v1.2不是一个普通工具,而是一个完整的Hermes Agent实例,它有自己的会话引擎、工具集、记忆库和MCP端点。Coordinator Agent不关心Worker内部如何实现,只通过标准MCP协议与其交互。
这种架构带来三大优势:
- 弹性伸缩:PLC控制器负载高时,可水平扩展多个
plc_controller实例,由MCP负载均衡器分发请求; - 领域隔离:设备控制逻辑与生产计划逻辑物理隔离,互不影响;
- 渐进演进:新加入的“能耗优化Agent”只需实现MCP接口,即可被现有Coordinator调度,无需改造旧系统。
我们在某高校实验室的模拟项目X中,用此架构实现了“跨楼层设备协同维护”:Coordinator Agent接收“三楼A区空调故障”指令后,自动调用floor3_hvac_agent诊断,再调用power_supply_agent检查供电,最后调用maintenance_scheduling_agent生成工单。整个网络中,各Agent通过Kafka交换MCP消息,状态快照存于各自独立的记忆库,彻底解耦。
这种演进不是推翻重来,而是Hermes四大支柱的自然延伸:会话层成为网络路由协议,工具层升级为Agent调用接口,MCP成为网络通信标准,记忆层则演化为分布式状态共识机制。它让我们看到,Agent的未来不在单点智能,而在群体协同——每个Agent都是一个可信、可验、可调度的智能细胞,共同构成有机的智能体网络。
我在实际使用中发现,真正决定Hermes落地成败的,从来不是模型有多强大,而是对确定性、可追溯、可审计的极致追求。当你的系统能清晰回答“这个操作是谁在什么时候、基于什么状态、调用了哪个工具、产生了哪些副作用、失败时如何回滚”这五个问题时,你就已经走在了正确的路上。