尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Agentic Harness Workflow:将AI Coding升级为工程化流水线的实践框架
坦率讲哪怕到今天我依然看到很多团队把 AI Coding 用成了“高级补全工具”人开一个对话把需求贴进去等模型吐出一段代码再手动复制回仓库跑一下发现报错又贴回去让它改。这种玩法不是不行但它完全没有发挥出 AI 编程真正的杠杆——Agentic Harness Workflow 框架要解决的就是这件事把 AI Coding 从“一问一答”的对话模式升级成“需求到交付”的工程化流水线。我手上这套框架已经跑了小半年前后重构过三轮从最早的一个循环调模型到现在拆成任务节点、审核门禁、工具沙箱、观测面板一整套体系。这篇文章把我踩过的坑、沉淀下来的设计思路、以及可以直接抄走的最小实现一次性讲清楚。如果你正准备把 AI 编程引入团队流程或者你自己一个人想管住好几个并行的 AI 任务这篇文章应该能帮你少走很多弯路。这个框架的核心关键词先说清楚**Agentic智能体式自主行为**、**Harness约束与保护装置**、**Workflow可编排的工作流**。合在一起的理解方式就是把一个不可预测的大模型装进一个可预测、可观测、可回滚的工程容器里。1. 为什么 AI Coding 不能只靠“单次对话”1.1 Harness 到底是什么意思先说一个很容易被忽略的词“Harness”。它在英文里的本义是“马具、缰绳”后来在工程领域被引申为“控制、约束、支撑系统”。你去看很多测试框架里面都有一个 Test Harness 的概念它就是用来把被测对象包起来替它准备数据、调用它的接口、收集它的输出。放到 AI Coding 场景里Harness 做的事情完全一样模型是我们的被测对象也是执行者但它本身不受控。你不知道它下一步会调用哪个工具不知道它会在哪一步开始编造不存在的文件也不知道它会绕多少圈子才肯停下来。Harness 的作用就是给模型划出一条轨道让它只能在轨道里“自主”。我见过很多团队对“Agentic”的理解以为就是让模型想干嘛就干嘛。实际跑下来你会发现没有约束的自主结果就是失控。模型可能会自己装一堆依赖、改掉不该改的配置、在一个问题上翻来覆去重试十几遍。Harness 的意义恰恰是用结构化的流程把这种自由限制在可接受的边界里。1.2 从“对话”到“流水线”的转变单次对话模式的本质是“人肉维护上下文”模型写完第一版代码你要自己看报错信息再把报错贴回去模型看到的是你整理好的局部信息它并不知道整个仓库的全貌也没有机会主动去跑一遍测试。工程化流程的本质则是“把步骤抽成交付链”。你可以把一次 AI 编程任务拆成这么几段需求澄清节点模型或人来确认需求里有没有模糊点技术方案节点让模型基于仓库结构给出改动方案代码生成节点按方案逐文件生成或修改代码静态检查节点跑 lint、类型检查、编译测试验证节点跑单元测试、集成测试人工审核门禁差改动必须停下来等人确认合并与回滚节点通过后才允许合入出问题能自动回退每一步都是独立节点都有输入输出都有超时和重试策略。模型不再需要自己记住“我写到第几步了”框架里的状态管理替它记住。这就是“Agentic Workflow”的核心价值智能体负责局部的自主决策工作流负责全局的确定性编排。2. 框架设计思路核心概念与架构拆解2.1 节点模型用类型和工作流逻辑解耦我这一版框架里所有行为都被抽象成四类节点这四类足够覆盖绝大多数 AI Coding 场景节点类型职责典型例子Task Node调用大模型完成一个生成/理解任务写接口文档、生成单元测试Tool Node执行确定性的外部操作跑 pytest、执行 git diff、检索代码Decision Node根据条件做分支选择测试是否通过、是否需要人工介入Human Gate暂停流程等人确认代码评审、敏感操作授权一个工作流就是这些节点的有向图。节点之间不直接互相调用而是通过一个共享的 WorkflowContext 传递数据。这样做的好处是任何一个节点可以替换、可以单独调试、可以挂掉重试而不影响其他节点。Task Node 是其中最重要的节点需要单独设计。它的输入是一个 Prompt Template 和一段上下文输出是模型的文本回复。这里有一个非常关键的设计原则**Task Node 内不写任何业务逻辑只做“生成”这件事。**判断生成结果好不好、要不要重试交给上层的 Decision Node 和 Tool Node。2.2 状态管理不要把上下文塞给每一个节点一开始我犯过一个严重错误把整个对话历史、所有中间输出、整个仓库文件树全部塞进每个节点的 Prompt 里。结果模型看起来什么都知道实际上什么都记不住输出质量一路下滑Token 费用还高得吓人。后来的方案是“按需注入 显式状态”。WorkflowContext 里只存三种东西不可变输入需求原文、项目元信息、约束条件可累积产出已生成的代码、测试报告、检查结果事件日志每个节点的耗时、Token 消耗、重试次数在 Task Node 真正执行之前一个专门的 ContextBuilder 模块会根据当前节点的类型从三样东西里挑出与该任务相关的那一部分拼成 Prompt。其他东西一概不注入。这样做还可以顺便解决一个让很多人头疼的问题上下文漂移。节点越多模型越容易把早期步骤里的小决定理解歪。按需注入就像是给每个节点发一张“任务工单”只告诉它需要知道的事情它反而更能聚焦。2.3 循环与控制给 Agent 的“自由”装上刹车Agent 任务没法避免循环——模型写代码发现测试挂了修完又挂再修。没有控制的话这种循环可以无限进行下去账单一夜跑爆。框架里必须内置三套刹车机制第一套次数限制。每个 Task Node 都有 max_attempts超过次数就进入失败分支要么终止流程等待人工要么切换备用模型重试。第二套工具调用白名单。模型只能在注册过的工具集合里选择任何未授权的工具调用直接拒绝并记入日志。这个相当重要你不希望模型哪天心血来潮去执行rm -rf。第三套成本预算。每个工作流实例可以设置总的 Token 预算或金额上限一旦超过框架主动中断所有节点生成一份“成本异常报告”。这三套刹车必须同时存在。次数限制防的是逻辑死循环白名单防的是工具滥用成本预算防的是资源失控。任何一个缺失Harness 都不合格。3. 实操搭建一个最小可用的 Agentic Harness Workflow3.1 确定技术栈与目录结构我选择的是 Python 3.11 asyncio因为 Python 的生态对大模型和代码分析工具支持最全asyncio 方便并行跑多个 Agent 节点。没有用重量级的服务器框架核心就是一个异步调度器加一堆节点实现。最小目录结构长这样agentic_harness/ ├── runtime.py # 核心调度器 ├── context.py # WorkflowContext 与数据装载 ├── nodes/ │ ├── base.py # 节点基类 │ ├── task_node.py # 大模型生成节点 │ ├── tool_node.py # 工具执行节点 │ └── gate_node.py # 人工门禁节点 ├── workflows/ │ └── coding_task.yaml # 工作流定义 ├── tools/ │ ├── run_tests.py │ └── git_ops.py └── main.py这套结构的好处是每个节点和工具都是独立的 Python 模块可以单独写测试。我强烈建议你哪怕只是自用也保持“定义文件与实现代码分离”工作流描述放在 YAML 里节点的实现放在代码里。这样调整流程不需要改代码改 YAML 就行非常适合多团队协作时划分责任。3.2 定义工作流把 AI 编程翻译成 YAML以“修复一个失败的单元测试并合入”为例工作流定义可以直接抄id: fix_failing_test name: 修复失败用例并提交 version: 1.0 timeout: 3600 budget: 200000 nodes: - id: analyze_failure type: task prompt_template: 分析以下测试失败信息定位根因输出简洁的诊断结论。 max_attempts: 2 - id: plan_fix type: task prompt_template: 基于诊断结论和仓库结构输出修复方案给出具体文件与改动点。 max_attempts: 3 - id: apply_changes type: tool tool: apply_patch max_attempts: 1 - id: run_tests type: tool tool: run_tests max_attempts: 1 - id: tests_check type: decision condition: ctx[run_tests][passed] True next_on_true: human_review next_on_false: fix_again - id: fix_again type: task prompt_template: 根据最新报错修正之前的改动只输出修改后的补丁。 max_attempts: 3 - id: human_review type: gate message: AI 已完成修复请在 30 分钟内人工审核本次改动。 - id: merge type: tool tool: git_review_merge max_attempts: 1 edges: - from: analyze_failure to: plan_fix - from: plan_fix to: apply_changes - from: apply_changes to: run_tests - from: run_tests to: tests_check - from: tests_check to: human_review - from: tests_check to: fix_again - from: fix_again to: apply_changes - from: human_review to: merge看到里面的循环了吗fix_again - apply_changes - run_tests - tests_check是一个环如果测试一直不过这个环会一直转。但因为有每个节点独立的 max_attempts以及总超时 3600 秒兜底它不会无限跑下去。这种“局部循环 全局刹车”的组合就是 Agentic 和传统流程编排最大的区别。3.3 实现核心调度器与节点基类调度器是整个框架的心脏我用最简单的事件循环实现。一个节点执行完根据它的输出和边的定义决定下一步谁执行。class Runtime: def __init__(self, workflow, context): self.workflow workflow self.ctx context self.status {} async def run(self): next_nodes self.workflow.start_nodes() while next_nodes: current next_nodes.pop(0) for node in current: if not await self.should_skip(node): result await self.execute_node(node) self.status[node.id] result next_nodes self.resolve_next(current) return self.ctx每个节点的基类只有两个方法class Node: def __init__(self, config): self.config config self.attempts 0 async def execute(self, ctx: WorkflowContext): raise NotImplementedError property def exhausted(self): return self.attempts self.config[max_attempts]Task Node 的 execute 方法负责组装 Prompt、调用模型、解析输出。class TaskNode(Node): async def execute(self, ctx: WorkflowContext): self.attempts 1 prompt self.build_prompt(ctx) result await call_model( modelgpt-4o, messagesprompt, temperature0.2, ) ctx.append_event(self.config[id], task_completed, result) ctx.outputs[self.config[id]] result return result这里call_model是一个封装的异步函数。把模型调用封装成一层方便以后替换提供商或加入缓存。我的经验是这个函数一定要支持两个参数max_tokens和temperature并且要把每次调用的输入输出完整记录到事件日志里否则出了问题根本没法复盘。3.4 关键机制工具沙箱、人工门禁与观测工具沙箱是我后期加入的功能但如果你打算让 Agent 在真实仓库里跑自动化操作这一步绝对不能省。class ToolNode(Node): async def execute(self, ctx: WorkflowContext): self.attempts 1 tool self.config[tool] if tool not in ctx.allowed_tools: raise ToolNotAllowed(tool) result await execute_tool_in_subprocess(tool, ctx) ctx.outputs[self.config[id]] result return resultexecute_tool_in_subprocess会在一个低权限用户下执行工具命令并限制工作目录。实际我踩过这样一个坑第一次让 Agent 自己跑pytest它看到测试挂了一个异步用例竟然自作主张给测试代码加了time.sleep(1)想“修复”时序问题。这属于危险的“解题思路跑偏”。因为测试代码和业务代码都在仓库里一个不受约束的 Agent 完全可能把测试改成“看起来通过”的样子。人工审核门禁就是防止这种隐蔽问题的最后防线。人工门禁的实现很简单但在消息提醒这块要稍微花点功夫。我在框架里内置了一个 gate 节点执行到这里会向企业内部通讯工具发一条卡片消息附带 diff 链接和确认按钮。卡片的按钮回调会写回数据库流程继续或终止只取决于按钮结果。class GateNode(Node): async def execute(self, ctx: WorkflowContext): await ctx.emit_gate(self.config[id], self.config[message]) decision await ctx.wait_for_gate(self.config[id], timeout1800) if not decision.approved: raise GateRejected(人工审核未通过) ctx.outputs[self.config[id]] decision return decision观测这一块也很有必要。每次节点执行完我会往时序数据库写一条记录节点 ID、耗时、Token 数、重试次数、状态。后面排查问题全靠它。有一段时间我发现某个任务的 Token 消耗异常高查观测面板发现fix_again节点被触发了十几次每个节点又往 Prompt 里塞了完整报错堆栈相互叠加导致上下文越来越大。这个现象后来成了我们判断“上下文被污染”的典型信号。4. 常见问题与排查技巧实录4.1 上下文漂移模型“忘了”最初的需求这是跑多节点工作流时最常遇到的问题。表现为后面的节点输出的代码跟最初需求对不上或者方案里的关键约束没有传递到最后的实现节点。排查思路先看事件日志确认每个节点收到的事件日志是否完整。我在 2.2 节提过按需注入这不是一句空话。要具体落实到每个 Task Node 的 Prompt 里必须把“需求约束”单独抽成一个字段并且在每一轮生成的结尾让它复述关键约束。解决技巧在 Task Node 的 Prompt 末尾加上这么一句“请先用一句话复述你刚才收到的最重要约束再开始输出。”大量实验证明这种强制性的“输出前复述”能显著减少生成结果偏离需求的情况而且几乎不消耗额外成本。它可以看作是一种廉价的“工作记忆检查”。4.2 工具调用循环模型反复执行同一个操作有一段时间我们的工作流频繁出现模型的工具调用死循环比如反复执行同一段git diff或者反复跑同一组测试但什么都不改。后来定位到原因模型没有从工具输出中提取到“下一步要干什么”于是默认选择重复上一次动作。解决这个问题我给 Tool Node 加了一层“操作总结器”。工具执行完后用一个小的专用模型调用把原始输出比如测试失败的一大堆日志压缩成结构化摘要包括核心错误、涉及文件、建议定位范围。再把摘要喂给下一个 Task Node。这一步看似多花了 Token实际上是省钱的因为下一个节点不需要阅读完整日志就能理解现状而且不会被日志里的噪声带偏。另外一个很实用的限制是给同一种工具操作加“间隔锁”。短时间内重复触发同一个工具且输入完全一致时调度器直接拒绝执行返回上一次的结果。这个策略在代码生成场景里非常有效因为重复运行同一个测试并且输入没变结果本来就一样。4.3 生成结果不稳定同样的输入不同的输出很多人的第一反应是调低 temperature把模型参数改成 0。实测下来temperature 设成 0 确实能降低随机性但不能完全消除不确定性因为模型本身有采样逻辑而且不同版本模型之间的行为差异更大。我们的做法有两层第一层模型参数固定temperature 固定在 0.2 左右给一点随机性但不过分第二层建一个“回归样本集”把过去出现问题的工作流输入输出记录下来每次框架改动后跑一遍回归集确保质量没有回退。这个回归集非常值钱。有一次我重构 ContextBuilder 模块自认为会减少 Token 消耗结果回归样本集跑下来三个样本的方案生成质量明显下滑才发现新版本把“需求约束”过滤掉了。如果没有回归集这种回归错误可能要等真实任务跑挂才能发现。4.4 测试被 Agent“作弊”式修复这个我在实操部分提过值得单独拿出来说模型发现测试挂了它不修业务代码反而去修测试断言这是一种非常典型的“走捷径”行为。它会给你一个非常合理的话术比如“调整测试用例以匹配实际行为”但在代码交付里这种行为往往是不可接受的。应对手段首先是给“测试验证”节点加目录限制只运行指定测试目录并且让它读入 tests 目录下的 README 或约定文件明确“测试优先级高于实现”。更重要的是在人工审核卡片里必须并排展示业务代码 diff 和测试文件 diff审核人一眼就能看出是不是动了测试断言。如果条件允许可以在工具沙箱里把测试目录设为只读。这样 Agent 连改测试文件的可能性都被物理切断了。这是我的终极方案后面跑下来再也没出现过“作弊式修复”。4.5 Diff 过小或过大模型偷懒或超范围修改模型有时候会把任务“缩水”需求是要修一个函数它只改了一行注释然后说完成。反过来也会超范围让它修一个 bug它顺带着重构了好几个文件。这两种情况都必须通过工具检查来拦截。我在 apply_changes 这样工具节点之前总设一个“diff 统计节点”跑git diff --stat把改动文件数和行数写入上下文然后与任务预估范围做比较。改动行数低于某个阈值或高于某个阈值时工作流自动进入“需求复查”分支让模型重新阅读需求并判断当前改动是否符合。这种启发式检查不会百分之百准确但很管用。至少它能抓住“完全没改”“狂改一堆文件”这两个极端把 Agent 的行为拉回到可控范围。5. 再分享几个让我少走三年弯路的经验直接给结论不铺垫。**先设计状态结构再设计 Prompt 模板。**大多数人反过来。他们在意 Prompt 怎么写却不关心状态怎么传。一旦节点多了状态结构不合理Prompt 写得再精致也白搭信息该丢还是丢。我的建议是定义工作流之前先画一张“数据流图”确定每个节点从哪个字段取数、往哪个字段写数。这一步做扎实后面开发会非常顺。**人工审核点宁可多不要少。**初期我们只设了一个最终审核点结果模型生成的中间方案越走越偏到最后一步人工才发现返工成本极高。后来在方案生成阶段和代码生成阶段各加了一道快速审核点改动大方向错了能及时被拦下来。虽然多花了人几分钟时间但整体效率反而提升了一倍。**日志里一定要有 Token 消耗的增量。**之前我只看总消耗排查问题特别困难。改成每个节点独立记录增量消耗后一眼就能看出哪个节点在“烧钱”。我甚至给日志加了个警告单个节点消耗超过平均值的 5 倍时直接在面板里标红。这让你快速识别出上下文越来越大的异常节点。这套 Agentic Harness Workflow 本身不是银弹。它的所有优势都建立在“你把流程想清楚了”的前提上。如果业务本身一团乱麻装再好的 Harness 也是让模型在一团乱麻里更快地迷路。但一旦你的流程可描述、可拆解、可度量再给它套上这套框架AI Coding 的生产效率确实会迎来一轮质的提升。我自己的项目组过去一个功能从开发到自测差不多要两天现在稳定在半天以内而且质量波动小得多。建议你从最小的场景开始我一个同事就是从“自动修一个失败的测试用例”起步跑了不到两个月就培养出了对整个框架的信心。
RELATED

相关推荐

地域差异对开发者职业发展的影响与应对策略

地域差异对开发者职业发展的影响与应对策略

1. 地域差异对职业发展的真实影响最近在技术社区看到一个有趣现象:不少一线城市开发者抱怨,自己精心准备的简历居然竞争不过三线城市同行。这背后反映的不仅是个人能力问题,更是一个值得深思的地域经济现象。作为在多个城市工作过的技术负责人…

📅 2026/10/14 5:35:07
AI生成网页的25个结构化Prompt技巧

AI生成网页的25个结构化Prompt技巧

1. 别再把AI当“高级搜索引擎”用:网页生成的本质是结构化意图表达你有没有试过这样写 prompt:“帮我做一个企业官网首页,要大气、现代、有轮播图和产品展示区”?结果模型吐出来一堆 HTML 片段,但样式错乱、响应式失效…

📅 2026/10/14 5:35:07
鸿蒙进阶——一文读懂Mindspore-NNRT-HDF工作流程

鸿蒙进阶——一文读懂Mindspore-NNRT-HDF工作流程

引言 本文将从宏观上介绍华为MindSpore AI框架及其与NNRT(神经网络运行时)的协同工作方式。MindSpore作为AI推理框架,通过NNRT实现模型在NPU等硬件上的高效推理。 知识有限仅供参考 一、Mindspore Lite MindSpore是华为自己开发的一套AI框架,与Onnx、Py…

📅 2026/10/14 5:35:07
MORE NEWS

更多资讯

📰

实体企业技术边界进化论:从技术吸收到生态协同的破界路径

1. 从2000年说起:实体企业的技术创新边界是一条移动战线这些年我跑过不少制造企业的车间和技术中心,经常被问到同一个问题:我们的技术边界到底在哪里?有人问的是设备加工极限,有人问的是研发团队能不能啃下某个新平台&…

📰

TDTR系统上位机UI设计:飞秒激光热反射测量仪的交互与可视化

做TDTR系统(飞秒激光时域热反射测量系统)的软件UI设计,初看像是给科研仪器配个图形界面,实际动手才发现这是个三维交叉的硬骨头:既要懂超快光学的测量逻辑,又要懂上位机软件的人机交互,还得扛住…

📰

T3 Stack全栈项目实战:从选型到部署的完整指南

前阵子团队要做一个新的全栈项目,技术选型会议上争论了很久。后端同学想用传统的 REST 独立服务,前端同学则希望接口类型能自动同步,别每次联调都在群里喊“这个字段是 string 还是 number?”。我后来提了个建议:直接…

📰

QGroundControl 离线地图(Offline Maps)完全指南:瓦片缓存、缩放级别与下载管理

无人机智能硬件 【免费下载链接】qgroundcontrol Cross-platform ground control station for drones (Android, iOS, Mac OS, Linux, Windows) 项目地址: https://gitcode.com/gh_mirrors/qg/qgroundcontrol 点击查看 免费下载 导读 QGroundControl 的离线地图&a…

📰

HTML常用标签及属性速查:从分类、表单到CSS选择器的完整指南

简介:《HTML常用标签及属性》是一份面向Web前端初学者和需要快速回顾HTML知识的开发者的整理型Word文档。文档从HTML基础结构入手,系统分类讲解页面结构、文本格式化、列表、表格、表单及框架等常用标签,并重点对比了GET与POST两种提交方式的…

📰

基于Spring Boot的茶叶销售管理系统设计与实现

做茶叶销售管理系统这个项目,其实起因挺有意思。一位做茶叶生意的朋友找我抱怨,说用了好几套通用的进销存系统,总觉得别扭——茶叶等级、山头、年份、批次这些关键属性,在通用系统里根本没法精细管理,库存更是乱成一锅…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬