别再混淆Agent Harness与Runtime!90%架构踩坑根源就在这里
文章目录
P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看,传送门https://blog.csdn.net/H1727548
前言
最近泡了几场AI Agent的技术沙龙,发现一个特别有意思的怪现象。
台上嘉宾分享架构,嘴里一会儿蹦出Harness,一会儿又说Runtime,台下听众一半记笔记一半皱眉头。
茶歇的时候有个哥们儿过来搭话,说:“兄弟实不相瞒,我做Agent快半年了,至今没搞懂这俩到底是不是一个东西。”
我当时差点笑喷。
这真不怪他。上周我们公司内部架构评审,两个工作五六年的老开发,为这俩词吵了快半小时。一个说“运行时就是外层那层东西”,一个说“不对,线束才是外层,运行时是底层”,吵到最后技术总监都听不下去了,说“行了,都是外层,差不多就行”。
差不多?差远了。
这俩概念要是稀里糊涂,写代码的时候分层乱堆,线上出故障就是必然的。到时候业务甩锅基建,基建甩锅业务,谁都觉得自己冤。
今天我就把这事儿给你掰扯得明明白白。保证你看完,再碰到有人聊这俩词,你能直接给他上一课。
1 先唠唠:这俩词为啥能把全行业绕晕
1.1 一场教科书级的术语漂移
说出来你可能不信,这场混乱本质上是两拨人各说各话。
一拨是AI工程派,从OpenClaw、Claude Code社区出来的,张口就是Harness。在他们眼里,模型外面那层工程化的壳,就叫Harness。
另一拨是传统软件派,张口就是Runtime。毕竟Java有JVM,Node有V8,什么东西跑起来不得有个运行时?Agent凭啥搞特殊?
于是就出现了特别魔幻的场景:同一张架构图,左边标注Harness,右边标注Runtime,说的居然是同一个系统。
就像你去菜市场买番茄,有人叫西红柿,有人叫洋柿子,俩人为叫法吵了十分钟,最后发现买的是一个东西。但比这更坑的是,Agent圈这俩还真不是一个东西。
1.2 Harness本来是干啥的?
Harness这个词,本来跟AI半毛钱关系都没有。
最早是马具的意思,套马身上那套皮带金属件。后来在工程圈火起来,靠的是俩场景:汽车线束和测试夹具。
汽车线束你懂吧?发动机、方向盘、刹车、车灯之间的所有电线。它自己不产生动力,也不做决策,但它决定了信号走哪条路、断了之后车会不会自燃。
测试夹具更形象:你给电路板做可靠性测试,把板子插进去的那套工装。板子是主角,夹具不改变芯片,但它决定板子能接触哪些探针、用多大电压供电。
总结一下核心特质:Harness是连接件,不是执行件。它的价值在于约束、接线、保护。
放到Agent里就是:模型是大脑,Harness就是大脑周围的工作台、笔记本、工具和权限系统。它不替模型思考,但它决定模型能碰哪些工具、能看哪些上下文、出错了往哪回滚。
1.3 Runtime又是打哪来的?
Runtime就不用多说了,开发圈的老熟人。
JVM管字节码解释、GC、线程调度;Erlang VM管进程隔离、消息传递;Node.js管事件循环、非阻塞IO。
它们的共性只有一个:让代码真正跑起来。
放到Agent语境下,Runtime就像是Agent专用的云函数。给你提供隔离的执行环境,管资源调度,管网络权限,管凭证注入,管进程死活。
说白了,Harness管“能不能做、该不该做”,Runtime管“怎么跑起来、跑崩了咋办”。
1.4 混用的真相:不是蠢,是框架太能装
那为啥全行业都在混用?三个原因,太真实了。
第一,Agent是个新物种,行业连标准都没有。Java生态花了30年才把Runtime、Container、Framework的边界吵清楚,Agent这才发展几年?
第二,现在的框架都是打包交付的。比如LangGraph,给你循环引擎的同时,还给你检查点存储、人工审批。前者是Runtime属性,后者是Harness属性。你装一个包等于装了两层,说起来自然混着说。
第三,Harness这个词听着就高级。比Runtime有画面感,有“工程手艺”那味儿,写博客标题都更容易火。结果传着传着,就变成“凡是外层工程都叫Harness”了。
2 一句话定义 + 判别三问:30秒分清敌我
先给你两个能直接抄进团队Wiki的定义。
Agent Harness(智能体线束):位于基础模型之上,负责组织智能体行为的软件层。包含提示工程、工具接口、执行循环、记忆和策略等,让只会生成文本的模型能完成多步骤任务。
说白了,换一套Harness,等于换掉Agent的人格、权限边界和工作方法论。
Agent Runtime(智能体运行时):提供智能体实际执行环境的基础设施层。类似云函数或容器环境,负责调度和运行智能体逻辑及工具执行。
换一套Runtime,Agent的人格和提示词可以完全不变,但稳定性、并发能力、部署形态全变了。
一句话总结精髓:
Harness决定Agent“想什么、能做什么、被允许做什么”;Runtime决定Agent“在哪儿跑、跑多快、挂了怎么恢复”。
2.1 判别三问:拿过来就能用
以后碰到任何Agent系统、任何开源框架,问自己三个问题,立刻就能分清。
第一问:这个模块改了,Agent的性格/行为/知识会变吗?
会变 → Harness
不会变,只影响性能、稳定性、部署形态 → Runtime
第二问:这个模块的核心产出是“内容”还是“进程”?
产出提示词、工具调用请求、记忆片段、评估报告 → Harness
产出任务调度结果、线程池状态、checkpoint文件、容器实例 → Runtime
第三问:把这个模块删掉,Agent会“变笨/变坏”还是“跑不起来”?
变笨、变危险,比如删掉工具权限校验,Agent开始越权操作 → Harness
直接跑不起来,比如删掉进程管理器,整个服务直接崩 → Runtime
就这么简单。以后再有人跟你瞎掰扯,你把这三问甩给他,基本就能终结话题。
3 职责拆解:俩层各干各的活
3.1 Harness的七项核心职责
Harness层说白了,就是围着模型转的逻辑层,管“想什么”和“怎么做”。
一共七件事:
- 执行循环:控制模型和环境的交互步骤,比如ReAct、计划-执行这些流程。
- 提示拼装与上下文管理:构造提示,管理对话历史和记忆,引导模型走正道。
- 工具接口:定义可用工具,处理工具调用请求和结果反馈。
- 消息/状态跟踪:跟踪会话内容和任务状态,存历史、方便恢复。
- 输出解析与校验:解析模型输出,检查格式和语义,不对就重试、纠正。
- 错误处理:识别工具失败、超时这些错误,该重试重试,该人工介入就介入。
- 子代理管理:协调多智能体,处理协作和冲突。
3.2 Runtime的六项核心职责
Runtime层就不一样了,全是基础设施层面的脏活累活。
也是六件事:
- 隔离与沙箱执行:每个会话在独立环境里跑,防止一个崩了全跟着炸。
- 资源限制:CPU、内存、磁盘、API调用次数,都给你卡死,防止无限循环搞崩服务器。
- 网络和凭证控制:控制能访问哪些网站哪些API,安全注入短期凭证,不让密钥暴露在模型上下文里。
- 持久化与检查点:长任务存状态,挂了能从检查点接着跑。
- 并发与可扩展性:调度多个会话,管理队列,高负载下也能稳住。
- 监控与审计日志:记录每次模型调用、工具执行、网络请求,方便调试和合规。
3.3 这条分界线划错,线上必甩锅
很多团队线上出问题,根源就是职责划错了。
记住一句话:网络出口控制、执行沙箱、凭证管理,这些基础设施安全,全归Runtime;工具调用权限、输出验证,这些业务安全,全归Harness。
我见过有的团队,把网络白名单写在Harness里,结果换个Runtime环境,直接就越权访问了。还有的把工具权限校验放在Runtime,改个工具还要动基础设施代码,效率低得离谱。
说白了,各回各家,各找各妈。边界清了,锅就少了。
4 生命周期全流程:谁是司机谁是干活的
从用户发请求到任务结束,整个流程是这样的:
用户发起请求 → Harness接收
Harness加载任务指令、上下文和策略
Harness调用模型生成下一步行动
模型要调用工具?Harness把调用分发到Runtime
Runtime在隔离环境里执行工具代码或命令
Runtime返回结果 → Harness接收
Harness继续循环,可能再调模型或者再调工具
达到终止条件,结束。
看出来没?Harness是整个循环的驱动者,发号施令的;Runtime是工具执行的承包者,埋头干活的。
就像你开车,Harness是方向盘和导航,决定往哪走、走哪条路;Runtime是发动机和变速箱,负责让车真的跑起来。
5 安全隔离:两层各管各的风险
5.1 Harness安全:业务层面的护栏
Harness的安全,是管业务逻辑的。
比如哪些工具能调用,哪些API不能碰;调用参数合不合法,有没有敏感信息;哪些操作需要人工审批,审批到什么粒度;模型输出格式对不对,要不要重试。
说白了,就是防止Agent“乱做事”。
5.2 Runtime安全:系统层面的防护
Runtime的安全,是管底层环境的。
每个会话独立沙箱,不共享文件系统和网络;只有允许的域名能访问,防止乱连外部服务;注入短期令牌,不让长期密钥泄露;定期打补丁,监控恶意行为。
说白了,就是防止Agent“搞破坏”。
一个管做的对不对,一个管跑的安不安全。俩层配合,才叫真正的安全。
6 三种经典部署模式,看看你家是哪种
6.1 模式一:一Harness一Runtime(紧耦合)
应用逻辑和执行环境绑在一起,同一个仓库管代码和基础设施。
优点:部署简单,调试方便,没什么跨团队协调成本。
缺点:没法独立扩展,环境差异难管理。
适合初创团队、小项目快速迭代。
6.2 模式二:一Harness多Runtime(多环境)
同一套业务逻辑,开发、测试、生产用不同配置的Runtime。
优点:同一套代码不同环境独立配置,安全隔离。
缺点:要维护多套Runtime配置。
正规点的团队基本都是这么玩的,总不能开发环境和生产环境用一套沙箱吧?
6.3 模式三:多Harness共用一Runtime(平台化)
多个不同业务的Harness,共用同一个Runtime平台。
优点:统一安全和监控,资源利用率高,治理效率高。
缺点:Runtime成了单点,需要成熟的平台团队维护。
大厂标配。毕竟每个业务线都自己搞一套Runtime,太浪费资源了,也管不过来。
7 五个最容易踩坑的地方,中招的举手
7.1 状态管理:两个“状态”根本不是一回事
这是混淆的重灾区,也是线上事故的高发区。
Harness的状态,叫“认知状态”,跨会话存活。比如长期记忆、技能库、用户画像、人格设定。生命周期按天、月、年算,存在文件、向量库、Git仓库里,不依赖进程。
Runtime的状态,叫“执行状态”,会话内存活。比如当前消息队列、未完成的子任务、临时checkpoint、活跃沙箱。生命周期按秒、分钟算,存在内存、本地盘、Redis里,高度依赖进程。
我见过最经典的事故:Runtime挂了重启,checkpoint还在,但Harness的审批记录丢了。重启之后Agent不知道自己刚才批准过什么,又去问用户一遍。用户当场就炸了:我三分钟前刚同意!你失忆了?
还有反过来的,Harness的记忆库迁移了,Runtime的沙箱还指向旧路径,Agent记得所有事,但现场文件全没了,跟失忆了一样。
这种问题根本不是代码bug,就是把两种状态混在同一个存储、同一条清理策略里了。
7.2 钩子(Hook)到底归哪层?
很多人以为钩子是Runtime的东西,毕竟K8s里有Pod Lifecycle Hooks,听着就像Runtime的。
错了。判断钩子归谁,别看它用了什么技术,看它挂在什么事件上。
挂在语义事件上,比如推理前注入上下文、工具调用后做安全审查、记忆刷新时沉淀事实,这都是Harness的钩子。
挂在系统事件上,比如进程启动前、内存溢出时、崩溃后重启,这才是Runtime的钩子。
举个反直觉的例子:工具审批钩子,哪怕它实现的时候起了个异步线程等用户点按钮,它也是Harness的。因为线程只是实现手段,核心是判断“这个工具调用能不能被允许”——这是策略问题,不是调度问题。
7.3 工具到底算谁的?
工具横跨两层,必须拆开看。
工具 = 工具Schema(Harness) + 工具执行器(Runtime)
Harness拥有:工具的定义、选择策略、结果格式化、权限白名单、调用审计记录。
Runtime拥有:工具进程的实际执行、并发控制、超时重试、沙箱隔离、凭据注入。
别搞混了。改工具的描述,找Harness;调工具的超时时间,找Runtime。
7.4 上下文压缩属于哪一层?
结论:Harness。
有人抬杠:压缩耗CPU啊,不得Runtime提供资源吗?
话是这么说,但压缩解决的核心问题是“模型该看到哪部分历史”,这是语义问题。哪怕它借用Runtime的计算资源,归属还是Harness。
就像你用电脑写文档,电脑是硬件,但写什么内容是你决定的。不能说电脑提供了算力,文档就归电脑所有了。
7.5 人工审批属于哪一层?
结论:跨层,但语义归属Harness。
审批的决策逻辑,比如什么操作需要审批、审批粒度、被拒绝后怎么调整,这是Harness的事。
审批的通道,比如阻塞任务、挂起协程、等待推送、超时取消,这是Runtime的事。
正确做法:Harness层定义审批策略,向Runtime发出“挂起当前任务直到某事件”的原子指令。Runtime只管执行挂起和唤醒,不管为什么挂起。
8 一张分层全景图:建议存工位
从下到上一共五层,记住铁则:下层为上层提供服务,上层绝不修改下层。
第5层:基础设施层。计算、存储、网络、模型网关、向量库、容器编排。
第4层:Runtime层。进程与调度、执行沙箱、状态与检查点、资源与网络。
第3层:Harness层。上下文工程、工具治理、记忆与状态、安全与评估。
第2层:编排层/Loop。Plan->Act->Observe->Evaluate->Revise的迭代循环。
第1层:业务层/应用层。产品逻辑、用户交互、场景Skill、业务API编排。
这里特别提醒:Loop是独立的一层,别塞进Harness或者Runtime里。
Loop决定“下一步干什么”,是策略;Harness决定“这一步能干什么”,是约束;Runtime决定“这一步在哪儿干”,是执行。三者是正交的,别混为一谈。
9 真实开源框架对照表:选型直接抄
光说抽象的没用,给你列一下常见项目的归属,选型的时候直接对照。
- 纯Harness向:OpenClaw、Hermes、Claude Code、Microsoft Agent Framework
- 两者兼备:AgentScope、LangGraph、AWS AgentCore、Azure Agent Service
- 偏Harness:CrewAI、AutoGen
- 纯Runtime向:Google Gemini Runtime、JVM、Node.js、Kubernetes
- 产品级整体:Devin、Codex、Trae Agent,黑盒交付,你拿不到分层
选型前先问自己:我需要的是Harness能力还是Runtime能力?如果都要,边界划在哪里?
10 最小可运行代码:把分层写进项目里
光说不练假把式,给你一段能跑的最小Python代码,看完你就知道分层该怎么落地。
# ============================================================
# Layer 4: AGENT RUNTIME ** Runtime 层:只关心"跑"
# ============================================================
class AgentRuntime:
"""Agent 运行时:进程、调度、沙箱、状态、资源。
铁律:本层不出现任何 prompt 文本、工具语义、记忆策略。"""
def __init__(self, sandbox=None, checkpoint_dir="./ckpt"):
self.sandbox = sandbox or LocalSandbox() # 执行沙箱
self.checkpoint_dir = checkpoint_dir # 执行 checkpoint
def spawn_worker(self, task_id):
"""创建隔离执行单元。Harness 完全不感知这个方法。"""
...
def suspend(self, task_id, reason):
"""挂起一个任务,等待外部事件唤醒。
注意:"为什么挂起" 由 Harness 决定,这里只负责"怎么挂起"。"""
...
def resume(self, task_id):
"""从执行 checkpoint 恢复任务现场(进程状态、沙箱快照)。"""
...
def enforce_budget(self, task_id, tokens_used, deadline):
"""资源与时间预算硬约束。语义无关。"""
...
# ============================================================
# Layer 3: AGENT HARNESS ** Harness 层:只关心"能做什么"
# ============================================================
class AgentHarness:
"""Agent 线束:上下文、工具治理、记忆、安全、评估。
铁律:本层不写线程池、不写重试、不写进程管理。"""
def __init__(self, workspace, allowed_tools, evaluator):
self.workspace = workspace # 唯一事实来源
self.allowed_tools = allowed_tools # 工具权限白名单
self.evaluator = evaluator # 评估器
self.audit_log = [] # 审批与审计记录
def build_context(self, session) -> str:
"""上下文工程:注入人格、知识、长期记忆,必要时压缩历史。"""
system = self.workspace.read("AGENTS.md")
memory = self.workspace.grep("MEMORY.md", session.user_id)
history = self._compress(session.history) # 压缩仍是 Harness
return system + "\n" + memory + "\n" + history
def gate_tool_call(self, name, args) -> bool:
"""工具治理 + 安全审批。语义问题,不是调度问题。"""
if name not in self.allowed_tools:
return False
if self._risk_level(name) == "HIGH":
return self._request_human_approval(name, args)
return True
def evaluate(self, trajectory) -> str:
"""评估这条轨迹是否逼近目标。Runtime 永远看不到语义对错。"""
return self.evaluator.score(trajectory)
def flush_memory(self, session):
"""运行结束后提炼新事实写回工作区。Harness 的认知状态。"""
self.workspace.append("MEMORY.md", self._extract_facts(session))
# ============================================================
# Layer 2: LOOP ** 编排层:只关心"下一步干什么"
# ============================================================
class AgentLoop:
"""标准循环:Plan -> Act -> Observe -> Evaluate -> Revise。
铁律:向 Harness 要约束,向 Runtime 要执行,自己不实现任何一方的能力。"""
def __init__(self, harness, runtime, goal, max_steps=8, token_budget=50_000):
self.h, self.r = harness, runtime
self.goal = goal
self.max_steps = max_steps
self.token_budget = token_budget
def run(self, session):
trajectory = []
for step in range(self.max_steps):
# (1) 上下文由 Harness 提供
ctx = self.h.build_context(session)
# (2) 模型推理 + 工具调用决策
decision = self._think(ctx, trajectory)
# (3) 执行前过 Harness 的闸门
if not self.h.gate_tool_call(decision.tool, decision.args):
self.r.suspend(session.task_id, "waiting_human_approval")
self.r.resume(session.task_id)
continue
# (4) 真正的执行交给 Runtime
observation = self.r.spawn_worker(session.task_id).execute(
decision.tool, decision.args
)
# (5) 预算硬约束由 Runtime 兜底
self.r.enforce_budget(session.task_id, decision.tokens, None)
trajectory.append(observation)
session.history.append(observation)
# (6) 评估是否达标
if self.h.evaluate(trajectory) == "GOAL_MET":
break
# (7) 收尾:认知状态回写 Harness,执行状态由 Runtime 清理
self.h.flush_memory(session)
self.h.audit_log.append({"goal": self.goal, "steps": len(trajectory)})
return trajectory
# ============================================================
# 装配:两层解耦,可独立替换
# ============================================================
harness = AgentHarness(workspace=Workspace("./ws"), allowed_tools={"read", "write", "grep"})
runtime = AgentRuntime(sandbox=<- 换成 K8s 也没关系
loop = AgentLoop(harness, runtime, goal="重构 auth.py 为 JWT 且保持 100% 测试覆盖率")
loop.run(session)
# 换 Harness(换人格/换工具集):runtime 不动
harness2 = AgentHarness(workspace=Workspace("./ws-analyst"), allowed_tools={"read", "grep"})
# 换 Runtime(单机 -> 分布式):harness 不动
runtime2 = AgentRuntime(sandbox=K8sSandbox(), checkpoint_dir="redis://ckpt")
看这段代码注意三点:
第一,AgentRuntime里没有一行提示词文本,没有任何工具语义判断。这就是“Runtime不碰语义”。
第二,AgentHarness.gate_tool_call内部会调用self.r.suspend——Harness借用Runtime能力,但语义归属仍在Harness。这是跨层协作的正确姿势。
第三,AgentLoop是纯粘合层。它向Harness要上下文和约束,向Runtime要执行和预算,自己不实现任何一方的能力。Loop是第三类,别塞进任何一层。
11 最后总结:一张速查卡
最后再给你总结一下,记不住的可以存下来贴工位。
Harness = 约束 / 策略 / 接口,决定“能做什么、被允许做什么”
Runtime = 执行 / 平台 / 环境,决定“在哪儿跑、跑多快、怎么恢复”
Loop = 编排 / 循环 / 策略序列,决定“下一步干什么”
安全分工:Harness管工具调用权限、输出验证、人工审批策略;Runtime管网络出口控制、执行沙箱、凭证管理。
部署模式:小团队紧耦合,正规军多环境,大厂平台化。
说白了,Runtime让Agent能做事,Harness让Agent做对事。
只有Runtime的Agent,是个快而乱的机器人;只有Harness的Agent,是个懂而慢的手册。两者合起来,才是能上线的智能体。
P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看,传送门https://blog.csdn.net/H1727548
更多推荐


所有评论(0)