当编码智能体离开代码库:多运行时AI智能体基础设施实践

发布时间:2026/10/27 17:59:05
当编码智能体离开代码库:多运行时AI智能体基础设施实践

我先说个场景。你花了两周时间,用某个大模型 API 搓了一个编码智能体,它能读仓库、改代码、提 PR,在代码库里活跃得像个资深工程师。然后老板说:"这玩意儿不错,让它顺便处理工单、查数据库、操作一下退款接口吧。"于是你把智能体从 IDE 里拉出来,丢到云服务器上,准备让它 7x24 小时自主运行——结果不到三天你就想把它塞回代码库。

这不是模型不行,而是你缺了一层东西:给 AI 智能体用的基础设施。编码智能体在代码库里干活时,"环境"是隐性的,有 IDE 兜底、有 Git 流程保护、有人 Code Review。一旦离开代码库,面对真实系统,它就像个刚毕业的实习生——聪明是真聪明,但没人管就敢闯祸。这就是今天这篇要聊的主题:如何基于 Azure KARS 的思路,为多运行时 AI 智能体搭建一套可靠的基础设施底层。

1. 解码标题:当编码智能体离开代码库,到底改变了什么

1.1 从"工具型智能体"到"独立运行型智能体"的质变

编码智能体在代码库内的运行模式,本质是"人在回路"的工具。它基于代码索引和上下文窗口做推理,输出补丁和 PR,每一次动作都有版本管理兜底,失败顶多就是代码写错了,重新 commit 一次就行。但离开代码库之后,智能体面对的不再是文本符号,而是真实的业务系统:数据库连接、第三方 API、消息队列、面向用户的写操作。这时候它就不再是一个"建议生成器",而是一个"自主执行者"。

我见过很多团队在这里栽跟头。他们以为自己只需要把智能体的执行环境从本地挪到云端,加个超时和重试,就算完成了"部署"。结果第一次真实故障就把他们打懵了:智能体在循环调用一个写接口,生成了几十条重复订单;或者在某次工具调用中拿错了参数,直接把测试环境的配置覆盖到了生产。这些事故的根因都一样——把智能体当普通 API 函数调,却忘了它有状态、有决策、会犯错。

工具型智能体和独立运行型智能体的差别是全方位的。工具型有固定的输入输出模式,有明确的成功失败标准,有外部的人类审核节点;独立运行型则要自己决定下一步动作,自己判断任务的完成标准,自己处理各种边界和异常。后者的复杂度不是前者的两倍,而是完全不同的数量级。说白了,你要管理的不是"一次函数调用",而是"一个正在持续做决策的过程"。

1.2 编码智能体离开代码库后的三堵墙

第一堵墙是可靠性墙。代码库环境是确定性的:编译会失败、测试会挂、API 会返回错误,但这些都在可预期的范围内。真实系统不一样,外部接口的响应延迟、超时、限流、拒绝服务,这些不确定因素会直接影响智能体的推理质量。它可能因为一次超时而产生幻觉,进而做出错误的后续决策。普通分布式系统的超时重试策略,放在智能体场景下根本不够用,因为你不仅要保证"下一次请求成功",还要保证"智能体不会因为失败而编造一个结果继续跑下去"。

第二堵墙是状态墙。编码智能体一次只处理一个任务片段,上下文重新构建很便宜。可独立运行的智能体往往是长时任务,一次会话可能持续几个小时甚至跨天,中间涉及多轮工具调用、部分成功部分失败的子任务、需要暂停等待人工审批等操作。这时候状态管理就成了核心问题:智能体当前执行到哪一步、哪些副作用已经产生、哪些还没产生、如果中止该如何回滚、如果崩溃该如何恢复。没有状态管理,长时运行的智能体就是一个随时会失忆的电子员工。

第三堵墙是治理墙。代码库里有权限控制,但那是针对人类开发者的。独立运行型智能体需要的是"按动作粒度"的权限:读操作可以自主执行,写操作需要人工审批,危险操作直接熔断。更重要的是,智能体的每一轮决策都需要可审计的痕迹记录,出了问题要能回溯到具体是哪一个模型调用、哪一个工具调用、哪一个上下文片段导致了错误的决策。没有治理层,智能体一旦出错就是黑盒犯错,你根本无从排查。

1.3 KARS 在 Azure 体系中的定位:智能体的基础设施控制面

Azure KARS(Kubernetes Agent Runtime Service,示例名,代表这一类基于 Kubernetes 扩展的智能体运行时服务)做的事情,简单说就是:把"智能体工作负载"变成 Kubernetes 中的一等公民。我们知道 Kubernetes 管理的是容器和 Pod,那 KARS 管理的则是 AgentWorkload——一种描述智能体运行方式的自定义资源。

它的思路非常值得借鉴:先承认智能体是分布式系统中的一个特殊工作负载,再为这个特殊工作负载定义一组专属的运行属性。这些属性包括:执行环境(容器沙箱、WebAssembly 沙盒、Serverless 函数,或它们的组合)、工具访问权限(每个工具调用是否需要审批)、可靠性策略(重试上限、熔断阈值、超时时间)、状态存储(会话快照存到 Redis 还是 Cosmos DB)等。

在 Azure 的体系结构里,KARS 这类服务是夹在模型层和执行层之间的"胶水"。上面接着 Azure AI Foundry 这样的模型服务平台,下面接着 AKS、Container Apps、边缘集群这些实际的算力位置。它把模型层的推理能力和执行层的计算能力打通,让智能体可以同时获得"聪明的决策"和"可靠的执行"。类比一下:Kubernetes 是分布式应用的操作系统,KARS 就是分布式智能体的操作系统。应用需要 CPU、内存这些资源,智能体需要工具权限、会话状态、审批流程这些资源——前者由 Kubernetes 管理,后者正是 KARS 这类基础设施要管理的。

2. 多运行时核心理念:为什么智能体需要的不止一个"运行环境"

2.1 "运行时"在智能体语境下,到底指什么

如果你把"运行时"理解为容器运行时(Docker、containerd),那"多运行时"这个概念就变得很费解——难道同一个智能体还能同时跑在两种容器运行时里?其实在智能体基础设施的语境下,"运行时"指的是智能体逻辑的执行载体和执行策略的集合,涵盖三个维度。

第一个维度是计算载体:同一个智能体的不同任务阶段,可能需要不同类型的计算资源。处理短小的意图识别请求,用 Serverless 函数更划算,秒级启动、用完即走;执行长时数据分析任务,需要持续的容器环境,还要挂载存储;调用不可信的外部工具时,则需要 WebAssembly 这种轻量级沙盒,防止智能体被恶意工具输出误导后执行危险操作。

第二个维度是交互模式:有的智能体任务是一次性的请求-响应模式,比如"根据这个日志判断故障原因";有的是流式会话模式,比如"帮我持续监控系统状态,异常时随时报告";有的是异步长任务模式,比如"每月底生成一次对账报告并发送邮件"。不同的交互模式对基础设施的要求完全不同,请求-响应模式可以走普通 HTTP 网关,流式模式需要 WebSocket 长连接,异步长任务则需要任务队列和持久化存储。

第三个维度是语义运行时:这是最容易被忽略、但实际作用最关键的一层。智能体的执行过程里有大量"软逻辑"需要被管控:工具调用的权限判定、多步执行中每个步骤的预算控制、失败场景下是否需要切换回退策略、什么时候应该停止"自主"并请求人工介入。这些逻辑不应该写死在智能体的 prompt 里,而应该由基础设施层通过策略引擎统一管理——就像 Kubernetes 不把监控逻辑写死在每个容器里,而是由 kubelet 和 controller manager 统一调度。

2.2 拆解一次智能体任务中的多运行时切换

我拿一个真实场景来拆解,你就明白多运行时是怎么回事了。假设你开发了一个"客服退款审核智能体",它要做的事情是:分析用户提交的退款申请,验证是否符合退款政策,通过后调用财务系统的退款接口打款。

整个执行链路上,不同阶段跑在完全不同的运行时里。第一步,用户的退款请求到达后,由 Serverless 函数快速调用 LLM 进行意图分类——这一步是纯计算密集,但要便宜、要快,按调用次数计费。第二步,智能体需要查询订单数据库和用户历史记录,它被调度到一个只读容器沙箱里,挂载了只读权限的数据库凭据,在这个沙箱里完成信息检索和推理。第三步,智能体得出结论"可以退款",但要真正执行退款操作,就得进入一个"策略运行时"——在这里,它的工具调用权限被策略引擎拦截,因为退款接口的写操作要求人工审批,于是智能体生成审批请求,暂停执行,等待管理员确认。第四步,管理员审批通过后,同一个智能体任务在异步后台运行时被唤醒,完成退款调用,并把执行结果写入审计日志。

这四步里,计算载体不同(函数、容器、策略引擎、后台任务队列),交互模式不同(一次调用、会话推理、暂停恢复、异步执行),语义运行时也不同(权限策略、审批策略、审计策略)。如果用传统单体应用架构的思路,你会试图把所有这些逻辑塞进智能体自身的代码里,结果就是智能体代码越来越复杂、越来越不可控。而多运行时架构的做法是:智能体只管做决策,运行时环境决定它在哪跑、能碰什么、出错了怎么办。

2.3 为什么 Kubernetes 是承载多运行时的天然底座

有人可能问,为什么不用更轻量级的方案,比如直接用函数计算加消息队列?因为函数计算适合无状态短任务,而独立运行型智能体恰恰是有状态、长时运行、对治理要求极高的。Kubernetes 的优势在于,它的扩展模型允许你基于它建立任意复杂的自定义控制面。

核心是 CRD 和 Operator 这套机制。你可以定义"AgentWorkload""ToolPermission""ReliabilityPolicy"这些自定义资源,再写一个 Operator 去协调它们。比如一个 AgentWorkload 资源被创建后,Operator 会根据它声明的运行时类型,自动在集群里创建对应的 Deployment、Service、NetworkPolicy、ServiceAccount 等原生资源。工具权限和审批策略则会被转换成 Open Policy Agent(OPA)之类的策略实例,挂载到智能体运行的网络路径上。

再加上 Kubernetes 生态里现成的基础设施能力:KEDA 支持基于事件源(消息队列长度、请求数、调度次数)的自动伸缩,让智能体可以在无事可做时缩到零个副本,省资源;OpenTelemetry 提供了统一的可观测性协议,可以让智能体的每一轮工具调用都作为 span 被追踪;NetworkPolicy 则天然支持细粒度的网络隔离,给写操作权限的 Pod 和只读权限的 Pod 分配不同的网络策略,从根本上防止越权访问。这些能力都是现成的,KARS 这类服务做的是把它们整合成"面向智能体"的抽象层,让应用开发团队不需要去理解 Kubernetes 本身的细节,就能部署和管理智能体工作负载。

3. 核心工程实践:构建可靠 AI 系统的自主容错控制

3.1 承认一个事实:LLM 智能体的故障模式是开放式的

传统分布式系统的故障模式,再复杂也是有边界的:节点宕机、网络分区、超时、限流、数据不一致。每个故障类型都有对应的处理范式。但 LLM 智能体不一样,它的错误模式是开放式的,你不知道它会在哪一步以什么方式偏离预期。我总结这几年实操中最常见的几类:

工具循环是出现频率最高的故障。智能体在某一步工具调用后没有得到预期结果,于是换一种参数反复调用同一个工具,一直打转。如果对应的工具是写操作,这就不是消耗 token 的问题了,而是直接的生产事故。上下文漂移也很常见,长时运行的对话里,智能体会逐渐"忘了"最开始的任务目标,被中间某个分支带跑偏。过度自主则是智能体在权限允许的范围内做了合理但错误的事,比如某个潜在的恶意输入诱导它调用了一个不该调用的工具。

这些故障模式的共同特点是:没法通过改进模型来根治。你换更大的模型、更好的 prompt,只能降低发生概率,不能消除。这就是为什么要把自主容错控制放在基础设施层来做,而不是期望智能体自己"靠谱起来"。

3.2 分层的自主容错控制模型

我在实际项目中验证有效的一套容错框架,分为四层:检测、决策、恢复、防护。

检测层负责"发现问题"。核心手段是三类信号叠加:执行指标(每轮工具调用的耗时、token 消耗速率、工具调用的频率分布)、行为模式分析(连续 N 次调用同一个工具且结果未改变,判定为疑似循环;任务步骤超过预设上限,判定为疑似失控)、外部反馈(被调用的外部系统返回的异常码,也是个重要信号,比如数据库查询超时、API 返回 429)。这三类信号实时汇入流式分析管道,由规则引擎和机器学习模型共同判定异常级别。

决策层负责"判断怎么处理"。判定结果被映射到一组预设的动作上:重试(采用指数退避)、切换(换一个等价工具或备选路径)、降级(从自主模式切换到半自动模式,关键操作改为人工审批)、终止(立即停止执行并保存当前状态快照)。决策的关键原则是渐进式干预:先轻后重,能重试就不终止,能让智能体自己恢复就不打断它。

恢复层负责"回到正确状态"。这里借鉴了数据库事务里保存点的思想:在智能体执行的每个里程碑节点保存会话快照,包括当前的上下文摘要、已执行的任务列表、已产生的副作用、每步工具调用的输入输出缓存。一旦发生需要回滚的事故,就从最近一个"干净"的保存点恢复,而不是从零开始。副作用补偿也很重要,比如智能体已经创建了一个订单但接下来一步失败,恢复动作需要优先处理这个"孤儿订单",而不是让它留在系统里。

防护层是最后一道闸门,也是最硬的约束。熔断器在连续失败超过阈值后自动断开,同时触发人工告警;限流器保护下游系统不被智能体突发流量打崩;权限边界则确保智能体在任何情况下都不能越权访问敏感操作。这层逻辑必须是强制的,就算智能体的最终判断是要执行某操作,防护层也可以基于预设策略直接拒绝。

3.3 可靠智能体的四个工程支柱

容错控制是"运行时"的事,但构建一个真正能上生产的智能体,还需要四个层面的工程设计配合。

支柱一是资源隔离与配额。每个智能体实例应该运行在独立的 Pod 里,配置 CPU、内存、并发上限和网络带宽限制。这不仅是资源管理问题,更是故障隔离问题。某个智能体实例失控打满 CPU,不能让整个集群的其他智能体都跟着遭殃。同时,为每类智能体配置独立的 API 配额和 token 预算,防止单个任务的失控推理消耗掉整个团队的模型预算。

支柱二是会话状态的持久化与序列化。智能体的会话状态必须支持任意时刻的保存与恢复。这意味着状态不能只存在于内存里、也不能只存在于模型上下文中,而是要结构化的存储下来:当前任务目标、已执行步骤、工具调用的结果缓存、局部的决策推理摘要。我用过一个粗浅的方案是把整个对话历史存成 JSON,但很快发现恢复时上下文太长导致 token 成本爆炸。后来改为"摘要 + 关键细节"的分层存储:全量历史存冷存储,近期状态摘要存热存储,恢复时只加载摘要和最近几轮的完整上下文。

支柱三是审批闸门与人工接管机制。不是所有操作都适合让智能体自主执行。我的经验是,写操作默认走审批闸门,读操作可以自主执行但需要审计。审批要通过消息队列与聊天机器人打通,管理员在即时通讯工具里点一下就能完成审批,不能让审批流程变成负担,否则团队会为了省事直接放开所有权限,失去这条防线的意义。

支柱四是端到端的可观测性。从模型调用到工具调用、从决策过程到最终执行结果,每一步都要有结构化日志和链路追踪。这里我强烈建议全面接入 OpenTelemetry 标准,对应的 trace span 带上智能体标识、任务标识、轮次号、工具名、权限判定结果这些维度的属性。出了问题,你要能在几分钟内定位到是第几轮决策、哪次工具调用、基于什么上下文做出了错误选择,这是智能体上生产的基本要求。

4. 实操参考:搭建一个最简的多运行时智能体基础设施

4.1 最小基础设施清单与部署顺序

动手之前先列一个清单。要跑起一个"能自主执行、有容错控制、可审计"的智能体,需要以下几类组件:

  • 一个 Kubernetes 集群。本地测试可以用 Kind 或 Minikube;生产可以基于 AKS。建议先不管集群规模,用单节点开发集群验证流程。
  • 一个模型服务端点。可以直接用 Azure AI Foundry 的模型部署,也可以用一个本地的 Ollama 实例跑测试模型,关键是能通过 OpenAI 兼容协议访问。
  • 一个状态存储。Redis 就够了,用于保存会话快照和工具调用结果缓存。生产环境建议托管 Redis 或 Cosmos DB。
  • 一个消息队列(可选但强烈建议)。用于异步任务调度和审批通知。Kafka、RabbitMQ、Azure Service Bus 都可以。
  • 一个可观测性栈。OpenTelemetry Collector 加 Prometheus 加 Grafana,部署成本低,排查问题价值巨大。

部署顺序有讲究。先把可观测性栈部署好,再部署状态存储和消息队列,最后部署智能体运行时服务。原因很简单:运行时服务本身的启动过程就需要状态和队列的依赖,而排查部署问题则完全依赖日志和监控。顺序反了,多半会陷入"不知道哪里出了问题"的困境。

4.2 用一个概念型 AgentWorkload 配置走通全流程

写一个概念示意配置,看了你就明白 KARS 这类服务管理智能体工作负载时的核心对象长什么样。注意,下面这份配置是参考模型,用来理解设计思想,实际产品形态可能不同。

apiVersion: kars.example.io/v1alpha1 kind: AgentWorkload metadata: name: refund-helper namespace: ai-agents spec: image: registry.example.cn/ai-agents/refund-helper:v1 model: endpoint: "https://ai.example.com/deployments/gpt-4o-mini" apiVersion: "2025-01-01" runtime: type: multi sandbox: restricted instances: - name: intent-classify mode: serverless maxReplicas: 20 - name: context-agent mode: container resources: cpu: "500m" memory: "1Gi" - name: write-actions mode: container resources: cpu: "1" memory: "2Gi" tools: - name: order-search permissions: [read] endpoint: "https://svc.example.cn/orders/search" - name: refund-execute permissions: [write] endpoint: "https://svc.example.cn/refund/execute" requireApproval: true approvalChannel: "teams-workflow" policy: maxTurnsPerTask: 15 maxTokenPerTask: 50000 timeoutSeconds: 300 reliability: retry: maxRetries: 3 backoff: exponential maxBackoffSeconds: 30 circuitBreaker: consecutiveFailures: 5 cooldownSeconds: 60 fallback: mode: notify-human escalationChannel: "pagerduty" state: backend: redis snapshotInterval: "30s" savepointOnMilestone: true observability: tracing: otel-trace metrics: prometheus audit: logTools: true logPrompts: false

看几个关键部分。runtime.multi表示这个智能体被拆分成多个执行模式,并在不同规模策略下运行:意图分类走 Serverless 模式,可以弹性扩展到 20 个实例处理并发请求;上下文分析走标准容器模式;写操作执行则分配更高的资源配额,因为退费操作涉及较重的外部系统同步。tools.permissions是权限控制的核心,refund-execute节点的写权限带有requireApproval标志,任何一次退费调用都会被基础设施层拦截触发审批流程,而不是直接执行。

policy.maxTurnsPerTask和maxTokenPerTask是任务级预算控制。前面提到工具循环问题,这两个参数就是兜底手段:无论模型怎么打转,触发上限就强制终止任务。reliability节点配置容错参数,包括指数退避重试、熔断器阈值、故障降级时通知人工。state.snapshotInterval定义了状态快照频率,30 秒一次的频率适合大多数任务;需要细粒度恢复场景可以调低,但存储开销也会上升。

4.3 从编码智能体到多运行时智能体的渐进迁移路径

最后分享一个我实际验证过的渐进迁移路径,适合从"代码库智能体"转向"独立运行型智能体"的团队。第一步只做只读的自治扩张。把智能体从代码库挪到集群上,但只允许它调用只读权限的工具:查日志、查数据库、搜文档、读配置。这个阶段,智能体的所有输出仍然经过人工审核后才会执行。目的是验证基础设施是否能够承接智能体的运行时需求,观察它的行为模式是否符合预期。

第二步开放低频写操作并加审批闸门。比如让智能体自动创建工单、发送通知、修改低风险配置,但每一个写操作都通过审批流程。这个阶段要重点测试审批闸门本身的效率——审批链路延迟是否可控,审批信息是否足够决策,能不能在移动端快速完成审批。如果审批成了瓶颈,团队就会寻找绕过路径,那样就危险了。

第三步全量运行但保留熔断与回退。当智能体在低频写操作上积累了足够的正确率数据后,逐步提高自主执行的限额,但保留三层底线:熔断器一定打开,预算控制一定生效,人工接管通道一定畅通。同时建立持续的可靠性评估机制,每个任务完成都要记录是否出现异常、是否触发过熔断、是否需要人工介入,按月汇总成可靠性报告。我的实际操作体会是:迁移失败率最高的环节不是基础设施,也不是模型能力,而是团队对"智能体犯错"的心理预期没有建立起来。基础设施只能降低犯错的影响面,不能保证零错误。接受这一点,做好降级预案,智能体生产化才能真正落地。

5. 常见问题与避坑实录

5.1 问题速查表

典型问题表现特征根因分析推荐解法
智能体陷入工具循环同一工具被高频调用,结果不变模型对工具输出产生"幻觉响应"式预期设置 maxTurns 上限,结合行为模式分析触发熔断
会话恢复后丢失上下文长时任务运行中断后,恢复时行为偏离状态存储只保存了对话原文,没有保存决策摘要采用摘要+关键细节的分层会话存储
审批闸门变成流程黑洞团队为了省事直接放开写权限审批链路太繁琐,阻碍效率审批接入即时通讯工具,一键完成,设置审批时效自动升级
模型 token 预算超支账单暴涨,单个任务消耗大量 token循环调用和无效推理没有被预算控制设置单任务 token 上限,触发上限即终断
下游系统被突发流量打崩外部 API 返回大量 429/5xx智能体任务并发调度和级别不受控配置 per-agent 桶限流,并对下游调用应用指数退避

5.2 我在实测中踩过的几个坑

坑一:把保存点做得过于频繁。我最初设置每 5 秒保存一次会话快照,结果 Redis 内存直接被打爆。后来才意识到,保存点不是越频繁越好,快照的目的是"灾难恢复时能回到一个干净状态",而不是"实时备份"。后来改为里程碑式保存,即每一步工具调用完成后保存一次,30 秒间隔做一次时间级兜底,效果好了很多,存储开销降低了近七成。

坑二:模型上下文中塞了太多历史工具调用结果。某次任务执行 20 轮之后,上下文里积累了十九轮工具调用的完整输入输出,模型开始出现严重的"注意力漂移",几乎忘了最初的任务目标。排查后发现是因为状态存储只存了原始对话,恢复时只能全量加载。解决方法是改造存储模型,恢复时只加载任务目标、当前进度摘要和最近三轮的完整上下文。

坑三:没给审批设计超时自动升级机制。调度层面的问题,某次线上事故的审批请求等了 40 分钟无人处理,智能体任务一直挂着,占用了长时运行实例的资源,还阻塞了后续队列里的任务。后来加了审批时效机制:5 分钟未审批自动升级到值班负责人,10 分钟仍无人处理则自动关闭任务并通知所有人。这条经验特别重要,因为智能体任务往往不是一个人在盯,没有升级机制就会"无人认领"。

坑四:低估了网络策略的隔离作用。最开始我图省事,所有智能体实例共享同一个 ServiceAccount 和 NetworkPolicy,结果某个实验型智能体拿到了不该有的写权限,还好及时发现没有造成真实事故。后来严格按权限等级拆分网络策略:只读智能体、写操作智能体、审批模式智能体各自独立组网,工具访问凭据通过 Secret 单独挂载。别嫌麻烦,智能体环境的隔离网是最值得投入的部分。

5.3 设计取舍与我的个人建议

关于智能体基础设施,一个很大的设计张力是:基础设施管得太多,智能体的灵活性和迭代速度会受限;管得太少,生产事故早晚会找上你。我的取舍原则是:凡涉及"钱、数据、对外动作"的操作,一律从严治理;凡属于"分析、生成、建议"的输出,尽量放开。换句话说,用确定性约束保护不确定性决策——让模型充分释放它的智能潜力,同时让基础设施牢牢守住执行边界。

另一个重要建议是,在设计基础设施时就考虑"标准层"的抽象。Kubernetes 的扩展机制允许你自定义资源,但如果你每个团队都自己定义一套智能体配置规范,后续统一治理就是灾难。最好在一开始就建立一套企业内部统一的 AgentWorkload 规范,各家团队在这套规范上扩展,而不是各自造轮子。

最后再多说一句。我个人在实际操作中体会最深的,不是某个具体的部署细节或配置参数,而是智能体基础设施本质上是在做"信任边界"的工程。你愿意让一个自主系统碰多少东西,取决于你能容忍它多少错误。基础设施的意义不是消灭错误——那是不可能的,而是在错误发生时,把影响范围控制在可接受的程度内,并且留下足够清晰的痕迹让你复盘。想清楚这一点,你在设计多运行时架构时,很多纠结就会迎刃而解。