先交代一下背景。我在实际工作中见过太多"通知系统"了——监控告警发出去了,结果是群里消息999+,真正出问题的时候没人看;业务通知推给用户,用户压根没收到;任务提醒发了,但执行的人半个小时后才在消息流里翻到。大多数系统做的都是"发消息",把消息丢进管道里就结束了,至于对方有没有看到、有没有看懂、有没有处理,一概不管。Agent-Reach这个项目就是为了解决这个问题做的。它不是一个传统的消息网关,而是一套把"触达"当核心目标的智能体系统。这篇文章我会从问题拆解、整体设计、核心细节、实操落地、常见坑位这几个角度,把这个项目完整拆开讲一遍。适合正在做通知中台、告警平台、IM机器人、运维自动化或者任何跟"触达人"相关的系统的工程师参考。
1. 为什么需要一个叫Agent-Reach的触达系统
1.1 从"发了消息"到"真的触达了"之间隔着什么
先说一个很反直觉的事实:消息发出去之后,大概率等于没发。
你自己回想一下,每天有多少微信消息、飞书消息、钉钉消息、系统弹窗、邮件通知是你根本没看就划掉的?告警群里的消息更是这样,一条error日志刷过来,没人知道该谁处理,几秒钟就被新的消息顶上去了。传统的通知系统认为"送达"等于"调用第三方接口成功",这是把问题想简单了。实际上"触达"至少包含四层:到设备——推送在用户的手机上弹出来;到眼睛——用户看到了这条消息;到脑子——用户理解这是什么、是不是自己的职责;到手——用户去处理了。任何一层断掉,触达就是失败的。
Agent-Reach这个名字,英文直译是"智能体触达"。它想做的事情很明确:让系统不光知道"消息发出去了",还要知道"目标对象到底有没有被触达成功",并且在没触达成功的时候自己想办法继续往下走。项目的核心价值不是做一个推送API,而是做一个带着判断力和执行力的触达智能体。
1.2 Agent-Reach的定位:不是消息网关,是触达智能体
市面上的消息推送SDK、短信网关、Webhook机器人,本质上都是"管道"——给你一个接入点,你把消息扔进去,它负责送到渠道。差别在于能送什么渠道、多稳定、多快。Agent-Reach做的事情跟这些完全不同,它在管道之上加了一层带判断逻辑的调度层,自己知道下面这些事:
- 一条告警进来之后,先判断严重级别和影响范围,决定要不要马上打扰人;
- 判断当前该走哪种渠道——是推微信/飞书,还是先发站内信,还是直接打电话;
- 判断该通知谁——是拉一个值班群,还是点对点找到具体负责的Oncall工程师;
- 判断触达有没有成功——如果发出去30分钟没人确认,要不要升级渠道、换人、二次触达;
- 最后把所有行为记录下来,做成一份"谁在什么时间、通过什么渠道、最终有没有处理"的完整链路。
所以Agent-Reach的定位是:一个具备触达策略决策能力的Agent系统。它不是一个"更聪明的消息发送器",而是一个"能自己决定怎么找到人并把事情处理完的智能体"。这句话是整个项目设计的原点,后续所有模块的划分都是从这里长出来的。
1.3 什么场景适合上Agent-Reach
从实际部署经验看,有三类场景收益最明显。
第一类是运维告警触达。监控平台Prometheus、Zabbix、自建监控系统检测到故障,需要第一时间找到该处理的人。这类场景最大的痛点是告警多、值班机制复杂、消息乱发。第二类是业务通知触达。比如订单异常、支付回调失败、用户投诉升级,这些业务事件需要让运营、客服或技术负责人及时介入。这类场景的痛点是通知对象不固定,可能要根据规则临时算出来。第三类是任务协同提醒。比如审批流卡住了、数据任务失败需要人工干预、日报未提交,系统要能盯着并定时催促。
这三类场景的共同特征是:消息重要、需要找对人、需要确认结果、失败要升级。如果你的场景只是"流量每小时汇报一下"这种不紧急的消息,不需要Agent-Reach,直接丢到群里就行。判断标准就一句话——这条消息发出去之后,如果没人处理会产生实际损失吗?会的话,才值得用这套体系。
2. 整体设计思路:触达这件事是怎么拆解的
2.1 触达的基本动作拆解
做架构设计和写代码不一样。写代码是先定义接口和数据结构,做架构设计是先拆解问题域。我把"触达一个目标对象并确认TA完成了处理"这件事,拆成了四个基本动作:
- 理解:把消息读懂。原始告警可能是一个JSON、一行日志、一段文本。Agent要从中提取出事件类型、严重级别、涉及系统、时间、责任人信息。这一步相当于人的"阅读理解"。
- 决策:决定怎么做。基于事件属性和既定策略,决定触达渠道、触达对象、触达节奏。比如级别为P0的故障,立即触发电话+IM双重触达;级别为P3的告警,聚合后定时推送摘要。
- 执行:按决策把消息推出去。这里涉及多渠道适配、限流控制、模板渲染、幂等去重。执行层内部要保证不管下游渠道怎么抖动,消息最终都能送出去。
- 反馈:获取触达结果并形成闭环。用户是否已读、是否确认、是否升级处理,这些结果要回流到决策层,决定下一步动作。这是Agent和普通消息系统最根本的区别:普通消息系统是一个单向管道,Agent-Reach是一个带反馈回路的行为系统。
这四个动作合起来,正好对应Agent-Reach内部的核心模块。理解模块负责解析和归一化,决策引擎负责策略和路由,触达执行器负责多通道分发,反馈回收器负责回执和升级。
2.2 触达渠道矩阵与优先级设计
渠道不能乱选,选错渠道有时候比不发还糟糕。想象一下,半夜三点因为一条不紧急的告警给值班工程师打电话,对方爬起来处理发现就是一个警告级别事件,几次下来就没人接电话了。所以Agent-Reach里,每条消息进来之后首先要过一道"渠道优先级"的关卡。
我在项目里设计了一张渠道矩阵表,用四个维度评估每个渠道:
| 渠道 | 打扰强度 | 实时性 | 信息承载量 | 回执能力 | 适用场景 |
|---|---|---|---|---|---|
| 电话 | 极高 | 即时 | 低 | 按键确认 | P0故障、夜间无人响应 |
| IM单聊 | 中高 | 秒级 | 中 | 已读回执、消息确认 | 值班人点对点通知 |
| IM群聊 | 中 | 秒级 | 中 | 已读(消息量大) | 周知型告警、发布通知 |
| 短信 | 高 | 秒级 | 低 | 无 | 备用渠道、弱网环境 |
| 邮件 | 低 | 分钟级 | 高 | 无 | 报表、日报、非紧急汇总 |
| 站内信/待办 | 低 | 拉取 | 高 | 点击确认 | 审批任务、工单 |
渠道优先级策略核心就是一句话:打扰强度跟事件严重程度成正比,信息量与紧急程度成反比。越紧急越打电话、消息越短;越不紧急越往"弱打扰渠道"沉淀。这个矩阵不是静态的,每个业务方可以自定义自己的映射关系。比如有些团队希望所有P1以上告警都必须走电话,而另一些团队觉得只要IM就够了,完全取决于那个"如果没人处理会产生多大损失"的判断。
2.3 为什么一定要有一个统一触达层
假设没有Agent-Reach,直接把所有业务系统都接到IM、短信、电话三个渠道上,会变成什么样子?每个业务系统都要自己维护一套渠道SDK、自己的重试逻辑、自己的模板渲染,只要任何一个渠道的API发生变化,所有上游都要改一遍。这是典型的多对多集成问题,复杂度爆炸。
统一触达层的作用是做一个"收口"。上游系统只需要按照一个标准协议把事件推给Agent-Reach,后面所有的事情——路由到哪个渠道、重试几次、找谁确认、失败怎么升级——都由触达层内部消化。这是典型的M对N收敛为M对1对N的架构思路。Agent-Reach作为中间层,沉淀各渠道的接入适配、限流退避、幂等策略、模板管理,上游不用关心,下游渠道的差异也被隔离掉了。
经验上有一个重要的边界要画清楚——Agent-Reach不是消息总线,它不应该承担"把所有数据导来导去"的事情。它只接收"需要触达人"的事件,业务数据流还是走自己的消息队列或者数据管道。很多团队一看到统一层就什么消息都往里塞,最后把Agent-Reach变成一个巨型垃圾桶,调优和排障都变得非常痛苦。这一点在架构评审时一定要堵住。
3. 核心细节解析与实操要点
3.1 语义压缩:让一条消息一眼看完
触达消息和日志消息有一个本质区别:日志是给机器看的,可以冗长;触达消息是给人看的,必须一眼看懂。很多人做告警通知时直接拿着监控原文往IM里丢,一坨JSON、几十行堆栈,用户扫了一眼根本不知道要看什么。
Agent-Reach在"理解"阶段做了一件关键事情:语义压缩。它会把原始事件抽象成四个要素:发生了什么、影响范围多大、该谁处理、多紧急。然后用模板渲染出一段不超过50个字的触达文案。举个例子,Kubernetes集群一个Pod CrashLoopBackOff的原始报警可能长这样:
{ "namespace": "production", "pod_name": "order-service-7b8c9d-2w3e4", "reason": "CrashLoopBackOff", "restart_count": 15, "message": "back-off 5m0s restarting failed container=order-service" }这段东西直接丢给值班工程师,对方要读好几遍才知道是怎么回事。Agent-Reach会把它改成:
生产集群 order-service Pod 频繁重启,15次/20分钟 状态: CrashLoopBackOff 处理人: 值班工程师 @张伟 请在30分钟内确认处理,超时将升级到服务负责人这段就是走完理解、决策、模板渲染之后的信息。它去掉了K8s的字段名,保留了"发生了什么、影响什么、该谁处理、什么时候必须响应"四个要素。语义压缩的目的就是让收到消息的人不假思索就能做出第一个判断。
做法上有几个实操要点。一个是不要贪多,把最有判断价值的信息放前面,一般场景最有价值的是"系统名+事件类型+重启次数/影响时长"。另一个是要注意模板和字段的动态对齐,底层事件结构变化时,压缩层要提前做好归一化适配。还有一点是谨慎保留原文,我建议在IM消息里提供"查看原始告警"的链接入口,而不是把原始文本直接透传。
3.2 同事件聚合与噪声抑制:不要让通知变成骚扰
触达系统最大的敌人是消息噪声。真正被重视的告警,反而会被淹没在大量低级别消息里。
Agent-Reach在噪声抑制上做了三层处理。第一层是时间窗聚合。同一个系统、同一类事件在5分钟内重复上报的直接合并,只更新次数,不重复通知。第二层是严重级别降级。当一个P3级别的错误已经持续刷了3个小时都没有实质业务影响,自动降级为摘要通知,不再逐条打扰。第三层是值班感知。系统知道当前这个时间段是不是有人在处理,如果已经有人在工单上标记"处理中",就不再重复触发触达,只在处理超时时提醒一次。
这三层逻辑看起来很朴素,但落地细节很磨人。最典型的是时间窗聚合的窗口大小该怎么定。窗口太短,告警还是会刷屏;窗口太长,真正紧急的故障就会延迟通知。我实测下来,P1级别窗口控制在1-3分钟,P2控制在5分钟,P3及以上走10分钟聚合或者走日报摘要,算是比较合理的默认值。这个值不是拍脑袋定的,跟服务自治愈能力有关——你的系统如果能在3分钟内自愈,那窗口设5分钟也不迟;如果自愈能力弱,窗口就得缩短。每一个团队应该按自己服务的MTTR来倒推决定。
这里有一个必须警惕的操作禁忌:不要为了降低噪声而把高优告警压掉。有些团队配置聚合策略时把时间窗口调得很大,结果P0故障被压了15分钟才通知,事故早就扩大了。聚合只是改变消息的展示方式,不应该改变事件触达的优先级判断。
3.3 模板引擎:愿意回复的消息长什么样
触达这件事,最重要的是让接收者产生行动意愿,而行动意愿首先取决于消息本身看上去是不是"活人写的"。
我做过一个对比测试。同一件"数据库连接池耗尽"的事故,用两种方式通知。第一种是机器模板:
【告警】数据库连接池使用率超过阈值 系统: order-db 指标: 连接数 180/200 时间: 2025-01-12 14:33:22 请及时处理。第二种是Agent生成的自然语言风格:
订单库连接池快被打满了(184/200),这个库最近三天第一次到这个水位。 已经影响下单接口的响应时间,建议先看一眼慢SQL和调用量。 如果5分钟内没人处理,我会自动把这条消息升级给服务负责人陈晨。没有任何悬念,第二种消息的已读和响应速度远远超过第一种。原因很简单,第一种消息像一个机器在喊"有一个人人都知道的指标超了",第二种消息像一个靠谱的同伴直接把该看什么、该干嘛、后果是什么都说清楚了。
模板引擎就是用来生成第二种消息的。底层我会维护事件类型到“意图模板”的映射关系,每一类事件都有固定的话术骨架,再通过Agent对当前上下文(最近变化趋势、影响接口、当前值班人)做变量填充。注意这里不是让Agent在每次触达时都"自由创作"——那会有幻觉和措辞不一致的风险,而是让Agent按照意图枚举选择话术结构,只让它在"发生了什么额外变化"和"建议关注点"两个环节做上下文推理。这样既有自然语言的可读性,又保留了模板的确定性。
实操中模板需要维护一套版本化体系。比如template_version: "2025-01",每次话术调整都在模板里面留痕。不然出了事故,想追溯"当时为什么给用户发了这么一句奇怪的话",根本查不到是哪一版模板渲染的。
3.4 幂等、超时、重试与回执确认
触达系统是典型的TCP重传哲学应用场——每次发送都不能保证送达,需要协议级的可靠性保证。
Agent-Reach在触达执行层实现了四个关键保障。
幂等是最基本的一条。同一个事件,无论上游推了两次、执行器重启导致重复调度,还是人类点击了两次"重新发送",系统都要保证同一事件同一触达目标不会收到两条触发消息。实现方式是事件指纹:(event_source + event_id + target_user + channel + dedup_window)拼接后算MD5,在触达执行前查重。我建议这个查重不要依赖Redis的过期键就完事,还要落一份SQLite或者关系库的记录,避免Redis抖动导致重复。
超时控制指的是触达动作不能无限期挂起等待渠道返回。不同渠道的超时窗口不一样,IM交互卡片回调一般给10-20秒,短信平台给5秒,外呼电话给30秒以上。超时之后的动作就是进入重试策略。
重试策略需要区分"必达型触达"和"通知型触达"。必达型(P0/P1)用退避递增:1分钟、5分钟、15分钟,三次重试后如果还没确认,自动触发升级,换一个渠道,甚至换一个接收者;通知型(P2以下)只做1次重试,隔5分钟,再失败就并入日报摘要。这个策略解决了"半夜被电话吵醒结果是个不紧急的事情"和"非常紧急但发出去就石沉大海"两种极端情况。
回执确认是Agent-Reach比普通网关多出来的能力层。IM消息支持已读回执,Agent在收到"已读"之后标记为"seen",但"seen"不等于"handled",会再跟一个确认卡:请点击"开始处理"或"无法处理"。如果用户已读但超过15分钟没有点击,系统自动认为"被忽略",触发升级。外呼电话语音确认按1,短信随访,邮件提供处理链接,都是同样的思路。这套回执体系是整个"智能触达"名称的真正出处——没有回执、没有反馈,Agent就是一个睁眼瞎的发射器。
4. 实操过程与核心环节实现
4.1 快速搭建:三大核心模块怎么落地
说了这么多思路,落到代码上怎么搭一套最小可用的Agent-Reach?我按自己项目里的做法给出一套可复制的骨架。
最小可用版本只需要三个模块:事件接入层、决策路由层、触达执行层。事件接入层面向外部暴露一个统一的Webhook入口,把各种监控源(Prometheus、自研监控、业务回调)的异构事件归一化为标准事件;决策路由层读策略配置,决定渠道和对象;触达执行层对接各渠道SDK,并回收回执。
事件接入层的核心代码如下,正常事件先做去重再进决策路由:
import hashlib import time class EventIngestService: def __init__(self, dedup_store, router): self.dedup_store = dedup_store self.router = router def ingest(self, raw_event: dict): normalized = self._normalize(raw_event) fingerprint = hashlib.md5( ( normalized["source"] + normalized["event_id"] + normalized["target_user"] + normalized["channel"] + str(int(time.time() // 300)) ).encode() ).hexdigest() if self.dedup_store.exists(fingerprint): self.dedup_store.incr(fingerprint) return {"status": "deduplicated"} self.dedup_store.put(fingerprint, normalized) self.router.route(normalized) return {"status": "accepted"} def _normalize(self, raw_event: dict): return { "source": raw_event.get("source", "unknown"), "event_id": raw_event.get("event_id", ""), "event_type": raw_event.get("event_type", ""), "severity": raw_event.get("severity", "P3").upper(), "title": raw_event.get("title", ""), "content": raw_event.get("content", ""), "target_user": raw_event.get("target_user", ""), "channel": raw_event.get("channel", "im"), "occurred_at": raw_event.get("occurred_at", int(time.time())), }这个指纹里面time.time() // 300是关键,它把去重窗口直接做成了5分钟粒度。同一事件5分钟内重复上报直接聚合,超过窗口后的事件指纹不同,不会挡掉真正的下一次故障。缺点是如果这个故障持续超过5分钟,会再次触发触达,所以我在正式版本里加了一个"持续故障抑制"字段,同一事件如果已经处于触达中,只更新内容不重复触发。
决策路由层的策略部分,我建议先配置文件后写死代码。不是每个团队都需要规则引擎,但至少要把渠道映射、对象映射做成可配置的。这样真实的策略调整(换个值班人、改个升级时间)不需要发版。我常用的配置结构是这样的:
# routing_policy.yaml routes: - id: "p0-oncall-immediate" match: severity: "P0" source: ["prometheus"] actions: - channel: "phone" target: "{oncall}" timeout_sec: 30 - channel: "im" target: "{oncall}" timeout_sec: 20 escalate_after_min: 5 escalate_to: - channel: "im" target: "service_owner" - id: "p2-digest" match: severity: "P2" source: ["*"] actions: - channel: "im_group" target: "oncall-group" aggregate_window_min: 10路由决策的核心就是match和actions的映射关系,加上超时升级。业务方只需要维护这样一张表,就能精确控制每一种事件该走什么流程。这种"配置文件做决策"的方式,比硬编码在Agent逻辑里要可控得多。Agent的任务是帮我解析事件,然后把路由表的匹配逻辑跑完并输出结果——不要把复杂判断、价值观选择放给大模型去自由发挥,这是Agent工程里一条非常重要的稳性原则。
4.2 实战场景:一条P0告警如何找到正确的人
我挑一个非常典型的故障场景走一遍全流程,这个例子基本能代表Agent-Reach最核心的运作方式。
场景设定:凌晨2点14分,Prometheus检测到payment-service的可用性跌到82%,过去5分钟5xx错误率超过10%。按照值班表,当前Oncall是李文,服务负责人是王琴。
第一步,Prometheus的Webhook把原始告警推到Agent-Reach的事件接入层。接入层做归一化后得到:
source=prometheus, event_id=alert-82931, severity=P0, title="payment-service 5xx rate high", target_user={oncall}第二步,决策路由层读取策略。命中p0-oncall-immediate这条路由,通过值班系统解析出当前Oncall对象是李文。输出决策结果:先给李文打电话(渠道超时30秒),同时发一条IM消息,如果5分钟内没有确认,升级给王琴。
第三步,触达执行层并行发起两个动作。电话渠道基于云呼叫能力,拨通李文手机,播放一段TTS语音:"生产环境支付服务5xx错误率超过10%,已影响交易链路,请立即登录系统查看,按1确认处理,按2转接服务负责人。" 同时IM渠道渲染出一条语义压缩后的消息,附加"处理中/无法处理"两个确认按钮。
第四步,李文在电话里按了1确认处理,IM消息也自动打上"已处理"标记。反馈回收器同时收到两个渠道的确认,把事件状态更新为acknowledged,决策层关闭升级计时器。整个过程中,Agent没有停下来等任何一步,而是异步地把每个动作串起来。用户从被触达、到理解、到行动,前后不超过两分钟。
这个案例的细节值得展开说一下。电话的TTS话术长度我要控制住,原文如果太长,人根本记不住关键信息。最优信息结构是:故障系统+故障表象+影响范围+确认指令。这里"按1确认、按2转接"就是给用户一个极低成本的行动入口——他不需要找鼠标、找手机解锁密码,只需要按一下键。永远把行动成本降到最低,这是触达成功率能超过90%的秘诀。
4.3 效果验证与指标看板
Agent-Reach这套系统,光部署完成不算完,必须用数据验证它是不是真的把触达率提上去了。我建议团队从三个维度定指标。
第一个维度是触达率。分子是成功下发给目标人的消息数,分母是应触达的消息总数。这个指标要拆到渠道看,能发现哪个渠道的失效率偏高。第二维度是响应率。已经触达成功的事件里,多久收到了"确认处理"的回执。我建议重点看两个分位数:P50(一半事件在多少秒内确认)和P90(绝大多数事件在多少秒内确认)。P50代表常态效率,P90代表最差场景下的兜底能力。第三个维度是升级率。多少比例的事件因为超时未确认触发了一级升级。升级率过高说明触达策略本身有问题,需要优先排查。
我自己的项目在接入Agent-Reach前后数据对比非常明显。接入前,告警群里的消息几乎没有人点击确认,值班工程师平均响应时间是40分钟;接入后,通过电话+IM双触达和回执机制,P0事件的P50确认时间压缩到1分50秒,P90在4分钟内,升级率从37%降到11%。这里面的差距很大程度上来自"点一下确认"这个交互设计——过去人说"我看了"但没有任何可记录的动作,现在系统把一个"看了且确认了"变成可追踪的动作。
指标看板建议直接做成事件全景的列表加漏斗。从事件产生、触达路由、用户已读、确认处理、到最终闭环,每一步的通过率和平均耗时都列出来。哪个环节最宽,就集中精力修哪个环节,触达率很快就能拉起来。
5. 常见问题与排查技巧实录
5.1 告警轰炸把人"通知麻了"怎么办
这是上线后第一个会遇到的问题,而且几乎一定会遇到。原因通常是团队把很多低级别告警都配置成了直接触达,每个人都觉得自己那条系统很重要。结果就是值班工程师一天收到几十条IM推送,过了一周看到推送就直接划掉,连P0真告警都一同划掉了。
我的排查路径是这样的:先看升级率和响应率有没有同时下降。如果响应率下降但升级率也下降,基本可以判定是噪声淹没——人已经麻木了。处理动作分三步走:第一步,把所有不影响核心链路的事情性消息从"即时触达"改成"聚合摘要",比如P2/P3级别只保留每10分钟一次的上报;第二步,对P0/P1强触达做"渠道强化",只对最强级别开放电话通道,让电话成为一种稀缺资源,人自然不会麻木;第三步,把消息的语义做区分,重要告警进来时标题加上[中断][恢复]之类的前缀,让消息流在视觉上就有梯度。
更多实操细节是"按业务线拆分群组"。很多人喜欢把所有监控消息都推到一个大群里,觉得"信息都在一个地方安全"。实际效果正好相反,群越大、越没人负责。Better的做法是每个业务线一个群,群内只放自己的告警和值班人。这样责任边界非常清晰,告警的命中率也高很多。
5.2 渠道限流与阻塞如何兜底
IM机器人、短信平台都有频率限制。比如有些IM开放平台对同一个用户一分钟内最多推5条消息,超过会返回429。如果底层渠道限流了,Agent-Reach不能跟着渠道一起失败。
我的做法是在触达执行层实现一层渠道级令牌桶。每个渠道每秒能消费多少个触达请求是可以配置的。当请求量超过渠道令牌桶时,高优事件绕过限流器直接投递,低优事件在本地队列排队,等待下一个令牌。如果排队超过30秒,低优事件会自动降级为摘要模式,合并成一条消息发出去。这个设计保证有限的触达名额永远优先让给最重要的事件。
另外还有一个兜底策略:渠道切换。如果IM机器人接口连续三次返回5xx或超时,Agent-Reach会自动把后面的触达切换到短信,同时将状态标记为"渠道降级中",持续监控渠道恢复情况。这个操作在代码里要有开关,因为有些团队希望渠道挂了就要告警出来,不希望静默切换。但至少作为可选项,它能在关键时刻救命。
5.3 消息已读但没人响应,怎么闭环
这是最隐蔽的一个坑。IM的"已读"回执常常给人虚假的安全感——系统显示消息已读,但没有一个人去处理。翻译过来就是"大家看到了,但没人觉得该自己动手"。
Agent-Reach对这个问题的处理策略分两层。下层是回执升级策略:消息已读不算完成,必须通过点击确认按钮、回复指定关键字或打开链接点击"开始处理",才算真正的ack。如果已读超过15分钟没有点击确认,这个事件自动进入"疑似被忽略"状态,触发原模板错峰再触达一次,并附上"已读未处理等待中"的提示。上层是全链路留痕:已读但未处理这个状态被完整记录,形成一个人的触达履历。这个履历不是用来扣分或者问责,而是帮团队复盘"是消息写得不够清楚,还是对象选错了"。我见过一个典型案例,某团队把一条升级任务发给了一个新入职的员工,对方读了,但根本不知道这个系统长什么样、怎么处理,自然没点确认。看履历发现"目标人认知不足,需要在消息里附带处理入口链接",完全变清楚了。
处理入口链接是这里的关键。消息里只写"请处理"是没人动的,给一个"点这里打开工单并标记处理中"的链接,行动转化率能提升好几倍。不要让用户自己去找系统、找工单号。
5.4 高频切换渠道导致体验割裂,怎么治理
有些事件在触达过程中会经历多轮升级:先IM,然后短信,然后再电话。如果消息文案每次都不同,用户会非常分裂。上一句还在IM里说"请点击确认",电话里又变成"按1确认",用户会怀疑是不是两个不同的系统在找他。
正确的做法是把整条触达链路统一到同一个事件上下文中。每轮触达都带一个唯一的事件编号,比如evt-7f3a,IM消息里是事件evt-7f3a:请确认处理,短信里是[evt-7f3a] 支付服务告警,请登录系统处理或其他同事处理,电话TTS开头也是"关于事件一维七F三A……"。这样用户在不同渠道收到的信息能串起来,前面已经通过IM处理过的人,再接到电话时不会重复操作。Agent-Raach里的上下文状态机是全局唯一的,每一个触达动作都会先查这个状态机:事件是否已被ack?哪个渠道已确认?是否已经升级过?只有没有被ack的事件才会继续触达。
这里要给一个非常容易忽略的细节:渠道切换时必须同步最新上下文。比如电话渠道触发之后用户还没按,IM渠道又发来一条"我们已尝试电话联系您",这就是典型的上下文不同步。正确做法是电话触达之后,先把电话状态回写,IM触达阶段才能感知到"当前处于电话触达中"并且只发送辅助提醒,不做重复触达。所有渠道交互都读到同一份状态,用户才能感受到是一个顺畅的流程,而不是好几个机器人各叫各的。
一些实操收尾的心里话
Agent-Reach这套体系上线已经有大半年了。我最深的体会是:做触达系统,技术架构本身没那么难,难的是持续对抗人的麻木感和系统的噪声。技术上解决"消息发出去"是最简单的一步,真正麻烦的是怎么让每条消息都值得被认真对待。有朋友问我,用Agent做触达,是不是就是让大模型写消息、做判断?我的答案是——Agent确实承担了理解和语义压缩这些智力活,但系统的骨架仍然是工程问题:幂等、路由、重试、回执、升级、上下文同步。大模型不能替代这些,它们只是让这些工程环节对用户更友好了一点。另外再说一个小技巧:刚开始做的时候不要贪多,先把IM一个渠道的触达闭环做通,回执和升级都走得顺了,再逐步加电话、短信渠道。一上来就铺所有渠道,大概率变成每个渠道都是半吊子,最后还得返工。大半年测试下来,Agent-Reach哲学中最有价值的一句话就是——真正好的触达,是让需要的人在最合适的时间用最省力的方式完成一个能留下记录的动作。做到这一点,你团队的告警就再也不会是"发了但等于没发"了。