首页 / 文章 / Sentry 的 Span 层次结构暴露了我的 5 Agent 管线中的静默重试
← 返回
AI技术

Sentry 的 Span 层次结构暴露了我的 5 Agent 管线中的静默重试

✍️ zhirenhun 📅 2026/7/30 👁 199 阅读 ⏱ 17 分钟
Sentry 的 Span 层次结构暴露了我的 5 Agent 管线中的静默重试

本文是DEV 的夏季漏洞清除:清理阵容的投稿,由Sentry提供支持。


项目概述

我构建了一个AWS 安全态势代理:五个专家 AI 代理,可以扫描您的 AWS 账户以发现安全配置错误,将发现映射到 CIS 基准,评估风险,并生成可复制的修复命令。

这些代理在 CrewAI 上依次运行,使用 Amazon Bedrock Nova Pro 作为 LLM:

1. ResourceDiscovery    → 枚举 EC2、S3、Lambda、IAM、安全组、API GW、DynamoDB
2. SecurityScanner      → 发现开放端口、公开存储桶、管理员角色、不安全配置
3. ComplianceChecker    → 映射到 CIS AWS 基础基准
4. RiskScorer           → 严重性 × 影响范围 × 可利用性
5. RemediationPlanner   → 生成 AWS CLI 修复命令
进入全屏模式 退出全屏模式

每个代理都有定制的 boto3 工具,这些工具针对一个包含 90 个 IAM 角色、14 个 S3 存储桶、9 个安全组和 7 个 Lambda 函数的实时账户进行真实的 AWS API 调用。不是测试数据。都是真实的发现。



演示

以下是在我的 AWS 账户上运行的完整扫描。扫描部分加速了 4 倍,结果演示以正常速度播放:


错误修复或性能改进

我的第一反应是归咎于 Bedrock 的延迟。每次遇到速度慢的问题,你都会怪 LLM,对吗?

SecurityScanner 代理耗时 22.6 秒,而其他代理平均只需 5-10 秒。如果不了解每个代理内部执行的情况,我可能会添加time.time()调用然后瞎猜。

Sentry 的跟踪瀑布图讲述了不同的故事。真正的问题不是 Python 执行时间或网络延迟。而是 LLM 收到了一个它无法在第一次尝试时顺利处理的上下文负载。

根本原因:我的 IAMAnalyzer 工具从账户中获取了所有 90 个 IAM 角色(过滤掉服务相关角色后剩 59 个),将它们序列化为一个 27KB 的 JSON 块,并将整个负载作为工具输出传递给 LLM。上下文窗口被撑爆了。CrewAI 的内部重试逻辑被触发,在第二次尝试时浪费了更多 token,上下文也更多。

一个工具。错误的默认值。整个管道都受到影响。


代码

修复的 PR:

fix: paginate IAM analysis and add token budget guard #1

做了什么

IAMAnalyzer 工具会获取账户中的每一个角色(共 90 个,过滤掉服务相关角色后剩 59 个),并将完整详细信息倾倒到一个 JSON 块中。该块达到了 26,980 个字符。LLM 处理不了,CrewAI 重试了任务,导致 SecurityScanner 代理最终耗时 22.6 秒,而其他代理只用了 5-10 秒。

如何发现的

为每个代理和工具添加了 Sentry span。跟踪瀑布图一目了然:SecurityScanner 的宽度是其他代理的两倍。深入工具 span,看到 iam_analyzerresult_length_chars: 26980,而其他工具大约只有 4000。

7 倍的输出差异。这就是问题所在。

我更改了什么

iam_analyzer.py 中做了三件事:

  1. RoleLastUsed 日期分页并排序角色,仅分析最活跃的前 20 个角色。其余的是几个月没人碰过的陈旧角色。
  2. 提前跳过 31 个服务相关角色(反正你无法修改它们,审计它们只是噪音)。
  3. 最后加一个 token 预算保护:如果 JSON 输出超过 4000 字符,则将 role_summary 截断为仅包含名称和策略列表。

数据

  • 工具输出:从 26,980 字符降至 15,532(缩小 42%)
  • SecurityScanner:从 22.6 秒降至 17.8 秒(快 21%,不再有 LLM 重试)
  • 对 IAM 的 API 调用:从 59 次降至 20 次
  • 总管道:从 62 秒降至 57.7 秒
  • 发现数量:仍然是 27 个。没有覆盖损失,因为最活跃的前 20 个角色包含了所有有问题的角色(AdminRole、Bedrock-Lambda-Role 等都被频繁使用)。

核心更改位于 src/security_posture/tools/iam_analyzer.py。以下是前后对比:

修复前(错误):

# 获取所有角色,无分页限制
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
    # 分析每个角色...
    attached = iam.list_attached_role_policies(RoleName=role_name)
    # ...构建庞大的 JSON 输出
进入全屏模式 退出全屏模式

对于一个拥有 90 个角色的账户,这将生成 26,980 个字符的 JSON。LLM 处理不了。

修复后:

# 修复:按相关性分页并排序
all_roles = []
paginator = iam.get_paginator("list_roles")
for page in paginator.paginate():
    all_roles.extend(page["Roles"])

# 过滤服务相关角色(31 个,无法修改)
auditable_roles = [
    r for r in all_roles
    if not r.get("Path", "").startswith("/aws-service-role/")
]

# 按最后使用日期排序(最活跃的在前)
auditable_roles.sort(key=_last_used_sort_key, reverse=True)

# 仅取前 20 个角色
roles_to_analyze = auditable_roles[:max_roles]
进入全屏模式 退出全屏模式

最后还有一个 token 预算保护:

# Token 预算保护:如果输出超过阈值则截断
if len(output) > 4000:
    result["role_summary"] = [
        {"role_name": r["role_name"], "policies": r.get("attached_policies", [])}
        for r in role_details
    ]
    result["note"] = "角色详情已截断,以保持在 token 预算内"
    output = json.dumps(result, indent=2, default=str)
进入全屏模式 退出全屏模式

三个更改。分页、相关性排序和安全阀。SecurityScanner 不再重试。


我的改进

先看结果:

指标 修复前 修复后 改进
IAM 工具输出 26,980 字符 15,532 字符 缩小 42%
SecurityScanner 时间 22.6 秒 17.8 秒 快 21%
IAM API 调用 59 次 20 次 减少 66%
总管道时间 62.0 秒 57.7 秒 快 7%
安全发现数量 97 97 无覆盖损失

SecurityScanner 21% 的速度提升来自 LLM 一次完成分析,而无需重试。

我是如何发现的:

修复本身很简单。有趣的是 Sentry 如何直接指向了问题。

没有跟踪瀑布图,我只会看到“管道耗时 62 秒”。跟踪图则指明了不同:

  1. 将每个代理执行包装在 gen_ai.invoke_agent span 中
  2. 将每个工具调用包装在 gen_ai.execute_tool span 中
  3. 运行管道并查看跟踪瀑布图
  4. SecurityScanner span 一目了然:宽度是其他 span 的两倍
  5. 在它内部,iam_analyzer 工具 span 显示 result_length_chars 为 26,980
  6. 相比之下,security_group_analyzer 为 4,200 字符,s3_config_checker 为 3,800 字符

差异就是线索。如果工具输出比它的兄弟工具大 7 倍,那就该减少它。


Sentry 的最佳使用

我使用 Sentry 的 AI 代理监控从零开始对多代理 CrewAI 管道进行检测。这不是一个 Web 应用或 API。这是五个自主 AI 代理进行 LLM 调用并执行自定义工具。标准 APM 在这里帮不上忙。


我检测了什么

每次管道运行都会创建一个 Sentry 事务,具有以下 span 层次结构:

Transaction: "Security Posture Scan" (57s)
├── gen_ai.invoke_agent: ResourceDiscovery
│   └── gen_ai.execute_tool: aws_resource_scanner
├── gen_ai.invoke_agent: SecurityScanner
│   ├── gen_ai.execute_tool: security_group_analyzer
│   ├── gen_ai.execute_tool: s3_config_checker
│   ├── gen_ai.execute_tool: iam_analyzer
│   ├── gen_ai.execute_tool: ec2_security_checker
│   └── gen_ai.execute_tool: lambda_security_checker
├── gen_ai.invoke_agent: ComplianceChecker
├── gen_ai.invoke_agent: RiskScorer
└── gen_ai.invoke_agent: RemediationPlanner