
高可用系统迁移怎样分阶段推进迁移应分批验证数据一致性和回退路径所谓“更稳”需要由演练结果证明。将规则引擎改成基于 Agent 工具调用的工作流会同时改变决策、依赖调用和失败语义。模型可能因信息不足继续请求工具下游也可能在超时后仍完成写入。迁移前要给每个请求设置调用预算、总体截止时间和停止状态并把工具副作用列清楚。分阶段的意义是让新流程先产生可比较证据再逐步取得副作用权限。旧流程能否回退、已经写入的数据如何处理应在第一次切流前确定。阶段一影子执行与双路比对 (Shadow Execution)迁移初期可让 Agent 只生成候选结果不直接修改生产状态。主流程继续使用原规则引擎脱敏后的任务样本再送入影子工作流。影子工具应连接只读或模拟接口避免“结果不采用但调用已经产生副作用”。日志和评测 Topic 只保留关联标识、版本、候选动作和失败原因不复制完整订单或凭据。比对服务不必要求步骤与旧引擎完全一致应检查最终业务结果、工具参数和拒绝行为。差异按“旧规则缺口、新流程错误、口径变化、尚待确认”分类。进入下一阶段的条件来自代表性场景覆盖、风险评审和回退演练不使用脱离业务后果的通用一致率。阶段二动态 Feature Flag 控频与百分比灰度切流从影子模式转为实际切流时按业务类型、租户或稳定散列缩小范围。分流键的选择要符合数据隔离和体验要求同一任务不能因重试随机落到另一套流程。系统入口通过配置中心控制范围并记录每次变更的操作者与版本。延迟、错误或预算耗尽可以触发暂停但自动回到旧引擎只适用于确认未产生副作用的请求。若 Agent 已写入或执行状态未知应返回可查询的任务状态不能再执行一次旧流程。下方 Go 代码表达稳定分流与超时。比例和时间值只是示例ErrSafeToFallback需要由执行器在确认没有提交任何副作用时返回。订单类请求还应携带幂等键日志不直接记录用户标识。type WorkflowExecutor interface { Execute(ctx context.Context, req *OrderRequest) (*OrderResult, error) } var ErrSafeToFallback errors.New(workflow stopped before commit) type HybridWorkflowEngine struct { legacyEngine WorkflowExecutor agentEngine WorkflowExecutor config *FeatureConfig } func (e *HybridWorkflowEngine) ProcessOrder(ctx context.Context, req *OrderRequest) (*OrderResult, error) { // 根据用户 ID 计算 Hash 灰度值 (0-999) userHash : crc32.ChecksumIEEE([]byte(req.UserID)) % 1000 // 检查全局开关与灰度比例 if e.config.IsAgentEnabled() userHash e.config.GetAgentRatioThreshold() { // 尝试执行 Agent 工作流设置严格的 Timeout 保护 agentCtx, cancel : context.WithTimeout(ctx, 600*time.Millisecond) defer cancel() res, err : e.agentEngine.Execute(agentCtx, req) if err nil { return res, nil } // 只有执行器明确证明尚未产生副作用才能调用旧流程。 if !errors.Is(err, ErrSafeToFallback) { return nil, fmt.Errorf(agent workflow status requires reconciliation: %w, err) } log.Warnf([WORKFLOW_FALLBACK] agent workflow stopped before commit: %v, err) } // 兜底策略使用稳定的旧版规则引擎 return e.legacyEngine.Execute(ctx, req) }阶段三Agent 工具调用的死循环保护与并发熔断Agent 的循环调用会消耗下游连接、线程和配额。预算应由外层编排器管理模型不能自行提高上限。深度、总调用数和并发度分别限制递归、总体工作量与瞬时压力数值根据依赖容量和任务风险设置。编排器至少要有调用预算、并发隔离与总体截止时间。达到上限后返回明确的“未完成”状态不把阶段性结果伪装成完整订单结果。不同 Tool 是否使用独立信号量要结合它们共享的数据库、连接池与外部配额决定。下面把原来的ThreadLocal计数改成请求级预算对象。线程池与异步切换会让ThreadLocal难以正确继承和清理显式传递更容易审计。public final class AgentExecutionBudget { private final int maxToolCalls; private int usedToolCalls; public AgentExecutionBudget(int maxToolCalls) { if (maxToolCalls 1) { throw new IllegalArgumentException(maxToolCalls must be positive); } this.maxToolCalls maxToolCalls; } public synchronized void consumeToolCall() { if (usedToolCalls maxToolCalls) { throw new AgentExecutionException( Agent tool call limit exceeded: usedToolCalls ); } usedToolCalls; } } public class AgentToolGuard { public ToolResult invokeToolSafely( AgentExecutionBudget budget, String toolName, Runnable toolTask ) { budget.consumeToolCall(); return executeWithRateLimiter(toolName, toolTask); } }存量切换生产验证 Checklist下线旧流程前实际演练配置暂停与旧引擎接管记录集群各实例看到新配置的时间差。模拟下游超时、拒绝、返回不完整和状态未知确认系统区分安全回退与需要人工对账的情况。监控工具调用、预算耗尽、拒绝、回退和未知状态并用 TraceID 关联编排与下游但链路中不记录 Prompt 全文或敏感参数。调用方登记完成、影子差异已解释、回退和对账流程通过后才逐步移除旧规则与临时双跑链路。