Agent-Reach:智能体驱动的实时用户触达与频控实践 1. 先把 Agent-Reach 这个事说透Agent-Reach 这个词第一次出现在我视野里的时候我脑子里蹦出来的不是某个具体产品而是一类问题的统称让智能体Agent去完成对用户的触达动作。所谓触达说白了就是把合适的信息在合适的时间通过合适的渠道送到合适的人面前。这件事听起来简单做起来全是坑。传统的做法是靠运营同学拉个名单、配个模板、设个定时任务然后一键群发。我在几家公司见过太多这样的链路了一份 Excel 名单在三个部门之间倒腾模板改到第八版还是有人不满意发出去之后打开率不到百分之三退订率却蹭蹭往上涨。Agent-Reach 想解决的就是把这套又笨又重、还特别容易惹用户烦的流程改造成一个能自己判断、自己决策、自己动手、自己复盘的闭环系统。它不是一个现成的开源项目更接近一套架构思路加上若干个可替换的工程组件。适合谁看如果你正在做用户增长、消息推送、客户成功、私域运营或者你是个后端/算法工程师被产品经理追问能不能让 AI 自动决定给谁发什么那这套东西你大概率用得上。我下面写的都是基于一线落地时的常见做法做的补全不是照抄某份官方文档里头的参数和代码是按真实场景里最能跑通的形态给的。2. Agent-Reach 的整体设计与思路拆解2.1 传统触达链路到底卡在哪先得把老路子的病根挖出来不然改造就是无头苍蝇。我梳理过传统触达基本卡在三个地方。第一个是决策静态化。名单是提前圈好的规则是运营拍脑袋定的比如最近 7 天没下单的用户发一张券。可问题是用户的状态是实时变的他可能昨天刚下单今天就被你的召回券砸中体验直接崩掉。静态规则没法感知这种即时变化。第二个是内容同质化。一个模板打天下所有人都收到一模一样的话术。用户刷到第三条就腻了第四条直接拉黑。更糟糕的是模板里的变量经常填错我见过把尊敬的{{name}}原样发出去的那种尴尬只有经历过的人懂。第三个是闭环缺失。发出去就完事了至于用户看了没、点了没、为什么没点没人管。下次还是同一套打法错的东西被重复放大。这三个病根叠加起来就导致触达这件事的投入产出比越来越难看——成本在涨效果在跌。2.2 Agent 介入后链路重构成了什么样Agent-Reach 的核心思路是把人定规则换成Agent 做判断把一次性群发换成逐个决策。具体来说它把整条链路拆成了感知、决策、执行、回流四段每一段都有 Agent 的参与。感知阶段系统持续监听用户行为事件流比如浏览、加购、支付失败、客服咨询、会员到期这些事件就是触发的信号源。决策阶段Agent 拿到事件和用户上下文之后不是简单地匹配规则而是真的想一下这个用户现在值不值得打扰如果打扰走哪个渠道最合适说什么内容他才会理我执行阶段把决策结果翻译成具体的发送动作可能是一条站内信也可能是一条短信还可能是一次 App 内的弹窗。回流阶段把所有结果——送达、打开、点击、转化、退订、投诉——都记录下来成为下一轮决策的输入。这么一改最直观的变化是触达从广播变成了对话。每个用户收到的可能是不同的内容、不同的渠道、不同的时机。我实测下来这套机制最值钱的不是文案有多花哨而是它敢不发。传统链路恨不得把所有名额发满Agent 会判断这个用户现在不适合打扰主动放弃一次触达。少发反而让留存和口碑变好了这一点很多人一开始想不明白。2.3 什么团队值得上什么团队先别碰坦白讲Agent-Reach 不是万能药它有自己的适用边界。如果你的日活用户还不到几千触达需求一周也就发个一两次那真的没必要上这套东西。一个规则引擎加几张表格人力完全 hold 得住上 Agent 属于杀鸡用牛刀运维成本反而更高。但如果你满足下面几个条件那就值得认真考虑日活百万级往上触达是核心增长手段渠道多且分散站内、短信、App 推送、邮件混着用团队里有能维护规则和小模型的人手最重要的是——你有真实的效果数据可回流。我踩过的一个坑是有团队没有做好数据回流就上了 Agent结果 Agent 拿不到反馈只能按照初始提示词瞎猜效果比原来的规则还差。数据回流是这套系统的地基没有它上层再花哨都是空中楼阁。所以评估的时候先问自己一句用户的触达行为数据我到底存下来了没存得全不全。3. 核心细节解析与实操要点3.1 分层架构五层结构怎么切把 Agent-Reach 落到工程上我习惯切成五层每一层职责单一方便替换和压测。第一层是事件接入层。它负责从业务系统抓事件来源可能是埋点、订单库的 binlog、客服工单系统形态五花八门。这一层的任务是把它们统一成一个标准的事件结构然后丢进消息队列。用 Kafka 或者类似的消息中间件都行关键是削峰填谷别让下游被瞬时流量冲垮。第二层是上下文组装层。光有事件不够决策需要知道这个用户是谁、买过什么、被触达过几次、上次是什么反应。这一层负责从用户画像库、触达历史库把数据拼装成一份完整的上下文快照。这里有个性能细节上下文组装要快最好控制在 50 毫秒以内否则整个链路的延迟会拖垮实时性。我们的做法是热数据放 Redis冷数据走本地缓存加定期刷新。第三层是决策层也就是 Agent 的核心。它接收上下文输出一个结构化的决策结果发不发、走哪个渠道、发什么内容、什么时候发。第四层是执行层负责把决策翻译成具体的发送动作对接各个渠道的 SDK 或者 API。第五层是效果回流层收集回执写回数据仓库同时把关键信号反哺给决策层。注意这五层之间一定要用异步解耦尤其是决策层和执行层之间。如果执行层某个渠道接口挂了不能把决策层拖死不然整个系统就瘫了。3.2 决策中枢Agent 的思考循环决策层是整个系统的大脑我把它设计成一个循环收集上下文 → 评估触达价值 → 选择渠道与时机 → 生成内容 → 输出动作。每一步都值得细说。评估触达价值这一步是很多人会忽略的。Agent 要先判断这个用户现在值不值得打扰。判断依据包括距离上次触达过了多久、用户近期的活跃度、这个事件的紧急程度、用户有没有明确表达过不想被打扰。我通常会给这个判断加一个阈值比如价值分低于 0.3 就直接放弃触达。这个阈值不能拍脑袋定要根据历史数据回归出来。渠道选择同样有讲究。不同的渠道有不同的触达强度和成本。站内信最轻几乎零成本但用户不一定看App 推送强度中等成本低但容易被系统限流短信强度最高、成本最贵国内大概每条几分钱但送达最稳。Agent 要根据用户的渠道偏好和事件紧急度来排优先级而不是所有事都发短信。内容生成这一步我建议不要把全部权力交给大模型自由发挥。更稳的做法是模板骨架 Agent 填充骨架由人来定保证信息不出错、品牌调性统一Agent 负责根据用户画像选择合适的措辞和变量。这样既有个性化又不会出现胡言乱语。3.3 频控体系最容易翻车的地方我可以负责任地说十个做触达的团队有八个在频控上翻过车。频控就是限制一个用户在单位时间内最多被触达多少次。做得不好要么频控太松用户被骚扰到退订要么太紧该发的信息发不出去。频控要分维度来做我一般设三层全局频控、渠道频控、业务频控。全局频控是这个用户每天总共最多被触达 X 次渠道频控是短信每周最多 Y 条业务频控是同一类营销活动每月最多 Z 次。三层叠加取最小值才是最终的上限。技术上滑窗计数用 Redis 的 ZSET 最合适。把每次触达的时间戳作为 score 存进去每次要判断时用ZCOUNT统计窗口内的条数。示例思路是这样的import time import redis r redis.Redis(hostlocalhost, port6379) def allow_reach(user_id, channel, window_sec86400, limit3): key ffreq:{channel}:{user_id} now time.time() # 清掉窗口外的记录 r.zremrangebyscore(key, 0, now - window_sec) # 统计窗口内次数 cnt r.zcard(key) if cnt limit: return False r.zadd(key, {str(now): now}) r.expire(key, window_sec * 2) return True这段代码简单但生产环境要考虑几个点一是zcard和zadd之间不是原子的高并发下可能超发需要用 Lua 脚本包成一个原子操作二是 key 一定要设过期时间不然 Redis 内存会被历史 key 撑爆三是窗口大小和限值要按业务定我见过短信限值设成每周 1 条的结果运营想发个重要通知都发不出去这就是没跟业务对齐。3.4 记忆与上下文Agent 别忘了聊过什么Agent 如果每次都从零开始那它跟规则引擎没区别。记忆机制让它能记住这个用户三天前刚被触达过当时没理我。记忆分短期和长期两种。短期记忆是当前会话或当前事件周期内的上下文比如用户刚咨询了客服Agent 在接下来的触达里应该带上这次咨询的信息。这种记忆放 Redis带 TTL。长期记忆是用户的历史触达档案比如这个用户对短信从不响应但对站内信反应很好这种是慢变量放数据仓库定期聚合。我要提醒一点上下文不是塞得越多越好。把用户三年的行为全塞给大模型不仅贵还容易让模型抓错重点。我一般控制在最近 30 天的关键行为加上汇总后的长期偏好标签总体控制在几百个 token 以内。塞太多反而会稀释关键信号实测效果不如精简版。4. 从零搭一套能跑的 Agent-Reach完整实操4.1 环境准备与依赖选型先说硬件和软件。中小规模日均触达十万级一台 8 核 16G 的应用服务器加一台 Redis 就够了别一上来就搞集群运维成本不值当。真正要花心思的是中间件选型。消息队列我推荐 Kafka理由是它能持久化消费失败可以重放这对触达场景特别重要——一条重要通知丢了可能就是一次投诉。缓存用 Redis频控、上下文热数据、分布式锁都靠它。用户画像和触达历史我建议落在列式存储里比如 ClickHouse 或者 Doris查询快聚合方便。Agent 决策服务用 Python 或者 Go 都行Python 生态好接大模型方便Go 性能好看团队技术栈。依赖清单大致是fastapi做决策服务的 HTTP 接口、kafka-python或confluent-kafka消费事件、redis频控和缓存、sqlalchemy读画像、一个 LLM 客户端。装完之后先跑通一条最小链路再逐步往里加东西。4.2 事件接入把杂乱信号统一成标准结构事件接入层的第一步是定义标准事件结构。我一般规定成这样的 JSON{ event_id: evt_20250101_0001, user_id: u_8891, event_type: cart_abandon, event_time: 1735689600000, payload: { sku_id: sku_233, amount: 199.00 }, source: app }字段设计有几个讲究。event_id用来去重防止同一条事件被消费两次导致重复触达event_time是业务发生时间不是入库时间决策时要用这个event_type决定后续走哪套判断逻辑。接入实现上业务系统把事件写进 Kafka 的一个 topicAgent-Reach 的消费端订阅这个 topic做一轮校验和补全比如把缺失的用户画像字段补上再转发到内部的决策 topic。注意事件接入一定要做去重。我见过因为上游重发导致同一个用户连收三条一样消息的事故退订率当天涨了两个点。去重靠event_id加 Redis SETNX 实现TTL 设个 24 小时就够。4.3 决策服务把 Agent 的判断逻辑写出来决策服务是整个系统的核心我用 FastAPI 起一个接口接收事件输出决策。骨架大概是这样from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class Decision(BaseModel): send: bool channel: str content: str send_at: int app.post(/decide, response_modelDecision) def decide(event: dict): ctx assemble_context(event[user_id], event) value_score evaluate_value(ctx) if value_score 0.3: return Decision(sendFalse, channel, content, send_at0) channel pick_channel(ctx) if not allow_reach(event[user_id], channel): return Decision(sendFalse, channel, content, send_at0) content build_content(ctx, channel) return Decision(sendTrue, channelchannel, contentcontent, send_atctx[best_send_time])这套骨架跑得通但真实场景里evaluate_value、pick_channel、build_content三个函数才是重头戏。我逐个拆。evaluate_value我一般做成一个打分函数输入是用户近期活跃度、事件紧急度、距上次触达的时间输出 0 到 1 的分数。可以用逻辑回归或者梯度提升树先用规则跑出初始样本慢慢积累标注数据再换成模型。pick_channel我建议用规则加优先级表别用模型因为渠道选择的逻辑相对确定用模型反而不好解释、不好调试。build_content这块引入大模型但用模板骨架约束它。4.4 渠道发送与效果回流执行层要对接各个渠道。我一般给每个渠道封装一个统一接口类似send(user_id, content)内部再调用具体渠道的 SDK。这样新增渠道时只写一个适配器上层逻辑不动。发送完成之后回执要写回 Kafka再由回流层消费。回执包括是否送达、是否打开、是否点击、是否退订、是否投诉。这里有个细节不同渠道的回执方式不一样。短信的回执是运营商异步回调的App 推送的回执是客户端上报的站内信的回执是页面埋点采集的。要统一成同一种结构才能让回流层不受渠道差异影响。回流数据最终落到数据仓库同时把关键信号通过 Redis 反向喂给决策层。比如这个用户刚退订了短信那决策层下次就该避开短信渠道。这个反哺链路越短越好最好做到准实时。4.5 灰度与影子模式别一上来就全量任何新的触达系统我强烈建议先跑影子模式。影子模式下Agent 照常决策但发的动作不真正执行只记录如果发了会发什么。对比影子决策和人工实际发送的结果看看 Agent 的判断靠不靠谱。跑一两周影子模式确认决策没有明显离谱之后再上灰度。灰度按用户维度切先切 5% 的用户观察留存、退订、投诉这几个指标有没有恶化。没问题再逐步放大到 20%、50%、全量。每次放大之间至少观察三天因为触达的副作用有延迟性当天看不出来。提示灰度分组一定要用稳定的哈希别用随机数否则同一个用户今天在实验组、明天在对照组数据会乱成一锅粥。用hash(user_id) % 100这种稳定哈希最保险。5. 效果度量别只盯着打开率5.1 北极星指标怎么选打开率是最容易看的但也是最容易骗人的。你把文案写得耸动一点打开率能涨可转化照样不动。我建议选一个更贴近业务目标的北极星指标比如触达带来的活跃回升率或者触达引导的付费转化率。围绕北极星指标再配一组护栏指标退订率、投诉率、消息屏蔽率。护栏指标是用来守住底线的一旦恶化不管北极星多好看都要停下来复盘。我踩过的坑就是只盯着转化涨结果退订率翻了倍长期把用户池给做干了得不偿失。5.2 AB 实验的三个常见错误做触达实验我见过太多翻车的。第一个错误是样本量不够就下结论今天 A 组打开率 5%、B 组 6% 就宣布 B 胜出其实这个差异可能纯属波动。样本量要基于预期的最小提升幅度反推别凭感觉。第二个错误是实验周期太短。触达有个疲劳效应第一周效果好第二周就衰减了。实验至少跑满一个完整的用户周期通常是一到两周。第三个错误是渠道之间互相干扰。你今天让 A 组收到短信、B 组收到站内信但用户可能同时还在被别的活动触达结果两组的结果都被污染了。做渠道对比实验时要尽量控制其他触达的变量。5.3 成本核算短信是真金白银算笔账就明白了。假设日活 200 万触达覆盖率 15%那就是每天 30 万条触达。如果全走短信按每条 0.045 元算一天就是 1.35 万元一个月 40 万。这还没算大模型的调用成本。所以成本控制是 Agent-Reach 必须内建的能力。我的做法是给不同渠道设不同的预算权重Agent 在满足触达目标的前提下优先选便宜渠道。只有当事件紧急度足够高或者用户对便宜渠道完全不响应时才动用短信。实测下来这套策略能把短信用量压掉六成以上效果几乎不打折。6. 常见问题与排查技巧实录6.1 问题速查表现象可能原因排查方向处理建议用户收到重复消息事件被重复消费或去重失效查事件的event_id是否重复入队加 Redis 去重检查消费端幂等某个渠道突然零送达渠道接口限流或凭证过期看发送层日志和渠道方返回码加限流熔断凭证轮换触达量远低于预期频控阈值设得太严查 Redis 频控计数器命中率按业务重新校准阈值打开率骤降内容同质化或发送时机不对抽样看最近发送的内容和时间加大个性化优化发送时段大模型输出乱码或错误信息提示词约束不足看 LLM 原始输出和模板填充逻辑用模板骨架约束加输出校验决策延迟高上下文组装太慢埋点看各阶段耗时热数据进 Redis冷数据异步刷6.2 几条真金白银换来的经验第一条Agent 的价值在于敢不发不在于发得多。我见过太多团队上了 Agent 之后还是把它当群发工具用只是文案换成了 AI 生成的那这套系统就白搭了。要让 Agent 有放弃触达的权力这个权力是它区别于规则引擎的关键。第二条频控一定要留人工兜底。系统再智能也架不住业务想临时发个紧急通知。我一般会留一个高优先级通道允许业务绕过频控发关键信息但这个通道要有审计日志谁绕过了、发了什么、为什么发都要记下来事后可追溯。第三条大模型只负责它擅长的部分。让大模型做意图理解、做措辞润色可以让它决定要不要给这个用户发钱这种涉及真金白银的决策风险太大。涉及金额、权益、合规的判断一定要用确定性逻辑兜底。第四条把所有决策都记下来。每条触达的决策依据、输入上下文、输出版本号都要落库。出了问题的时候你能一秒定位到底哪一版的逻辑出了岔子。没有这个可追溯性调试就是盲人摸象。第五条用户说不想被打扰就真的别再打扰。用户点了一次退订Agent 就该把这个人从所有营销触达里永久排除只保留必要的服务类通知。这条听起来是常识但我真的见过系统忘记的案例用户投诉到监管那里才收手。7. 关于这套东西的一点个人体会我自己从规则引擎一路做到现在这套 Agent 化的触达最大的感受是技术上的难点其实都还好解决真正难的是克制。触达这件事天生有一种多发一条多一份收益的诱惑系统做得越好用越容易滥发。我见过效果最好的团队反而是那些给自己设了严格红线、每天主动控制触达总量的团队。他们的用户池是健康的退订率长期压在很低的水平复购和口碑都稳。如果你正准备动手做 Agent-Reach我建议前两周别急着上大模型先把事件接入、频控、回流这三块基础打牢。这三块是地基地基稳了上层换什么模型都跑得动。等基础跑通、有了真实数据再去迭代决策逻辑步子会稳很多。这套系统后续还能往下延展的方向也挺多比如把触达结果反过来优化用户分层或者把决策逻辑沉淀成可复用的组件库让新业务接入时少走弯路。反正别指望一步到位边跑边调才是常态。