
开头先亮观点Agent Harness 和 Agent Runtime 是智能体开发里最容易被人混着说的两个词。你去翻开源项目、看技术博客、跟做 Agent 的工程师聊天会发现很多场景下这俩词被当成同义替换来用。有人管编排循环叫 Runtime有人把工具调用框架叫 Harness还有人干脆统一叫Agent 框架。这种混乱不是小事它直接影响你怎么设计系统、怎么分工、怎么定位线上问题。我最早做智能体项目时也踩过这个坑花了好几天排查一个Runtime 层的问题最后发现根因在 Harness 层的策略编排上相当于在发动机里找空调的毛病方向完全错了。这篇就把两者的边界彻底拆开讲清楚。先说明白一个事实这不是纯粹的理论概念辨析。你只要真的动手写过 Agent 系统的核心逻辑一定会撞上两者边界模糊带来的实际问题——比如回调该挂在哪一层、状态同步该谁负责、工具调用失败该由哪边兜底。这些问题不搞清楚代码写得再漂亮跑起来也是提心吊胆。这篇文章适合刚接触智能体开发、准备选型或自研框架的工程师也适合已经把系统跑起来但总觉得架构哪里不对劲的团队。先说个我观察到的现象绝大多数关于 Agent 的教程讲的是模型怎么调用、工具怎么注册、上下文怎么拼。这些内容确实重要但它们几乎全部停留在 Runtime 层面。而真正决定一个 Agent聪明不聪明的上层策略——比如什么时候该追问、遇到冲突怎么决策、多步任务怎么拆解——属于 Harness 的职责范畴。很多人把这两层混为一谈导致项目一开始就没分清边界。等到要扩展、要加功能、要排查问题时代码里到处都是越层的逻辑改一处崩三处。所以这篇文章的目的很直接帮你在动手之前把这两个概念的边界钉死在心里。1. 两者的本质差异调度边界与控制边界先给出一个最直观的区分方式Runtime 是执行引擎Harness 是操控台。你可以把 Runtime 想成发动机它负责把燃料转成动力把模型调用转成具体的函数执行而 Harness 是驾驶舱里的仪表盘和方向盘它决定什么时候踩油门、什么时候转弯、遇到障碍物怎么处理。这个类比虽然朴素但足够帮你在脑子里建立一个基本框架。1.1 Runtime 的职责边界对执行负责Runtime 管的事情非常纯粹模型推理、工具调用、上下文管理、内存分配。你可以把它理解成一个无脑但高效的执行者。你告诉它调用 get_weather(tomorrow, beijing)它就去调用然后把结果返回。它不关心为什么要调用这个函数也不关心调用结果之后应该做什么——那是 Harness 的事。从技术实现看Runtime 的核心组件包括几个部分模型适配层把不同的模型 API 统一成一套接口、工具执行器负责把模型的函数调用参数映射成真实代码执行、会话状态管理保存对话历史、上下文窗口的滑动和截断策略、以及阻塞/异步调度的底层机制。这里有个容易被忽略的细节Runtime 的上下文管理绝不仅仅是把历史消息拼在一起。它要做 token 计算、长度控制、关键信息优先级的重新排序这些策略虽然看起来有点智能但本质上是执行层为了让模型能正确处理输入而做的工程优化不是决策行为所以仍然属于 Runtime 的范畴。有一个很典型的现象能帮你判断一个组件是不是 Runtime 的一部分_它是否在每次 Agent 运行循环中都会被调用到且不需要决策。比如把用户消息转成模型输入格式这个过程没有任何分支判断是纯粹的执行逻辑属于 Runtime。而决定此时是否需要调用工具、还是直接回复用户——这是需要决策的属于 Harness。1.2 Harness 的掌控范围对策略负责Harness 的逻辑层次比 Runtime 高。它负责的核心问题是Agent 该如何决策、如何规划、如何从错误中恢复、何时终止。用实际例子来说。一个简单的多工具 Agent 在工作时会面对这种情况用户说帮我查一下明天杭州飞深圳的航班然后看看那边天气怎么样。系统先要查询航班列表然后根据航班落地时间查询天气。这个先查航班、再查天气的顺序是谁决定的不是 Runtime而是 Harness 中的规划模块在决定。它把用户的大目标拆解成子任务按依赖关系排序再逐个交给 Runtime 去执行。Harness 还负责处理更复杂的决策场景。比如模型返回了一个格式错误的工具调用参数Harness 需要决定是重试一次、还是换个方式重新提问、还是直接放弃并告诉用户我无法处理。这个错误处理策略本质上是控制逻辑不在执行逻辑的范畴。同理当可用工具数量很多时Harness 负责做工具选择——只把当前任务相关的工具暴露给模型而不是把所有工具的说明一股脑塞进上下文里。我把两者之间的核心差异用一个表格来呈现方便对照理解维度Agent RuntimeAgent Harness核心问题怎么执行执行什么、何时执行典型模块模型适配、工具执行、上下文管理任务规划、工具选择、错误恢复策略决策层级无决策遵循指令有决策基于策略状态变更会话状态记录任务状态迁移失败类型执行失败API 报错、参数异常策略失败方向错误、规划不合理变更影响影响所有任务的执行效率影响 Agent 的智能水平和行为模式这个表格可以作为团队内部评审架构时的参考清单。如果你在设计系统时发现某个模块的属性在两个维度之间摇摆不定说明边界划分有问题需要重新考虑职责归属。1.3 划清界限后对系统设计的三个直接影响边界划清楚的意义不只是概念上爽它对工程有实打实的好处。我总结了三个最直接的影响第一故障定位效率提高一个量级。当一个 Agent 系统出问题时你首先能判断问题来自哪一层。模型反复返回错误格式——大概率在 Runtime 的工具执行器或模型适配层Agent 的行动方向完全不对比如用户问天气它却去查航班——这是 Harness 规划策略出了问题。有了这种第一时间的判断排查范围直接砍掉一半。第二团队分工明确。做 Runtime 的人关心延迟、吞吐、稳定性、上下文利用率做 Harness 的人关心策略效果、任务成功率、决策准确性。这两拨人的 KPI 是不同的如果混为一谈会出现谁都在改、谁都不负责的局面。我见过一个团队Agent 的规划逻辑写在 Runtime 的工具调用回调里结果每次改策略都要重新做回归测试部署节奏被拖慢了一倍。第三框架选型有依据。如果你想用 LangGraph、AutoGen、CrewAI 这类现成框架你得先分辨它们的哪部分属于 Runtime、哪部分属于 Harness。有些框架擅长编排Harness 强但执行层偏弱有些框架执行效率很高但策略扩展困难。搞清楚两者的边界你就知道应该在哪个层面做自定义扩展而不是把框架的每个角落都改一遍。有一点值得补充现代 Agent 框架里Runtime 和 Harness 并不一定由同一个团队开发甚至可能来自不同的开源项目组合。这种情况下明确接口约定尤其重要。Runtime 对外暴露什么接口、Harness 如何通过该接口控制执行流必须形成清晰的契约文档否则两个独立发展的组件会越走越远最终无法集成。2. Agent Harness 的构成拆解决策层的实际面貌光说不练是空谈。这一节我直接用工程视角拆解 Harness 应有的组成模块。这里讲的不是某一个具体框架的实现而是基于多智能体系统和单 Agent 协作场景的通用抽象。2.1 四个关键模块规划器、调度器、记忆访问控制、策略注入规划器Planner是 Harness 的大脑随身版。它接收用户目标输出一个可执行的步骤序列。最简单的实现是 ReAct 模式模型不断交替生成思考-行动对直到任务完成。但工业级系统的规划器没这么简单它要考虑资源约束不能无限循环、步骤间的依赖、以及当前上下文已经获得了哪些信息。规划器通常会被设计成可插拔的因为不同任务的规划策略差异很大——一个客服机器人的规划器和一个代码生成 Agent 的规划器工作方式完全不同。调度器Dispatcher是 Harness 的动作派发员。它根据规划器给出的步骤决定在什么时机调用 Runtime 的哪个执行函数。调度器还要处理并发问题。比如规划器生成了三个可以并行执行的子任务调度器要决定是同时并行、还是按优先级顺序执行。并发控制、超时管理、以及部分成功场景的处理都在调度器的职责范围内。记忆访问控制Memory Access Control是个容易被忽视的模块。Agent 的记忆分成短期工作记忆当前对话上下文和长期存储向量数据库里的历史信息。Harness 层面的记忆访问控制要做的事情是判断当前这一步是否需要查询长期记忆、查询哪部分记忆、以及如何把检索结果融入到当前上下文中。这是决策不是执行——所以它不属于 Runtime。很多团队把记忆模块直接塞进 Runtime结果导致记忆的读写策略和模型的调用逻辑耦合在一起每次调整记忆策略都要动底层执行代码造成不必要的风险。策略注入Policy Injection是 Harness 的规则引擎。它负责把业务规则、安全限制、风格约束等注入到决策过程。举个具体例子一个金融客服 Agent被要求当用户询问收益率时必须同时提示风险。这个规则不是模型天然知道的需要通过策略注入在决策层面强制生效。在设计 Harness 时策略注入模块必须支持动态更新否则每次改规则都要重新部署整个服务这在业务快速迭代的场景下完全不可接受。2.2 Harness 在两种主流框架里的实际呈现接下来我结合两个业界常用的开源框架看看 Harness 在这些项目里长什么样。先看 LangGraph。LangGraph 本质上是一个状态机驱动的编排框架它的核心抽象是 Graph——节点Node和边Edge。在 LangGraph 里你可以显式定义条件边比如某个节点执行完后根据结果内容决定跳到哪个节点。这套机制就是典型的 Harness 实现。你可以用 LangGraph 实现非常复杂的决策流重试循环、人工介入节点、并行分支汇聚等等。它甚至内置了检查点机制用于在步骤之间持久化状态——这是 Harness 层的状态管理而非 Runtime 的会话记录。再看 AutoGen。AutoGen 的核心概念是对话式多智能体协作。它通过 Conversations 和 Agent 之间的消息传递来实现任务协作。这个框架的 Harness 特征体现在对话模式上——你可以定义两个 Agent比如一个 Assistant 一个 Critic进行多轮对话直到达成共识。谁来控制对话的结束条件谁来决定下一个发言的是谁答案都在 AutoGen 的 Harness 层机制里。这两个例子想说明的是当你选型框架时要主动识别框架中哪些部分是你需要的 Harness 能力哪些是它的 Runtime 底子。如果框架的 Harness 能力太弱你可能要自己搭一层编排逻辑如果 Harness 能力很强但 Runtime 不满足你的性能要求你就得考虑替换或者绕过它的执行层。搞清楚边界后这类判断会清晰很多。2.3 Harness 设计常见误区把控制逻辑散落在应用各处我在实际项目中见到最多的一个错误是无意间把 Harness 的决策逻辑打散到 Runtime 和应用代码的各个角落。举个例子有个团队做客户支持 Agent他们的代码里用户在对话中点击转人工按钮时应用层直接调用了一个人工接管函数然后这个函数又在某个回调里修改了对话上下文的状态——这个流程看起来没问题但实际上跨了三层职责应用层发起了决策、Runtime 回调做了状态变更、而真正的转人工策略比如判断是否应该先让机器人再尝试一轮没有形成统一入口。后续要修改转人工的触发条件时团队成员找了半天才定位到分散在三个文件里的逻辑改一处还得同步另外两处。正确的做法是所有决策点都由 Harness 暴露成统一接口。转人工就是一个策略应该以Harness 监听某个事件 - Harness 决策 - Harness 调用 Runtime 的方法切换会话状态这样的链路来设计。哪怕初始实现简单一点也要让控制流的拓扑是清晰的。3. Agent Runtime 的执行基础设施别把这些内容算到 Harness 头上如果说 Harness 是决策层那 Runtime 就是支撑所有决策落地的执行基础设施。这一节的重点是帮你识别什么必须放在 Runtime以及 Runtime 的设计会怎样影响上层 Harness 的可控性。3.1 模型适配、工具执行与上下文管理的内部细节模型适配Model Adapter是 Runtime 最底层的一环。它的职责是抹平不同模型之间的差异——不管是 OpenAI 格式、Claude 格式、还是开源模型的自定义格式适配层统一成内部接口供上层调用。一个好的模型适配层不仅仅是把请求格式做转换它还要处理模型服务的重试策略、token 速率限制、模型返回流式与批量的切换。你会遇到一个现实问题不同的模型对同样工具定义的写法有细微差别有的支持并行函数调用有的必须串行适配层要把这些差异消化掉让 Harness 的规划逻辑感觉不到底层的模型变化。工具执行Tool Executor是 Runtime 里最容易出问题的部分。模型返回一个调用函数A参数是{...}的指令工具执行器要解析参数、校验参数、执行函数、捕获错误并返回给模型。这里有大量工程细节参数不匹配怎么办模型经常编造参数、函数执行超时怎么办、函数返回结果太大超出上下文怎么办。成熟的执行器要做 schema 校验、超时熔断、结果截断。这中间参数解析和校验虽然看起来带有一些判断色彩但它的本质是机械性的格式匹配不是策略决策。你要确保这一类逻辑留在 Runtime让 Harness 专注于更高层的要不要调这个工具的决策。上下文管理Context Manager负责构建模型每次调用时的输入。它要考虑的事情包括历史消息如何截断只保留最近的 N 轮还是按 token 窗口比例截断、工具调用的中间结果如何嵌入到对话流、系统提示词如何与动态检索的内容叠加。上下文管理对模型响应质量的影响极其显著。同一个模型上下文拼得好与拼得差效果差距可能达到 30% 以上。但它的本质仍然是对已有信息的工程化组织——不涉及策略决定所以放在 Runtime 层是合适的。如果这里做的不够好上层 Harness 的规划再怎么聪明模型也看不到必要的信息效果一样打折扣。3.2 Runtime 层常见的性能瓶颈与扩展挑战Runtime 的性能瓶颈往往集中在上下文管理和模型调用的吞吐上。上下文管理的瓶颈主要在重复计算。每次模型调用都需要把全部历史消息序列化成 token如果每次都是从原始消息列表重新编码一遍token 消耗和时间开销都会指数级增长。工业级实现通常会做累加式 token 计算——增量编码新消息复用之前缓存好的前缀 token。这需要非常细致的内存管理属于 Runtime 里的硬核优化方向。模型调用的吞吐问题来自外部 API 的速率限制和网络延迟。一个 Agent 任务可能包含 10 次到 20 次模型调用如果串行执行用户体验会非常糟糕。Runtime 要做的是尽可能将独立的模型调用并行化同时对同一 key 的调用做并发配额管理。这层优化与 Harness 的调度息息相关但实现机制完完全全属于 Runtime。一个设计良好的 Runtime 会给 Harness 暴露足够的并行控制接口让上层能够表达这 3 个子任务可以并行执行而具体的并发实现完全由 Runtime 完成。3.3 Runtime 状态管理与 Harness 状态管理的分界点很多人在状态管理上栽跟头。要搞清楚这个先理解两种状态的本质不同Runtime 维护的是会话状态Session State——对话历史、上下文 window 的内容、消息 ID、模型调用的中间产物。这些状态是执行过程的信息留存它们的生命周期跟随对话会话。Harness 维护的是任务状态Task State——当前目标是什么、已经完成了哪些步骤、下一个计划动作是什么、当前处于哪个决策分支。任务状态的生命周期跟随一个完整的任务执行过程一个会话里可能包含多个任务。这两类状态必须分开存储、分开维护。我见过一个团队把所有状态都塞到一个 Redis 对象里用一个大 JSON 包含会话历史加任务进度结果每次并发更新都会出现写冲突而且排查问题时分不清某个字段是执行痕迹还是决策依据。后来他们把状态拆成两层Runtime 的会话状态用消息队列做有序写入Harness 的任务状态用独立的事务性存储问题迎刃而解。有一个简单方法来判断一个字段该放哪层如果这个字段是给模型看的会作为输入传给模型放在 Runtime 层如果这个字段是给决策模块看的影响下一步动作的选择放在 Harness 层。这条规则在绝大多数场景下都准确。4. 边界模糊的常见陷阱与应对方式真实项目中的拉锯战理论讲清楚了接下来进入实战中最痛苦的环节真实项目里两者的边界经常被各种需求拉扯到模糊。我总结了几类最常遇到的陷阱。4.1 陷阱一把工具调用的决策逻辑写进 Runtime 的回调里很多框架允许你在工具调用前/后挂载 hook回调函数。于是不少人顺手就把决策逻辑写进回调里——比如如果工具 A 返回的值大于 100就自动调用工具 B。这个逻辑看起来方便但它是在 Runtime 的执行链路里完成的绕过了 Harness 的统一规划。这样写的问题马上就会出现当你希望整体决策策略能根据上下文动态调整时比如用户是 VIP 时走一条路径、普通用户走另一条路径你没办法在 Harness 层统一控制因为决策逻辑分散在 Runtime 回调的各个角落。排查问题时也是一样你很难回答为什么系统会自动调用工具 B因为触发条件藏在一个不显眼的回调文件里。应对方式回调只做事件通知不做决策。工具执行完的回调里只做数据格式转换、写入事件日志然后把结果返回给 Harness 的调度循环去统一决策。刚开始你可能觉得多绕了一层很麻烦但当地决策逻辑变复杂时这个分层带来的收益会远超多出来的那一点样板代码。4.2 陷阱二让用户确认这一步该放哪涉及人工介入的场景是边界最模糊的地方。一个 Agent 在执行关键操作前需要向用户确认你确定要这样做吗。这个让用户确认的逻辑放在哪一层放在 Runtime不对因为 Runtime 并不能决定什么时候需要用户确认——这个触发条件是策略由业务规则驱动的。比如涉及转账的操作必须人工确认而普通查询不需要。放在 Harness对因为是否需要人工介入和如何暂停任务等待用户输入是典型的决策与编排逻辑。Harness 应该提供暂停/恢复机制当规划器发现当前步骤需要用户授权时它将任务状态挂起到等待确认状态等到用户输入事件到达后再唤醒任务并继续后续步骤。区分这类问题的通用方法很简单如果某个行为在同等条件下对所有用户都一致执行可以考虑放 Runtime如果它会根据业务场景、用户属性、上下文而变化必须放 Harness。用户确认是典型的策略型逻辑放 Harness 就对了。4.3 陷阱三框架默认行为把你带偏还有一个隐蔽的陷阱——开源框架的默认行为会无意中把边界推向你不想看到的位置。比如某些框架允许你在创建 Agent 时传入一个固定的 System Prompt这个 Prompt 会由 Runtime 在每次调用时自动附加。如果团队把业务策略直接塞进 System Prompt当用户情绪激烈时必须转人工这块策略逻辑就掉进了 Runtime 层的犄角旮旯里——修改策略需要改 Agent 定义、重新部署、甚至要做对旧任务的迁移麻烦至极。应对方式把 System Prompt 里不变的执行指令工具使用的格式说明、输出 JSON 的 schema放在 Runtime 的固定部分把变化的策略内容业务规则、当前营销活动话术、敏感话题处理方式作为变量经由 Harness 在每次任务执行时动态注入。这样一来策略调整就不需要动 Runtime 代码了。5. 判别一个 Agent 组件归属的实操标准三问法讲了这么多你很可能需要一个简单好用的判别工具帮你在实际开发中快速判断某个组件到底属于 Harness 还是 Runtime。这里分享一个我用了很久的三问法。5.1 三问法详解问自己三个问题每个问题都有一个明确的倾向性答案问题一去掉这个组件Agent 还能正常跑吗如果去掉后Agent 依然可以完成基础的工具调用和模型推理只是不够聪明那这个组件大概率属于 Harness。如果去掉后Agent 连基本的调用个函数返回结果都做不到那它是 Runtime 的一部分。问题二这个组件的失败会以什么形式暴露如果失败表现为模型输出了异常内容、工具调用返回明显错误、程序直接报错——这是 Runtime 层的失败。如果失败表现为模型输出了合理但方向错误的内容、执行了不合适的步骤、任务最终没达到目标——这是 Harness 层的失败。问题三改一行策略需不需要重新部署整个系统如果策略调整比如修改什么时候该转人工的触发条件应该只是改配置、改规则脚本、甚至只是改一段 Prompt 模板——那么这个策略必须由 Harness 管理。如果它被硬编码到 Runtime 的执行逻辑里你就被迫做全量部署。反过来说如果修改的是模型调用重试次数、超时阈值这类执行参数虽然也是配置项但它们属于 Runtime 的调优维度。你要注意这个三问法并不是一个绝对严谨的逻辑推导而是一个帮助你快速建立直觉的启发式方法。用的次数多了你会慢慢形成一种条件反射看到一个组件自动评估它是在影响Agent 的思考还是在影响Agent 的行动。5.2 用三问法分析一个真实组件记忆模块拿记忆模块来做一个完整的分析演练。假设你在设计一个带长期记忆的 Agent 系统记忆模块要从向量数据库中根据用户问题检索相关信息然后注入上下文。第一问去掉记忆模块Agent 还能正常跑吗能跑但每次对话都是失忆状态。所以它不影响基础执行能力。第二问它的失败形式是什么如果检索结果为空模型会正常且自信地回复一个基于无记忆状态的答案——不会报错但不准确。这是方向性的错误不是执行异常。第三问检索策略调整需要重新部署吗比如原来召回 top-3 条记忆现在想改成按时间衰减加权召回 top-5 条——这是策略调整理想情况下应该以配置或动态规则的形式完成而不是改一坨 C 代码重新编译。三个问题的答案全部指向 Harness。所以记忆访问控制确实应该由 Harness 负责——但注意这里说的是访问控制与召回策略而不是向量检索的物理实现。向量数据库的连接、相似度检索的计算这些底层执行逻辑属于 Runtime 的基建Harness 只是在决策层面决定要不要查、查什么、查完怎么用。又是一个典型的边界问题——同一件事里同时包含了两个层的职责这才是实际工程里最考验架构能力的地方。6. 一次完整的 Agent Harness 与 Runtime 协作实例电商客服系统概念全部讲完用一个完整的实例把整个协作过程串起来。假设你在做一个电商客服 Agent用户向它询问我上周买的手机壳到现在还没发货能帮我查一下吗6.1 一次查询请求在两层之间的完整流转Harness 层——规划与调度开始Harness 接收用户消息规划器判断这是订单查询意图拆解任务步骤先获取用户身份 - 获取订单信息 - 判断订单状态 - 决定回复策略。调度器发现获取用户身份需要调用一个用户服务接口于是向 Runtime 发起工具调用请求。Runtime 层——执行动作3. Runtime 收到调用请求通过工具执行器调用用户服务接口拿到用户 ID。 4. Runtime 将工具调用和返回结果都记录到上下文状态中并把结果返回给 Harness。Harness 层——继续决策5. Harness 看到用户 ID 已拿到决定下一步调用订单查询接口。调度器再次向 Runtime 发起请求。 6. 订单接口返回了该订单已发货但物流信息未更新Harness 规划器需要决策直接告诉用户已发货晚点再看物流还是去调一次物流查询接口再回复规划器根据减少用户等待、优先提供确切信息的策略决定调用物流查询接口。Runtime 层——再次执行7. Runtime 执行物流查询返回包裹已到达配送站。 8. Harness 综合所有信息决定直接回复用户手机壳已经在配送途中预计明天送达同时附带一个物流链接。整个过程看起来像一个流畅的直线但实际上每一轮决策-执行的循环都是在 Harness 和 Runtime 之间来回跳转。Harness 没有亲自去访问数据库或调用 APIRuntime 也没有决定下一步要做什么。两层各司其职才构成了一个完整的 Agent 行为。6.2 这个案例暴露出来的两个边界风险点这个案例里有两个值得注意的小细节它们暴露出了边界设计的风险。第一个风险在于工具调用后结果的呈现方式。物流查询返回的原始数据可能是一个 JSON包含快递公司编码、轨迹数组、时间戳等等。直接把原始 JSON 塞给用户显然不合适。这是谁的责任我的建议是Raw 数据到自然语言的转换由 Harness 层的回复生成策略负责因为它决定了哪些信息该呈现给用户、以什么语气呈现。Runtime 要做的只是把原始结果原封不动地传给 Harness不做加工。第二个风险在于失败后的补偿动作。假设物流查询接口恰好超时了Runtime 返回了一个错误。此时 Harness 可以选重试一次、换一个物流查询渠道、或者不查物流直接回复已发货信息。这个补偿策略完全在 Harness 的决策范围内。但很多团队会把重试逻辑写在 Runtime 的工具执行器里——接口超时自动重试 3 次——这就让 Runtime 做了本该由 Harness 做的事。正确的分工是Runtime 提供一个可重试的底层 API但是否要重试、重试几次由 Harness 的业务策略决定。这样区分的好处是你可以在不修改执行层的情况下灵活调整重试策略比如用户是 VIP 时多试一次、普通用户直接放弃。6.3 如何在实际项目中落地这种分层演进式设计最后给你一个实操层面的落地建议。如果你面对的是一个从零开始的新项目或者一个代码已经比较混乱的存量项目不要试图一步到位实现完美的分层。建议采用演进式设计阶段一代码结构上物理分层。先把项目按harness和runtime两个目录/模块分开即使里面的代码还不够纯也先把路径打通。这一步成本很低但收益立竿见影——后续改代码时你会自然思考这段逻辑该放哪边。阶段二用接口隔离双方。Harness 只通过明确的接口调用 Runtime禁止 Harness 直接访问 Runtime 的内部数据结构。同理 Runtime 只能通过事件通知把执行结果告知 Harness不能直接调用 Harness 的决策函数。这个阶段会让代码量小幅增加但可控性大幅提升。阶段三逐步上收决策点。审视现有代码里散落的 if-else 决策逻辑把策略相关的部分逐步收拢到 Harness 的统一调度循环里。每收拢一个决策点就补一个测试用例保证行为一致性。阶段四状态拆分。最后处理状态归属问题。将会话状态和任务状态彻底分开存储通过事件关联而非共用可变对象。这个阶段要谨慎建议在系统相对稳定、有足够测试覆盖后再行动。这套演进路线已经在我参与过的多个项目中验证过虽然不是最快的路径但绝对是风险最低的路径。边界拆分这种事最忌讳一次性大重构——很容易改到一半发现逻辑根本跑不通最后回退又浪费时间。小步快跑每一步都要能独立交付价值这才是工程上稳健的做法。