Harness Engineering 到底在做什么:从概念到代码实战

发布时间:2026/10/2 1:00:08

Harness Engineering 到底在做什么:从概念到代码实战 1. 引言Harness Engineering 是什么Harness Engineering工程化编排是近年来在 AI Agent、自动化流水线和复杂系统集成领域快速兴起的一类工程实践。它的核心目标是把多个松散的组件——模型、工具、数据源、人工审批、外部服务——通过一套可编排、可观测、可回滚的工程框架组织成稳定、可控、可复用的自动化流程。简单来说Harness Engineering 解决的是「如何把能力变成可靠的工程系统」的问题。它关注的不只是单个模型或单个工具的效果而是整条链路的稳定性、可维护性和可治理性。2. 核心概念拆解要理解 Harness Engineering需要先厘清几个关键概念Harness编排框架承载流程定义、状态管理、错误处理和资源调度的运行容器。Step步骤流程中的最小执行单元可以是调用模型、执行代码、查询数据库或触发外部 API。Workflow工作流由多个 Step 按顺序或条件组合而成的完整执行链路。Guardrail护栏对输入输出进行校验、限流、审计和人工确认的机制是 Harness 区别于普通脚本的关键。Observability可观测性对每一步的输入、输出、耗时、成本和失败原因进行记录与追踪。3. Harness Engineering 与普通脚本的区别很多人会问这不就是写脚本把几个 API 串起来吗区别在于工程化程度维度普通脚本Harness Engineering错误处理try-catch 散落各处统一的重试、降级、熔断策略状态管理全局变量显式的工作流状态机可观测性print 日志结构化追踪、指标采集、链路回溯人工介入难以实现内置审批节点、暂停恢复复用性复制粘贴Step 组件化、版本化4. 代码实战构建一个最小 Harness 框架下面我们用 Python 从零实现一个轻量级 Harness 框架包含 Step 抽象、工作流编排、重试机制和结构化日志。先定义基础组件from dataclasses import dataclass, field from typing import Any, Callable, Dict, List, Optional import time import uuid import logging from enum import Enum logging.basicConfig(levellogging.INFO) logger logging.getLogger(harness) class StepStatus(Enum): PENDING pending RUNNING running SUCCESS success FAILED failed SKIPPED skipped dataclass class StepResult: step_name: str status: StepStatus output: Any None error: Optional[str] None duration_ms: float 0.0 retries: int 0 class Step: 所有步骤的基类子类实现 execute 方法即可。 def __init__(self, name: str, max_retries: int 2, timeout_ms: int 5000): self.name name self.max_retries max_retries self.timeout_ms timeout_ms def execute(self, context: Dict[str, Any]) - Any: raise NotImplementedError def run(self, context: Dict[str, Any]) - StepResult: start time.time() attempt 0 while True: try: logger.info(f[{self.name}] attempt{attempt 1} start) output self.execute(context) duration (time.time() - start) * 1000 logger.info(f[{self.name}] success in {duration:.1f}ms) return StepResult( step_nameself.name, statusStepStatus.SUCCESS, outputoutput, duration_msduration, retriesattempt, ) except Exception as e: attempt 1 duration (time.time() - start) * 1000 if attempt gt; self.max_retries: logger.error(f[{self.name}] failed after {attempt} attempts: {e}) return StepResult( step_nameself.name, statusStepStatus.FAILED, errorstr(e), duration_msduration, retriesattempt - 1, ) logger.warning(f[{self.name}] attempt{attempt} error{e}, retrying...) time.sleep(0.2 * attempt)/code/pre 5. 工作流引擎实现 有了 Step 基类接下来实现 Workflow 引擎负责按顺序执行步骤、传递上下文、收集结果 dataclass class WorkflowResult: workflow_id: str status: StepStatus step_results: List[StepResult] field(default_factorylist) context: Dict[str, Any] field(default_factorydict) class Workflow: 按顺序执行一组 Step共享一个 context 字典。 def init(self, name: str): self.name name self.steps: List[Step] [] def add_step(self, step: Step) - Workflow: self.steps.append(step) return self def run(self, initial_context: Optional[Dict[str, Any]] None) - WorkflowResult: workflow_id uuid.uuid4().hex[:8] context dict(initial_context or {}) results: List[StepResult] [] logger.info(f[workflow:{workflow_id}] {self.name} started with {len(self.steps)} steps) for step in self.steps: result step.run(context) results.append(result) if result.status StepStatus.SUCCESS: # 把输出写入共享上下文供后续步骤使用 context[step.name] result.output else: logger.error(f[workflow:{workflow_id}] step {step.name} failed, aborting) return WorkflowResult( workflow_idworkflow_id, statusStepStatus.FAILED, step_resultsresults, contextcontext, ) logger.info(f[workflow:{workflow_id}] completed successfully) return WorkflowResult( workflow_idworkflow_id, statusStepStatus.SUCCESS, step_resultsresults, contextcontext, )lt;/codegt;lt;/pregt; 实战示例构建一个带护栏的 AI 内容审核工作流 下面用一个真实场景串联整个框架对用户提交的文本先做敏感词过滤再调用大模型生成摘要最后经过人工审批节点。先实现具体的 Step class SensitiveWordFilter(Step): 护栏步骤检查输入是否包含敏感词。 def init(self, name: str, sensitive_words: List[str]): super().init(name) self.sensitive_words sensitive_words def execute(self, context: Dict[str, Any]) - Any: text context.get(input_text, ) hit_words [w for w in self.sensitive_words if w in text] if hit_words: raise ValueError(f包含敏感词: {hit_words}) return {filtered: True, text: text} class LLMSummarizer(Step): 调用大模型生成摘要此处用模拟实现。 def execute(self, context: Dict[str, Any]) - Any: text context[input_text] 真实场景这里调用 OpenAI / Claude / 本地模型 API summary call_llm(f请总结{text}) summary f[模拟摘要] 原文共 {len(text)} 字主题为示例内容。 return {summary: summary} class HumanApproval(Step): 人工审批节点模拟等待人工确认。 def execute(self, context: Dict[str, Any]) - Any: summary context[LLMSummarizer][summary] 真实场景这里会推送审批任务到 IM/邮件等待回调 approved True # 模拟审批通过 if not approved: raise ValueError(人工审批未通过) return {approved: True, summary: summary}/code/pre 7. 组装并运行工作流 def main(): 1. 定义护栏词表 sensitive_words [违规词A, 违规词B] 2. 组装工作流 wf Workflow(content_review_pipeline) wf.add_step(SensitiveWordFilter(SensitiveWordFilter, sensitive_words)) wf.add_step(LLMSummarizer(LLMSummarizer)) wf.add_step(HumanApproval(HumanApproval)) 3. 运行 result wf.run({input_text: 这是一段需要审核的正常内容用于演示 Harness 工作流。}) 4. 输出结果 print(f工作流状态: {result.status.value}) for sr in result.step_results: print(f - {sr.step_name}: {sr.status.value} ({sr.duration_ms:.1f}ms)) if result.status StepStatus.SUCCESS: print(f最终摘要: {result.context[HumanApproval][summary]}) if name main: main() 运行输出示例 [workflow:3f2a9c1d] content_review_pipeline started with 3 steps [SensitiveWordFilter] attempt1 start [SensitiveWordFilter] success in 0.2ms [LLMSummarizer] attempt1 start [LLMSummarizer] success in 1.1ms [HumanApproval] attempt1 start [HumanApproval] success in 0.3ms [workflow:3f2a9c1d] completed successfully 工作流状态: success SensitiveWordFilter: success (0.2ms) LLMSummarizer: success (1.1ms) HumanApproval: success (0.3ms) 最终摘要: [模拟摘要] 原文共 28 字主题为示例内容。 进阶条件分支与并行执行 真实场景往往不是简单的线性链路。下面扩展 Workflow 支持条件分支 class ConditionalStep(Step): 根据条件决定执行哪个子步骤。 def init(self, name: str, condition: Callable[[Dict[str, Any]], bool], if_step: Step, else_step: Optional[Step] None): super().init(name) self.condition condition self.if_step if_step self.else_step else_step def execute(self, context: Dict[str, Any]) - Any: if self.condition(context): return self.if_step.run(context) elif self.else_step: return self.else_step.run(context) return {skipped: True} 使用示例内容长度超过阈值才走详细审核 def is_long_text(ctx): return len(ctx.get(input_text, )) 50 wf Workflow(conditional_pipeline) wf.add_step(SensitiveWordFilter(SensitiveWordFilter, [违规词A])) wf.add_step(ConditionalStep( RouteByLength, conditionis_long_text, if_stepLLMSummarizer(LLMSummarizer), else_stepHumanApproval(HumanApproval), )) 9. 可观测性结构化追踪 生产环境必须能回溯每一步的执行情况。在 Step.run 中已经记录了耗时和重试次数进一步可以接入追踪系统 import json import datetime def export_trace(result: WorkflowResult) - str: 把工作流执行结果导出为 JSON 追踪日志。 trace { workflow_id: result.workflow_id, status: result.status.value, timestamp: datetime.datetime.utcnow().isoformat(), steps: [ { name: sr.step_name, status: sr.status.value, duration_ms: round(sr.duration_ms, 2), retries: sr.retries, error: sr.error, } for sr in result.step_results ], } return json.dumps(trace, ensure_asciiFalse, indent2) 使用 trace_json export_trace(result) print(trace_json) 10. 生产落地的关键考量 从 Demo 到生产Harness Engineering 还需要关注以下几点 持久化工作流状态要写入数据库支持中断恢复和重新执行。 幂等性每个 Step 要设计成可重复执行且结果一致避免重试造成副作用。 超时控制外部 API 调用必须设置超时和熔断防止链路阻塞。 审计日志涉及人工审批和敏感数据的步骤要记录完整的操作轨迹。 版本管理工作流定义要纳入版本控制支持灰度发布和快速回滚。 成本控制对模型调用等昂贵步骤做预算限制和用量统计。 11. 总结 Harness Engineering 的本质是把「能跑通的脚本」升级为「可治理的工程系统」。它通过 Step 抽象、工作流编排、护栏机制和可观测性让复杂的自动化链路变得稳定、可控、可审计。本文从零实现了一个轻量级框架并演示了带敏感词过滤、模型调用和人工审批的完整工作流。生产环境中可以基于同样的思想借助成熟的编排平台或自研框架把 Harness Engineering 落地到实际业务中。
延伸阅读

更多相关文章

2026/9/27 16:49:23

UAssetGUI:专业级虚幻引擎资产离线编辑解决方案

UAssetGUI:专业级虚幻引擎资产离线编辑解决方案 【免费下载链接】UAssetGUI A tool designed for low-level examination and modification of Unreal Engine game assets by hand. 项目地址: https://gitcode.com/gh_mirrors/ua/UAssetGUI 虚幻引擎资产编辑…

2026/9/27 17:41:47

2026高中生英语词汇学习APP测评:天学网等4款产品实测对比

【摘要】本文基于第三方教育科技研究机构2026年Q1实测数据,从课标适配度、记忆效率与合规性三个维度,深度测评天学网学生端、百词斩、网易有道词典、墨墨背单词4款产品,并针对不同学习场景给出选购建议,帮助高中生和家长高效选择适…

2026/10/1 21:19:04

国产算力接管银行:5国产LLM适配屠夫榜

国产算力接管银行:5国产LLM适配屠夫榜 适用读者:想在银行风控 Agent 里调 GLM / Qwen / DeepSeek / 文心一言 / MiMo 这些国产大模型 API 的开发者 阅读时长:约 12 分钟 测试时间:2026 年 7 月(基于 炻光 AI 接入管理平台 公开文档) 一、为什么 2026 年 Q3 银行风控突然都在聊国…

2026/10/2 0:58:00

MCP协议、服务与Tool三层解析:从WebSocket通信到AI工具链集成

1. 别再被“MCP”三个字母绕晕了:先撕开它身上的三层面纱你是不是也这样?刷技术群、看文档、查报错日志,冷不丁就撞上“MCP”——在 Playwright 的 GitHub Issue 里看到playwright mcp;在 Burp Suite 插件说明里读到“需对接 MCP …

2026/10/2 0:58:00

基于LLM的AI智能体Office套件:架构设计与工程化实践

1. 为什么传统Office套件需要一个"智能体层"1.1 从"人找功能"到"功能找人"的转变任何人如果每天要花两三个小时在Word、Excel、PPT、邮件和日历之间来回切换,都会产生一个念头:能不能让这些工具主动替我把活干了&#xff…

2026/10/2 0:58:00

AI网关与RAG融合实践:用MAI Gateway统一模型调用

MAI Gateway 落地实践:把 AI 网关用在 RAG 场景里,到底是不是叠床架屋?这是我们立项时被产品和技术两头追问最多的一句话。当时团队要做的是一个面向企业内部资料的知识库问答系统,RAG 方案自然成了首选;但在模型调用层…

2026/10/2 0:53:00

ESP32双模网关实战:从硬件选型到App控制完整链路

看到不少人在智能家居上折腾,最头疼的就是“协议不统一”和“平台锁定”这两个问题。用树莓派当网关,性能和价格都过了头,还费电;用STM32自己做,WiFi模块和蓝牙模块电路复杂化,调起来特别折磨人。ESP32几乎…

2026/10/2 0:53:00

PMSM矢量控制实战:Simulink建模、参数精调与实物调试全路径

1. 这不是教科书里的“矢量控制”,而是我调通PMSM电机真实转速的全过程永磁同步电机、PMSM、矢量控制、Simulink——这四个词凑在一起,不是论文标题,也不是课程作业编号,而是我在新能源电控实验室连续熬了17个通宵后,终…

2026/10/1 5:21:14

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/10/1 17:09:46

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 10:48:55

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/2 0:02:57

PWN入门:从栈溢出原理到ROP链实战

1. 这不是“学PWN”,是重新理解你每天敲的每一行C代码我第一次在CTF赛场上写出能控制程序流的exp时,手抖得连gdb的c命令都输错三次。那道题只有23行C代码,一个gets()调用,一个printf(),一个return——它甚至没开NX&…

2026/10/2 0:02:57

Windows下cudaMallocHost显存占用之谜:WDDM与TCC模式差异及优化方案

1. 一个反直觉的显存占用现象第一次在 Windows 上看到cudaMallocHost把显存吃掉的时候,我的反应是打开任务管理器反复确认了三遍。明明调用的是主机端锁页内存分配,按 CUDA 文档的说法,这块内存应该落在系统 RAM 里,跟 GPU 的显存…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑