Agent 应用正在从单一 SDK 走向多框架组合:团队可能用 LangGraph 编排流程,用 LlamaIndex 做检索,也可能选择 OpenAI Agents SDK、Google ADK、Claude Agent SDK 或 Strands Agents。框架选择变多后,评估系统最容易陷入重复建设:每换一个框架,就要重新接入追踪、指标和评分逻辑。
Amazon Bedrock AgentCore Evaluations 采用了另一种思路:把 Agent 评估从具体框架中解耦出来。只要 Agent 能发出 OpenTelemetry telemetry,评估服务就可以基于这些运行数据进行评分。
关键不在 SDK,而在遥测契约
这种框架无关的设计,核心是一个稳定的边界:Agent 负责执行并记录运行过程,评估服务负责读取 telemetry 并完成评分。
Agent 运行时至少应让观测系统能够识别这些信息:
- 一次完整的 Agent 运行,例如用户请求、最终响应和整体耗时。
- Agent 调用过的工具,以及每次工具调用的输入、输出和耗时。
- 多步推理或工作流中的父子关系,便于还原调用链。
- 使用的框架、模型或业务标签,便于按版本和场景比较结果。
- 错误、超时和异常结束状态。
重点是数据形态,而不是 Agent 内部采用了哪种图结构、工具注册方式或消息对象。LangGraph 的节点、LlamaIndex 的检索步骤和 Strands Agents 的工具调用,只要能映射为可追踪的 OpenTelemetry spans,就能进入同一套评估流程。
这也带来一个实际收益:评估逻辑可以独立演进。业务团队更换 Agent 框架时,通常只需要保持 telemetry 契约稳定,而不必重写整套评分管线。
一个最小的 OpenTelemetry 运行记录
下面的示例用 Python 创建一个简单的 Agent 运行和工具调用链。它不依赖某个具体 Agent 框架,使用控制台导出器打印 spans,方便本地验证。生产环境中,可以把导出器替换为组织现有的 OTLP 管道,并按照实际 AgentCore 接入要求配置传输方式。
运行前安装依赖:
python -m pip install opentelemetry-api opentelemetry-sdk
保存为 agent_trace_demo.py 后运行:
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
SimpleSpanProcessor,
ConsoleSpanExporter,
)
resource = Resource.create({
"service.name": "support-agent",
"service.version": "2025.01",
})
provider = TracerProvider(resource=resource)
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("support-agent")
def lookup_order(order_id: str) -> str:
with tracer.start_as_current_span("tool.lookup_order") as span:
span.set_attribute("tool.name", "lookup_order")
span.set_attribute("tool.input.order_id", order_id)
result = f"order {order_id} is ready to ship"
span.set_attribute("tool.output.status", "ready")
return result
def run_agent(user_request: str) -> str:
with tracer.start_as_current_span("agent.run") as span:
span.set_attribute("agent.framework", "custom-python")
span.set_attribute("agent.task", "order-status")
span.set_attribute("agent.input", user_request)
order_status = lookup_order("A-1001")
response = f"I checked the order: {order_status}."
span.set_attribute("agent.output", response)
span.set_attribute("agent.status", "success")
return response
if __name__ == "__main__":
print(run_agent("Where is order A-1001?"))
这个例子展示了几个值得保留的实践:agent.run 代表一次完整执行,tool.lookup_order 作为子 span 自动继承父上下文,属性则记录框架、任务、输入、输出和状态。实际接入时,不应把密码、访问令牌或未经处理的个人信息直接写入 span;输入输出也应根据数据分类策略进行脱敏或摘要化。
接入不同框架时保持什么稳定
框架适配层不需要暴露完整的内部实现,重点是把关键生命周期映射到统一的观测结构:
agent.run
├── retrieval.search
├── tool.get_customer
└── model.generate
无论底层使用哪一种框架,都可以围绕以下字段建立最小约定:
span name: agent.run
framework: langgraph | llamaindex | openai-agents | ...
task: customer-support
status: success | error | timeout
input/output: redacted request and response
trace relationship: parent agent span -> child tool/model spans
这些名称和属性是实践示例,具体字段应以目标环境的接入要求为准。更重要的是,团队要把约定写成版本化文档,并在 CI 或集成测试中检查每次 Agent 运行是否产生完整 trace。否则,评估结果可能只是“没有数据”,而不是 Agent 真的表现良好或不佳。
从“能追踪”到“能评估”
OpenTelemetry 解决的是运行过程的可见性,评估还需要明确的任务和质量标准。例如客服 Agent 可以分别评估:
- 是否调用了正确的工具。
- 是否依据工具结果回答,而不是编造状态。
- 是否在工具失败时正确处理异常。
- 最终答案是否满足任务要求。
- 延迟、成本或步骤数量是否超过约束。
因此,迁移到 AgentCore Evaluations 时,建议把工作拆成三层:
- 在 Agent 内建立稳定的 trace 和 span 生命周期。
- 为不同任务准备可重复的输入集、期望行为和评分维度。
- 用相同的评估流程比较不同框架、模型和提示词版本。
这样评估结果才有可比性。单纯把 telemetry 发出去,并不会自动解决数据集质量、评分标准偏差或生产流量与测试流量不一致的问题。
落地检查清单
采用这种框架无关的评估方式前,可以检查:
- 每次 Agent 请求是否都有唯一且完整的根 span。
- 工具调用、检索和模型调用是否保留父子关系。
- 成功、失败、超时是否使用一致的状态表示。
- 关键输入输出是否已脱敏,并设置合理的保留期限。
- 框架、模型、提示词和应用版本是否作为可筛选属性记录。
- 测试数据集是否覆盖工具错误、空结果和长链路场景。
- 更换 Agent 框架后,是否仍能生成同样可消费的 telemetry。
AgentCore Evaluations 的价值不在于要求团队统一使用某个 Agent SDK,而在于把评估边界放在更稳定的 OpenTelemetry 契约上。对于仍在快速试验框架的团队,这能降低评估系统的重复集成成本;对于已经运行多个 Agent 栈的团队,则可以提供一套共同的观测和比较语言。真正落地时,应优先固定 telemetry 结构和数据治理规则,再逐步扩展评分维度。