AI Agent开发必懂:Harness与Runtime的区别与协作 📅 发布时间:2026/9/9 0:23:36 👁 浏览次数: 做 AI Agent 开发的人大概率都见过这两张脸Agent Harness 和 Agent Runtime。猛一看像是同一个东西的两种叫法再看一眼文档又发现两者经常在同一段话里交替出现。我在 GitHub issue 和社区讨论里已经见过不少人把这两个词混着讲更别提那条著名的报错——error: agent harness runtime codex is unavailable because its plugin registry...一句话里同时塞了 harness 和 runtime初学者直接看懵。这篇文章就想一次性把这两个概念拆开揉碎各自负责什么、边界在哪里、如何协作顺带把那条报错的排查思路完整走一遍。适合刚开始接触 agent 框架的开发者也适合已经被这两个词绕晕、想彻底理顺的人。1. 容易被绕晕的根源先理解它们在体系中的位置1.1 从一个真实报错切入先看这条报错的完整形态error: agent harness runtime codex is unavailable because its plugin registry ...第一次遇到的人一般会有三个疑问harness是什么runtime是什么为什么一条错误里能同时出现两个词还说其中一个作为另一个的运行时注册不了这里的关键在于在成熟的 agent 框架里Harness 和 Runtime 是两层独立的东西。Harness 是整个 agent 行为的组织者Runtime 是具体干活儿的执行引擎。报错里所谓agent harness runtime codex is unavailable翻译成人话就是组织者在启动时按名字去插件注册表里找名为codex的执行引擎结果没找到或加载失败。这个错误本身已经在暗示两者的主从关系了。1.2 一句话定位Harness 是驾驶舱Runtime 是发动机如果非要给它们一个最通俗的定位我会这样打比方Agent Harness是驾驶舱里面坐着驾驶员agent 策略面前是仪表盘状态、上下文、记忆、方向盘决策逻辑、油门刹车工具调用开关。它负责决定接下来该做什么。Agent Runtime是发动机舱真正输出扭矩、转动曲轴的那部分。它负责工具代码怎么跑、跑到什么环境里、用多少资源、出错怎么兜底。它不决定做什么只负责干得动、干得稳。开车的人踩下油门车能往前跑是因为驾驶舱的指令通过线束传到了发动机发动机再把燃烧的能量转成轮上动力。Agent 的调用链也是如此用户输入先进 HarnessHarness 编排完意图后把具体的工具执行工作交给 RuntimeRuntime 把结果返回Harness 再决定下一步。理解了这个主从关系后面所有的细节都能顺下来。2. Agent Harness 到底管什么负责怎么想的编排层2.1 Harness 的核心职责拆解我在实际项目里给 Harness 层的功能列过一个清单基本可以覆盖绝大多数框架的职责范围Agent 主循环agent loop这是最核心的一块。模型推理、工具调用、结果观察、再推理这个循环的推进逻辑就在 Harness 里。谁来触发下一轮、什么时候该停止、达到什么条件要收敛都是 Harness 定的。工具注册与调度agent 能调哪些工具、工具的参数是什么、多个工具之间的优先级和依赖关系由 Harness 统一管理。它相当于一个事件总线和路由表LLM 说要调用某个工具Harness 负责把请求正确分发到对应实现。权限与审批策略不是所有工具都要无条件放行。哪些操作需要人工确认、哪些操作被禁止、哪些目录只读、哪些命令必须加白名单这一层是安全策略的主要落点。把权限放在 Harness 而不是 Runtime好处是策略可以做到和具体执行环境解耦。状态与上下文管理对话历史、长期记忆、中间推理过程、重试状态这些状态信息由 Harness 统一维护。Runtime 执行完一个工具后不会自己保存我是谁、我在哪、刚才聊到哪这些都要回到 Harness 里面更新。插件化入口很多框架允许你用插件扩展 agent 的能力插件注册表、加载顺序、版本兼容检查通常就在 Harness 这一层做。前面那条报错里说的 plugin registry就是 Harness 加载插件时的注册表。2.2 为什么偏偏叫Harness这个命名背后是有讲究的我第一次接触这个词的时候也觉得很奇怪为什么不用Controller或者Orchestrator非要叫Harness。后来发现这个名字源自两个领域一个是马具horse harness一个是电子线束wiring harness。马具的作用不是代替马跑而是把马的力量导向车辕、约束马的行动范围、让骑手可以通过缰绳控制方向和节奏。Agent Harness 里的 Harness 就是这个意思它不产生智能智能在模型那一端它也不是执行者执行在 Runtime 那边。它真正做的是约束、导向、连接——把模型的能力套在正确的行为框架里让 agent 不至于脱缰。电子线束的类比更直白一块电路板上有很多芯片线束负责把供电、信号、地线准确接到该接的引脚上接错一根整个板子都跑不起来。Harness 之于 Agent就是那捆线束负责把所有组件按正确的方式连起来并且定义连接的顺序和约束。2.3 Harness 设计里最容易踩的几个坑把提示词工程全部塞进 Harness有些人写 agent 框架喜欢在 Harness 里做大量 prompt 拼接、few-shot 示例管理结果 Harness 变成一个巨大的字符串处理模块。我建议 prompt 模板单独分层Harness 只负责调用渲染好的模板别让自己的编排逻辑和提示词纠缠在一起否则后面改一处崩一片。状态管理各自为政有的 Harness 实现里上下文存一份、工具状态存一份、会话配置又存一份三份数据经常对不上。处理方式是把所有状态收敛进一个统一的上下文对象由 Harness 持有并负责序列化和恢复。循环控制不当引发死循环agent loop 如果没有最大轮数限制、没有重复结果检测、没有成本熔断LLM 翻来覆去调用同一个工具是真实会发生的事。在 Harness 层设计终止条件比在任何其他层都合适因为只有 Harness 能通观整个循环的全局。3. Agent Runtime 到底管什么负责怎么干的执行层3.1 Runtime 的核心职责拆解如果说 Harness 是大脑的决策回路那 Runtime 就是身体的运动系统。具体到工程实现Runtime 通常包含以下几块进程与生命周期管理工具可能是一个脚本、一个本地命令、一个远程 API 调用。Runtime 负责在正确的进程里把工具跑起来跑完回收资源超时能杀掉崩溃能兜底。这听起来简单实际上一堆细节环境变量怎么传、工作目录设在哪里、标准输入输出怎么重定向全在 Runtime 实现里。真实环境的隔离与权限落地Harness 那层定义了哪些操作允许但允许的操作怎么在物理上执行并且被限制住是 Runtime 的事。比如把 Python execute 工具跑到一个容器里、把文件操作限制在某个缀目录、把网络请求代理到指定的出口这些都是 Runtime 能力。生产级 agent 框架的沙箱、容器隔离、网络策略全部落在这一层。系统资源的供给与限制CPU、内存、磁盘配额、并发上限Runtime 在创建执行环境的时候就得把这些约束注入进去。我见过不少 agent 项目在开发环境跑得好好的一到生产就 OOM就是因为 Runtime 层没有做资源约束工具代码可以无节制地吃内存。执行结果的标准化返回工具五花八门输出格式千奇百怪。Runtime 的职责之一是把这些原始输出统一成结构化结果再交还给 Harness。这一步不做好Harness 解析工具结果就得写一堆兼容代码。3.2 Runtime 的三种典型实现形态我按自己接触过的项目把 Runtime 实现大致分成三类各有优劣进程内直接执行最简单直接在 agent 进程里调函数。适合纯计算型工具、内置信得过的工具。优点是快、零额外开销缺点是没有隔离工具一旦把进程搞崩agent 整个就没了。独立进程执行每个工具调用起一个子进程通过标准输入输出或本地 socket 通信。隔离性比进程内好一些崩了不影响主进程。缺点是跨平台行为不一致进程创建销毁有性能开销而且并发管理要自己操心。容器/沙箱执行工具跑在 Docker 容器、Firecracker 微虚机或者 gVisor 沙箱里。隔离性最强适合执行不可信代码、做多租户隔离。缺点是需要额外的资源管理和镜像维护调度链路长端到端延迟明显上升。选择哪种形态取决于你的 agent 到底要执行什么。只跑自己写的 SQL 聚合进程内足够要运行 AI 写的随机代码老老实实上沙箱否则出事就是事故级。3.3 Runtime 选型时的三个硬指标隔离强度 vs 性能开销这不是二选一而是先想清楚你的工具集里最危险的东西有多危险。没有不可信输入就不必为隔离付出过多性能成本。可观测性Runtime 跑完之后日志、指标、调用链能不能方便地透出到监控系统直接决定你排障时的体验。很多框架死在工具执行失败但没有任何日志这种局面。跨平台一致性如果你的 agent 要同时跑在本机 macOS、CI 里的 Linux、生产环境 K8s 上Runtime 的路径处理、shell 行为、权限模型必须保持一致。我在这方面吃过亏本地用/bin/bash -c写得好好的Windows 上直接废掉。4. 一张表看懂区别Harness 与 Runtime 的对照4.1 核心维度对照表用表格对照永远是区分两个概念最高效的方式下面这张表来自我的项目复盘对比维度Agent HarnessAgent Runtime核心定位决策编排、行为控制任务执行、环境承载回答的问题接下来做什么这件事怎么跑起来主要载体主循环、上下文、插件注册表进程管理器、沙箱、资源控制器与模型的关系直接与 LLM 交互、构造推理链路一般不直接接触模型与工具的关系选择哪个工具、何时调用把选中的工具真正执行出来权限落地定义策略能做什么执行策略怎么限制住状态管理持有全局状态、记忆、会话只维护执行态、不关心全局上下文典型故障死循环、上下文溢出、工具选错崩溃、超时、资源不足、隔离被绕过这张表每一条都能对应到具体的代码模块。你在一个框架里找agent loop、context manager、tool registry基本就是在找 Harness 的实现找进程执行器、sandbox、execution backend基本就是在找 Runtime。4.2 一次完整 agent 调用的时间线为了把两者的协作讲透我描述一条完整调用链读者可以对照着自己的框架验证用户输入到达 HarnessHarness 把当前上下文、历史、系统提示打包发送给 LLM。LLM 返回一个工具调用请求比如execute_python参数是一段代码。Harness 收到请求后先走策略该工具在白名单里吗参数有没有触碰禁止项需要管理员审批吗这些都过了才继续。Harness 拿着工具名去注册表查具体执行实现拿到实现引用之后把它交给 Runtime。Runtime 创建一个隔离的执行环境注入参数运行代码拿到 stdout、stderr、退出码再把这些标准化返回给 Harness。Harness 把执行结果作为新的观察observation写回上下文然后判断循环是继续还是终止如果继续带着新上下文再问一次 LLM如果满足终止条件收敛并返回最终答案。整条链路里第 2、3、4、6 步是 Harness 的地盘第 5 步是 Runtime 的地盘。区别在哪个模块写了什么逻辑看得非常清楚。4.3 边界并不总是清晰三类容易重叠的场景工具选择也带了执行逻辑有的框架在工具注册时就直接把实现对象塞进注册表Harness 调工具时实际上对象自己负责执行这时候选择和执行的边界就模糊了。解法是把工具对象拆成 spec声明 backend实现spec 归 Harness 管backend 归 Runtime 管。状态同步跨层某些框架出于性能考虑把上下文快照直接放进了 Runtime 的共享内存里导致 Harness 状态和 Runtime 状态出现双写。这种设计不是不行但必须有明确的同步协议否则并发场景下必然出现状态漂移。插件既扩展 Harness 又扩展 Runtime一个插件往往同时注册了 Harness 层的工具定义和 Runtime 层的执行器这没问题但你要清楚它到底改的是哪一层。改执行器不动策略和改策略不动执行器对系统的影响范围完全不同。5. 实战排障拆解那条harness runtime 不可用的报错5.1 报错信息逐个词看回到开头那条报错error: agent harness runtime codex is unavailable because its plugin registry ...逐词拆解agent harness runtime这里指的是挂在 Agent Harness 下的 Runtime也就是说 Harness 在启动阶段会初始化若干具名的 runtime。codex具名 runtime 的标识。它通常对应某个插件或某个配置项里声明过的执行引擎名字比如配置文件里写了runtime codex那么 Harness 就会去注册表里找这个名字。is unavailable because its plugin registry报错的关键原因。Harness 从插件注册表里加载codex这个 runtime 时注册表本身加载失败或者注册表里根本没有这一条记录。这个报错的本质不是你的 agent 逻辑写错了而是运行时插件的注册链路断了。就像汽车启动时钥匙拧了、发动机没反应查到最后是电瓶线束接头的螺丝松了。松的是注册关系这条线。5.2 从零开始的排查步骤我按实际踩坑的经验把排查顺序固定成以下五步确认名称是否匹配先检查配置里写的 runtime 名字和插件注册的名字是否完全一致包括大小写、连字符、作用域前缀。Codex和codex在某些注册表里是两个键这种小坑最容易忽略。检查插件是否真正安装成功查看插件的安装目录、版本号、依赖声明是否完整。很多时候是插件装了一半主包存在但依赖缺失。检查注册表配置路径插件注册表通常会在用户配置文件或环境变量里指定路径。路径写错注册表就是一个空壳任何 runtime 都加载不出来。用框架自带的 list 命令看当前到底有哪些 runtime 可用一目了然。清理并重建注册缓存注册表在首次启动时会生成缓存索引缓存损坏或版本不一致会导致 runtime 加载被跳过。删掉缓存目录、重新执行插件索引重建是解决这类问题的常用手段。验证版本与二进制来源如果你用的是二进制分发的工具注意检查版本是否被刷新过。源码构建和包管理器安装的版本如果不一致插件可能引用了一个不存在的内部接口注册自然会失败。5.3 三个容易忽略的细节环境差异本地能跑CI 上报错优先检查 CI 环境里插件安装步骤是否被跳过。很多流水线只装了主程序没装插件清单。多用户配置如果机器上有多个用户配置文件runtime 注册信息可能写在了 A 配置文件里而 agent 启动时加载的是 B 配置文件。用绝对路径显式指定配置文件能绕开这种玄学。代理与镜像源导致的下载不完整插件从公共源拉取时如果网络中断会出现看似装了、实则缺文件的状态。重装时先卸载干净再装避免新旧文件混在一起。这个建议同样适用于任何语言包管理工具。6. 常见问题速查与我的实操心得6.1 高频问题速查表问题现象可能原因建议处理报错说某个 runtime 不可用插件注册表加载失败或未注册按 5.2 的五步排查agent 能跑但工具调用后无响应Runtime 进程假死或超时未回收在 Runtime 层加超时控制和进程看门狗工具执行结果乱码/结构不对Runtime 没有做输出标准化统一在 Runtime 出口做解析器和结构封装权限策略没生效策略写在 Runtime 而 Harness 未引用把策略定义收归 HarnessRuntime 只做执行环境变量对不上不同 Runtime 进程的环境注入不一致用统一的 env 快照运行时按快照注入并发工具调用互相污染Runtime 复用了共享状态每个工具调用创建独立执行实例禁止共享可变状态6.2 分层架构落地时的个人建议做了这么多年 agent 相关开发我最大的体会是一定要从第一天就把 Harness 和 Runtime 的代码目录分开。哪怕你目前只写一个 demo也建议建两个目录或两个模块一个叫harness/一个叫runtime/接口层面先定义清楚。等 agent 规模变大、需要加权限、加沙箱、加多租户的时候你会发现当初这个分层帮你省了大量重构时间。还有一个建议是给所有涉及 Runtime 的调用统一打上 trace 日志。日志里至少包含工具名、执行环境标识、开始时间、结束时间、退出码、资源消耗。Harness 的日志负责为什么这样决策Runtime 的日志负责实际发生了什么两者用同一个 request_id 串起来。排障的时候这套日志体系比任何调试器都管用。最后分享一个我常用的测试思路分别写 Harness 的纯逻辑测试和 Runtime 的契约测试。Harness 测试用假的 Runtimemock 执行结果专注验证编排逻辑Runtime 测试用固定的工具集专注验证执行的正确性和隔离性。两套测试都过了再上集成测试。这样任何一层出问题都能第一时间定位到具体模块而不是在集成环境里大海捞针。我现在但凡是新起一个 agent 项目都会先把这两层画清楚、把契约定下来再开始写业务逻辑——这个顺序基本决定了一个 agent 项目后期能走多远。