
Agent-Reach一套面向智能体的可观测性平台从会话触达到链路追踪最近团队在做一个比较有意思的内部项目代号叫 Agent-Reach。起因很简单我们把大模型的能力包装成了十几个智能体有做客服的、有做数据分析的、还有跑内部流程审批的结果上线两周就发现一个尴尬的问题——大家只知道智能体“好像跑起来了”但到底跑得好不好、用户问题有没有真正被触达、哪一步在拖后腿完全是一团黑盒。传统 APM 只能看到服务层面的健康状态但对智能体这种“非线性执行”的东西基本无能为力。智能体不是简单的请求-响应模型它有规划、有工具调用、有中途改道、有失败重试还会自己跳出预定义的逻辑框架。想搞明白每个会话里到底发生了什么必须有一套专门为智能体设计的可观测手段。Agent-Reach 就是干这个的。这篇文章我会完整聊聊这个项目从需求拆解、架构选型到落地的全过程包括我们自己踩过的一些坑和一些不一定写进文档里的经验。如果你也在做 Agent 类应用或者正在为“智能体跑起来后怎么监控”发愁这篇的内容应该能帮你少走不少弯路。1. 项目背后的真实需求智能体监控为什么不能用老一套1.1 传统监控解决不了的问题先说一个典型的场景。我们的客服智能体接入了工单系统、知识库和订单查询三个工具用户在对话框里问了一句“我上周的订单为什么还没发货”。正常情况下智能体应该先查订单状态发现异常后调取物流信息再给出解释和补偿方案。但实际情况是这个简单的对话可能在第五步就断了——比如订单查询工具调用超时智能体直接回复了一句“正在为您查询请稍后再试”然后用户就流失了。这类问题用传统监控能发现吗服务端监控只能看到调用了哪个接口、返回了什么状态码、耗时多少但看不到智能体在这个过程里“思考”了哪些步骤、为什么选择了某个工具、最终输出有没有满足用户预期的信息。更关键的是传统监控不会告诉你“这条会话的意图没有被成功触达”因为从接口层面看一切正常返回值 200耗时也不高。Agent-Reach 立项时的核心目标就是解决这类问题我们要能回答“每个用户请求在智能体内部到底被怎么处理的、在哪个环节断掉的、为什么没有得到有效响应”。这是一套面向智能体执行逻辑的细粒度追踪体系而不是面向服务节点的粗粒度监控。1.2 智能体执行模型与传统服务调用的本质差异要设计好这套系统首先得理解智能体的执行和普通 API 服务有什么不同。普通服务的请求链路是确定的一个请求进来调用 A 服务A 调 BB 调数据库最后返回。这条链路的拓扑是稳定的所以 APM 工具可以通过 trace ID 把日志串联起来。智能体完全不同。一个用户请求进来后大模型会基于当前的上下文决定下一步调用什么工具这个决策过程可能有分支、有循环、有回退。举个最直观的例子用户问“帮我查一下最近的营业网点”智能体判断需要获取用户地理位置但这需要调用定位服务定位服务返回结果为空智能体重新决策改为询问用户所在城市用户回答后智能体再调用网点查询这个过程中智能体经历了多轮 LLM 推理和工具调用每一步都消耗 Token每一步都可能出错但整体链路不是预先定义好的。普通的 trace 系统只能记录“发生了哪些网络请求”记录不了“智能体为什么发起这个请求、中间做了哪些决策、决策依据是什么”。所以 Agent-Reach 的一个关键设计理念是追踪对象是结构化数据流包括用户消息、系统指令、LLM 推理摘要、工具调用参数和响应、中间结果以及最终输出。这套数据流完整记录了智能体在每轮会话中的每一步执行过程能还原出完整的“决策路径”。2. Agent-Reach 的整体设计与核心模块拆解2.1 架构总览采集、传输、存储、分析四层结构Agent-Reach 的架构在落地时保留了足够的简单性没有一上来就搞微服务大杂烩。整体分为四层接入层、传输层、存储层和应用层。接入层是通过 SDK 方式嵌入到智能体运行时里的。我们目前提供了 Python 和 Node.js 两种语言的 SDK用起来很简单不用改业务逻辑只需要在初始化智能体时挂一个中间件。SDK 会自动拦截智能体的执行循环把所有关键事件以结构化的方式记录下来。传输层走的是 OpenTelemetry 协议基础上的扩展。用 OTel 不是因为它有多少功能而是因为它有成熟的后端生态我们只需要实现一个自定义 Exporter 就能把数据推给内部集群。数据在本地做缓冲异步上报绝不让观测逻辑阻塞业务主线程。存储层用了两套系统ClickHouse 存时序和链路数据ES 存日志数据。链路数据和日志分开存是因为查询模式差别很大。链路数据需要按 trace ID 聚合、按时间范围扫描ClickHouse 对这种分析型查询非常擅长而日志主要是关键词检索ES 更顺手。应用层就是控制台。我们做了一套 Web 界面提供会话列表、链路详情、覆盖度报告、成本分析和告警配置让业务团队和研发团队各取所需。2.2 Reach 指标怎么量化“触达成功”Agent-Reach 这个名字里的 Reach指的是“用户问题被智能体有效响应的程度”。这个指标是我们整个平台最核心的创新点传统监控里没有对应的概念。Reach 的计算需要一个基准线。我们把一次会话分为三个结果状态成功触达智能体在限定步数内完成了对用户意图的理解、相关知识检索或工具调用生成了可验证有效的最终响应部分触达智能体给出了响应但缺失了用户提问中的部分关键信息或者工具调用失败后只给了兜底话术触达失败智能体经过循环重试仍未完成核心任务或出现幻觉或者超出步数限制被强制退出这个分类标准不是凭空定的我们会根据业务场景配置“关键信息完整性校验规则”。比如客服场景里用户问订单状态如果智能体最后只回复了“您的问题已记录”而没有给出订单状态那这条会话就是部分触达会进入人工复核队列。计算上Reach 率 成功触达会话数 / 总会话数。只是一个简单的公式但要让它真正有用必须做多维度拆解。我们会在控制台里按渠道、按时间段、按智能体版本、按业务标签分别统计 Reach 率这样能快速定位是哪个机器人、哪个版本、哪类问题在拉低整体表现。这个指标上线后效果立竿见影。以前我们只能靠用户投诉来感知智能体质量问题现在直接通过控制台的 Reach 率趋势就能判断版本迭代是变好了还是变差了不用再靠猜。2.3 链路追踪与步骤回放让黑盒变得可解释链路追踪是控制台里最有价值的功能模块。每个会话会有一个唯一的 conversation ID会话内的每个执行步骤会记录以下字段步骤序号、类型LLM 推理、工具调用、系统分支判断、输入摘要、输出摘要、耗时、Token 消耗、状态、异常信息。这些字段组合起来就能用时间线的方式还原出智能体在当时的完整行动轨迹。举个例子某个用户投诉说机器人乱回答我们在控制台里输入他的会话 ID就能看到完整的时间线步骤 1LLM 推理判断需要调用订单接口意图置信度 0.87步骤 2调用订单接口入参 order_id123456接口返回超时步骤 3LLM 推理判断使用上下文中的缓存数据进行回答步骤 4生成回复“您的订单已签收”问题就很清楚了订单接口超时后智能体错误地使用了其他相同 ID 的历史订单数据来回答而那个订单根本不是当前用户的。这个案例让我们第一次感觉到智能体不是不可解释的只是缺少合适的观测工具把它“翻译”成人能看懂的过程视图。链路追踪模块等于给每个智能体装了一个行车记录仪随时还原它在每个岔路口是怎么选的、为什么选了这条路。3. 实操过程从零到一搭建 Agent-Reach 的完整记录3.1 环境准备与依赖选型工具链的选择直接决定后续的开发效率我们在项目启动时没有使用特别冷门的技术栈全部分布式组件都选的是有成熟社区支持的方案。组件用途选型理由Python 3.11SDK 与采集 Agent 开发异步生态成熟与 LLM 生态兼容性最好Go 1.22传输网关服务高并发处理能力强部署简单ClickHouse链路与时序数据存储分析查询性能极强适合聚合统计Elasticsearch日志存储与检索关键词检索体验最好有现成 UIKafka数据缓冲与解耦能承受采集端突发高吞吐Kubernetes部署编排团队已有基础设施运维成本低如果你只是想快速跑通不需要一上来就上 Kafka。采集端直接通过 HTTP 推送到后端小规模场景下完全够用。我们一开始也没上 Kafka后来采集的量级上来了才在传输链路里加了一层缓冲这个后面会讲。3.2 Python SDK 的埋点设计与实现SDK 的埋点设计是整个平台能用好用的关键。我们的实现思路是给智能体运行循环打补丁而不是要求业务代码手动调用上报函数。以 Python 为例现在大多数智能体框架都基于 LangChain 或自研的 Agent LoopSDK 通过包装 Executor 实现自动拦截from agent_reach import ReachTracer, trace_agent ReachTracer.init( service_namecustomer-service-agent, endpointhttp://collector.agent-reach.local:4318, tracing_modeasync, # 异步上报不阻塞业务 enable_cost_captureTrue, # 开启 Token 成本统计 reach_policystrict # 严格模式记录完整决策路径 ) # 在智能体初始化后挂载 agent CustomerServiceAgent() tracer trace_agent(agent) # 后续完整执行 result await tracer.arun( user_input我上周的订单为什么还没发货, session_idconv_123456, user_iduser_789, tags{channel: wechat, version: v2.3.1} )核心还是在这个 trace_agent 的包装逻辑里。它会接管 Agent 的每一步执行动作自动捕获类型、输入输出摘要做了截断控制、耗时、Token 数和异常。我们在采集时还会把核心的 tool 调用参数做脱敏处理比如手机号、身份证号会在本地替换成掩码后再上报避免敏感信息落到日志平台。3.3 传输层的缓冲与压缩处理刚开始做的时候我们把所有事件都实时上报遇到高峰期数据量一大控制台查询慢是一回事采集端还会反过来拖慢业务服务的响应。后面改成异步加本地缓存效果好了很多。具体实现上SDK 内部维护一个有界队列事件先写入队列后台线程每 5 秒批量上报一次。队列满了以后采用丢弃策略只丢弃采样数据不影响核心链路。这个设计故意牺牲一点实时性来换取绝对的稳定性。上报的数据是 JSON 格式通过 gzip 压缩后再传输。实测下来压缩比大概在 70% 左右也就是说原来 10M 的数据量压缩完只有 3M 左右对带宽压力减少很多。传输到后端后先写入 Kafka再由消费者任务批量写入 ClickHouse。Kafka 在这里扮演缓冲池的角色ClickHouse 扛不住写入峰值时消息可以先在 Kafka 里暂存。3.4 控制台落地从会话列表到链路详情控制台的实现比较常规前后端分离后端用 Go 写的 API 服务前端直接用的 React。但有几个交互细节我觉得值得分享。会话列表页不是简单的表格。我们给每条会话打了一个“体验状态灯”绿色是成功触达黄色是部分触达红色是触达失败。这个状态灯由后端的判定引擎实时计算用户进列表页就能一眼看到哪些会话有问题。点进任何一条左侧是完整的会话时间线右侧是这一段时间的 Token 消耗统计和耗时明细。链路详情页有一个特别实用的功能——回放模式。点击回放后前端会把每一步的执行过程按时间顺序重新播放一遍包括每一步 LLM 的决策摘要、工具调用的请求和响应、状态转换。这个功能在排查问题时特别高效因为我们不用再对着日志和代码脑补执行过程了直接看回放就能理解智能体当时的行为逻辑。4. 疑难杂症速查Agent-Reach 上线后我们遇到的 8 个问题4.1 采集端吞吐量过载导致业务服务响应变慢上线第一天就遇到了。当时流量量级不大但是客服智能体的高峰流量非常集中消息全部挤在同一秒进来SDK 里的有界队列被快速打满上报线程忙于发送 HTTP 请求占用了业务线程的上下文切换资源。排查的时候通过火焰图发现 SDK 内部的 JSON 序列化占了不少 CPU问题出在每次上报都重新序列化整条链路数据。优化方式做了两件事一是把序列化改为缓存式的相同结构的链路数据复用 Schema 模板二是把上报改为批量模式每次合并多条链路一起发送减少 HTTP 握手次数。4.2 Kafka 分区不足导致链路数据乱序Kafka 在链路数据里不只是缓冲还承担了排序的关键职责。同一个会话的数据必须按时间顺序写入 ClickHouse否则链路时间线就是乱的。默认情况下我们按会话 ID 做 Key 进行分区但因为并发会话多分区数量设置得太少不同的会话还在有序写入但同一个会话的多个事件偶尔会分到不同的分区。这个问题的根治方法很简单把 Kafka 的分区数调整为符合预期并发规模的数值同时设置max.in.flight.requests.per.connection1保证同分区顺序写入。调整之后乱序问题基本消失偶尔出现的乱序会在写入前通过会话缓冲区做一次重排兜底。4.3 ClickHouse 查询链路慢数据量暴增后的优化开始的时候 ClickHouse 写入端我们用的是最简单的批次 INSERT一次插几千条。数据量小的时候没问题到了几亿条以后控制台侧按时间段查询开始变慢要 5 到 8 秒才出结果。优化手段用了三招。第一是建表时把ORDER BY设为(conversation_id, step_time)让 ClickHouse 按会话和时间的组合顺序存储查询同一会话的完整链路时能直接走稀疏索引。第二是对conversation_id加了minmax跳数索引大幅缩小扫描范围。第三是查询时按天分区裁剪控制台默认只查最近 30 天没特殊要求基本半天内秒出。4.4 Token 成本统计数据口径不一致成本统计一开始算出来总是对不上账单。后来发现原因账单是按模型输入输出分别计价的但我们只采集了模型的 Token 使用总数没区分输入和输出。而且不同模型的计价规则不一样比如有的模型单独对缓存命中计费有的没有。后面在采集层加了模型类型的维度和详细的 Token 拆分字段并且在控制台配置了每个模型的单价表格现在成本统计能精确到每轮对话每一类 Token 的价格。4.5 链路详情缺步骤部分事件丢失有段时间发现部分会话的链路详情里缺少了工具调用的步骤中间直接是断的。排查发现是传输层的采样策略太暴力了高峰期我们会开启抽样模式只保留 20% 的会话数据。不巧的是抽样逻辑是按请求 ID 的哈希值抽的而同一会话的请求 ID 并不相同导致许多会话只保留了一部分步骤。修正方案是把抽样键改成会话 ID同一会话要么全部保留要么全部丢弃这样抽样的数据就是完整的会话链而不是碎片的步骤。4.6 SDK 版本升级引发线上智能体执行异常这是个比较严重的教训。有个版本我们在 SDK 里加了本地模型推理缓存的功能本意是减少重复计算结果因为缓存 key 设计失误导致不同用户的相同问题命中同一份缓存智能体回答串了用户上下文。发生在客服智能体上影响特别严重。这个问题的深刻教训是可观测性工具本身也是运行在业务进程里的代码它的任何优化都必须以不改变业务语义为前提。后来我们对所有 SDK 功能加了 A/B 开关默认关闭验证没副作用后再按比例灰度放开。4.7 链路数据量大ES 存储扩容成本失控日志索引的增长比链路快得多因为日志是明文记录每一步的输入输出全量内容。一个月下来 ES 存储涨了 1TB费用压力很大。我们做了几层优化日志全文做截断默认只保留前 2000 字符超过 30 天的日志切换到冷存储对不需要正文检索的日志去掉全文索引只保留字段索引。这几招组合下来存储成本降了大概 65%查询体验没有明显变差。4.8 控制台报表数据刷新延迟高Kafka 到 ClickHouse 的消费链路有延迟尤其在故障恢复后积压严重时控制台上的数据可能滞后十几分钟。我们把消费端的 batch size 调大写了批量 INSERT 的 flush 策略从原来每条数据单独刷改成攒 2 万条或 3 秒刷一次吞吐量提升了一个量级。同时在消费端加了积压监控积压超过阈值就自动报警。5. 几个核心模块的实现细节与避坑心得5.1 数据脱敏与合规这一块绝对不能省智能体处理的数据里经常包含用户隐私信息不管内部使用还是外部合规要求数据脱敏必须是采集端本地完成的功能而不是后端清洗。原因很简单数据一旦出了本机就不再完全可控了。我们在 SDK 里内置了敏感字段识别器支持手机号、身份证、银行卡号、地址等常见模式的自动识别和掩码处理。对于一些无法用正则识别的内容还支持配置自定义字段名匹配到的字段值会整体替换为[REDACTED]。这里有个教训脱敏规则一定要在测试环境做全量验证别以为配了正则就万事大吉。我们曾经漏了“企业邮箱”这个字段导致部分客户信息被明文传到日志系统幸好是在内部测试阶段发现的没造成实际数据外泄风险。5.2 链路数据的生命周期管理链路数据的增长是很快的尤其当会话量大时。如果不做好生命周期管理存储成本会是一个无底洞。目前的保留策略是数据类型热存储保留时间冷存储保留时间全量保留时间链路数据7 天30 天90 天日志数据3 天15 天60 天聚合报表————永久热存储放在 SSD 上冷存储放到普通机械盘超过 90 天的数据会定期归档到对象存储做压缩备份。这样设置后控制台的查询性能不受旧数据拖累同时保留了足够长的回溯窗口方便做长周期分析。5.3 告警规则配置的最佳实践Agent-Reach 的告警模块用了两层指标告警和事件告警。指标告警主要盯着 Reach 率、平均响应耗时、Token 消耗增速这些连续指标事件告警则关注具体异常比如单条会话连续三次工具调用失败、单轮回复 Token 数超预期等。用得最顺手的告警规则组合是以“Reach 率低于 90% 持续 5 分钟”为基础阈值叠加“相对基线下降超过 8%”这个相对阈值做触发。相对阈值可以避免一刀切带来的误差——不同业务的基线本来就不一样金融客服的问题复杂度和天气查询完全不是一个级别。告警渠道我们接入了内部飞书群。这里有一个体验上的提升告警内容不只是说“Reach 率降到 85%”而是会附带 Top 5 问题会话的链接点进去能看到完整的链路详情和当时的环境上下文。告警链路打通之后值班人员定位问题的时间从平均 40 分钟压缩到 10 分钟以内。5.4 多环境隔离与权限控制我们的智能体分布在开发、测试、生产三套环境Agent-Reach 做了环境隔离。生产环境的会话数据只有核心研发和对应业务负责人能访问开发测试环境则全员开放。控制台的登录接到了公司 SSO 系统每条链路详情都记录访问日志审计起来很方便。这里踩过一个坑最开始环境隔离只是加了标签字段查询时靠条件过滤听起来没问题但实际执行时偶尔漏过滤导致串数据。后来改成彻底的分库分索引方案环境之间物理隔离这个问题才根治。6. 最终效果与扩展方向Agent-Reach 上线三个月从刚开始的“强制要求接入”变成了团队默认的标配调试工具这个转变很有说服力。目前平台上接入的智能体数量超过 30 个日均处理的会话追踪数据量在 150 万条左右链路数据入库量保持稳定整体运行情况良好。从数据上看到了一些比较有意思的业务结果客服智能体的 Reach 率从最初的 76% 提升到了 91%。这里面有模型优化、话术调整的功劳但如果没有平台提供的数据支撑这些优化是无从下手的工单智能体的平均处理时长从 5 分钟降到了 2 分半以前排查一个卡住的任务要翻半天日志现在直接在时间线上看到卡在哪一步成本统计落地后各业务线第一次能说清楚每个月花在智能体上的 Token 费用到底是多少也能看清是哪个环节的调用最费钱从纯技术视角看更深的体会是它改变了我们调试智能体的方式。以前调试基本靠加 print、加日志、看返回结果猜逻辑现在可以在回放模式下完整看每个决策步骤开发效率的提升是质变级别的。后续扩展方向上我们正在做两件事一是把 Reach 判定从规则引擎升级成基于评估模型的自动判别。现在判定的准确率大概在 92% 左右还是会有漏判等评估模型的精度提上来后可以进一步减少规则的维护成本。二是建立智能体的“能力雷达图”。结合链路数据把每个智能体在不同类型问题上的表现、工具调用的成功率、Token 效率这些都量化出来生成一张综合能力图。业务团队看这张图就能直观了解自己的智能体擅长处理什么、薄弱点在哪为训练数据的收集和模型微调提供方向。7. 关于 Agent 可观测性谈谈我的几个体会做 Agent-Reach 的过程中我越来越觉得“智能体可观测性”这个词的含金量被大多数人低估了。很多人觉得开发 Agent 应用最大的难点是模型能力不够但真正到了生产环境最大的问题往往是不可控、不可解释、不可审计。你可以用很强的模型快速搭一个原型但如果没有一套完整的数据体系支撑这个原型很难变成一个有 SLA 承诺的正式业务系统。以前我们上线一个新版本靠的是上线后的抽检和用户反馈来评估好坏反馈周期长、样本有限基本是碰运气。Agent-Reach 把这个问题变成了像普通软件工程一样的东西——有明确的指标、有可视化的链路、有自动化的告警。这让我感觉 Agent 开发正在从一个偏实验性的领域慢慢进入工程化的阶段。最后再分享一个窝心的经验做这套系统时不要一开始就追求大而全先把核心的“链路追踪 会话回放”做好这两个功能可以覆盖 80% 以上的日常排查需求。再配合一个大家都能看懂的 Reach 指标业务侧的接受度和配合度会高很多。基础设施工具最怕的是没人用而没人用的核心原因往往不是功能少而是学习成本高、看不懂价值。尽量把复杂的东西留在后台把简单的视图留给用户这是 Agent-Reach 能落地成功的最大经验。