大规模灾难恢复的难点,不只是把流量切到备用区域,而是在高压环境下同时保证决策正确、操作可控、过程可追溯。Intuit 构建的 EWOK Agent 展示了一种实践方向:值班工程师用自然语言提出生产故障转移请求,智能体负责理解意图和协调执行,同时让每一步操作保持可审计、符合策略并具备安全边界。
这类系统的关键不是让大模型直接操作生产环境,而是把它放在受约束的控制平面里:模型负责解释请求和生成计划,确定性代码负责检查、审批和执行。
自然语言只是入口,不是授权凭证
一条看似简单的请求可能是:
将支付服务从 us-east-1 故障转移到 us-west-2,变更单号 CHG-4821。
智能体需要把它转换成机器可验证的结构,例如:
{
"service": "payments",
"source_region": "us-east-1",
"target_region": "us-west-2",
"change_ticket": "CHG-4821",
"requested_action": "failover"
}
结构化并不等于获准执行。后续仍应由传统程序完成以下检查:
- 服务和目标区域是否在允许列表中。
- 调用者是否拥有生产故障转移权限。
- 变更单是否有效,是否处于允许执行的时间窗口。
- 备用区域的容量、复制延迟和健康检查是否达标。
- 当前是否存在冻结窗口或冲突中的部署。
- 高风险操作是否已经获得双人审批。
这种分工缩小了模型的权限范围。即使模型误解请求,它也只能生成候选计划,不能绕过身份认证、策略引擎或执行器。
把恢复过程设计成有状态工作流
生产故障转移通常不是一次 API 调用,而是一条包含等待、验证和回滚的状态机。可以将流程拆成以下阶段:
- 解析请求:Bedrock 将自然语言转换成固定 schema。
- 收集证据:查询服务目录、监控指标、复制状态和变更系统。
- 生成计划:列出预检查、流量切换、验证及回滚步骤。
- 策略判定:由确定性规则决定拒绝、等待审批或允许执行。
- 人工确认:向值班工程师展示目标环境、风险和影响范围。
- 受控执行:调用预先注册的 runbook,而不是执行模型生成的任意命令。
- 持续验证:检查错误率、延迟、依赖健康度和业务指标。
- 完成或回滚:记录结果,并在阈值越界时触发预定义回滚。
Amazon Bedrock 可以承担自然语言理解和计划生成,AWS Step Functions 可以编排长时间运行的状态,Lambda 或内部自动化平台则执行受限动作。这里描述的是一种可以落地的参考架构,不代表 EWOK Agent 未公开的具体内部实现。
审计记录应覆盖每个阶段,而不只是最终结果。至少需要记录原始请求、调用者身份、模型与提示词版本、结构化计划、策略判断、审批人、工具调用参数、执行结果和时间戳。敏感字段应在写入日志前脱敏,并使用不可随意修改的存储和保留策略。
一个最小的 Bedrock 计划生成器
下面的 Python 示例演示“模型生成计划,代码执行策略检查”的边界。它默认只生成并验证计划,不连接真正的故障转移执行器。
运行前需要 AWS 凭证、可访问的 Bedrock 模型,以及 Python 3.10 以上版本。将 BEDROCK_MODEL_ID 替换为账户和区域中已启用、支持 Converse API 的模型 ID。
python -m venv .venv
source .venv/bin/activate
pip install boto3
export AWS_REGION=us-east-1
export BEDROCK_MODEL_ID='your-enabled-model-id'
python dr_planner.py 'Fail over payments from us-east-1 to us-west-2 under CHG-4821'
创建 dr_planner.py:
import json
import os
import sys
from datetime import datetime, timezone
import boto3
ALLOWED_SERVICES = {"payments", "billing", "identity"}
ALLOWED_TARGETS = {
"payments": {"us-west-2"},
"billing": {"us-east-2"},
"identity": {"us-west-2"},
}
SYSTEM_PROMPT = """You convert disaster-recovery requests into JSON plans.
Return JSON only, with exactly these string fields:
service, source_region, target_region, change_ticket, requested_action.
requested_action must be failover. Never invent missing values; use an empty string.
Do not emit commands, scripts, credentials, or explanatory text.
"""
def build_plan(request_text: str) -> dict:
client = boto3.client(
"bedrock-runtime",
region_name=os.environ.get("AWS_REGION", "us-east-1"),
)
response = client.converse(
modelId=os.environ["BEDROCK_MODEL_ID"],
system=[{"text": SYSTEM_PROMPT}],
messages=[{"role": "user", "content": [{"text": request_text}]}],
inferenceConfig={"temperature": 0, "maxTokens": 300},
)
text = response["output"]["message"]["content"][0]["text"]
return json.loads(text)
def evaluate_policy(plan: dict) -> list[str]:
required = {
"service",
"source_region",
"target_region",
"change_ticket",
"requested_action",
}
errors = []
if set(plan) != required:
errors.append("plan schema does not match the approved schema")
if plan.get("service") not in ALLOWED_SERVICES:
errors.append("service is not approved for automated failover")
if plan.get("target_region") not in ALLOWED_TARGETS.get(plan.get("service"), set()):
errors.append("target region is not approved for this service")
if plan.get("requested_action") != "failover":
errors.append("unsupported action")
if not plan.get("change_ticket", "").startswith("CHG-"):
errors.append("a valid change ticket is required")
if plan.get("source_region") == plan.get("target_region"):
errors.append("source and target regions must differ")
return errors
def main() -> None:
if len(sys.argv) != 2:
raise SystemExit("usage: python dr_planner.py '<request>'")
request_text = sys.argv[1]
plan = build_plan(request_text)
errors = evaluate_policy(plan)
audit_event = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"request": request_text,
"plan": plan,
"decision": "REJECTED" if errors else "AWAITING_APPROVAL",
"policy_errors": errors,
}
print(json.dumps(audit_event, indent=2))
if __name__ == "__main__":
main()
这段代码刻意不执行故障转移。生产实现还应增加身份校验、变更单 API 查询、模型输出 schema 校验、提示词注入防护、请求幂等键、审批签名和集中审计存储。通过策略检查后,系统也应该只传递一个已验证的 runbook ID 及受限参数,而不是运行模型生成的 shell 命令。
安全性来自纵深防御
灾难恢复智能体拥有较大的潜在影响范围,因此不能把安全性寄托在提示词上。更可靠的设计应包含多层独立控制:
- 最小权限:计划生成组件没有生产写权限,执行器只拥有特定 runbook 所需权限。
- 明确的工具目录:智能体只能调用版本化、带参数 schema 的操作,不接受任意代码。
- 默认试运行:先展示将要修改的资源、流量比例和验证条件。
- 风险分级审批:演练环境可以自动执行,生产全量切换要求人工确认或双人审批。
- 幂等与互斥:重复请求不会重复切流,同一服务不能并发执行冲突工作流。
- 自动止损:错误率或关键业务指标越过阈值时暂停或回滚。
- 完整审计:把模型输入输出、策略版本和工具结果关联到同一个执行 ID。
还要防范自然语言入口带来的提示词注入。来自告警、工单和聊天记录的文本都应视为不可信数据。模型不能因为文本中出现“忽略审批”就改变权限,真正的授权必须由身份系统和策略引擎判定。
从演练助手逐步走向生产执行
引入这类系统时,可以按风险逐级开放能力:先让智能体解释 runbook 和收集证据,再让它生成只读计划;随后在隔离环境中执行,最后才允许经过审批的生产故障转移。
上线前应确认以下事项:
- 故障转移和回滚 runbook 已经独立验证,不依赖智能体才能运行。
- 每个生产动作都有清晰的前置条件、超时和失败语义。
- 模型异常、Bedrock 不可用或审计系统故障时,流程默认停止。
- 团队定期进行演练,并验证手工接管路径。
- 指标同时衡量恢复速度和安全性,包括误触发、策略拒绝、回滚次数与审计完整率。
EWOK Agent 的价值不只是让值班工程师少写几条命令,而是把自然语言、标准化 runbook、策略控制和审计证据连接成一个统一入口。真正适合生产的 agentic 灾难恢复系统,应当让操作更快,但绝不能让权限边界变得模糊。