第三部分:Goose、agentgateway与Quarkus的端到端追踪与可观测性
企业背景 --- Acme FinServ。SOC 2 CC7(系统监控)要求 Acme 能够检测并调查异常活动。当代理驱动的工作流在凌晨 2 点接触客户数据时,“我们在某处有日志”不是审计员能接受的答案。本部分构建的分布式追踪是取证证据链:一个单一的追踪 ID,将 Goose 提示与每个 agentgateway 策略决策和每个 Quarkus 工具调用联系起来,因此事后事件审查可以准确重建哪个代理做了什么、按什么顺序、以及每个受治理的跳花费了多长时间。
核心问题
在第 1 部分中,我们构建了一个 Quarkus MCP 工具服务器。在第 2 部分中,我们使用 agentgateway 的 JWT 认证、RBAC 和 ExtMCP 护栏对其进行了保护。架构是有效的 --- 但当生产环境出现问题时,你就是在盲目飞行。
代理工作流与传统请求-响应 API 有根本的不同。一个简单的用户提示,如*“调试客户 CUST-4091”*,会触发一个多轮往返循环:
- Goose 调用
tools/list以发现可用工具 - LLM 选择
getCustomerStatus,然后 Goose 发送tools/call - LLM 读取响应,看到
primaryRegion: US-EAST-1,并链式发起第二个tools/call到getZoneHealthLogs - LLM 关联两个结果并生成诊断摘要
这些跳中的每一个都跨越进程边界:Goose → agentgateway → Quarkus。没有分布式追踪,你会在访问日志中看到四个孤立的 HTTP 请求。你无法判断它们属于同一个代理工作流。当第 3 步花费 12 秒而不是 200 毫秒时,你没有瀑布图来定位延迟是来自 agentgateway 策略评估、Quarkus Bean 验证,还是缓慢的下游调用。这会在遥测仪表板中造成黑洞 --- 这正是自主代理利用来静默降级的缺口。
解决方案:跨所有三层的 W3C 追踪上下文
修复方法是将标准分布式追踪应用于 MCP 传输层:
[LOADING...]
- agentgateway 为每个代理的 MCP 请求导出 span,并将
traceparent头传播到后端。 - Quarkus 使用
quarkus-opentelemetry获取传入的traceparent,为工具执行和 Bean 验证创建子 span,并将它们导出到同一个 Jaeger 实例。 - Jaeger 将两侧关联为单个追踪瀑布图 --- 从代理提示到工具结果的单一视图。
先决条件
第 1 部分和第 2 部分的所有内容,外加:
- Podman -- 用于运行 Jaeger(
podman compose)
验证 Podman 是否可用:podman --version
步骤 1:启动可观测性后端
我们使用 Jaeger v2 作为 OTLP 收集器和追踪 UI。单个容器在端口 4317(OTLP gRPC)上接受来自 agentgateway 的追踪,在端口 4318(OTLP HTTP)上接受来自 Quarkus 的追踪,并在端口 16686 上提供查询 UI。
这将启动 Jaeger v2,默认启用 OTLP 收集。验证其正在运行:curl -sf http://localhost:16686/ > /dev/null && echo "Jaeger UI is ready"
打开 http://localhost:16686 --- 你会看到一个空的 Jaeger UI。我们将在以下步骤中用 MCP 追踪填充它。
生产替代方案:Grafana Tempo
对于生产部署,请将 Jaeger 替换为由对象存储(S3/GCS)支持的 Grafana Tempo。OTLP 端点保持不变 --- 只有 compose.yml 发生变化。Grafana 提供更丰富的仪表板、告警和长期追踪保留。
步骤 2:在 Quarkus 中启用 OpenTelemetry
将 quarkus-opentelemetry 扩展添加到第 1 部分的 pom.xml 中:
在 application.properties 中配置导出器:
当没有 OTLP 收集器运行时(第 1 部分和第 2 部分没有 Jaeger),Quarkus 会记录连接警告,但 MCP 服务器正常工作。当收集器正在运行时(第 3 部分),追踪会自动流动。对 MCP 工具零代码更改。
重新构建第 1 部分:
Quarkus 自动检测什么
当 quarkus-opentelemetry 在类路径上且 SDK 已启用时,Quarkus 会自动为以下内容创建 span:
不需要 @WithSpan 注解。Quarkus OpenTelemetry 扩展会自动检测响应式管道。
步骤 3:在 agentgateway 中配置 W3C 追踪上下文
agentgateway 支持原生 OpenTelemetry 追踪导出。将 tracing 块添加到网关配置中:
追踪传播如何工作
当 agentgateway 收到 MCP 请求时:
- 为代理操作创建根 span(例如
agentgateway.mcp.proxy) - 将
traceparent头注入到转发给 Quarkus 的请求中:traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01 - Quarkus 读取
traceparent,在同一个追踪 ID 下创建子 span,并记录工具执行 - 两个 span 都通过 OTLP 导出到 Jaeger,在那里它们显示为单个关联追踪
这是标准的 W3C 追踪上下文传播 --- 与所有 OpenTelemetry 插桩服务中使用的机制相同。
配置文件
第 3 部分提供了两种 agentgateway 配置:
步骤 4:运行交互式演示
使用一键脚本启动所有服务:
该脚本启动 Jaeger、Quarkus(启用 OTel)和 agentgateway(启用追踪导出),然后在 :8890 上启动演示 SPA。
打开 MCP 可观测性控制台,网址为 http://localhost:8890/index.html,并完成三个演示步骤:
- 初始化 -- 通过 agentgateway 建立 MCP 会话。架构图动画展示追踪传播:agentgateway 中的根 span 创建、
traceparent注入、Quarkus 中的子 span,以及 OTLP 导出到 Jaeger。 - 列出工具 -- 通过已追踪的代理发现所有 5 个工具。追踪瀑布图面板并排显示 agentgateway 代理 span 和 Quarkus HTTP span 及时间。
- 多工具工作流 -- 模拟 Goose 的多轮推理:
getCustomerStatus(找到区域 US-EAST-1)→getZoneHealthLogs(检查区域健康)→getSLACompliance(关联 SLA 指标)。每一步都会生成带有瀑布图可视化的完整追踪。
统计磁贴跟踪生成的追踪、收集的 span 和 Jaeger 状态。点击 打开 Jaeger 以在 http://localhost:16686 的 Jaeger UI 中查看真实的追踪瀑布图。
步骤 5:通过 CLI 生成追踪
要手动生成额外的追踪,请模拟一个多轮代理工作流:
这些请求中的每一个都会生成一个追踪,该追踪通过 agentgateway 流入 Quarkus 并到达 Jaeger。
步骤 6:在 Jaeger 中可视化追踪瀑布图
在浏览器中打开 http://localhost:16686。
查找追踪
- 在服务下拉菜单中,选择
customer-tools(Quarkus)或agentgateway - 点击查找追踪
- 点击任意追踪以打开瀑布图视图
阅读瀑布图
一个典型的 tools/call 追踪显示以下 span 层次结构:
要寻找什么
- 代理开销:agentgateway span 和 Quarkus span 之间的差距显示网络 + 策略评估时间。如果这个增长,检查护栏服务器延迟。
- 验证时间:Bean 验证 span 出现在工具执行之前。像
^CUST-[0-9]{4,8}$这样正则表达式密集的模式很快,但大型负载上的复杂验证器可能会增加延迟。 - 多轮关联:当 Goose 链式调用多个工具调用(例如
getCustomerStatus→getZoneHealthLogs)时,每个都显示为单独的追踪。mcp-session-id标签允许你过滤属于一个代理会话的所有追踪。 - 错误追踪:验证失败(无效的客户 ID 格式)或护栏拒绝(阻止毒化负载)会产生带有异常详细信息的错误 span。
连接 Goose 以获取真实追踪
启动指向 agentgateway 的 Goose,并提示一个多工具工作流:
goose session
"调试客户 CUST-4091 --- 检查他们的账户状态,然后获取其区域的健康日志以及 api-gateway 的 SLA 合规性。"
这会在 Jaeger 中生成一批关联的追踪,显示 Goose 从代理层到单个工具执行 span 的多轮工具编排。
我们实现了什么
从第 2 部分的安全架构开始,我们在不更改任何 MCP 工具代码的情况下添加了完整的可观测性:
整个堆栈通过单个 ./start-all.sh 命令在本地运行,并在 Jaeger 中生成端到端的追踪瀑布图。
生产考虑因素
第 4 部分即将推出
有了追踪,你现在可以看到系统中流动的每个 MCP 工具调用。在第 4 部分中,我们将超越单代理工具调用,转向多代理编排 --- 使用代理到代理 (A2A) 协议来协调自主代理,这些代理可以委派工作、通过 AGENTS.md 强制执行治理,并回调我们的 MCP 工具服务。