Agent 不再只是按脚本跑的流水线——它会推理、会变道、会自己拍板。这意味着传统 DevOps 的监控、回滚、成本管控手段,在 Agent 场景下几乎全部失效。一次"聪明"的自主决策,可能让调用链多绕三圈,Token 费用翻十倍,而日志里只留下一句模糊的 tool_invoked。
Amazon 在 Bedrock AgentCore 上提出了一套 AgentOps 纪律:把 Agent 当作一类全新的运维对象,从部署、观测、成本到持续改进,全链路重新设计。下面拆开看。
Agent 的运维难题到底在哪
传统服务的故障是确定性的——请求超时、异常码、资源耗尽,根因可追踪。Agent 的故障是非确定性的:
- 决策漂移:同一个输入,Agent 今天调了搜索工具,明天直接用内置知识回答,后天又组合了三个工具。不是 bug,是推理路径本身在变。
- 成本失控:一个本该 2 步完成的任务,Agent "深思熟虑"后走了 8 步,每步都带上下文累积,Token 消耗指数级增长。
- 黑箱失败:Agent 返回了错误结果,但中间推理过程只存在于一次会话的内存里,事后无法复现、无法调试。
这三件事叠加,让"上线一个 Agent"变成"上线一个你无法预测其行为的系统"。
AgentOps 的核心支柱
Bedrock AgentCore 把 AgentOps 拆成四个可落地的方向:
1. 可观测性——把推理链变成可审计的事件流
不是只看最终输出,而是记录 Agent 每一步的决策:选了哪个工具、传了什么参数、推理依据是什么、耗时多少。这要求 Agent 运行时主动 emit 结构化事件,而不是靠事后拼日志。
2. 护栏与成本控制——给自主决策加边界
Agent 可以自由推理,但不能自由花钱。设置单次任务最大步数、单步最大 Token、工具调用白名单——这些不是限制能力,是防止失控。Bedrock AgentCore 提供了 Guardrail 和 Invocation 级别的限额机制。
3. 评估与回归测试——对非确定性输出做确定性评判
传统 CI 测的是"输出等于期望值"。Agent 测试测的是"输出在可接受区间内,且推理路径合规"。需要定义评估维度:事实准确性、工具使用合理性、成本效率,然后跑批量回归。
4. 持续改进——从生产数据反哺 Agent 配置
收集真实任务的轨迹数据,分析哪些场景 Agent 走了弯路,然后调整提示词、工具描述、护栏阈值。这不是一次性调优,是持续循环。
实践:用 Bedrock AgentCore 搭一个可观测、有护栏的 Agent
下面给出一个最小可运行的示例,展示如何在 Bedrock AgentCore 上创建一个带步数限制和工具白名单的 Agent,并接入轨迹采集。你需要一个 AWS 账号,且已开通 Bedrock 权限。
前提:安装 boto3 并配置 AWS 凭证。
pip install boto3
aws configure # 填入 Access Key、Secret Key、region(如 us-east-1)
创建 Agent 并设置护栏
import boto3
import time
import json
client = boto3.client("bedrock-agent", region_name="us-east-1")
# 1. 创建 Agent
create_resp = client.create_agent(
agentName="ops-demo-agent",
agentResourceRoleArn="arn:aws:iam::<YOUR_ACCOUNT_ID>:role/BedrockAgentRole", # 替换为你的 IAM Role
foundationModel="anthropic.claude-3-5-sonnet-20241022-v2:0",
instruction="你是一个运维助手。用户报告服务异常时,先查询日志,再给出诊断建议。不要猜测,必须基于工具返回的数据回答。",
idleSessionTTLInSeconds=600, # 会话超时 10 分钟
)
agent_id = create_resp["agent"]["agentId"]
print(f"Agent ID: {agent_id}")
# 等待 Agent 创建完成
time.sleep(10)
# 2. 创建 Guardrail —— 限制输出内容 + 限制工具调用范围
guard_resp = client.create_guardrail(
name="ops-demo-guardrail",
description="限制 Agent 只讨论运维话题,拒绝无关请求",
contentPolicyConfig={
"filtersConfig": [
{
"type": "DENIED",
"inputStrength": "HIGH",
"outputStrength": "HIGH",
"topics": ["金融投资", "医疗诊断"] # 拒绝这些话题
}
]
},
contextualGroundingPolicyConfig={
"filtersConfig": [
{
"type": "GROUNDING",
"threshold": 0.75 # 要求输出至少 75% 有依据
},
{
"type": "RELEVANCE",
"threshold": 0.80 # 要求输出与问题相关度 ≥ 80%
}
]
},
blockedInputMessaging="抱歉,我只能协助处理运维相关的问题。",
blockedOutputsMessaging="输出被护栏拦截:内容缺乏充分依据或偏离运维领域。",
)
guardrail_id = guard_resp["guardrailId"]
print(f"Guardrail ID: {guardrail_id}")
# 3. 将 Guardrail 绑定到 Agent
client.update_agent(
agentId=agent_id,
guardrailConfiguration={
"guardrailId": guardrail_id,
"guardrailVersion": "DRAFT",
},
)
print("Agent 已绑定护栏,准备进入 DRAFT 版本测试。")
关联工具并准备运行
# 4. 创建一个模拟的日志查询工具(Lambda 函数)
lambda_client = boto3.client("lambda", region_name="us-east-1")
lambda_client.create_function(
FunctionName="ops-log-query-tool",
Runtime="python3.12",
Role="arn:aws:iam::<YOUR_ACCOUNT_ID>:role/LambdaExecutionRole", # 替换
Handler="index.handler",
Code={"ZipFile": b"""
import json
def handler(event, context):
# 模拟日志查询结果
service = event.get("service", "unknown")
return {
"statusCode": 200,
"body": json.dumps({
"service": service,
"last_errors": [
{"time": "2025-01-15T08:32:00Z", "message": "Connection timeout to DB"},
{"time": "2025-01-15T08:33:15Z", "message": "Retry succeeded"},
],
"error_rate_last_1h": "0.03%"
})
}
"""},
)
time.sleep(5)
# 5. 注册工具到 Agent
tool_resp = client.create_agent_action_group(
agentId=agent_id,
agentVersion="DRAFT",
actionGroupName="LogQuery",
actionGroupExecutor={
"lambda": "arn:aws:lambda:us-east-1:<YOUR_ACCOUNT_ID>:function:ops-log-query-tool"
},
functionSchema={
"functions": [
{
"name": "query_service_logs",
"description": "查询指定服务的最近错误日志和错误率",
"parameters": {
"service": {
"type": "string",
"description": "服务名称,如 order-service、payment-service",
"required": True,
}
},
}
]
},
)
print(f"工具已注册: {tool_resp['actionGroup']['actionGroupId']}")
# 6. 准备 Agent 版本(DRAFT → 可调用)
prepare_resp = client.prepare_agent(agentId=agent_id)
print(f"Agent 版本已准备: {prepare_resp['preparedAgent']['agentVersion']}")
运行 Agent 并采集轨迹
runtime = boto3.client("bedrock-agent-runtime", region_name="us-east-1")
# 7. 发起一次对话,启用轨迹记录
resp = runtime.invoke_agent(
agentId=agent_id,
agentAliasId="TSTALIASID", # 测试别名
sessionId="ops-session-001",
inputText="order-service 最近有异常吗?帮我查一下日志。",
enableTrace=True, # 关键:开启轨迹采集
)
# 8. 解析轨迹数据
trace_data = []
for event in resp.get("completion", []):
if "trace" in event:
trace = event["trace"]
trace_data.append(trace)
# 打印每一步决策
if "orchestrationTrace" in trace:
ort = trace["orchestrationTrace"]
if "modelInvocationOutput" in ort:
reasoning = ort["modelInvocationOutput"].get("rawResponse", "")
print(f"[推理] {reasoning[:200]}...")
if "actionInvocationOutput" in ort:
action = ort["actionInvocationOutput"]
print(f"[工具调用] function={action.get('functionName')} input={action.get('actionInput')}")
if "chunk" in event:
answer = event["chunk"].get("bytes", b"").decode("utf-8")
print(f"\n[最终回答] {answer}")
# 9. 将轨迹保存为 JSON,供后续分析
with open("agent_trace_session_001.json", "w") as f:
json.dump(trace_data, f, indent=2, ensure_ascii=False)
print(f"\n轨迹已保存,共 {len(trace_data)} 个决策节点。")
运行后你会得到两样东西:Agent 的最终回答,以及一份完整的推理轨迹 JSON。轨迹里包含每一步的模型推理原文、工具选择理由、调用参数和返回值——这就是 AgentOps 可观测性的基础。
成本护栏的补充配置
上面的 Guardrail 控制了内容边界。步数和 Token 限制需要在 Agent 别名级别配置:
# 10. 创建带执行限制的 Agent Alias
alias_resp = client.create_agent_alias(
agentAliasName="prod-alias",
agentId=agent_id,
routingConfiguration=[
{
"agentVersion": "1", # 使用已发布的版本
}
],
# Bedrock AgentCore 支持在会话级别设置 maxSteps 等参数
# 通过 session-level 配置传入:
# maxSteps: 5 # 单次任务最多 5 步
# maxTokensPerStep: 4096
)
print(f"生产别名已创建: {alias_resp['agentAlias']['agentAliasId']}")
实际调用时,在 invoke_agent 的 sessionState 里可以传入执行限制:
resp = runtime.invoke_agent(
agentId=agent_id,
agentAliasId=alias_resp["agentAlias"]["agentAliasId"],
sessionId="ops-session-002",
inputText="payment-service 响应变慢了,帮我排查。",
enableTrace=True,
sessionState={
"invocationId": "inv-002",
# 限制单次对话最多 5 轮工具调用
# (具体参数名以 Bedrock AgentCore 最新 SDK 文档为准)
},
)
落地前要想清楚的几件事
| 决策点 | 建议 |
|---|---|
| 护栏粒度 | 先从粗粒度入手:话题拒绝 + 步数上限。精细化护栏(如特定关键词过滤)等有真实数据再调。过早收紧会让 Agent 变笨。 |
| 轨迹存储 | 不要只存最终输出。每条轨迹的完整 JSON 存到 S3 或 DynamoDB,按 sessionId + timestamp 组织。这是后续评估和改进的唯一数据源。 |
| 评估体系 | 上线前至少定义三个维度:事实准确率(输出是否基于工具数据)、路径效率(步数是否合理)、成本比率(Token/步数是否在预期区间)。用批量测试集跑回归,而不是手动试几条。 |
| 成本监控 | Bedrock 的 Token 计费是后置的。在 AgentOps 层面,你需要从轨迹数据里实时统计 input_tokens + output_tokens,设告警阈值,而不是等月底账单出来才发现超标。 |
| 版本策略 | Agent 的提示词、工具描述、护栏阈值都是"代码"。每次修改走 DRAFT → 测试 → 发布流程,不要在生产别名上直接改。 |
AgentOps 不是给 Agent 加一层监控面板就完事——它要求你重新定义"什么是正常行为"。传统服务的正常是"返回 200",Agent 的正常是"在允许步数内、基于工具数据、给出合规回答"。这个标准需要你根据业务场景自己定,Bedrock AgentCore 提供的是采集和执行基础设施,判断标准得你自己写。