Sentry 追踪揭秘
原本以为这套流程跑通了就没问题,结果实测发现有个巨大的坑:其他 Agent 跑完也就 5 秒左右,唯独那个负责“安全扫描”的 SecurityScanner 动不动就要跑 22.6 秒。
很多人遇到这种情况的第一反应是模型响应慢(LLM Latency),我也这么想过。但如果只是慢,时间应该是线性分布的,而不是突然暴涨 4 倍。为了搞清楚这 22 秒到底在干嘛,我用了 Sentry 的 Span Hierarchy(跨度层级)去追踪。
结果在 Sentry 的瀑布流图里一眼就看出来了:根本不是网络延迟,而是触发了 CrewAI 的内部重试机制。

具体原因是我的 IAMAnalyzer 工具在调用 AWS API 时太“贪婪”了。它把账号里所有的 90 个 IAM 角色全部抓下来,过滤掉服务关联角色后还剩 59 个,然后直接把这 27KB 的 JSON 大块头塞给了 LLM。面对这么大且冗余的上下文,模型第一次处理失败了,导致框架自动触发了重试,第二次尝试时上下文更臃肿,时间直接被拉长。
这种“静默重试”最恶心的地方在于,最终结果是对的,但性能损耗极大。
为了解决这个问题,我给工具增加了分页处理和 Token 预算拦截,不再一股脑地把所有 JSON 丢进去,而是优先排序最活跃的角色。

以下是具体的代码优化对比:
优化前(直接导致 LLM 崩溃的写法):
# 没有任何分页限制,直接全量抓取
roles = iam.list_roles(MaxItems=100)
role_details = []
for role in roles["Roles"]:
role_name = role["RoleName"]
if role.get("Path", "").startswith("/aws-service-role/"):
continue
# 为每个角色分析策略,导致输出的 JSON 极其庞大
attached = iam.list_attached_role_policies(RoleName=role_name)
# 最终产生约 26,980 个字符的 JSON,直接撑爆上下文优化后(引入分页与相关性过滤):
# 1. 使用 Paginator 处理分页,避免单次请求过载
all_roles = []
paginator = iam.get_paginator("list_roles")
for page in paginator.paginate():
all_roles.extend(page["Roles"])
# 2. 严格过滤掉无法修改的服务关联角色(减少约 31 个冗余项)
auditable_roles = [
r for r in all_roles
if not r.get("Path", "").startswith("/aws-service-role/")
]
# 3. 核心优化:按最后使用时间排序,只给 LLM 提供最相关的上下文
auditable_roles.sort(key=_last_used_sort_key, reverse=True)
# 仅截取前 N 个高风险/高活跃角色,将输出量降低 42%
top_roles = auditable_roles[:20]这次实操下来,效果非常明显:SecurityScanner 的执行时间从 22.6 秒直接降到了 8 秒左右,整体管道速度提升了 21%。
这次踩坑给我最大的启发是:在构建 AI Agent 工作流时,千万不要信任 LLM 能够处理所有工具返回的数据。工具输出的 Token 数量必须在代码层做硬限制(Token Budget),否则一旦数据量波动,触发的重试机制会让你的响应时间变得不可预测。
建议在部署大模型应用时,一定要接入像 Sentry 这种能看到具体 Span 耗时的链路追踪工具,否则你永远在猜测是模型慢还是代码慢。
