基于Embedding与智能聚类的Agent Trace行为分析实战

发布时间:2026/10/1 8:35:08
基于Embedding与智能聚类的Agent Trace行为分析实战 1. 从一堆 Trace 里挖出 Agent 的真实行为为什么这件事值得认真做做 Agent 开发的朋友大概率都经历过这个场景线上跑着几十上百个会话每个会话里 Agent 要调用工具、检索知识、做多轮推理一天下来 Trace 数据能堆到几个 G。打开日志一看密密麻麻的 span 记录每条都带着时间戳、输入输出、token 消耗、工具调用链路。你想知道用户到底在问什么类型的问题Agent 在哪些环节容易卡住哪类会话的 token 消耗异常高靠肉眼翻日志基本等于大海捞针。这就是智能聚类要解决的问题。简单说它做的事情是把海量 Trace 数据里的每个 Session 或每个 Agent 执行片段通过 Embedding 转成向量再用聚类算法自动分组让行为模式相似的那些会话自己聚到一起。你不用提前定义什么算客服类问题什么算代码生成类问题聚类会告诉你数据里天然存在哪几类模式。做完聚类之后你再去看每一类的典型 Trace就能快速理解 Agent 在真实场景下的行为分布和表现差异。这套方法适合谁如果你是大模型开发工程师、Agent 平台的建设者、或者正在做 AI 应用可观测性相关的工作这套思路可以直接落地。如果你只是刚接触 Agent 开发想了解怎么评估自己的 Agent 表现这篇文章也能给你一个可操作的框架。核心关键词就几个Trace、Agent、Session、Embedding、智能聚类我会围绕这几个点把整条链路拆开讲。我自己的经验是很多团队在 Agent 上线初期只盯着成功率和平均延迟这两个指标结果出了问题根本定位不到根因。Trace 数据里其实藏着大量信息只是缺少一个自动化的手段把它们组织起来。聚类就是那个把原始矿石变成可读地图的环节。2. 整体设计思路Trace、Session、Embedding、聚类怎么串起来2.1 先搞清楚 Trace 和 Session 的关系在动手之前必须把数据模型理清楚。Trace 通常指的是一次完整请求的调用链里面包含多个 span每个 span 代表一个操作单元比如一次 LLM 调用、一次工具执行、一次检索。Session 则是更高层的概念它把同一个用户在一段时间内的多次交互串在一起。一个 Session 里可能有多个 Trace一个 Trace 里可能有多个 span。做聚类的时候你得先决定聚类的粒度。我试过三种粒度各有适用场景聚类粒度数据单元适合回答的问题计算成本Session 级整个会话的所有交互拼接用户意图分布、会话整体表现低Trace 级单次请求的完整链路单次任务类型分布、失败模式中Span 级单个操作单元工具调用模式、LLM 调用特征高大多数情况下从 Session 级或 Trace 级入手性价比最高。Span 级聚类虽然细但噪声大而且数量级可能是 Session 的几十倍Embedding 和聚类的成本会迅速上升。2.2 为什么用 Embedding 而不是关键词匹配有人可能会问我直接用关键词分类不行吗比如包含退款的归一类包含代码的归一类。这种做法在早期确实能用但问题很明显。第一用户表达千变万化我要退钱这个能退吗申请售后其实是一类意图关键词很难穷举。第二Agent 的 Trace 里不只有用户输入还有工具调用序列、中间推理步骤这些结构化信息用关键词根本表达不了。第三你事先不知道数据里有哪些类别关键词分类的前提是你已经知道要分几类这跟探索性分析的目标是矛盾的。Embedding 的好处是把文本映射到高维语义空间语义相近的内容在向量空间里距离就近。这样聚类算法就能自动发现数据里的自然分组。对于 Trace 数据你可以把用户输入、Agent 的推理摘要、工具调用名称序列拼接成一段文本再做 Embedding也可以对不同类型的字段分别 Embedding 再加权融合。2.3 聚类算法的选型逻辑聚类算法不是随便选一个就行。我实际用下来这几种最常见K-Means速度快适合数据量大、类别数大致已知的场景。缺点是要提前指定 K 值而且对非球形簇效果一般。HDBSCAN不需要指定类别数能识别噪声点适合探索性分析。缺点是参数敏感数据量大时比较慢。层次聚类能生成聚类树方便你从粗到细观察。缺点是复杂度高不适合超大规模数据。BERTopic 这类基于主题模型的方案结合了 Embedding 和主题发现输出可解释性好适合做报告。我的建议是第一轮探索用 HDBSCAN 或 BERTopic先看看数据里大概有多少类、每类长什么样等对数据分布有感觉了如果要做线上实时分类再换成 K-Means 或者训练一个分类器。这样既保证了探索阶段的灵活性又兼顾了后续工程化的效率。注意聚类结果没有绝对正确这一说。同一批数据换个 Embedding 模型、换个距离度量、换个参数结果可能都不一样。关键是要结合业务场景去解读而不是追求某个标准答案。3. 核心细节拆解从原始 Trace 到可解读的聚类结果3.1 Trace 数据的预处理与特征构造原始 Trace 数据通常长这样一堆 JSON 记录字段包括 session_id、trace_id、span_name、start_time、end_time、input、output、token_count、status 等。直接把这些丢给 Embedding 模型效果不会好因为里面有很多噪声字段而且结构化信息没有被利用。我的做法是分三步构造文本表示第一步抽取关键字段。对每个 Session按时间顺序把用户输入、Agent 的最终回复、调用的工具名称列表、是否发生错误这些信息抽出来。工具名称列表特别重要它能反映 Agent 的行为模式比如检索总结和代码执行测试明显是两类任务。第二步拼接成自然语言描述。不要简单用逗号拼接而是写成一段有结构的文本。比如用户请求帮我查一下上个月的销售数据并生成图表 Agent 调用的工具database_query, data_analysis, chart_generation 执行结果成功 交互轮数3这种格式对 Embedding 模型更友好因为模型在预训练时见过大量类似的结构化文本。第三步对超长文本做截断或摘要。Embedding 模型都有最大输入长度限制一般 512 到 8192 token 不等。如果 Session 很长可以只保留前几轮和最后几轮或者用一个小模型先做摘要再 Embedding。我实测下来保留首轮用户意图工具调用序列最终状态这三样信息损失最小。3.2 Embedding 模型的选择与对比Embedding 模型的选择直接决定聚类质量。我对比过几个主流方案模型类型代表模型维度优势劣势通用文本 Embeddingtext-embedding-3-small/large1536/3072语义理解强多语言成本较高维度大开源 Embeddingbge-large, gte-large1024可本地部署成本低需要自己调优领域微调 Embedding基于业务数据微调自定义贴合业务语义需要标注数据如果数据量不大、预算充足直接用商用 API 最省事。如果数据敏感或者量特别大本地部署开源模型更划算。我自己的经验是对于 Trace 这种半结构化文本通用 Embedding 模型已经够用不一定非要微调。但如果你的业务领域特别垂直比如医疗、法律微调能带来明显提升。还有一个细节Embedding 的维度会影响聚类速度和效果。高维向量表达能力强但距离计算慢而且容易受维度灾难影响。实践中 768 到 1536 维是比较平衡的选择。如果维度太高可以先做 PCA 或 UMAP 降维再聚类UMAP 降维后聚类效果往往比直接在高维空间聚类更好。3.3 聚类参数调优的实操方法以 HDBSCAN 为例核心参数有两个min_cluster_size 和 min_samples。前者控制一个簇最少要有多少个点后者控制核心点的邻域密度要求。调参的思路是这样的先看数据总量假设你有 10000 个 Session那 min_cluster_size 可以从 50 开始试也就是至少 0.5% 的数据才算一个簇。如果发现簇太多太碎就调大如果发现很多点被归为噪声就调小 min_samples。我一般会跑一组参数网格然后用轮廓系数和 Calinski-Harabasz 指数来辅助判断。但这两个指标只能参考最终还是要人工看每个簇的典型样本。因为聚类是为了理解数据不是为了刷指标。实操心得聚类前一定要做归一化。Embedding 向量通常已经归一化了但如果你自己拼接了额外特征比如 token 数量、交互轮数这些数值特征的量纲和 Embedding 完全不同必须标准化后再融合否则数值大的特征会主导距离计算。4. 完整实操流程从数据到洞察的每一步4.1 数据导出与清洗假设你的 Trace 数据存在 ClickHouse 或者 Elasticsearch 里第一步是导出。我一般会写一个查询按时间范围拉取最近 7 天或 30 天的数据字段包括 session_id、trace_id、span 列表、用户输入、最终输出、状态、token 消耗。导出后要做清洗去掉测试账号和内部调试产生的 Session去掉明显异常的记录比如 token 数为 0 或者状态为超时的对超长 Session 做截断保留关键轮次统一时间格式和字段命名这一步看起来简单但实际做的时候坑很多。比如有些 Session 的结束时间缺失有些工具调用记录不完整。我的建议是宁可少要一些数据也要保证质量因为脏数据会严重干扰聚类结果。4.2 构造 Embedding 并降维清洗完之后对每个 Session 构造文本描述然后批量调用 Embedding 接口。这里要注意并发控制和重试机制因为批量调用容易触发限流。我一般用 10 到 20 的并发每批 100 条失败自动重试三次。拿到 Embedding 后先做 UMAP 降维到 5 到 10 维。为什么是 5 到 10 维而不是 2 维因为 2 维适合可视化但信息损失太大聚类效果会下降。5 到 10 维能在保留主要结构的同时降低计算复杂度。降维后再做聚类最后用 2 维的 UMAP 结果做可视化展示。import umap import hdbscan import numpy as np # embeddings 是 N x D 的矩阵 reducer umap.UMAP(n_components10, n_neighbors15, min_dist0.1, metriccosine) reduced reducer.fit_transform(embeddings) clusterer hdbscan.HDBSCAN(min_cluster_size50, min_samples10, metriceuclidean) labels clusterer.fit_predict(reduced)这段代码里n_neighbors 控制 UMAP 关注局部还是全局结构值小更关注局部值大更关注全局。min_dist 控制降维后点的聚集程度。这两个参数需要根据数据规模调整数据量大就适当调大 n_neighbors。4.3 聚类结果的可视化与解读聚类跑完之后你会得到每个 Session 的簇标签-1 表示噪声点。接下来最重要的一步是解读每个簇的含义。我的做法是对每个簇随机抽 10 到 20 个典型样本看它们的用户输入、工具调用序列、执行结果。然后给每个簇起一个描述性的名字比如数据查询与报表生成代码调试与修复多轮澄清型对话。可视化方面用 2 维 UMAP 散点图每个点代表一个 Session颜色代表簇标签。这样能直观看到簇的分布和重叠情况。如果两个簇在图上严重重叠说明它们的语义确实接近可以考虑合并。簇编号样本数典型特征建议命名01200数据库查询图表生成数据查询类1800代码执行错误修复代码调试类2600多轮追问澄清澄清对话类3400检索总结知识问答类-1300无明显模式噪声/长尾4.4 把聚类结果接入日常监控聚类不是跑一次就完事。我建议把它做成一个定期任务比如每天凌晨跑一次对比前一天和后一天的簇分布变化。如果某个簇的样本量突然暴涨或者出现了新的簇那可能意味着用户行为发生了变化或者 Agent 的某个功能出了问题。具体做法是把每个 Session 的簇标签写回数据库然后在监控面板上展示各簇的占比趋势、各簇的平均 token 消耗、各簇的失败率。这样你就能回答哪类任务的成本最高哪类任务的失败率在上升这类问题。注意簇的编号在不同批次之间是不稳定的因为聚类算法每次跑出来的编号可能不一样。所以不要直接用编号做跨批次对比而是要用簇的语义描述或者典型样本来对齐。5. 常见问题与排查技巧实录5.1 聚类结果全是噪声怎么办这是最常见的问题。HDBSCAN 把大量点标为 -1说明参数太严格或者数据本身太分散。排查顺序是先看 min_cluster_size 是不是设太大了调小试试再看 UMAP 降维后的维度是不是太低信息损失太多最后检查 Embedding 质量是不是文本构造得太粗糙。我遇到过一次聚类结果 80% 都是噪声后来发现是 Embedding 时把整个 Session 的原始 JSON 直接丢进去了里面全是无意义的字段名和括号。改成结构化文本描述后噪声比例降到了 15% 以下。5.2 簇的数量太多或太少簇太多说明 min_cluster_size 太小或者数据本身类别就多。簇太少说明参数太宽松把不同类的东西合并了。我的经验是对于 10000 条左右的 Session 数据10 到 30 个簇是比较合理的范围。如果超过 50 个簇基本就没法人工解读了。另一个技巧是分层聚类。先用大粒度聚出 5 到 10 个大类再对每个大类内部做细粒度聚类。这样既能把握整体分布又能看到细节差异。5.3 Embedding 成本太高怎么优化如果数据量很大Embedding 成本确实是个问题。几个优化方向一是只对关键字段做 Embedding不要全文都做二是用更小的模型比如从 large 换成 small三是做增量更新只对新产生的 Session 做 Embedding老数据复用之前的向量四是对相似 Session 做去重很多 Session 其实高度重复没必要每个都单独 Embedding。我实测下来通过字段筛选和去重能把 Embedding 成本降低 60% 以上而聚类效果几乎不受影响。5.4 聚类结果不稳定怎么处理同样的数据跑两次结果不一样这很正常。因为 UMAP 和 HDBSCAN 都有随机性。解决办法是固定随机种子并且用多次运行取共识的方法。具体来说跑 10 次聚类然后统计每对 Session 被分到同一簇的频率用这个频率矩阵再做一次层次聚类得到最终稳定的结果。这个方法叫共识聚类虽然计算量大了点但结果稳定性和可解释性都明显更好。对于需要长期跟踪的场景我强烈建议用这种方式。问题现象可能原因排查方向解决建议大量噪声点参数过严/文本质量差检查 min_cluster_size 和 Embedding 文本调小参数优化文本构造簇数量过多参数过松/数据类别多检查 min_cluster_size调大参数或做分层聚类结果不稳定算法随机性检查随机种子固定种子用共识聚类成本过高数据量大/模型大检查 Embedding 字段和模型筛选字段换小模型增量更新6. 几个我踩过的坑和实际体会第一个坑是过早追求自动化。我一开始想做一个全自动的聚类流水线每天自动跑、自动生成报告。结果发现聚类结果的解读必须有人参与因为算法不知道你的业务含义。后来改成半自动算法负责分组和可视化人负责命名和判断。这样效率反而更高。第二个坑是忽略时间维度。同样的用户请求在 Agent 刚上线时和迭代几个月后行为模式可能完全不同。如果聚类时不考虑时间就会把不同阶段的数据混在一起。我的做法是按周或按月分别聚类然后对比不同时期的簇分布变化这样能看出 Agent 行为的演化趋势。第三个坑是只看聚类结果不看原始 Trace。聚类给的是宏观视图但真正的洞察往往藏在具体的 Trace 里。我现在的习惯是每发现一个有意思的簇就抽几条原始 Trace 仔细看经常能发现一些指标上看不出来的问题比如 Agent 在某类任务上反复调用同一个工具、或者中间推理步骤明显冗余。这套方法我用了大半年最大的感受是Trace 数据的价值远不止于排查故障。当你把海量 Trace 通过 Embedding 和聚类组织起来之后它其实变成了一张 Agent 行为的地图。你能看到用户真正在用什么、Agent 在哪些地方表现好、哪些地方还有提升空间。这种全局视角是单看几个指标或者翻几条日志永远给不了的。如果让我给一个最小可落地的建议那就是先从一周的 Session 数据开始构造简单的文本描述用现成的 Embedding API 和 HDBSCAN 跑一遍人工看 20 个簇的典型样本。整个过程一个人一天就能搞定但收获的洞察可能比你看一个月监控面板还多。