企业级AI Coding落地:Harness与Skill全链路实践指南
大半年前我接手团队内部 AI Coding 落地时第一批试点让 Agent 直接改核心服务结果它交回一个“自信满满”的 300 行 diff声称所有测试通过实际上连测试都没跑。那次翻车让我意识到企业级 AI Coding 缺的不是更强的模型而是一套能约束、编排、审计 Agent 的 Harness以及一批可复用的 Skill——把从需求到上线这条链路拆成有边界的、可验证的环节。这篇文章想把我们后来沉淀下来的经验完整写一遍Harness 工程到底在工程什么8 个 Skill 是怎么把需求解析、方案设计、编码、测试、审查、安全、文档、发布这八段串成一条可回放、可熔断、可入审的全链路以及我们在这条链路上踩过的坑。适合正在企业里做 AI Coding 落地、又不想把 AI 当“高级自动补全”用的工程师和架构师。1. 为什么裸 Agent 会在企业代码库上翻车三个真实事故现场1.1 上下文失焦模型在“看到”和“理解”之间隔着一座仓库在本地 demo 里我们很喜欢把整个仓库路径塞给 Agent让它自由爬代码。仓库 50 万行以内还行到了百万行级上下文窗口直接被冲爆更糟糕的是 Agent 会抓取“看起来相关”的变量名然后一本正经地改错模块。我印象最深的一次老服务里存在两个名字相近的 sendAlert 函数一个负责日志告警一个负责用户短信Agent 只看了其中一处就把短信接口的类型签名改了改完单元测试居然还过了——因为另一个模块没有测试覆盖。这就是“局部理解 全局操作”的典型事故。模型不是故意乱改它根本没意识到仓库里还藏着另一个同名模块。这个问题靠提示词解决不了必须在 Harness 层把“一次查询全库”改成“检索、聚焦、修改、验证”的受控循环让模型每一步只拿到当前环节真正需要的代码切片。1.2 权限失控给 Agent 开 shell 就是给团队埋雷很多 Agent 框架默认会暴露 shell 执行、文件写入、git 提交、网络请求等工具。在个人电脑上没问题但企业环境里模型对命令的理解是概率性的它不知道“这条命令会影响生产库”。我们当时放开过一个“执行测试”的权限结果 Agent 在本地 docker 里跑监控脚本还能接受可一旦 Agent 能 push 到 feature 分支所有人都开始担心代码审核变成“事后追认”。这里有个很有意思的细节模型本身并不“贪婪”它只是没有能力评估命令的副作用边界。在 Harness 的工具层做最小权限、命令白名单、写入路径限制不是为了防模型故意干坏事而是为了防它“无意中干大事”。1.3 验证缺位模型说“测过了”不等于真的跑过Agent 的“自信”是出了名的。它的回答里出现“tests passed”可能只是基于代码结构的推测而不是实际执行了 pytest。要让验证真正发生必须由 Harness 把“执行测试”当作一次外部工具调用并把 stdout、exit code、覆盖率报告返回给模型。人为信任模型声称的验证结果是试点阶段返工率最高的原因之一。提示任何涉及“验证”“测试”“构建”的结论都必须在 Harness 日志里有对应的工具调用记录否则默认视为未验证。1.4 没有黑匣子事故复盘只能靠猜如果模型直接跑在终端里出了 bug 你很难回答三个问题它改了什么为什么这么改当时看到了什么上下文没有这些信息SRE 就会把 AI 产出的代码当垃圾对待。Harness 最重要的价值之一就是把一次任务变成一条可回放的日志链模型的每一步决策、每一次观测、每一条工具返回都沉淀成结构化记录。个人玩票可以不要黑匣子企业落地不行。维度个人玩票企业级 Harness上下文读取整仓塞入检索切片 聚焦循环工具权限默认全开最小权限 白名单验证结论模型自述工具调用记录失败排查重跑一次审计日志回放上线门槛无审批节点 门禁2. 先把概念钉死Agent 是内核Harness 是运行时Skill 是工序卡2.1 Agent 是专家Skill 是工序卡Harness 是工地管理系统我自己给团队讲概念时通常用工地做类比Agent 像一位会砌墙的师傅Skill 是标准化工序卡比如“浇筑前检查钢筋间距”Harness 则是工地管理体系——它不替你砌墙但管着工人的施工资质、材料进出、质量验收、安全日志。没有管理体系的工地师傅水平再高也会出事没有 Harness 的 AI Coding模型再强也容易跑偏。这个类比还能解释很多现象为什么同一个模型在个人项目里很好用换到企业代码库就失控因为个人项目没有“工地管理制度”师傅凭经验干活出事概率低企业项目里模块边界、历史包袱、权限约束、发布流程都极其复杂单靠模型经验远远不够。Skill 的价值则是把“师傅的经验”显式化、标准化让它可复用、可评审、可替换。2.2 Harness 的五个核心职责状态、循环、工具、策略、观测Harness 不是某个具体框架而是一组职责的集合状态管理记录一次任务从需求到交付的上下文而不是让模型自己脑内保存。每个 Skill 的输入输出、每个步骤的中间产物都应当被 Harness 持久化。控制循环决定下一步调哪个工具、何时结束任务、何时求助人工。这里既包括线性编排也包括遇到失败时的“再试一次”或“降级给人”。工具调度通过注册表把工具暴露给 Agent保证权限可控、调用可审计。Agent 不应该能访问未注册的工具。安全策略在工具调用前后加拦截和过滤。比如代码生成前检查上下文是否包含密钥生成后检查 diff 是否引用了未授权路径。可观测性记录每次 LLM 调用、工具调用的输入输出便于回放与计费。这条在故障复盘时几乎是救命稻草。从工程视角看Harness 就是在模型和真实系统之间加了一层“转换层控制层”。没有这层模型的输出是内容有了这层模型的输出才变成可治理的变更。2.3 Skill 的解剖学输入输出、工具白名单与失败信号Skill 可以理解为一段领域知识 工具列表 输入输出约定 验收标准的组合。好的 Skill 不是“更长的 prompt”而是把“什么时候能调用、调用后会触发什么副作用、失败后怎么降级”都写清楚。下面是我们内部一个 Skill 的元数据示例这个 Skill 负责从工单里提取验收标准name: spec-analyzer description: 从工单文本和仓库上下文中提取需求、边界条件和验收标准 inputs: ticket_text: string repo_context: object outputs: requirements: array edge_cases: array accept_criteria: array tools: - repo-search - db-schema-reader guardrails: max_tokens: 4000 forbid: [edit_files, shell] verification: - requirements 为空时必须返回 needs_human 信号 - 必须列出至少 5 个边界场景否则视为生成失败注意这个文件不是被直接塞进模型 prompt 的而是由 Harness 读取的运行时元数据。Harness 根据它决定允许这个 Skill 调用哪些工具、输出要满足什么 schema、失败时该走什么分支。Skill 本身可以理解为“封装了领域知识、又受 Harness 约束的原子能力”。3. 从薄壳到平台最小可用 Harness 的选型与骨架3.1 选型先套壳后抽象企业里最容易犯的错误是一上来就买一个巨大的 Agent 平台或者自研一个“全宇宙调度中心”。我建议反过来先用成熟 CLI 型 Agent 作为“模型执行单元”无论是 codex 系还是 deepseek 系外层套 Harness 的思路完全一致外面包一个很薄的 Harness 壳提供任务队列、状态存储和审计日志当任务类型变多、并发上来后再把通用能力抽象成平台。很多人问要不要直接用网上现成的 harness 项目比如 codex harness、deepseek harness 这类封装。我的建议是把它当成参考实现可以直接拿来上生产要谨慎。企业流程差异太大工具链、权限模型、审批节点、审计要求各不相同几乎必然要二次开发。3.2 最简任务循环safe_call 与 should_stop 是关键下面这个伪代码是我见过的很多企业级 Harness 的最初形态。它不是完整系统但把控制循环的核心逻辑讲清楚了class MinimalHarness: def __init__(self): self.tool_registry {} # 注册表name - callable self.skill_defs {} # skill 元数据 self.audit_log [] # 结构化审计日志 self.task_queue deque() # 任务队列 def dispatch(self, skill_name, payload): skill self.skill_defs[skill_name] if not self.check_permission(skill): return self.need_human_approval(skill_name) plan self.build_plan(skill, payload) for step in plan.steps: if step.action call_tool: result self.safe_call(step.tool, step.args) self.audit_log.append({ step: step.id, tool: step.tool, input: step.args, output: result.summary(), }) if self.should_stop(result, plan): return self.escalate_to_human(skill_name, plan) return self.finalize_output(plan) def safe_call(self, tool, args): if tool not in self.tool_registry: raise PermissionError(f未注册工具: {tool}) if not self.tool_whitelist_allows(tool, args): raise PermissionError(f工具参数超出白名单: {tool}) return self.tool_registry[tool](**args) def should_stop(self, result, plan): if result.status failed and plan.retry_count 3: return True if plan.total_token_usage plan.token_budget: return True return Falsesafe_call 保证模型只能调用已注册、且参数符合白名单的工具should_stop 是熔断逻辑防止 Agent 陷入“失败、重试、再失败”的死循环。这两点就是 Harness 与传统“把 prompt 丢给模型”最本质的区别。3.3 落地前必须补齐的三个企业工程底座Harness 本身不复杂复杂的是它需要接入企业已有的工程体系。我们落地前花了大约三周就干三件事代码仓库事实源必须有可靠的代码索引/搜索接口否则 Skill 很容易捞到过期文档和镜像函数。没有索引的时候Agent 每次搜索的结果就是不可复现的这是很多“玄学问题”的根源。CI/CD 验证钩子测试、静态检查、构建要能被外部调用并返回结构化结果否则 Harness 无法把它变成闭环。很多企业 CI 是“人看网页”的形态Agent 拿不到机器可读的验证结果闭环就断了。权限与密钥隔离不要给 Agent 直接读生产密钥使用临时令牌、scope 极小的服务账号。模型会复制上下文里出现的任何信息所以上下文里不应该出现不该让它看到的东西。这三个底座不补齐后面 8 个 Skill 做得再精细也是沙上建塔。4. 八个 Skill 怎么串起需求到上线的全链路4.1 全链路地图八道关卡的输入输出一条自然的需求到上线链路可以拆成八个环节需求解析、方案设计、编码实现、单元测试、代码审查、安全扫描、文档同步、发布说明。我们把这八段分别做成独立 Skill每个 Skill 有明确的输入输出、工具权限和人工检查点Skill输入输出主要工具人工检查点spec-analyzer 需求解析工单文本/PR 描述验收标准、边界条件repo-search需求 owner 确认arch-planner 方案设计需求条目改动方案、影响面、风险等级code-graph、db-schema架构师审批code-gen 编码实现方案 相关代码切片代码 diffrepo-search、editor无由下游把关test-gen 测试生成代码 diff新增测试代码test-runner无code-reviewer 代码审查diff 测试结果审查意见、改进建议static-analysis工程师 reviewsec-scanner 安全扫描diff 依赖清单敏感信息/漏洞报告secret-scan、dependency-check安全负责人审批doc-writer 文档同步diff 需求设计文档/API 文档变更docs-sync文档 ownerrelease-notes 发布说明已合并 commit 集合面向用户/产品的发布说明git log产品经理确认这么拆的好处很直接每个 Skill 可以单独调优、单独替换不会牵一发动全身。每个环节都能插入人工审批比如方案设计后必须架构师确认再进入编码。某个环节失败时可以单独重试不需要整条链重新跑。4.2 上游三个 Skill把“人话需求”变成“可执行方案”spec-analyzer 输入的是 Jira/飞书工单的标题和描述里面混着产品语言、用户吐槽和复制粘贴的报错日志。它的任务不是“理解”而是“结构化”提取真实需求、非目标、边界条件、验收标准。最容易漏的是边界条件所以我们要求它至少列出 5 个异常场景比如空数据、重复请求、权限不足、超时、并发竞争。输出是一份 requirement JSON作为整条链路的“宪法”。arch-planner 把需求变成代码改动方案。它要能回答改哪些文件、不动哪些文件、有没有兼容性问题。输出是一个 plan JSON包含文件路径、改动类型、风险等级。企业里这个关卡必须有架构师审批因为架构层面的错误成本最高——改错一个模块边界后续所有代码都是错的。这两个 Skill 表面看是“阅读理解”实际考验的是 Harness 的检索能力。如果 repo-search 返回的代码片段是过期的后面所有 Skill 都会基于错误事实开工。这也是为什么第 3 章把“代码索引”列为前置底座。4.3 中游两个 Skill用“测试先行”的闭环压制幻觉code-gen 是在 arch-planner 的 plan 基础上实施。我强烈建议不要让 code-gen 自己拉全仓库要让它只看到计划指定的文件清单和最近的代码上下文。它的输出是 diff且必须通过 lint、类型检查、编译三个前置校验否则直接判定失败。传统流程是“写完代码再补测试”但在 AI 时代我建议反过来先让 test-gen 基于需求生成关键路径测试再让 code-gen 实现功能去满足测试形成一个“测试先行”的循环。测试用例是需求的可执行翻译它天然比提示词更能约束模型行为。这能显著抑制模型幻觉因为“自认为正确”和“测试真的通过”之间有一道客观闸门。当然test-gen 生成的测试质量也参差不齐所以 CI 里要设置覆盖率阈值和一条特殊策略禁止模型修改测试预期来迎合实现。这一条非常重要测试生成 Skill 最容易被反向利用变成“粉饰实现正确性”的工具。4.4 下游三个 Skill让 diff 变成团队敢合并的东西code-reviewer 的作用和真人 PR review 类似但它不是替代而是给工程师省出“第一遍看代码”的时间。它会检查反模式、潜在 bug、安全问题、命名一致性输出“必须修改/建议修改/可忽略”三级意见。这个 Skill 里我们沉淀了内部代码评审经常强调的规则禁止吞异常、禁止裸返回内部错误信息、禁止在循环里查数据库等。sec-scanner 对 diff 做敏感信息扫描、依赖版本检查、危险 API 调用检查。企业里把它做成“合并前的硬门禁”命中高危规则比如硬编码密钥、执行 shell 命令、连接内网未授权地址直接阻断合并。它不是替代安全团队而是把安全团队的例行检查自动化。doc-writer 和 release-notes 这两个 Skill 很容易被忽略但企业里价值极高。doc-writer 负责同步设计文档与 API 文档避免“代码改了文档没改”release-notes 从 git log 和 PR 标题中生成面向用户/产品的发布说明并且严格禁止把内部 commit 消息直接粘进去。两个 Skill 的 prompt 里都要写死“不许虚构变更”的约束一切内容必须来自已合并的 diff 或工单。5. 编排八个 Skill 时最容易翻车的三个工程细节5.1 上下文瘦身喂给模型的必须“刚刚好”在一次需求到上线的链路里如果每个 Skill 都把上一个 Skill 的全部输出、代码仓库搜索摘要、工具结果一股脑传给模型上下文很快就会爆。我们当时的做法是把上下文包设计成“当前任务提示 上游产物摘要 最近 50 个相关文件片段 工具结果缓存”而不是“所有产物全量”。实际经验单个 step 的上下文尽量控制在 8K token 以内。超过后模型行为会变得不稳定常见表现是开始重复调用工具、前后矛盾、或者在一个小问题上绕圈。你可以把上下文当作一个“短期工作台”工具则是“抽屉”。人的工作习惯是不会把整个仓库摊在桌上干的模型也一样。5.2 工具返回的脏数据比模型幻觉更常见Agent 调用静态检查工具时返回的 JSON 可能包含几百个字段模型会自动关注那些“看起来像问题”的字段即使它们是噪声。比如 lint 结果里既有 error 也有 warning 和 deprecated 字段模型经常被 warning 带偏去修一些不该修的代码。所以 Harness 在工具接入层要做 schema 清洗只保留当前 Skill 关心的核心字段并把工具结果统一转成标准结构。这比在 prompt 里写“请忽略 warning”可靠得多。prompt 是建议schema 是约束。模型通常不会违反 schema但经常会忽视 prompt 里的软性要求。5.3 重试不是默认动作熔断要写死在 Harness 里AI Coding 链路里“自动修复”很容易变成“自动瞎改”。我们定的策略是某个生成动作连续重试 3 次仍通不过校验就从自动循环切到人工工单把 Harness 日志与失败快照附上。成本上一次重试平均 2K—5K token重试 10 次的成本远高于工程师本地改 5 分钟。更麻烦的是重试次数越多模型越容易为了“通过”而修改验证条件产生自欺欺人的结果。熔断条件必须显式写在 Harness 里不能靠模型自己判断。模型永远是乐观的你需要一个悲观的看门人。6. 三个从生产环境挖出来的故障复盘6.1 密钥是怎么绕过两层检查的现象一次 sec-scanner 检查通过却被真人 review 发现 diff 里疑似硬编码 token。排查链路我们导出 Harness 审计日志发现 code-gen 在某个上下文里同时看到了“.env.example”和“测试环境配置”两个片段于是把样例值误填充成了真实 token。更深一层的原因是 sec-scanner 的规则只覆盖了标准 secret pattern没覆盖这个自定义配置格式。这不是模型“故意泄漏”而是“上下文里出现了不该出现的内容”。修复方案做了两件事在 sec-scanner 后增加“变量来源追踪”任何填充值必须来自依赖清单而不是来自代码片段同时把密钥服务器的敏感信息从模型上下文里彻底隔离。这里有个规律值得反复强调模型会复制上下文里出现的任何信息所以与其事后过滤不如从源头保证上下文干净。6.2 同一个需求为什么三份方案完全不同现象arch-planner 对同一份需求生成了差异巨大的三份改动方案人工审批压力很大。排查链路对比 Harness 审计日志里的上下文发现问题不在 prompt而在代码检索结果不一致。代码搜索服务刚上线索引还没完全刷新每次搜索返回的“相关文件”都不一样导致方案自然漂移。更隐蔽的是即使语义相同排列顺序不同模型也会表现出不同的偏好。修复给检索步骤加“索引版本号”方案生成前先校验索引 freshness另外给 arch-planner 增加“稳定输出”约束——先基于固定文件清单生成候选方案再允许二次搜索补充信息。这个故障告诉我们AI Coding 的确定性不来自模型温度参数而来自 Harness 流程的固定性。6.3 一次“简单修 bug”怎么触发了三十个子任务现象一个 fix 任务跑了将近一小时任务队列里出现大量同质化子任务Token 消耗比预期高了一个数量级。排查链路从控制循环日志发现code-gen 修好一个函数后test-gen 生成的测试又失败于是 code-gen 继续修改形成“修改、测试、修改”循环。最离谱的是一次失败触发了对另一个无关键路径文件的改写产生了连锁修改最后波及十几个文件。修复在 Harness 里加了两条硬规则一是同一任务最多三层嵌套子任务二是 code-gen 只能在 plan 指定的文件清单内修改除非人工临时授权。这条规则后来被写进了所有 Skill 的通用元数据里。循环失控是控制循环没有尽头的典型症状必须要用“结构半径”限制模型的探索范围不能指望模型自己知道何时该停。7. 试点与推广企业落地 AI Coding 的节奏和衡量标准7.1 试点选型找“有测试、有 owner、有耐心”的服务别拿核心交易系统试也别拿完全没有测试的遗留老系统试。最好的试点是一个中型内部服务有比较完整的单测覆盖、有明确 owner、可以接受一定返工。试点周期建议 4—6 周前两周只让 AI 产出 draft PR人工重写也无所谓重点是把 Harness 链路跑顺后面再逐步放开自动合并。有一种误区是“找一个很难的任务来验证”。企业落地不需要证明模型能写多难的系统需要证明的是流程可控、结果可复现、成本可预期。7.2 用四个指标判断 AI Coding 是否真的有效我们团队当时盯着四个指标讲真它们比“AI 替代了多少岗位”这类说法靠谱得多指标定义参考目标自动化产出占比AI 产出并合入的代码量 / 总合入量20%—40%太高要警惕把关失效返工率AI 生成的代码被打回重做的比例低于 30%否则验证环节太弱人工介入率每个任务平均需要工程师救场的次数趋势持续下降交付周期变化同量级需求从工单到合入的平均时长相比人工基线缩短指标不能只看单个要组合看。比如自动化产出占比很高但返工率也很高说明 AI 产出了大量废代码人工介入率下降但交付周期没变可能只是把人工工作前置了。7.3 半年后团队的真实变化工程师变成了“评审者”我们团队落地半年后的体会是AI Coding 没有让工程师失业反而把大量低创造的模板代码、重复修改和文档同步工作交给了 Agent工程师的时间更多花在“判断模型产出是否合理”上。全链路被 Skill 切成了一段段可以检查、可以问责的工序后模型在哪一步弱就在那一步加人审或换工具。我个人认为企业级 AI Coding 的难点从来不是“让模型写代码”而是“让模型在一个有边界、有审计、可回退的容器里写代码”。回头看那批 Skill 本身并不难写难的是 Harness 提供的纪律感——它逼着我们把每个环节的输入、输出、期望和失败动作都定义清楚。如果你也想在企业里落地建议先不要急着买一堆 Agent 平台。花一两周把当前团队从需求到上线的真实流程画出来找出哪些环节是反复的、可验证的然后挑三个最痛的地方做成 Skill 试点。剩下的链路会自己长出来。