
很多朋友在学习 AI Agent 开发时最先接触的往往是 Prompt Engineering再往后就是各种 Agent 框架。可真到自己动手做一个能落地的多智能体项目时经常会卡在几个非常实际的问题上多个 Agent 之间的消息怎么编排工具调用怎么保证安全和可控沉淀出来的能力如何复用不同 Agent 的结果怎么汇总成最终答案这些问题的答案指向的都是同一个方向Harness 工程。本文会把 Harness、Multi-Agent、SandBox、Skill 这几个概念串起来讲清楚不只用“名词解释”的方式而是带着一个完整的实战案例从零搭建一个小型温室环境监测与决策系统。你可以把 Harness 理解成 Agent 的“运行环境和编排骨架”把 SandBox 理解成“安全沙箱”把 Skill 理解成“可复用的技能包”最后把它们放到同一个系统里协作。文章比较适合这几类读者想从单 Agent 进阶到 Multi-Agent 开发的同学想弄清楚 SandBox 和 Skill 到底解决什么问题的开发者以及准备在自己的项目里抽象一套 Agent 基础设施的工程师。读完以后你应该能独立设计一个简单的 Harness 骨架并把工具、技能、消息通信、沙箱隔离都纳入同一个框架。1. 背景Harness 工程为什么突然火了1.1 从“调 API”到“搭 Agent”提到大模型应用很多人第一反应还是“写 Prompt调 API”。这种模式在简单问答场景够用但一旦涉及工具调用、任务拆解、多步执行就会很快失控。举个例子。现在要在温室大棚场景里做一个“环境监测 智能决策”系统只靠一次 Prompt 很难完成。你需要先读取温度、湿度、土壤数据再判断是否需要灌溉、通风、补光最后还要生成一张可执行的操作建议清单。这些步骤不能全部塞进一段 Prompt更不能每一步都依赖人工介入。于是 Agent 的概念出现了Agent LLM 工具 执行循环。其中工具可以是搜索、计算器、数据库查询、API 调用也可以是文件读写和代码执行。但“执行循环”看起来简单真正落地时却涉及很多工程问题Agent 调用工具时的输入输出怎么验证和管理多个 Agent 之间如何通信、如何决定谁先执行工具运行在什么环境里能不能随便访问整个文件系统沉淀出来的能力如何命名、注册、复用每一步的日志、消耗、结果怎么记录Harness 工程就是专门解决这些问题的。它不是某个大模型厂商的专属概念而是在 Agent 应用走向工程化之后自然长出来的一层基础设施。1.2 什么是 HarnessHarness 直译是“线束、挽具”在 AI Agent 领域可以理解为“承载 Agent 运行的骨架与执行环境”。早期 Agent 开发代码往往长这样一个 while 循环里放上 LLM 调用、工具调用、结果解析然后根据模型返回决定是否继续。这个循环本质上就是一个最简 Harness。但工程化之后我们需要的远不止一个循环。一个完整的 Harness 通常要提供这些能力环境准备与沙箱隔离工具与技能的注册、发现、调用多 Agent 的消息传递与任务编排会话状态管理与结果记录对模型提供商的统一封装。社区里讨论较多的 deepseek harness、codex harness 等工程实践虽然具体实现各不相同但核心思想都是一致的把 Agent 的思考、工具调用、执行环境统一管理起来而不是让每个 Agent 各写一套。这里需要强调一点Harness 不是 Agent。Agent 负责决策Harness 负责承载和约束。如果把 Agent 比作一个员工那么 Harness 就是工位、办公流程、权限系统和会议机制。员工可以换但公司的办公流程应该稳定。1.3 Harness 与 Agent 的区别很多初学者会问我有 Agent 了为什么还需要 Harness答案很简单Agent 是业务逻辑Harness 是基础设施。Agent 知道自己要完成什么目标比如“分析这批环境数据并给出灌溉建议”。Harness 决定 Agent 能调用哪些工具、在哪个目录里读写文件、能访问哪些资源、消息如何传递。在单 Agent 场景下两者的边界不太清晰因为你可以写死一个循环。但在 Multi-Agent 场景下没有 Harness 做统一约束每个 Agent 都会按自己的方式调用工具、处理状态、记录日志。等 Agent 数量到 3 个以上系统就会变得极难维护。更实际的区别是分工粒度如果你需要的是“让模型回答一个问题”那么只需要 Agent。如果你需要的是“多个角色协作完成一个复杂任务并且每个角色都能安全地使用工具”那么你真正需要的是 Harness Agent 的组合。1.4 为什么偏偏是 Multi-Agent、SandBox、Skill 三个词Harness 工程实践里最常被一起提起的三个关键词是 Multi-Agent、SandBox、Skill。它们分别回答三个问题Multi-Agent任务太复杂一个 Agent 搞不定需要拆给多个角色分工协作。SandBoxAgent 要执行工具、读写文件必须限制在安全可控的范围内。SkillAgent 的能力不能每次都重新发明要沉淀成可复用的技能包。这三个概念并不是孤立的。Multi-Agent 决定了 Agent 之间需要消息通道Skill 决定了 Agent 能做什么SandBox 决定了 Agent 能碰什么环境。Harness 则把这三者统一管起来。2. 核心概念拆解Multi-Agent、SandBox、Skill2.1 Multi-Agent不是堆数量而是分角色Multi-Agent 不是简单地把多个 Agent 放在一个进程里跑而是根据任务目标划分角色让不同 Agent 各司其职。常见的设计模式有三种。第一种是“主从模式”。一个主控 Agent 负责任务拆分和结果汇总多个子 Agent 分别执行子任务。比如“数据分析主控”把任务拆给“数据采集 Agent”和“报告生成 Agent”最后汇总成完整答案。第二种是“协作模式”。多个 Agent 处于平等地位通过消息队列交换信息共同完成一个复杂任务。比如一个 Agent 负责查天气另一个负责分析土壤数据最后再由第三个生成建议。协作模式里比较常见的坑是“踢皮球”Agent A 把消息发给 BB 又把消息发回给 A两边来回讨论却一直没有产出。第三种是“编排者模式”。Harness 层维护一张 DAG有向无环图每个节点是一个 Agent 或工具调用严格按照依赖关系顺序执行。这种模式最稳定也最适合生产环境。在实际项目中我更推荐从“编排者模式”入手。因为主从模式下主控 Agent 的 Prompt 会非常复杂协作模式又容易出现循环而 DAG 模式至少能保证流程可控。2.2 SandBox给 Agent 加一道隔离层SandBox 直译为“沙箱”作用是给 Agent 提供一个受限的执行环境。大模型本身并不直接执行代码也不会主动删文件。但当模型接入了工具、允许读写文件、允许执行命令之后风险就出现了模型可能生成一个“删除某个目录”的命令模型可能把敏感信息写到非预期位置模型调用外部 API 时可能造成不可逆的结果多个任务并发执行时文件可能互相污染。SandBox 要做的就是把所有这些副作用限制在一个可控范围内。常见沙箱方案包括文件系统沙箱每个任务一个临时目录工具只能在目录内读写命令沙箱默认禁止执行系统命令只有白名单命令才允许网络沙箱限制 Agent 能访问的外部地址和端口容器沙箱用 Docker 等容器技术做更彻底的隔离。很多 Agent 框架里会看到“disable no sandbox”之类的配置表示关闭沙箱或者在沙箱不可用时的降级策略。生产环境不建议关闭沙箱更不应该让 Agent 直接在宿主机上执行任意代码。2.3 Skill让能力可以注册、发现、复用Skill 是 Agent 开发里非常实用的一层抽象。你可以把它理解成一个带描述和参数协议的函数包。与工具Tool相比Skill 更强调“面向任务”和“可复用”。工具往往是原子操作比如“读取文件”“执行SQL”“调用天气API”而 Skill 往往是组合能力比如“生成周报”“分析温室环境并给出灌溉策略”“把数据整理成图表”。一个设计良好的 Skill 至少应该包含name技能名必须是唯一的、有意义的标识description对技能功能的描述这部分最终会传给大模型帮助模型判断何时该调用input_schema输入参数协议说明需要哪些字段、字段类型和约束run_func实际执行函数内部可以是任意业务逻辑。更进一步社区里还出现了 Skill Creator、Skill Recorder 这类概念。前者让模型自己生成并注册新 Skill后者让系统记录用户操作并自动沉淀为 Skill。它们的最终目标是一致的让能力可以被发现、被复用而不是散落在各处代码里。2.4 三者如何在 Harness 中协作把它们放在一起看Harness 是容器持有 SandBox、SkillRegistry、消息队列、工具注册表Multi-Agent 在 Harness 里运行通过 Harness 的消息队列通信Agent 要读写文件时只能通过 Harness 提供的 SandBoxAgent 要执行能力时通过 SkillRegistry 查找并执行 Skill。换句话说Agent 之间不会直接互相调用而是都通过 Harness 完成“找技能、用工具、传消息、写结果”这些动作。3. 环境准备与设计思路3.1 环境要求本文的示例代码使用 Python 3.9 编写建议使用 Python 3.10 或更高版本。原因是代码中使用了Path.is_relative_to和list[AgentMessage]这类新语法特性低版本会直接报错。其他环境要求不需要 GPU不需要安装任何第三方深度学习框架不需要提前申请大模型 API Key建议使用venv创建独立虚拟环境。如果你本地还没有创建虚拟环境可以先执行下面两条命令python -m venv harness_demo_env source harness_demo_env/bin/activate # Windows 下使用 harness_demo_env\Scripts\activate3.2 示例项目结构为了让代码结构更清晰我把示例项目拆成两个文件harness_demo/ ├── harness_core.py # Harness、SandBox、Skill、Tool 的核心抽象 └── main.py # 温室场景的完整业务逻辑与入口harness_core.py与具体业务无关你可以把它直接复制到自己的项目里作为 Agent 框架的雏形。main.py则演示了如何使用这些抽象来解决一个具体问题。3.3 整体设计思路在这个实战案例中我们不直接调用真实大模型而是用一个responder函数模拟大模型返回结果。这样做有三个好处不需要 API Key任何读者都能直接运行排除了网络波动和模型随机性便于演示 Harness 本身的设计生产环境替换 responder 为真实 LLM 调用即可业务逻辑不需要大改。我们设计的温室系统包含两个 AgentDataAgent负责读取传感器模拟数据并把数据写入沙箱目录AdvisorAgent负责读取数据调用灌溉和通风 Skill生成操作建议。Harness 负责注册工具、注册 Skill、管理消息队列、创建 SandBox并按顺序执行两个 Agent。4. 完整实战从零搭建一个带 Skill 和 SandBox 的 Multi-Agent 系统4.1 场景与需求场景是一个小型温室大棚。大棚里有多个传感器实时返回温度、湿度、土壤湿度、土壤 pH 和光照强度。我们需要系统完成如下流程第一步DataAgent 采集传感器数据 第二步DataAgent 将数据整理成 JSON 并写入沙箱目录 第三步AdvisorAgent 读取沙箱中的数据 第四步AdvisorAgent 调用灌溉 Skill 和通风 Skill 第五步AdvisorAgent 生成决策建议并写回沙箱的 report 目录。整个过程中Agent 不能直接访问宿主机其他目录只能操作 Harness 分配给它的沙箱目录。4.2 第一步核心 Harness 抽象先创建harness_core.py这是整个示例的框架层。# 文件路径harness_demo/harness_core.py from __future__ import annotations import json import shutil import tempfile from dataclasses import dataclass, field from pathlib import Path from typing import Any, Callable, Dict, Optional # ---------- 1. 工具Tool ---------- dataclass class Tool: 一个最小工具抽象函数可以作为参数传入并统一封装。 name: str description: str func: Callable[..., Any] def run(self, **kwargs) - Any: return self.func(**kwargs) # ---------- 2. 技能Skill ---------- class Skill: 技能比 Tool 更面向任务带输入参数说明便于模型理解。 def __init__( self, name: str, description: str, input_schema: Dict[str, Any], run_func: Callable[..., Any], ): self.name name self.description description self.input_schema input_schema self.run_func run_func def execute(self, **kwargs) - Any: return self.run_func(**kwargs) class SkillRegistry: 技能注册表负责技能的注册与查找。 def __init__(self): self._skills: Dict[str, Skill] {} def register(self, skill: Skill) - None: self._skills[skill.name] skill def get(self, name: str) - Optional[Skill]: return self._skills.get(name) # ---------- 3. 沙箱SandBox ---------- class SandBox: 简化版沙箱每个任务一个临时目录工具只能在目录内读写。 def __init__(self, root: Optional[str] None): self.root Path(root) if root else Path(tempfile.mkdtemp(prefixharness_sandbox_)) self.root.mkdir(parentsTrue, exist_okTrue) def resolve_path(self, relative_path: str) - Path: 把相对路径解析到沙箱目录内并阻止路径穿越。 target (self.root / relative_path).resolve() if not target.is_relative_to(self.root.resolve()): raise PermissionError(f目标路径超出沙箱范围: {relative_path}) return target def write_file(self, relative_path: str, content: str) - str: target self.resolve_path(relative_path) target.parent.mkdir(parentsTrue, exist_okTrue) target.write_text(content, encodingutf-8) return str(target) def read_file(self, relative_path: str) - str: target self.resolve_path(relative_path) return target.read_text(encodingutf-8) # ---------- 4. 消息与 Harness ---------- dataclass class AgentMessage: Agent 间传递的消息。 sender: str receiver: str content: str metadata: Dict[str, Any] field(default_factorydict) class Harness: Harness 骨架统一管理沙箱、工具、技能、消息队列和 Agent 执行。 def __init__( self, task_id: str, sandbox: Optional[SandBox] None, responder: Optional[Callable[[str, str, Harness], str]] None, ): self.task_id task_id self.sandbox sandbox or SandBox() self.skills SkillRegistry() self.tools: Dict[str, Tool] {} self.message_queue: list[AgentMessage] [] self.agent_outputs: Dict[str, str] {} self.responder responder or default_responder def register_tool(self, tool: Tool) - None: self.tools[tool.name] tool def register_skill(self, skill: Skill) - None: self.skills.register(skill) def send_message(self, message: AgentMessage) - None: self.message_queue.append(message) def run_agent(self, agent_name: str, prompt: str) - str: 执行一个 Agent。responder 可以是模拟逻辑也可以是真实 LLM 调用。 response self.responder(agent_name, prompt, self) self.agent_outputs[agent_name] response return response def summary(self) - Dict[str, Any]: return { task_id: self.task_id, sandbox_root: str(self.sandbox.root), messages: [ {sender: m.sender, receiver: m.receiver, content: m.content} for m in self.message_queue ], agent_outputs: self.agent_outputs, } def default_responder(agent_name: str, prompt: str, harness: Harness) - str: 默认 responder在没有真实模型时返回一个占位结果。 return fAgent {agent_name} 收到任务{prompt}这段代码里最值得留意的两个设计是SandBox.resolve_path使用is_relative_to检查目标路径是否仍然位于沙箱根目录内。即使传入../../etc/passwd这样的路径也会被拦截并抛出异常。这在 Agent 机制里是一个不能省略的安全边界。SkillRegistry单独抽出来管理技能而不是让 Agent 直接持有技能对象。这样做的好处是技能可以被多个 Agent 共享也方便后续做技能热更新和统计。4.3 第二步编写温室业务逻辑接下来创建main.py实现我们的温室环境监测与决策业务。# 文件路径harness_demo/main.py import json import random from harness_core import AgentMessage, Harness, SandBox, Skill, Tool # ---------- 1. 模拟传感器工具 ---------- def read_sensor_data(sensor_type: str) - dict: 模拟读取温室传感器数据生产环境可替换为真实 IoT 接口。 data { temperature: round(random.uniform(15.0, 35.0), 1), humidity: round(random.uniform(30.0, 90.0), 1), soil_moisture: round(random.uniform(0.2, 0.8), 2), soil_ph: round(random.uniform(5.5, 8.0), 1), light: round(random.uniform(100, 2000), 1), } return {sensor_type: sensor_type, data: data} # ---------- 2. 灌溉技能 ---------- def irrigation_skill(soil_moisture: float, temperature: float) - str: 根据土壤湿度给出灌溉策略。 if soil_moisture 0.4: return 建议立即灌溉 20 分钟 elif soil_moisture 0.6: return 建议短时灌溉 5 分钟 return 当前土壤湿度充足无需灌溉 # ---------- 3. 通风技能 ---------- def ventilation_skill(temperature: float, humidity: float) - str: 根据温度和湿度给出通风策略。 if temperature 30: return 建议开启顶部通风窗口 if humidity 80: return 建议开启循环风扇降低湿度 return 当前通风条件良好 # ---------- 4. 模拟大模型决策的 responder ---------- def greenhouse_responder(agent_name: str, prompt: str, harness: Harness) - str: 模拟两个 Agent 的大模型推理逻辑。 实际生产环境中这里应该替换为真实的 LLM 调用 - 把 prompt、可用工具描述、可用技能描述组装成 system message - 调用大模型接口 - 解析返回结果决定调用哪个工具或技能 - 本文为了可运行直接写死流程。 if agent_name DataAgent: # DataAgent 调用传感器工具并把数据写入沙箱 sensor_data harness.tools[sensor].run(sensor_typegreenhouse) harness.sandbox.write_file( data/environment.json, json.dumps(sensor_data, ensure_asciiFalse, indent2), ) return f数据采集完成{sensor_data} if agent_name AdvisorAgent: # AdvisorAgent 从沙箱读取数据调用技能生成建议 raw harness.sandbox.read_file(data/environment.json) data json.loads(raw)[data] irrigation harness.skills.get(irrigation).execute( soil_moisturedata[soil_moisture], temperaturedata[temperature], ) ventilation harness.skills.get(ventilation).execute( temperaturedata[temperature], humiditydata[humidity], ) suggestion f灌溉策略{irrigation}通风策略{ventilation} harness.sandbox.write_file( report/decision.json, json.dumps({suggestion: suggestion}, ensure_asciiFalse, indent2), ) return suggestion return f收到任务{prompt} # ---------- 5. 构建 Harness ---------- def build_demo_harness() - Harness: harness Harness( task_idgreenhouse-demo-001, sandboxSandBox(), respondergreenhouse_responder, ) # 注册工具 harness.register_tool( Tool(sensor, 读取温室传感器数据, read_sensor_data) ) # 注册技能 harness.register_skill( Skill( irrigation, 根据土壤湿度给出灌溉策略, {soil_moisture: float, temperature: float}, irrigation_skill, ) ) harness.register_skill( Skill( ventilation, 根据温度和湿度给出通风策略, {temperature: float, humidity: float}, ventilation_skill, ) ) return harness if __name__ __main__: harness build_demo_harness() # 第一步DataAgent 采集环境数据 harness.send_message( AgentMessage(sendermain, receiverDataAgent, content采集温室环境数据) ) data_result harness.run_agent(DataAgent, 采集温室环境数据) print([DataAgent], data_result) # 第二步AdvisorAgent 基于数据生成决策建议 harness.send_message( AgentMessage( senderDataAgent, receiverAdvisorAgent, content环境数据已写入沙箱请生成决策建议, ) ) advisor_result harness.run_agent(AdvisorAgent, 基于环境数据生成决策建议) print([AdvisorAgent], advisor_result) # 打印 Harness 内部摘要 print([Harness Summary], json.dumps(harness.summary(), ensure_asciiFalse, indent2))这段代码虽然不长但已经把 Multi-Agent、SandBox、Skill 三件事都串起来了Multi-Agent 体现在DataAgent和AdvisorAgent两个角色按顺序执行并通过AgentMessage记录通信过程。SandBox 体现在数据文件和报告文件都被写入沙箱目录而不是直接写在项目根目录。Skill 体现在irrigation和ventilation两个技能的注册与动态调用上。4.4 运行与验证在harness_demo目录下执行python main.py预期输出大致如下[DataAgent] 数据采集完成{sensor_type: greenhouse, data: {temperature: 28.3, humidity: 63.5, soil_moisture: 0.32, soil_ph: 6.8, light: 1450.0}} [AdvisorAgent] 灌溉策略建议立即灌溉 20 分钟通风策略当前通风条件良好 [Harness Summary] { task_id: greenhouse-demo-001, sandbox_root: /tmp/harness_sandbox_xxxxxx, messages: [ { sender: main, receiver: DataAgent, content: 采集温室环境数据 }, { sender: DataAgent, receiver: AdvisorAgent, content: 环境数据已写入沙箱请生成决策建议 } ], agent_outputs: { DataAgent: 数据采集完成{sensor_type: greenhouse, ...}, AdvisorAgent: 灌溉策略建议立即灌溉 20 分钟通风策略当前通风条件良好 } }由于传感器数据是随机生成的所以每次运行的温度、湿度数值不会完全一致。如果soil_moisture小于 0.4就会触发“立即灌溉 20 分钟”的建议如果温度超过 30 度就会触发通风建议。沙箱目录会在临时目录下创建路径会打印在sandbox_root字段里。在沙箱目录中你可以看到data/environment.json和report/decision.json两个文件前者是 DataAgent 的采集结果后者是 AdvisorAgent 的决策结果。这里要特别提醒沙箱临时目录在程序退出后不会自动清理。如果你的机器上临时文件很多建议在真实的 Harness 设计中增加cleanup()方法在任务完成后主动清理沙箱目录。4.5 怎么接入真实大模型有的读者可能会问如果我不想用模拟 responder而是想接入真实大模型应该怎么改只需要把greenhouse_responder中每个 Agent 的分支替换为真实调用。以 DataAgent 为例大致思路是def real_responder(agent_name: str, prompt: str, harness: Harness) - str: if agent_name DataAgent: system_prompt ( 你是一个数据采集 Agent。你可以使用以下工具 f{json.dumps(list(harness.tools.keys()), ensure_asciiFalse)} ) # 调用大模型得到工具调用意图 # model_result call_llm(system_prompt, prompt) # 解析 model_result执行对应的 harness.tools[xxx].run(...) # 把结果返回给流程 ...真实项目中模型返回的往往不是最终答案而是一个“工具调用请求”。你需要循环执行模型产出意图 → 执行工具 → 把工具结果返回给模型 → 模型继续决策直到模型认为任务完成。这个循环本身就可以封装成 Harness 的另一个方法比如run_with_llm。由于不同厂商的 API 格式和工具调用协议差异较大这里不写死某一家代码。你只需要记住本文的responder就是大模型推理逻辑的占位层真实模型调用只影响这一个函数的实现不影响 SandBox、SkillRegistry 和消息队列的整体设计。5. 常见问题与排查思路实战过程中下面几个问题出现频率非常高我把它们整理成表格方便你快速定位。问题现象常见原因解决思路启动时报错AttributeError: Path object has no attribute is_relative_toPython 版本低于 3.9升级到 Python 3.9推荐 3.10沙箱目录可以访问../../etc/passwd没有使用 resolve 后再判断相对路径使用Path.resolve()之后再调用is_relative_to校验Agent 调用工具后流程直接结束没有把工具结果交给模型再次判断执行循环没有写完整把“调用模型 → 执行工具 → 把结果回传 → 再次调用模型”封装为一个循环多个 Agent 并发执行时文件互相覆盖所有 Agent 共用了同一个目录每个任务分配独立 SandBox路径中携带任务 ID日志里出现disabled no sandbox相关字样沙箱未启用或配置被关闭显式开启 SandBox并检查工具执行环境是否被替换为宿主机路径Skill 定义太粗糙模型不知道怎么调用description 和 input_schema 不够清晰补充 Skill 的用途说明、参数类型与示例Multi-Agent 之间消息循环token 消耗暴涨没有终止条件或消息去重在 Harness 中设置最大轮次同一消息 ID 只处理一次数据文件写入失败目标路径包含不存在的目录在 write_file 中先执行parent.mkdir(parentsTrue, exist_okTrue)想接入真实模型但每次都超时网络或模型服务不稳定增加超时重试、指数退避把可缓存的结果保存到沙箱下面挑选两个最容易踩的坑展开说明。第一个坑是沙箱路径穿越。很多简单实现只做字符串替换比如把../替换成空字符串这种做法很容易被绕过。真正的路径隔离应该使用模块提供的路径解析能力先resolve()获取绝对路径再判断目标路径是否仍然属于沙箱根目录。如果你的框架不支持类似is_relative_to的 API可以用str(target).startswith(str(root))代替但要注意尾部斜杠问题。第二个坑是 Multi-Agent 靠消息循环推进。如果两个 Agent 都可以向对方发消息而且没有任何“最终结果判定器”系统很容易陷入无限讨论。生产环境建议增加三条规则任一 Agent 连续发言超过 N 轮强制结束只有主控 Agent 或编排者可以发起新一轮任务消息内容如果和上一轮重复率过高直接跳过。6. 最佳实践与工程建议6.1 Skill 的粒度与命名设计 Skill 时最重要的不是实现代码而是它的描述和参数协议。大模型不像普通函数调用那样可以看源码它只能通过name、description、input_schema来判断“这个技能适不适合当前任务”。建议命名使用动词开头例如generate_weekly_report、analyze_soil_ph、send_irrigation_command。不要使用utils、process这种含糊名字。输入协议尽量只暴露必要参数并且给出合理取值范围。一个 Skill 最好只完成一个原子动作。如果某个 Skill 内部逻辑过于复杂建议拆成多个 Skill再由一个“编排 Skill”依次调用它们。不用过度拆分到“函数级别”但要拆分到“任务级别”。另外Skill 的执行结果最好可以结构化输出例如 JSON 字符串这样便于下游 Agent 继续解析。6.2 SandBox 默认启用最小权限安全边界是 Harness 工程中最不能省的部分。沙箱默认应该开启并且遵循最小权限原则默认不允许访问网络除非任务明确需要默认不允许执行外部命令除非有白名单默认只允许读写当前任务目录不允许访问宿主机其他目录涉及代码执行的场景尽量使用容器隔离。同时要记录所有被拦截的越权操作。这类日志在 Agent 行为分析和安全审计中非常有价值。6.3 Multi-Agent 先设计编排者在生产环境落地 Multi-Agent 时优先考虑“编排者模式”。用一个主控 Agent 负责拆解任务、分发任务、汇总结果子 Agent 只响应主控 Agent 的消息。这样的好处是问题定位更容易也避免了多个 Agent 争抢执行权的问题。子 Agent 之间的直接消息尽可能收敛。如果发现两个子 Agent 频繁交换中间结果说明任务拆分可能不合理应该考虑把这些中间结果统一写到 SandBox 的共享目录里由主控 Agent 读取。6.4 可观测性日志与追踪在生产环境一个 Multi-Agent 系统的调试难度远大于普通后端服务。每一步中以下信息都建议记录当前 Agent 名称和任务 ID收到的 Prompt 内容调用的工具名和具体参数调用的 Skill 名和执行耗时模型返回的原始结果token 消耗和成本估算。这些日志最好统一写入同一个追踪系统按任务 ID 聚合成一条完整的调用链。一个实用的做法是Harness 的summary()方法不只是调试用还可以在生产环境作为“任务执行报告”持久化保存。6.5 模型选择与成本控制大模型选型没有“最好”只有“最合适”。简单任务可以使用参数较小、响应更快的模型复杂推理任务才需要使用更大参数量模型。这里的判断标准不是模型品牌而是任务复杂度。成本控制方面建议做三层优化把相似任务合并成同一个会话减少重复 Prompt对确定性工具调用不一定非要走大模型可以写规则直接短路建立 token 预算上限超过上限时强制终止并给用户返回提示。如果考虑本地部署模型要注意显存和推理速度的平衡。量化后的模型可以降低显存占用但可能带来一定精度损失。建议先用小规模测试集评估量化前后效果再决定是否上生产。7. 总结与进阶路线这篇文章围绕 Harness 工程做了一次完整拆解。我们先理解了 Harness 与 Agent 的区别再分别掌握 Multi-Agent、SandBox、Skill 三个核心概念最后通过一个温室环境监测案例在几十行代码的范围内跑通了“多 Agent 协作 沙箱隔离 技能复用”的完整流程。你可以把harness_core.py看作一个极简框架原型。继续进阶的话有几个方向值得深入把 responder 替换成真实大模型调用并实现工具调用的循环解析在 Harness 中增加对会话状态的持久化让任务中断后可以恢复为 SkillRegistry 增加动态加载能力支持从外部目录加载新 Skill引入真正的容器沙箱让 Agent 可以在隔离环境中执行任意代码增加失败重试、超时控制、任务队列让 Harness 更接近生产级基础设施。最后分享一个判断标准当你发现自己的 Agent 项目里工具调用散落在各个函数里、多个 Agent 的通信靠全局变量、技能无法复用、文件写入没有目录约束时就是时候引入 Harness 工程了。希望这篇文章能帮你少走一些弯路也欢迎你把实践中的踩坑经验带回来一起交流。