ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Agent Harness与Runtime解析:从决策编排到运行保障的关键分层

2026/9/9 0:05:37 拓冰建站 浏览量
Agent Harness与Runtime解析:从决策编排到运行保障的关键分层 很多做 Agent 应用的朋友在群里问过我同一个问题Agent Harness 和 Agent Runtime 到底是不是一回事为什么有些文章说 Harness 是“智能体工作台”另一些又说是“运行时框架”还有人直接用两个词指代同一个 SDK。我先说我的结论这是两个层的概念。Agent Harness 管的是“Agent 怎么想、怎么做决策”Agent Runtime 管的是“Agent 跑在什么环境里、靠什么被调度、崩溃了怎么办、流量大了怎么扩容”。搞混它们短期看不出毛病一旦你开始做生产级部署遇到问题会连该改代码还是该改配置都分不清。这篇文章我结合自己做客服 Agent、多智能体系统的经验把这两个概念彻底拆开讲清楚。1. 先把概念摆正这两个词分别回答什么问题1.1 Agent Runtime承载 Agent 运行的“地基”Agent Runtime 指物理上承载和执行 Agent 程序的基础设施层。注意我用的是“物理上”因为 Runtime 通常由进程管理器、任务调度器、容器平台、状态存储、模型网关、沙箱等组件构成它不关心你写的 Agent 用的什么提示词模板也不关心你是用 ReAct 还是 Plan-and-Execute 模式。Runtime 回答的问题是这段 Agent 代码放在哪里跑、怎么被调度、内存不够了怎么办、进程崩溃后怎么恢复、日志指标从哪里采集、多个用户同时访问时怎么保证不互相踩踏。举个例子方便理解。写后端服务时Spring Boot 是你的程序框架但把它跑起来的是 Tomcat 容器、是 K8s 集群、是 JVM 本身。Agent Runtime 就是 Agent 世界里的 Tomcat、K8s、JVM。LangGraph 写出来的 agent 图如果只是在本机调用那你的 Runtime 就是一个 Python 进程一旦部署成服务Runtime 就得包含任务队列、工作流引擎、容器编排系统甚至微虚拟机沙箱。Agent Runtime 的典型代表包括但不限于Temporal它为 Agent 提供持久执行、定时重试、故障恢复能力一个长时运行的 Agent 任务即使进程被杀掉也能从上次停顿的地方继续跑。各类 Serverless 容器平台AWS 的 App Runner、Google Cloud Run、自建的 K8s Deployment它们负责把 Agent 进程拉起来、做健康检查、根据流量扩缩容。沙箱执行环境比如 E2B 这类云端微虚拟机专门隔离 Agent 调用工具时执行的不可信代码。向量存储和记忆服务的运行集群虽然很多人把它归为“基础设施”但它确实是 Agent 在运行时依赖的外部状态服务。Runtime 出问题时表现通常是系统性的突然超时、全部实例重启、内存飙升、请求堆积、状态丢失。它的故障和你的提示词好坏没有任何关系。1.2 Agent Harness驱动 Agent 决策的“操作台”Agent Harness 指的是用于构建、编排和控制 Agent 行为的软件抽象层。它落在你写的代码仓库里它处理的是 Agent 的决策循环、状态机、工具调用协议、记忆读写逻辑、人机确认机制。Harness 回答的问题是当用户输入到达时Agent 应该经过哪些节点、以什么顺序调用工具、模型返回的哪些字段可以当作系统状态、出错后如何回退到人工、多步任务中间结果怎么缓存。更直白地说Harness 是你给 Agent 套上的“操作台”。我见过最好的类比是一位前同事说的Harness 像赛车方向盘和中控面板它决定了车手能看什么、能操作什么、自动辅助系统如何干预而 Runtime 是发动机、变速箱、轮胎和赛道本身。方向盘再灵敏发动机熄火你也跑不了发动机再强方向盘逻辑混乱一样冲出赛道。工程上Harness 层的产物通常包括Agent 的图定义StateGraph、节点、边ReAct 循环里的 prompt 模板和 parser工具调用的 schema、白名单、重试参数短期上下文与长期记忆的读写逻辑human-in-the-loop 的暂停、审批、恢复机制不同 LLM 之间切换的适配器LangChain、LangGraph、Semantic Kernel、CrewAI、AutoGen、Pydantic AI 这些框架大部分时候你说的其实是它们的 Harness 能力。它们把“让模型完成多步任务”的工程问题抽象成了几个对象至于这些 Agent 部署后如何保持长期运行那是另一层的问题。1.3 一句话抓住本质区别对比维度Agent HarnessAgent Runtime核心职责决策编排与行为控制进程调度与资源保障关注代码agent 状态、节点、工具路由副本数、线程池、持久化、重试故障表现Agent 答非所问、不调工具、决策死循环请求超时、任务丢失、进程崩溃、无法扩容修改方式改代码、改提示词、改图结构改部署配置、加资源、换调度策略、升级集群典型例子LangGraph 图、OpenAI Agents SDK 的 AgentLoopTemporal、K8s Deployment、沙箱执行器类比飞机的自动驾驶逻辑飞机的液压与航电系统心里记住一句话就行Harness 处理“下一步该做什么”Runtime 处理“这一步凭什么能执行成功”。2. 为什么大家总是搞混这两个概念2.1 SDK 把 Harness 和 Runtime 打包得太严密了很多主流 SDK 为了提升体验把开发框架和服务端执行环境做成了同一个产品。最典型的是 OpenAI Assistants API你用 SDK 创建 Assistant、定义 Tool、发起 Run这部分是 Harness但 Run 实际上跑在服务端托管的执行环境里线程状态、工具调用、模型调度都不暴露给你这部分是 Runtime。当产品经理说“Agent SDK 就是运行时”的时候他确实没有错因为在那个上下文里 SDK 确实把两个层都包进去了。但对你这种要写生产代码的人来说就会产生一个错觉所有 Agent 行为异常都可以通过换提示词或改框架参数解决可惜完全不是这样。我见过一个团队线上 Agent 每隔几小时就丢一次任务他们在 Harness 层折腾了一周反复修改状态定义和工具调用逻辑最后才发现是消息队列消费者没做确认确认机制进程重启后 offset 没提交任务从头执行。这就是典型的 Runtime 问题被误判成了 Harness 问题。2.2 “Agent 框架”这个词本身语义就漂移了早期 LangChain 出来的时候大家都叫它 Agent 框架主要管逻辑编排。后来 LangGraph 更进一步把状态机做到框架里。但云服务商和平台厂商也在说“Agent 框架”他们说的是托管执行环境、模型路由、沙箱服务和可观测性。同一个名词一类人用来指 Harness另一类人用来指 Runtime不混乱才怪。更麻烦的是成熟的框架往往两头都做一部分。LangGraph 生态里既有 StateGraph 这种纯 Harness 组件也有 LangGraph Platform 这种负责服务化部署的 Runtime 组件。Semantic Kernel 里既有规划器这类 Harness 组件也有部署到 Azure 后的托管运行时。遇到这类横跨两层的框架你最好的办法不是纠结它属于哪一类而是把它拆开看它提供给我的是“写逻辑的 API”还是“跑服务的能力”。写逻辑的归 Harness跑服务的归 Runtime。2.3 单机 Debug 掩盖了 Runtime 的存在大多数人第一次写 Agent 是在 Jupyter Notebook 或本地脚本里完成的。在那个场景下Runtime 约等于你本机的 Python 解释器你完全感知不到它的存在。模型调用失败就重新运行一次状态丢失就再问一遍用户所有“执行保障”都是你手动完成的。但生产环境里用户不会因为你进程崩溃就体贴地重试一遍。生产 Agent 需要并发隔离、任务持久化、自动扩缩容、故障恢复这些没有一个是 Harness 能提供的全部要依赖 Runtime 层去解决。很多团队上线后才发现自己只写了一个精美的 Harness却完全没有设计 Runtime。所以我建议从你决定做生产级 Agent 的第一天起就要在架构图上把 Harness 和 Runtime 画成两条泳道泳道不属于同一个负责人也要分开设计。3. 上实例把同一个 Agent 的 Harness 与 Runtime 拆出来看3.1 一个客服工单 Agent 的 Harness 长什么样假设我们要做一个客服 Agent用户描述问题后Agent 先判断问题类型然后检索知识库如果需要创建工单就调用 CRM 接口最后生成回复。从 Harness 视角看我用 LangGraph 风格写一个简化版本的状态图示意。这里不追求可运行代码而是让你看清哪些代码属于 Harness。# agent_harness.py示意代码 from langgraph.graph import StateGraph, END from typing import TypedDict, Literal class AgentState(TypedDict): user_message: str problem_type: str kb_contexts: list[str] ticket_id: str | None final_answer: str # 通俗说这三个函数就是 Agent 的“思考节点” def classify_problem(state: AgentState) - AgentState: # 调用 LLM将用户问题分成退款技术故障咨询等类型 state[problem_type] llm_classify(state[user_message]) return state def retrieve_knowledge(state: AgentState) - AgentState: # 根据 problem_type 检索向量知识库 state[kb_contexts] vector_search(state[problem_type], top_k3) return state def open_ticket(state: AgentState) - AgentState: # 只有技术故障类才创建工单其他直接回复 if state[problem_type] technical_issue: state[ticket_id] crm_create_ticket(state[user_message]) return state # 这里是 Harness 的核心状态图定义 graph StateGraph(AgentState) graph.add_node(classify, classify_problem) graph.add_node(retrieve, retrieve_knowledge) graph.add_node(ticket, open_ticket) graph.set_entry_point(classify) graph.add_edge(classify, retrieve) graph.add_edge(retrieve, ticket) graph.add_edge(ticket, END) agent_app graph.compile()上面这段代码里问题分类逻辑、知识库检索顺序、是否创建工单的判断条件、回复组合方式全都在 Harness 层。你可以随时把classify_problem的提示词改得更好也可以把“ticket”节点挪到“retrieve”之前这些修改不会影响 Agent 跑在什么环境里。3.2 同一个 Agent 的 Runtime 需要哪些配置到了生产环境这个客服 Agent 不可能作为单个 Python 函数裸跑。你需要让它能同时服务 1000 个用户某一个用户调 CRM 接口卡住了不能拖垮别人进程在凌晨三点崩溃后正在运行中的任务第二天要能恢复。一个务实的 Runtime 方案是把上面编译好的 agent 包装成一个 Temporal Workflow让 Temporal 负责持久执行再用 K8s Deployment 承载 Worker。# agent_runtime_worker.py示意代码 from temporalio.worker import Worker from temporalio.client import Client async def main(): client await Client.connect(temporal-server:7233) worker Worker( client, task_queueagent-tasks, workflows[run_customer_agent], # 这里把 Harness 包装成 Workflow activities[call_crm, search_kb], ) await worker.run()上面这段代码意味着用户请求会变成 task queue 里的一个任务Temporal Runtime 负责保证任务不丢、失败重试、按需调度真正执行业务逻辑时才会调用你在 Harness 里定义的状态图。同时K8s 层的 Deployment 描述了这个 Agent Worker 的运行资源apiVersion: apps/v1 kind: Deployment metadata: name: agent-worker spec: replicas: 3 template: spec: containers: - name: worker image: registry.example.com/customer-agent:1.2.0 resources: requests: cpu: 500m memory: 1Gi limits: memory: 2Gi env: - name: OPENAI_API_KEY valueFrom: secretKeyRef: name: llm-secret key: api_key这里你可能注意到了K8s Deployment 和 Temporal Worker 都不关心你的 Agent 是 ReAct 模式还是 Plan-and-Execute 模式它们只负责“任务有没有在跑”“资源够不够”“宕机后能不能自动拉起新副本”。3.3 一次请求从进入到返回两边各做了什么假设一个用户发来消息“我昨天扣款成功了但没收到会员权益帮我看看。”完整的处理路径大体是这么走的网关层收到请求后把内容封装成一条任务放进 Temporal 的 task queue。这一步是 Runtime 在干活。Temporal Worker 取出任务调用你编译好的 Harness 状态图。状态图的第一个节点执行问题分类这里会发起一次 LLM 调用。LLM 返回结果后Harness 内部分支判断走知识库检索检索完成后需要调用 CRM 系统确认订单。这步如果 CRM 接口很慢Runtime 层的 activity timeout 会介入不会让你无限等下去。Harness 根据检索和查询结果生成最终回复Worker 把回复写入结果队列。如果中间 Worker 崩溃Temporal 会在另一个健康 Worker 上重新调度这个任务并且从最近完成的 activity 之后继续执行而不是让用户重新描述问题。整个过程中Harness 负责完成“从用户问题到回答”的推理拼图Runtime 负责保证这块拼图在恶劣的分布式环境下仍然能拼完。4. 一张对照表解决选型中的 90% 困惑下面这张表我总结了很多次评审经验。每次团队里因为概念争论不下时我就拿出它来对齐。建议你保存下来遇到具体问题时先查表再决定找谁排查。判断维度Agent HarnessAgent Runtime修改周期代码版本每次发布都可能变相对稳定配置变更频率低核心数据用户消息、上下文、工具结果任务队列、执行历史、容器状态垂直扩展方式优化推理步骤、换更强的模型、精简工具链扩容 Worker、增加沙箱资源、加队列消费者水平扩展方式多 Agent 拆分职责多副本负载均衡、分区队列可测试性单元测试、提示词回归、工具 mock混沌工程、故障注入、压测典型性能指标决策延迟、工具调用成功率、上下文有效利用率worker 吞吐、任务积压量、错误恢复时间对成本的影响token 消耗量由它决定资源占用、并发许可证由它决定失败后副作用回答错误、生成垃圾信息任务丢失、流量超时、下游重复执行调试入口LLM trace、状态图节点日志进程日志、任务队列 backlog、容器事件团队角色Agent 工程师、算法工程师平台工程师、SRE框架举例LangGraph、CrewAI、AutoGen、Pydantic AITemporal、K8s、E2B、托管 Workflow配一个实战判断方法上线后出现问题先问自己一句——如果把所有 Agent 相关代码替换成一个最简单的 echo 服务只保留你这个 Agent 依赖的外部系统调用问题还会不会发生如果会那是 Runtime 问题比如外部系统依赖、进程管理、网络超时、队列积压。如果不会那大概率是 Harness 问题比如状态设计错误、工具选择不合理、提示词导致模型误判。我还有第二个判断方法把同样的问题手动用脚本模拟一遍绕过 Harness 直接调用底层工具。如果脚本稳定成功说明你的工具链没问题问题出在 Harness 的编排逻辑如果脚本本身也不稳定那要从 Runtime 的稳定性去查。5. 工程落地建议你在不同阶段该关注什么5.1 先用 Harness 快速验证再把 Runtime 当正式产品搭我见过很多团队把顺序搞反了。项目刚起步时他们花大量精力搭 K8s、接监控、设计高可用结果 Harness 的 Agent 逻辑还很粗糙连用户意图都分不清一套复杂的生产环境只会拖慢迭代速度。我的建议很直白在 PMF 验证阶段用轻量 Harness 加一个最简单的容器部署就够。把注意力放在提示词、状态图、工具调用是否真的对用户有帮助上。确认业务逻辑跑通后再引入 Temporal 这类持久执行引擎把高可用和故障恢复补齐。Runtime 是给规模做准备的不是给想法做验证的你不需要在实验阶段就背上运维包袱。5.2 Harness 层最容易忽略的四个设计细节第一个是状态显式化。不要把所有临时变量都塞进一个全局字典Agent 跑几轮之后状态变得不可预测。我在实际项目里吃过亏两个不同租户的消息因为共享一个 key导致跨租户串数据。Harness 层必须明确定义状态 schema哪些字段会被持久化、哪些只在本轮有效一分一秒都不能含糊。第二个是工具调用抽象。Agent 要访问 CRM、订单系统、知识库不要让 Harness 代码直接拼 HTTP 请求。每个工具都应该有清晰的名字、描述、输入输出 schema这样模型才能正确选择工具后续替换底层实现也更容易。第三个是 human-in-the-loop 接口。不是所有操作都适合让 Agent 自动完成尤其是创建工单、发邮件、退款这类动作。Harness 必须预留暂停点让 Agent 在关键操作前停下来把上下文提交给人工确认。这个接口如果后期补会非常痛苦因为状态图每个节点都要改。第四个是模型适配层。不要把 prompt 和某个具体模型的 API 格式绑死。早先我用某个模型做 function calling 时效果很好后来因为成本和性能需要换另一个模型Harness 里的工具调用解析逻辑全部重写了一遍。后来我改成统一 ModelAdapter 接口任何模型进来都转成同一套 tool call 协议切换模型时间从几天缩短到两小时。5.3 把 Runtime 当作运维资产来管理而不是业务代码Runtime 层改进通常不是靠写业务代码完成的而是靠配置、资源、调度策略、观测体系。你需要为 Agent 建立三件套日志、指标、分布式 Trace。尤其是当你接入了 Temporal 或 K8s一定要把 Workflow 执行历史、队列积压量、Worker 内存使用量、任务重试次数接入统一监控面板。我建议给每个 Agent 任务分配一个可追踪的 request_id从用户请求进入消息队列开始一直贯穿 Harness 的每个节点和 Runtime 的每次调度。没有这个贯穿 ID出了问题你会在 Harness 日志和 Runtime 日志之间来回复制粘贴非常消耗生命。另外Runtime 层的故障恢复机制要主动测试。不要等线上任务丢了再查你可以在预发环境手动 kill 掉 Worker 进程观察任务能否恢复、恢复位置是否准确、有没有重复执行。这类演练做两三次之后你对 Runtime 的信任感会完全不同。5.4 团队协作时的职责边界划分如果你们团队大于五个人强烈建议在分工上把 Harness 和 Runtime 分开。Agent 工程师专注 Harness 层负责状态图、工具链、提示词、模拟测试平台工程师专注 Runtime 层负责工作流服务、容器集群、沙箱、监控告警、容量规划。两个角色需要协作的地方是接口定义尤其是任务超时、重试策略、幂等键、限流参数的设计。我踩过最大的坑是消息重试没有做幂等Harness 里生成的工单重复创建了好几个。后来我们约定所有外部写入操作都必须带一个业务幂等键由 Harness 生成并传到底层接口Runtime 重试时不会产生副作用。6. 常见问题与排查技巧实录6.1 为什么我的 Agent 本地测试正常一上线就超时这是最常见的问题大概率出在工具调用没有设置超时或者 Runtime 层的 Worker 并发不够。本地测试时你只面对一个请求外部接口慢一点也无所谓线上有几百个并发请求时一个外部 API 卡住会导致整个 Worker 线程池耗尽后面的任务全部排队。排查思路是从外到内一层层剥。先看任务队列积压量确定瓶颈在 Worker 还是下游然后看 Agent trace找到具体卡在哪一个工具调用上最后检查这个工具的 timeout 和重试策略。修复时一般要同时改两层Harness 层给模型可调的工具设置超时参数Runtime 层给 Workflow 设置整体执行超时和隔板隔离。6.2 任务重试后为什么下游系统被重复执行Agent 在调用支付、发消息、建工单这类非幂等接口时Runtime 的任务重试会导致同一个请求被执行两次。这不是 Harness 状态图的问题但它需要 Harness 来治。解决办法是在 Agent 状态里增加一个幂等键字段每次用户会话生成唯一 request_id所有外部写入型工具都必须携带这个 key。下游接口需要支持按 key 去重如果接口不支持你就得在 Harness 里加一层写入去重表先查再写的原子操作可以通过 Redis 或数据库唯一索引实现。6.3 Agent 运行几轮后“失忆”状态丢得到底算谁的问题多数情况是 Harness 层的状态设计缺陷也就是该持久化的中间状态没有持久化。比如你在状态图里把上下文放在局部变量里节点执行完后变量就没了模型下一轮当然不记得。这是典型的 Harness 问题。另一种情况是 Runtime 重启后任务状态没恢复。这常见于直接跑在 K8s Pod 中的 Agent没有引入持久化工作流引擎Pod 一重启进程内上下文就全丢了。这种情况属于 Runtime 选型问题修复方案是换用 Temporal 这类支持持久执行的工作流引擎。区分方法很简单你在本地单步调试时如果状态也会丢那是 Harness只有部署成多副本或重启进程才丢那是 Runtime。6.4 Agent 决策质量不稳定该换模型还是换框架先别急着换模型也不要马上推翻框架。我建议先看 Harness 的工具调用和上下文管理是否合理。模型决策质量差往往是因为关键信息没有传给模型或者工具描述模糊导致模型选错了工具。检查一遍提示词里的工具描述是否明确说明了工具是为了完成什么目标、输入参数有哪些限制、什么时候不该调用。很多时候把工具描述从一句话扩充到三句话并给出使用实例准确率提升效果远大于切换模型。如果工具描述已经很完善了再考虑换更强的模型或者增加一个校验节点让模型输出先经过简单规则验证再执行。6.5 我应该用托管 Runtime 还是自己搭基础设施对绝大多数中小团队我建议优先用云厂商或开源社区已经验证过的托管 Runtime比如 Temporal Cloud、托管沙箱平台或者云平台自带的 Agent 服务。自己搭 K8s 加工作流引擎意味着你还要维护集群版本升级、节点故障自愈、网络策略、存储备份这些工作会消耗掉你本来应该花在业务创新上的精力。自建 Runtime 只适合两种情况一是数据合规要求严格核心数据不能出特定环境二是你的多 Agent 系统规模大到托管方案费用完全不可控。即便如此我也不建议你从零造轮子用开源的 Temporal、K8s、沙箱组件组合出来会是更稳妥的选择。7. 最后分享两个快速判断口诀我这些年评审太多 Agent 项目最后沉淀出两句口头禅分享给大家。第一句决策层靠 Harness保障层靠 Runtime。遇到任何 Agent 问题先在脑子里归类再决定去哪里排查。第二句Harness 错了是答错Runtime 错了是跑不了。如果你在排查一个问题时发现 Agent 回答质量变差但你最近没有改动 Harness 的代码那要赶紧检查模型是不是被限流了、知识库是不是连不上了。反过来Agent 直接崩溃或请求堆积你改一千行提示词也是白费力气。最后一个小技巧我在做技术评审时一定会问对方这样一个问题——“如果这个 Agent 现在从集群里完全消失用户会感知到什么”答“任务丢了、服务不可用”的人基本理解 Runtime答“不能对话了、没有自动回复了”的人往往还停留在 Harness 层思维。让整个团队都能正确回答这个问题你们的 Agent 系统离生产级就更近一步了。