
先坦白一件事我最初对“AI Coding 工程化”这件事是持怀疑态度的。那时候团队里大家已经在用各类 AI 编程工具单文件生成、代码补全确实快可一旦任务跨多个文件、涉及公共模块改动AI 写出来的东西就经常失控——要么改坏了别人的逻辑要么自己没跑测试就自信地提交。折腾了几次线上事故之后我意识到问题的关键不是模型能力不够而是缺少一层“工程约束”。后来我逐步搭建了一套 Agentic Harness Workflow 框架把 AI Coding 从“让模型自由发挥”变成了“按流程、按门禁、可回滚、可审计”的工程化流水线。这篇文章就把我设计这套框架的全过程、核心机制和踩过的坑完整写出来希望对正在把 AI 编程引入正式项目的团队有实际参考价值。1. 为什么我在第五次被 AI 改崩代码库之后决定写这个框架先说一个典型的失控场景。某次我们做业务系统改造任务本身不复杂把一套老的会话校验逻辑统一抽到一个公共模块里然后让所有调用方切换到新接口。模型很快生成了第一版代码diff 里看起来改得挺干净。我大概扫了一眼就合入了主干结果当天下午就收到线上告警某个核心链路里判断会话状态的结果完全反了。排查之后发现AI 在“顺手优化”公共工具函数的时候把返回值的语义悄悄改掉了。传统代码评审能拦住这类问题是因为人会读 diff而 AI 生成的改动往往量大且零散人工审查很容易只扫表面、漏掉语义变化。这是第一次改崩之后同样的问题以不同形式又出现了四次模式都非常相似AI 的执行边界不明确、验证标准不强制、操作行为不可审计。后来我坐下来复盘发现团队用 AI 写代码遇到的高频问题其实只有几类改动范围不可控明明只让改某个模块AI 为了“让代码更整洁”顺手改了公共依赖和无关文件。验证缺失AI 生成代码之后不会自己跑测试、跑静态检查它甚至不知道自己改坏了什么。上下文失忆多文件任务里AI 改到第三个文件时已经忘了第一个文件的约束条件导致接口调整前后不一致。行为不可复现同一个任务描述昨天能生成正确代码今天同一个模型换了个上下文可能就完全跑偏。这四类问题的共同点在于它们不是模型能力问题而是缺少一层“流程外壳”。传统工程实践里我们不会让一个初级工程师在没有代码评审、没有测试门禁、没有权限控制的情况下直接改核心模块那为什么换个“AI 初级工程师”我们就放松了标准想清楚这一点之后我开始设计 Agentic Harness Workflow 框架。核心思路很简单让 AI 待在套子里干活。它仍然可以利用大模型的代码生成能力但生成之前有结构化任务定义生成之后有强制验证门禁运行全程有沙箱隔离和审计日志。用工程化的方式把“智能”约束在流程边界之内。这套框架的目标用户很明确已经不再满足于“让 AI 帮我写个函数”这类零散玩法而是想把 AI 编程接入正式 Git 工作流、CI 门禁和代码评审体系的团队。它适合有一定工程基础、愿意花时间搭流程的人而不是只想拿 AI 做一次性脚本的爱好者。2. Harness 到底管什么Agent 不是越多越好而是越受控越好“Harness”这个词在测试领域有另一个含义——测试夹具。它的作用是让被测对象能在稳定、可控、可重复的环境里运行。我给这套框架起名 Agentic Harness想表达的也是这个意思给 Agent 装上一层确定性外壳让它的随机性、创造性被约束在可控范围内。很多团队一上来就搞“多 Agent 协作”让几个 AI 角色互相讨论、轮流写码结果发现效率反而更低。我见过一个项目让三个 Agent 分别扮演“架构师”“开发者”“评审者”最后它们三个在一个接口命名上互相踢皮球浪费了大量 token 和等待时间。多 Agent 的问题在于如果没有外在的工程约束它们之间的交互和人类不靠谱会议没什么区别甚至更糟因为没有人会记得会议纪要。Harness 框架管的不是 Agent 的“思考过程”而是它的“行为边界”。具体来说Harness 层负责四件事任务结构化把模糊的自然语言需求转成有明确输入、输出、验收标准的任务定义。上下文管理决定给 Agent 看哪些代码、看多少历史避免上下文无限膨胀导致失忆或跑偏。工具权限约束明确告诉 Agent 能执行哪些操作读文件、写指定目录、跑测试不能碰哪些操作推分支、改配置、装依赖。验证与审计每个步骤产出必须经过验证门禁通过才能进入下一步所有动作留痕。这里有张表可以清楚看出“裸 Agent”和“Harness 约束下的 Agent”的差异维度裸 AgentHarness 约束下的 Agent任务输入聊天式自然语言结构化 Task 定义含路径、验收标准改动范围不受限可能改全局白名单路径禁止越界修改工具调用Agent 自行决定预定义工具集 高危操作拦截验证过程通常跳过强制跑通静态检查、单测、门禁命令失败处理重新生成直到“看起来对”携带日志重试限次超限转人工审计追踪基本没有全量 trace输入、输出、工具调用、验证结果这个设计的哲学是让模型做它擅长的事让流程做模型不擅长的事。模型擅长的是模式匹配、代码生成、快速产出候选方案模型不擅长的是记住约束、坚持验证、控制边界——这些恰恰是工程化流程最擅长的。在实际运行中Harness 主循环非常朴素看起来像一串一步一步执行的状态机而不是一个什么都管的“超级智能体”。我用 Python 伪代码描述一下核心逻辑def run_workflow(task: Task): ctx build_initial_context(task) # 收集仓库结构、相关文件、约束 for step in task.workflow_steps: if step.type agent: result run_agent_with_harness(step, ctx) elif step.type gate: result run_gate(step.gate_config, ctx) elif step.type human_approval: result wait_for_human_approval(step.approval_config) # 每个步骤执行完都持久化 state persist_state(task.id, step.id, result) # 验证失败则走重试或转人工 if not step_passed(result): handle_failure(task, step, result) return task.result流程本身不复杂难的是每一步的细节设计。后面几章逐个拆开讲。3. 工作流定义把一次编码任务拆成可审计的步骤链框架的第一步是让用户用一个可读的配置文件来声明“这次任务怎么跑”。我的做法是用 YAML 定义工作流每个任务对应一个 workflow 文件。它定义了 Agent 能碰哪些文件、必须跑哪些验证命令、哪些环节需要人工介入、重试次数上限是多少。这个文件本质上是把原来靠嘴说、靠 prompt 描述的任务要求变成机器可执行的合同。下面是我实际用过的简化示例# workflow/login-refactor.yaml name: refactor-login-session description: 把登录会话校验逻辑抽到公共模块并迁移所有调用方 agent: model: 商用大模型接口 # 实际配置里填具体服务商与模型名 temperature: 0.2 # 尽量保持输出稳定 max_tokens: 8000 scope: allowed_paths: - src/auth/** - src/shared/session_validator.* forbidden_paths: - src/payment/** - package-lock.json - ci/** tools: enabled: [read_file, write_file, run_test, git_diff] disabled: [git_push, install_dependency, modify_config] context: include_files: - src/auth/login_flow.py - src/shared/session_validator.py - tests/**/test_login*.py steps: - type: agent id: generate_impl prompt_ref: prompt_templates/refactor.md - type: gate id: static_check command: python -m pylint src/auth src/shared - type: gate id: unit_tests command: pytest tests/ -k login or session - type: gate id: diff_check rule: allowed_paths_only - type: human_approval id: review_pr required: true retry: max_attempts: 3 on_failure: escalate_to_human写这个文件的过程本身就是把任务想清楚的过程。我经常遇到这种情况团队让我“用 AI 把这个模块重构一下”但当我追问“允许改哪些文件、验收标准是什么、哪些测试必须过”时对方往往答不上来。这说明问题根本不在 AI而是需求本身就模糊。工作流定义文件强迫需求方先把这些信息补齐。任务拆解的粒度也很重要。我踩过的一个坑是一开始让一个 Agent 任务覆盖整个模块重构结果就是失控因为改动面太广上下文塞满了各种相关信息。后来我总结了一条经验单个 Agent 任务尽量控制在 3 到 5 个文件的改动范围内超过这个范围要么拆任务要么让 Agent 只做探索分析不做实际修改。拆任务不是让 Agent 自己拆而是在工作流层面拆成多个步骤每个步骤有独立的验证点。比如“重构登录会话”这个需求拆成三步第一步生成新公共模块实现改动 src/shared/session_validator.py第二步迁移调用方改动 src/auth/ 下的文件第三步清理废弃逻辑删除旧代码跑全量回归每一步之间都有验证门禁上一步没过下一步根本不会启动。这样即使中间出问题也能快速定位是哪个环节挂了而不是拿到一个大而全的失败结果无从下手。状态持久化是另一个容易被忽略的点。工作流跑了一半挂了或者验证没通过需要重试这时候 Agent 得知道之前发生了什么。我的做法是把每个步骤的输入、输出、验证结果都存下来重试时把这些信息注入上下文让 Agent 基于真实结果继续而不是从头再来一遍。这个机制的价值在后来的使用中体现得很明显尤其是处理那些需要多轮修复的编译错误。4. 三个失控点上下文怎么管、工具权限怎么约束、沙箱怎么隔离框架搭起来之后最大的麻烦不是流程本身而是三个具体环节的失控。我把它们单独拿出来说就是因为这三块是实际运行中最容易出问题、也最需要精细设计的地方。4.1 上下文管理与其让模型自己记不如由 Harness 注入和裁剪大模型的上下文窗口再大也是有限的。多文件任务里最常见的问题就是Agent 一开始记得约束条件改到第三个文件时把第一个文件的接口签名忘得一干二净或者被无关的代码信息干扰产生了“过度优化”的冲动。我的方案是让 Harness 负责上下文的组装和裁剪而不是让 Agent 自己去读文件。流程上分三层基础上下文包括任务定义、工作流配置、仓库结构树、相关文件的只读内容。这些在第一步统一注入避免 Agent 通过工具反复搜索浪费 token。过程上下文每个步骤运行结束后Harness 把 diff、测试输出、验证结果按结构化格式存起来。重试时这些内容作为“最近进展”注入让 Agent 知道当前代码处于什么状态。摘要上下文如果过程上下文太长Harness 会用一次独立的摘要调用把历史压缩成要点减少 token 占用。这个操作相当于人的“翻笔记本”不是让模型记住所有细节而是记住关键决策和当前状态。有个细节要注意注入上下文的时候路径引用要统一、绝对。不然 Agent 容易在相对路径里绕晕。我在框架里把仓库根路径做成模板变量在注入前渲染成绝对路径效果比让 Agent 自己猜路径好很多。4.2 工具权限给 Agent 列一张“能做什么”和“不能做什么”的清单这一步是最容易被轻视的。很多人觉得给 Agent 接上工具就完事了结果 Agent 自己调用了不该调的接口。我见过最离谱的情况是Agent 在测试全部失败之后自作主张改了测试用例来“匹配”错误的实现最后测试通过了但代码逻辑是错的。Harness 的权限控制不是靠“提示词约束”而是靠技术上禁止。具体做法是在工具调用层做拦截TOOL_WHITELIST { read_file: allowed, write_file: allowed_if_in_allowed_paths, run_test: allowed, git_diff: allowed, git_push: denied, install_dependency: denied, modify_config: denied, }所有 Agent 要发起的工具调用都经过一个代理层代理层先检查调用是否匹配白名单和路径规则不匹配的直接拒绝并记录到审计日志而不是把错误结果返回给 Agent 让它自己“改一改再试”。这里我还要强调一个“禁止修改测试”的特殊规则。默认情况下如果测试失败Harness 会把失败日志交给 Agent 修复代码但禁止 Agent 修改测试用例本身除非任务明确声明了“本次任务包含测试代码修复”。为什么这么严格因为测试是衡量 Agent 工作的标尺如果连标尺都可以被改写整个验证体系就失去了意义。这个规则在实际使用中避免了好几次“假通过”的坑。4.3 沙箱隔离让 Agent 在容器里折腾别碰真实环境工具权限约束的是“逻辑层”沙箱隔离解决的是“物理层”。我的做法是每个 Agent 任务跑在一个独立的容器里容器挂载仓库的只读副本Agent 的所有改动先写到容器内的临时目录通过验证门禁之后再统一合并回工作区。这样做有几种好处网络出口受限Agent 不能从外部下载来源不明的依赖。文件系统隔离Agent 即使误操作也不会破坏宿主环境里的真实文件。依赖安装走内部镜像版本可控不会出现“昨天能跑今天不能跑”的玄学问题。容器可以随时销毁重建环境恢复到任务开始时的状态保证重试的确定性。我在第一版框架里偷懒没做容器隔离直接用宿主机跑 Agent结果它有一次在沙箱外的临时目录里创建了一堆垃圾文件还改了系统级的环境变量。从那之后我把容器隔离列为默认必选项而不是可选项。4.4 高频踩坑汇总失控现象根因应对手段Agent 改坏公共模块没有路径白名单在 scope 里限定 allowed_pathsAgent 修改测试“证明”自己正确测试被视为可操作对象默认禁止修改测试除非任务显式声明Agent 修改依赖版本工具权限过于宽泛禁用 install_dependency依赖变更走人工审批任务上下文过长导致失忆没有裁剪和摘要机制Harness 分三层管理上下文超限自动摘要重试后代码和之前不一致没有状态持久化每个步骤保存 state重试时注入真实历史5. 验证门禁的设计没有门禁的 Agent 只是打字机整个框架里我最想强调的就是验证门禁。可以这么说如果你只想在现有流程上加一个东西那就加验证门禁。因为它能把“AI 生成了一堆看起来对的代码”这件事彻底改变成“AI 生成的代码必须通过客观标准检验才能进入下一步”。门禁不是一个单一动作而是一条流水线。我的配置里至少包含四类检查按执行顺序排静态检查pylint / eslint / type check负责抓语法错误、未定义变量、类型不匹配。单元测试跑与本次改动相关的定向测试速度要快能快速反馈。集成测试跑核心链路相关测试确保改动没有破坏跨模块的交互。改动范围校验对比最终 diff 和任务定义的 allowed_paths任何越界文件都算门禁失败。这里为什么把“改动范围校验”也做成一道门禁而不是只靠权限拦截因为权限拦截是防 Agent 越权但有时候 Agent 会在白名单目录内生成一些无关的杂散文件比如备份文件、临时文件。范围校验关注的是最终产物里有没有“多余的东西”两者互补。门禁失败后的处理逻辑同样重要。第一版框架我设计得很粗暴测试挂了就让 Agent 重新生成结果它在一个错误修复上连续失败 7 次每次都是改一个编译错误又引入一个新的。后来我加了两个机制重试限次默认最多 3 次。每次重试时Harness 会把上一次的测试失败日志完整交给 Agent并明确告诉它“基于这个日志修复不要重写整个文件”。这比让它凭空重写有效得多。失败升级3 次重试仍失败自动转给人工处理。框架生成一份失败报告内容包括任务定义、Agent 尝试过的修复方案、最后一次失败日志。人拿到这份报告可以直接接手不需要重新走一遍上下文收集的过程。这里我还有一个真实经验验证门禁本身也可能出错尤其是那些慢测试、不稳定测试。如果一个测试经常闪断Agent 修了好几次都“失败”最后发现其实是 CI 环境问题。所以门禁跑的环境要尽量稳定跑之前先做一次“基线验证”——用未改动的代码跑一遍门禁确认环境本身是绿的。这个步骤看起来多花了时间但在长期使用里省下的排查时间远远大于成本。人工审批节点也是门禁体系的一部分但它验证的不是“技术正确性”而是“业务合理性”。我的配置里把这些场景设为必须人工审批修改 CI 配置、更换依赖版本、删除公共 API、大规模重构涉及 10 个文件以上。Agent 在这些节点会被挂起等待审批结果。人审的时候不需要看完整 diff重点看工作流生成的“改动摘要 验证结果 风险提示”这个设计大大降低了人工评审的成本。有人问我加了这么多门禁AI 编码的效率不是反而降低了吗确实单次任务耗时变长了但把“返工、线上事故、AI 写崩代码后人工排查”的时间算进去总账是省的。我宁可让一次 AI 编码任务多花 20 分钟验证也不愿意花两天时间排查一个线上问题。6. 落地到现有工程体系CI、评审与 Agent 的权责边界框架在本地跑通之后下一步就是把它融入团队已有的开发流程。我的经验是不要尝试用这套框架替代现有的 Git 工作流和代码评审体系而是让它作为“自动化的结对工程师”接入目标是减少人的重复劳动而不是增加新的流程负担。具体落地方案分几个阶段阶段一AI 只提方案不改代码。让 Agent 生成实现方案和关键 diff由人来决定是否采纳。这一步的风险最低适合验证框架的产出质量。阶段二AI 在特性分支上产出改动。Agent 的修改只发生在独立分支通过全部门禁后自动创建 PRPR 描述里带上工作流生成的改动摘要。评审人仍然可以走正常评审流程但因为有摘要和验证结果评审负担大幅降低。阶段三授权范围扩展。当团队对框架的信任建立之后再逐步放开高危操作的权限比如依赖升级、配置修改每一步都保持“默认禁止显式批准”的原则。与 CI 的集成方式也很关键。我建议把 Harness 的结果直接映射成 CI 的检查项比如把“静态检查通过”“单元测试通过”“改动范围校验通过”分别暴露成三个独立的 check。这么做的好处是 GitHub / GitLab 的 PR 页面能清楚看到哪些环节过了哪些没过。Agent 产生的改动和人类提交的代码在评审流程上没有区别唯一的区别是 PR 描述里多了“本 PR 由 Agentic Harness Workflow 生成”的标记评审人可以选择更严格地审查。关于“权责边界”这是所有团队都必须面对的问题代码出问题了是 Agent 的错还是工程师的错我的答案是Agent 对满足验证门禁负责工程师对需求理解和最终合入负责。换句话说Agent 生成的代码只要通过了所有门禁就完成了它的职责但把这份代码合入主干的人需要承担需求正确性的责任。这个原则要写进团队的协作规范里否则很容易出现“AI 生成的不关我事”的甩锅文化。试点范围的选择也是落地成败的关键。我的建议是先从风险低、边界清晰的模块开始工具函数库、测试代码生成、文档生成、配置模板更新。这些任务的特点是验证标准明确出错了影响面小。等流程跑顺畅之后再逐步扩展到业务逻辑模块。我当时犯过一个错误第一周就直接让 Agent 处理核心支付链路的改造结果喷了一下午后来才切换成“先试点再扩大”的节奏。另外要提一下成本控制。框架跑 Agent 会消耗大量 token特别是重试和上下文注入。我在工作流配置里给每个任务设了 max_tokens 上限并在 Harness 层记录每个步骤的 token 消耗。实际运行下来一次中型重构任务的成本大约相当于几次长对话的量还在可接受范围内。真正贵的不是单次生成而是“让 Agent 反复读不需要的文件”所以上文提到的上下文裁剪机制在成本控制上比想象中更重要。我踩过的最深的一个坑是Agent 在沙箱里跑测试时因为容器里的 Node 版本和宿主环境不一致导致测试环境挂了而 Agent 误以为是自己代码的问题反复重试。从那之后我把“容器内环境版本与 CI 环境保持一致”列进了基线验证的硬性要求这个问题再没出现过。最后说一个自己最近的体会。我发现 Agentic Harness Workflow 框架最有价值的产出不是让 AI 写了多少代码而是让团队被迫把“任务边界”“验收标准”“验证门禁”这些原本模糊的事说清楚。以前很多人觉得 AI Coding 无法工程化是因为他们想用 AI 替代人类的判断能力但工程化恰恰相反人类负责设定边界和标准AI 负责在边界内高效执行。这套框架本质上是在教团队和 AI 建立起一种分工清晰、互相制约的协作关系。如果你也在为 AI 编程的工程质量头疼不妨先别急着换更强的模型试着给你的 Agent 套上流程的缰绳。