☰
Harness Engineering:给AI智能体搭建安全高效的运行环境
2026/10/1 13:44:08 网站建设 项目流程

第一次听到 "Harness Engineering" 这个词,是在一次技术评审会上。当时我们团队正为一个 AI 编程智能体项目(内部代号就叫 CodeBuddy)接入公司的代码仓库、测试环境和发布流水线,结果发现真正难的不是模型选型,而是怎么把这个智能体的"工作环境"搭得既像一个人一样顺手,又不会越界闯祸。后来我们慢慢把这件事总结成一句话:给 AI 配一间办公室,而这间办公室的设计与建造过程,就是 Harness Engineering。

如果你不了解这个概念,我先用大白话解释一下。Harness 在英文里的原意是马具、挽具,也就是把马和车连接起来的那套装置。在 AI 工程领域,Harness 指的就是连接大模型与外部世界的整套运行环境——包括模型怎么接入、上下文怎么管理、工具怎么调用、权限怎么控制、人和 AI 怎么配合、出了问题怎么追溯。Harness Engineering 则是设计、搭建并持续维护这套装置的全部工程实践。

这篇文章适合谁看?只要是正在做 AI 应用、AI Agent、AI 编程助手,或者打算把大模型接进真实业务系统的人,都会用得上。我会按六个模块展开:接入与权限、上下文与记忆、工具与执行、规划与协作、人机协同、观测与评估。每个模块都会讲清"为什么需要它"以及"我们是怎么实现的",最后给出一套 CodeBuddy 从零落地的完整路径和踩坑记录。

1. 先从"办公室"这个比喻说起:Harness Engineering 到底是什么?

把 AI 放进一个空地上,它什么都干不成。它需要工位、电脑、文件柜、会议室、主管、前台和监控。同样,一个 LLM 如果只有裸的对话接口,也完成不了真实项目任务。它需要一套完整的"办公环境":知道自己的能力边界(工位)、过去发生了什么(文件柜)、能调用什么工具(电脑和工具箱)、遇到大活怎么拆解(主管和会议室)、什么节点必须请示(前台和审批窗),以及出了问题怎么回溯(考勤和监控)。

这六个部分,就是 Harness Engineering 的六大模块:

模块办公室角色对应工程能力
接入与权限门禁/工牌模型接入、身份认证、权限边界
上下文与记忆工位/文件柜系统提示、短期上下文、长期记忆
工具与执行工具箱/实操间工具注册、函数调用、沙箱执行
规划与协作主管/会议室任务分解、多 Agent 编排、状态机
人机协同前台/审批窗关键节点确认、人工干预、反馈回传
观测与评估考勤/监控室日志追踪、指标评估、回归与审计

我见过很多团队,一上来就死磕 prompt,觉得只要把提示词写得足够花哨,AI 就能稳定输出。但实际跑一段时间你会发现:Prompt Engineering 解决的是"怎么说",而 Harness Engineering 解决的是"怎么干活"。一个任务最终能不能成,往往取决于 60% 的 harness 设计和 40% 的模型能力。举个最简单的例子:同样是写一个函数,模型能力决定它写得好不好,但工具层决定它能不能真的把代码写进文件、能不能跑测试、能不能在出错时回退——后面这些才是真实项目里最花时间的地方。

我们内部还有一个更形象的比喻:Prompt 是"开会时说什么",Harness 是"公司长什么样"。你可以在会上把需求讲得很清楚,但如果公司没有门禁、没有文件柜、没有能干的工具箱,这个人再聪明也交不出活。下面,我们就按这个公司的设计蓝图,一间房一间房地搭。

2. 门禁与工牌:接入、身份与权限模块

2.1 模型接入不是一个 API Key 那么简单

很多人以为接入模型就是配一个 API Key,填进环境变量就完事。实际一旦进入工程化,你会发现至少要回答这些问题:用哪个模型当主脑?不同任务要不要路由到不同模型?Key 怎么管理?本地开发、CI、生产各用什么凭据?请求超时、熔断、降级策略是什么?成本预算怎么控制?

拿我们 CodeBuddy 项目举例,模型接入层大致长这样:

# harness.yaml —— 模型接入与路由配置(节选) model: primary: provider: deepseek-v3 max_tokens: 8192 temperature: 0.2 fallback: provider: deepseek-r1 max_tokens: 8192 temperature: 0.2 router: default: primary code_review: r1 # 代码审查场景走推理模型 semantic_search: embedding_model # 检索场景走 embedding

这样设计有三个好处。第一,Key 统一在运行时注入,不会散落在各台机器和代码库里。第二,不同任务可以分流到更合适的模型,省钱也省时间。第三,主模型失败时自动切到备用通道,避免整个任务中断。很多人忽略第三点,实际跑起来你就知道,生产环境里模型接口超时是家常便饭,没有 fallback 的话,一次超时就能让整条流水线堵半天。

这段配置里我想重点提醒的是:别在高频路径上让 Agent 自由选择模型。看起来"让模型自己选择最合适的模型"很智能,真跑起来你会发现不同模型的上下文格式、工具调用习惯、返回风格千差万别,最后调试成本远高于省下的那点钱。最稳的做法是默认一条主链路,只有极少数特殊场景(比如代码评审)再显式路由过去。

2.2 权限设计:工牌能进哪扇门

门禁最容易被忽略,也最容易出大事。一个 AI 智能体如果拥有和你一样的全量权限,它干活确实方便,但一旦被注入恶意指令(比如读了某个 README 后照着里面的"建议"执行),或者误操作删除了生产数据,后果非常严重。

我们给 CodeBuddy 设置的权限边界遵循"最小权限 + 按环境分级"的原则:

  • 本地开发环境:允许读写项目目录、执行构建和测试命令;
  • CI 环境:只读代码 + 写报告目录;
  • 生产环境:禁止直接操作,只能生成正式的审批请求;
  • 敏感操作(git push、部署、删除文件、支付等):必须触发人工确认。

权限本身还做成可审计的。我们在工具调用层加了一个 authorize() 中间件,每个 tool call 进来先查一遍策略表:

# permission.py —— 工具调用前的权限校验(简化版) def authorize(tool_name: str, env: str, payload: dict) -> bool: rules = { "execute_command": {"dev": True, "ci": ["safe_cmds"], "prod": False}, "read_file": {"dev": True, "ci": True, "prod": ["whitelist"]}, "write_file": {"dev": True, "ci": ["report_dir"], "prod": False}, "deploy": {"dev": False, "ci": False, "prod": "require_human"}, "git_push": {"dev": False, "ci": False, "prod": "require_human"}, } allowed = rules[tool_name].get(env, False) if allowed == "require_human": return human_approval_queue.enqueue(tool_name, payload) return allowed

踩坑记录:最初我们觉得"AI 需要灵活,所以权限尽量放开",于是在生产环境也允许执行命令。真跑一次才发现,AI 在调试时会出于"好奇心"去执行各种命令,有些真的就误伤了测试数据。后来加了权限中间件,这类事故基本消失了,换来的是偶尔要人工点一下确认。这个成本完全值得——毕竟你招一个实习生,也不会第一天就把生产库的口令直接给他。

3. 工位与文件柜:上下文与记忆模块

3.1 系统提示词就是办公室里的员工手册

每个 AI Agent 开工前,都需要一份"员工手册",也就是 system prompt。但真正做好它,远不止写几句"你是我的 AI 助手"那么简单。我们建议手册里至少包含五块内容:

手册章节对应内容目的
角色与目标我是谁,在哪个项目里,服务谁定位
工作规范任务如何拆解,先规划后执行约束行为
环境说明仓库结构、构建命令、测试命令减少试错
边界条款什么不能做、什么必须请示安全兜底
协作约定与人类/其他 Agent 的协调方式打通协作

我们给 CodeBuddy 的 system prompt 里有一个特别关键的设计:强迫它一开始就把任务拆成 todo list,并且每个 todo 后面都标注"做完之后怎么验证"。比如不写"优化数据库查询",而写"把订单列表查询从 N+1 改为 join,并跑 test_orders.py 通过"。这个设计治好了 AI 最常见的毛病——闷头干完一大坨,最后发现方向从一开始就错了。

3.2 短期上下文就是工位桌面,要防止爆炸

Context window 现在越做越大,128K 甚至 1M 的模型都出来了。但真以为可以随便往里塞东西,就会遇到"上下文飘移":模型读到后面忘了前面,或者被无关信息干扰,出错率明显上升。这就像把桌子堆满文件,人反而找不到当前该看的那一份。

我们的做法是"桌面收纳法":桌面只放当前该干的活。每次任务开始时,先做一次上下文清理,把上次任务的日志、中间文件、无关讨论全部归档,只保留当前真正需要的东西:

  • 完整的项目说明书(如果 Agent 是第一次接触这个仓库);
  • 当前 ticket / issue 的描述;
  • 相关代码文件片段(按需从仓库检索,不一股脑全塞);
  • 上一次会话的 summary,而不是原始对话记录。

检索式接入很好用。我们在 CodeBuddy 里接了一个轻量向量库(本地用 SQLite + embeddings),让 Agent 按需"拉开文件柜"取资料。实测下来,一次中等规模项目的编程任务,上下文消耗从原来的约 200K tokens 降到了 60K 左右。成本降了一大截,任务完成率反而稳中有升——因为模型终于不用在噪音里找信号了。

3.3 长期记忆怎么做才不会变成垃圾堆

长期记忆是很多人都会做,但很容易做成"把什么都存下来"。要记住一个原则:记忆不是存档,是决策支持。我们给 CodeBuddy 的长期记忆分了三个抽屉:

  1. 项目知识库:架构决策、接口规格、领域术语,来源是文档和人工整理;
  2. 经验教训:每次踩坑后沉淀的教训,比如"不要直接改 migration 文件";
  3. 用户偏好:代码风格、命名习惯、常用库版本号等。

每个抽屉都有写入门槛。尤其是经验教训,必须经过"人工或评估模块评审通过"才能入库。否则 AI 会把自己偶然的错误当成金科玉律,越存越歪。有一次,它因为一次单元测试超时就永久记住了"不要跑完整测试",差点带偏后面好几天的所有任务。那条记录是后来人工清理掉的。从那以后,我们所有教训入库都加了一道"是不是一个稳定规律"的审查。

4. 工具箱与实操间:工具集与执行沙箱

4.1 工具不是越多越好

在办公室里,给员工 100 个工具,不如给他 10 个常用且顺手的工具。工具多了,模型的选择就难,选择难就更容易出错。我们在 CodeBuddy 里给编程智能体用的工具,常年保持在十来个:

  • read_file / write_file / edit_file
  • list_dir / search
  • bash(沙箱内执行命令)
  • run_tests(专用测试入口)
  • git_status / git_diff / git_commit(但不开放 push)
  • ask_human(遇到歧义时提问)

不必要的工具我们甚至会刻意关掉。比如"发送邮件""发消息通知"这类工具,让智能体在工作流里去发消息,十有八九会出乌龙。更合理的做法是,把这些通知动作放到人机协同阶段,由人工或者固定流程来触发。

4.2 Function Calling 的接口设计

工具接口设计的关键,是让"填表"一样明确。每个工具都要有:功能描述、参数定义、返回结构、失败语义。一个常见的不太好的设计,是让 Agent 传自由格式的 JSON 字符串,结果就是你整天在解析各种各样的写法,解析逻辑越写越肥。

我们用 JSON Schema 定义工具签名,比如 edit_file:

{ "name": "edit_file", "description": "对指定文件做精确内容的替换。用于局部修改,不适合整体重写。", "input_schema": { "type": "object", "properties": { "file_path": {"type": "string"}, "old_content": {"type": "string", "description": "需要被替换的原内容片段"}, "new_content": {"type": "string", "description": "新内容片段"} }, "required": ["file_path", "old_content", "new_content"] } }

特别注意 description 的写法。LLM 对工具的选择高度依赖 description,我们甚至在描述里写反例:"不要用 edit_file 做大型重构,那种情况请先和用户讨论方案。"这一句看着不起眼,实测能减少大量顽固错误——模型不会因为"能做"就"该做",你得明确告诉它什么场景不该用。

4.3 沙箱:工具最危险的其实是执行

比模型选型更让人头秃的一环,是 AI 生成代码并执行。执行环境必须沙箱化,这是我们用血泪教训换来的结论。所谓沙箱,拆开看就三点:网络隔离或白名单;文件系统虚拟化(Agent 只能看到项目目录,实际写入落到指定目录);资源受限(CPU、内存、超时、命令数)。

在实现上,我们早期用 Docker,每个任务一个容器,后来为了速度换成了轻量进程隔离加容器兜底。现在 CodeBuddy 跑测试命令,统一走 run_tests 这个专用入口。这个入口内部会:先在临时目录构建,再抓取环境变量,限制网络,跑完后把日志回传。这样一来,就算 Agent 在 bash 里瞎折腾,也碰不到开发环境。

有人问:为什么不干脆不开 bash?答案很简单:真实任务里,AI 需要查依赖版本、看进程列表、统计日志,这些灵活操作没法全部封装成固定工具。所以正确思路不是禁用执行,而是把它关进笼子里,给它一个可以随便折腾但不影响外界的"实操间"。

5. 主管与会议室:任务规划与多 Agent 协作

5.1 单 Agent 也要有任务状态机

如果说前面是办公室的硬件,这一节就是办公室的流程制度。一个 Agent 干活时,需要一个显式的状态机,防止它在"思考、执行、验证"之间乱跳。我们给 CodeBuddy 设计了四态循环:

  • planning:拆分任务、定 todo、写验证方式;
  • acting:逐个执行工具,每调一次工具更新 todo;
  • checking:跑测试、静态检查、取证;
  • reflecting:根据检查结果修订计划,或者宣布完成。

关键是 todo 必须写成"可验证的动作",而不是愿望。比如"优化数据库查询"这种 todo,执行完你根本没法判断做没做;改成"把订单列表查询从 N+1 改为 join,并跑 test_orders.py 通过",模型执行起来就有明确的完成标准,人也容易审核。这一点怎么强调都不过分,我见过太多 Agent 任务失败,根源都在 todo 写得像口号。

5.2 多 Agent 协作:主管、经理、员工

当任务大到一个人做不完(比如跨模块重构、根因排查),可以开"会议室",用多个 Agent 分角色协作。我们试过两种模式,各有优劣。

模式一:Manager-Workers 树状结构。Manager 负责规划和拆解,WorkerA 处理前端模块,WorkerB 处理后端模块,各自执行后把结果交回 Manager 收口校验。优势是职责清晰、上下文天然隔离;劣势是 Manager 需要很强的全局判断力,拆解得偏了,整条线就偏了。

模式二:多智能体评审模式。一个 Agent 写实现,另一个 Agent 专门挑毛病(代码评审、安全审计、异常场景测试)。优势是能在早期发现单视角盲区;劣势是上下文成本翻倍,评审 Agent 还容易过度保守,把什么改动都打回去。

我们的原则是:默认单 Agent,只在任务规模大、失败代价高的场景才上下多 Agent。每个 Agent 都是办公室里的一个脑袋,开会开销不小,电费也不低。

5.3 一个复杂任务的完整走查

拿 CodeBuddy 处理"实现一个带缓存的用户详情接口"这个任务来演示一遍状态机:

  1. planning 阶段:读接口文档和现有 service 层,拆成 5 个 todo,包括"加 Redis 依赖 -> 写缓存装饰器 -> 改 service -> 写单测 -> 跑全部测试"。
  2. acting 阶段:逐项执行。中途发现原有 service 依赖了一个旧配置项,于是它主动调 read_file 去查配置,然后回头更新 todo,把"更新配置说明"加进去。
  3. checking 阶段:跑单测,发现缓存命中场景覆盖率不够,补了测试再跑。
  4. reflecting 阶段:自己生成一段 release note 和一页排查要点,然后停在 ask_human,请人工确认是否合并。

整个流程下来,人工只介入了一次——就是最后的合并确认。如果没有状态机这一层,大概率它会一口气 push 代码,甚至顺手改掉生产配置,那可能就是事故了。

6. 前台与监控室:人机协同与可观测性

6.1 不是所有环节都要 AI 自己拍板

办公室必须有人,而且人在关键节点要能拦住 AI。这个"人工确认"不应该是打断,而是设计好的节奏。我们在 CodeBuddy 里把需要确认的节点收敛为三类:

  • 高风险动作:写生产数据、删除、部署、任何影响多人协作的操作;
  • 方向性决策:重构方案、技术选型、接口设计变更;
  • 语义模糊处:需求有歧义、无法确定边界时,宁可多问一句。

实现上很简单,就是让 Agent 在对应动作前调用 ask_human 工具,并且把它显式做成权限的一部分。注意,确认消息不能只是让 Agent 自己生成一份"我很靠谱"的总结,否则人会盲目点同意。我们要求确认消息必须同时列出"将要做什么、影响面、回滚方案"。这个约束写在 system prompt 里,再配合后面的日志,能有效防止 AI 把错误包装得很合理。

6.2 日志与追踪:给每个决定都留证据

没有可观测性的 Agent 系统是不能上生产的。我们要求每次任务运行都产出一份"办公室巡检报告":所有 model call 的耗时与 token 数、所有 tool call 的入参与返回、每次 planning/reflecting 的状态流转、每个人工确认的决策与理由。

技术上,最简单的方式就是结构化日志。把关键事件统一打到 JSON 日志流里,跑完任务后用脚本生成 HTML 报告。有一次排查"AI 为什么改了不该改的文件",就是靠日志回放定位的:它在一次 tool call 的 payload 里带上了错误路径,而那个路径来自前一个任务遗留的工作目录。没有日志,这个 bug 根本无从查起。

6.3 评估体系:考勤不只是为了扣钱

评估模块回答三个问题:任务完成了吗?完成得好不好?花的代价值不值?我们给 CodeBuddy 搭了一个很朴素的评估矩阵:

维度指标通过线
完成度验收测试通过率、需求点覆盖数全部关键点通过
质量静态检查告警数、评审打分、覆盖率变化无新增 critical 告警
效率任务耗时、token 消耗、工具调用次数与人工基线可比
安全越权次数、危险命令数、人工干预次数越权次数为 0

评估数据会倒灌回两个地方。一是 Agent 的经验教训库——只有评估通过的教训才允许入库。二是我们的复盘报告,每周看一次,看看哪些任务类型总失败,然后去修对应的工具、权限或状态机配置。这一层是最容易被砍掉的,但我强烈建议别砍:没有评估,前面五个模块都是在裸奔。

7. 用 CodeBuddy 从零搭一套办公室:完整落地路径与踩坑记录

7.1 别一上来就搞大而全的航空母舰

我见过不少团队,一听说 Harness Engineering 有六大模块,就猛冲猛打:先接五个模型,再上四十个工具,然后做多 Agent,搞一堆 metrics 面板。结果系统复杂到没人敢改,项目还没上线就先被自己绊倒了。

我们自己的落地路径是"从一间房起步":

  1. 第一周:只做"模型接入 + 权限 + 三个核心工具(读、写、执行测试)";
  2. 第二周:加 todo 状态机和人工确认节点;
  3. 第三周:补结构化日志和每周报告;
  4. 第四周:根据真实失败案例,再决定要不要上多 Agent、扩展记忆。

这套路径的核心判断标准是:每加一个模块,都必须有真实的失败案例或瓶颈支撑,否则不加。没有业绩压力的模块,纯属给自己找麻烦。

7.2 完整案例:让 CodeBuddy 修一个生产环境偶现超时问题

这里给一个端到端示例,方便大家理解六大模块是怎么一起工作的。

背景:订单服务在生产环境偶发 502,排查成本高。我们把这个任务交给 CodeBuddy:

  • 门禁与权限:赋予读日志、执行压测脚本、读代码的权限;禁止写生产配置。
  • 上下文与记忆:注入服务架构图和最近三天的日志摘要;从经验库调取一条"偶现问题先查线程池耗尽"的教训。
  • 工具与执行:它依次用 search、read_file、bash(跑压测,50 并发),发现线程池核心线程数设置过小,高峰时请求排队积压。
  • 规划与协作:todo 拆成"压测复现 -> 定位线程池参数 -> 评估修改方案 -> 提交代码并跑回归",每一步都带验证命令。
  • 人机协同:到"修改核心配置"节点,弹确认窗,它附上了影响面(高峰 QPS 下线程数变化)和回滚方案。
  • 观测与评估:全程结构化日志;改完跑 100 并发压测,完成度、质量、效率指标全部按报告模板输出。

人工最终只点了两次"同意":一次是确认配置修改,一次是确认合并 PR。这就是六大模块协同工作的样子。

7.3 我们踩过的四个坑,和对应的解法

  1. 上下文过载:最初把整个 monorepo 塞给 Agent,它越到后面越"失忆"。解法是检索式接入,只给当前任务相关的文件。
  2. 工具万能化:给了 Agent 全部 shell 权限,它开始乱试命令,甚至清掉了测试环境目录。解法是最小权限 + 专用入口 + 容器兜底。
  3. 人不看就跑:自动确认让 Agent 在错误路径上一路狂奔。解法是所有高风险动作强制人工确认,且确认消息必须包含影响面和回滚方案。
  4. 记忆污染:Agent 把偶发错误当经验入库,后来带偏后续任务。解法是经验教训必须通过评估验证才允许进入长期库。

7.4 关于下一阶段的几点个人体会

说实话,Harness Engineering 到现在还在快速演化,远远没到一个标准答案。我自己最大的感受是:它不是一个"配置完就完事"的静态工程,而是一个持续迭代的系统。每次加工具、改权限、调状态机,本质上都是重新装修那间办公室。装修没有终点,因为业务在变、模型在变、踩过的坑也在变。

如果让我给新手一个最实在的建议,那就是:先把最小的闭环跑通——一个 Agent、一个工具、一个确认点、一份日志——然后再往外扩。办公室可以慢慢装修,但第一间能开灯能干活的房间,越早落成越好。上面讲的六大模块,本质上是六张检查清单,而不是六堵墙。先拿它们对齐思路,再按自己项目的实际情况取舍,比照抄任何模板都管用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询