一、简介
之前在Claude Code相关的文章中曾经提到过,Agent可以分为以下两个大类:
这其实也给我们的工作也带来了一点启发,目前的 agent 从实现技术上来说一共分成两大类,workflow和autonomous。以我们的开发业务来看,应该选用更多的workflow,并把AI控制的部分做到最小,而非让不稳定的autonomous去调用工具结果出各种错误。
不过目前市面上主流的文章都会默认把autonomous视为agent,workflow就认为是workflow,所以随大流的讲我们以后也可以这么定义。
在Harness这个词还没流行之前,我看到的主要两种对Agent的公式定义如下:
Formula A: Agent = LLM + Planning + Memory + Tool Use
Formula B: Agent = Loop (LLM + Context + Tools)
二者表达的其实是同一个核心概念,只是视角和侧重点有所不同。在代码开发的实际应用中,通常需要按照第一个公式去设计功能,并按照第二个公式去编写代码。
而在Harness这个词流行以后,这个公式有有所变化:
Formula C: Agent = Harness + LLM
在英语中,Harness 原意指“马具”(套在马身上用来拉车的皮带)。在工程和 AI 领域,它的含义演变为 “治理架构” 或 “约束框架”。也就是为了解决LLM的“不可控性”而设计的一套工程理论。
三个公式的其实是递进的,只是解决的问题不一样。
| 公式 | 重点 |
|---|---|
| A | LLM如何产生智能 |
| B | LLM如何完成任务 |
| C | LLM如何可控的完成任务 |
往远了说,我之前提到的 OpenSpec其实就是Harness工程的一部分。
往近了说,现在很火的OpenClaw其实就是一个Harness的范例(但就其表现来看其实并不是真的那么可控)。对于接触过Claude Code、Cursor之类编码工具的开发工程师来说,OpenClaw并不是多么惊艳的玩意,但它给了普通人一个远程操控本地编码助手的方案从而走红,也从侧面展现出一个大众对于可控的AI助手的需求还是非常旺盛的。
二、Harness 工程的诞生时间线
| 时间 | 事件 | 团队 | 文章 |
|---|---|---|---|
| 2025年11月 | Anthropic 发布长时 Agent Harness 工程报告 | Anthropic 工程团队 | https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents |
| 2026年1月 | Phil Schmid 预言”Agent Harness 将定义2026年” | Hugging Face 技术专家 | https://www.philschmid.de/agent-harness-2026 |
| 2026年2月5日 | Mitchell Hashimoto 首次命名”Harness Engineering” | HashiCorp 联合创始人 | https://mitchellh.com/writing/my-ai-adoption-journey |
| 2026年2月11日 | OpenAI 发布百万行代码实验报告,标题使用”Harness Engineering” | OpenAI Codex 团队 | https://openai.com/zh-Hans-CN/index/harness-engineering/ |
| 2026年2月17日 | Martin Fowler 网站发布权威评析 | Birgitta Böckeler / Thoughtworks | https://martinfowler.com/articles/harness-engineering.html |
| 2026年3月 | LangChain 发布”Agent Harness 解剖学”,实证仅改Harness排名从Top30升至Top5 | LangChain 团队 | https://www.langchain.com/blog/the-anatomy-of-an-agent-harness |
| 2026年3月 | Anthropic 再发长文报告,阐述长时运行系统的相关调查 | Anthropic 工程团队 | https://www.anthropic.com/engineering/harness-design-long-running-apps |
三、Harness 到底是什么
- 模型 = 马:强大、快速,但自己不知道往哪跑
- Harness = 缰绳系统:约束、反馈回路、文档、工具编排、生命周期管理
- 工程师/用户 = 骑手:不再亲自写代码,而是设计让 Agent 可靠写代码的「环境」
以上东西都不是新鲜概念,其实都是控制论里的闭环控制系统玩烂了的东西加了一个LLM的内核就拿出来吹了。但是老概念之所以为老概念,就是因为它真的有用。
从用户的角度看,现有的代码工程难点有两个,一个是当代码几乎都由 Agent 生成时,仓库、架构、文档和反馈系统应该怎么被重新设计;另外一个是任务一跑就是几小时,模型为什么会跑偏、为什么会自评失灵,以及怎样通过Planner、Generator、Evaluator这些智能体让系统继续收敛。
一个比较直观的例子就是Anthropic做了一个实验,用“做一个2D复古游戏编辑器”这个Prompt让同一个模型跑了两次,一次用单agent,一次用Harness工程,结果就是一个花了9刀20分钟完成了一个跑不了的废品,一个花了200刀6个小时跑了一个完整的系统。
当然这个例子肯定是吹的,想都不用想,不过这个思维可以学习一下。
Harness旨在解决以下四个问题:
- 模型能看什么。
- 模型能做什么。
- 怎么判断做对了。
- 出错了怎么修。
对于解决这些问题,结构上通常有以下三层:
1.知识层
举个简单的例子,也就是Claude Code执行/init这个指令后生成的一个文档。
以现在我在公司写的正在运行的AI-PPT为例(已脱敏),我的项目结构是:
AI-PPT/
├── backend/ # Web 服务模式
│ ├── app.py # FastAPI 入口
│ ├── taskRunner.py # 后台任务编排
│ ├── middleware.py # 认证中间件
│ ├── authClient.py # 企业微信 OAuth 封装
│ ├── database.py # SQLite 操作
│ ├── config.py # 全局配置
│ ├── routes/ # API 路由
│ │ ├── authRoutes.py # 登录相关接口
│ │ ├── taskRoutes.py # 上传/状态/下载接口
│ │ └── historyRoutes.py # 历史记录接口
│ └── operators/ # 算子层(Web 端副本)
│ ├── llmClient.py # OpenAI 兼容 API 封装
│ ├── mineruClient.py # MineRU API 封装
│ └── pptBuilder.py # python-pptx 生成幻灯片
├── frontend/ # 前端纯 HTML/CSS/JS
│ ├── index.html # 主页面
│ ├── login.html # 登录页面
│ ├── app.js # 前端逻辑
│ └── style.css # 样式表
├── templates/ # PPT 母版与附件
│ ├── 母版_带缩写.pptx # PPT 母版文件
│ └── IF表.xlsx # IF 数据表
├── storage/ # 运行时数据(运行时生成)
│ ├── app.db # SQLite 数据库
│ ├── uploads/{taskId}/ # 上传的 PDF 文件
│ └── output/{taskId}/ # MineRU 解析结果 + 生成的 PPT
├── CLAUDE.md # 项目说明(面向 Claude Code)
├── code.md # UOP 代码规范
├── requirements.txt # Python 依赖
├── .env # 环境变量
└── .gitignore # Git 忽略规则
而我的CLAUDE.MD文件则是:
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 语言要求
优先用中文回复问题。
## 代码规范
写代码前必须遵循 `code.md` 中的"面向理解编程 (UOP)"规范。
## 项目概述
批量学术论文 PDF → 单页 PPT 摘要工具,支持两种运行模式:CLI 直接处理 和 Web 在线服务。
核心流程:PDF → MineRU API 解析 → LLM 两轮提取(文本提取 + 多模态选图)→ python-pptx 生成 PPT。
## 运行命令
pip install -r requirements.txt
# --- CLI模式(根目录脚本) ---
python main.py # 处理当前目录所有PDF
python main.py paper1.pdf paper2.pdf # 处理指定文件
python main.py --output result.pptx # 指定输出文件名
# --- Web服务模式 ---
uvicorn backend.app:app --reload # 启动FastAPI开发服务器(默认8000端口)
## 架构
项目有两套独立入口,共享同一套算子层逻辑:
### CLI模式(根目录)
- `main.py` — 编排层,直接调用根目录下的算子模块
### Web服务模式(backend/)
- `backend/app.py` — FastAPI入口,注册路由、中间件、静态文件
- `backend/taskRunner.py` — 后台任务编排,在 BackgroundTasks 线程中执行转换流程
- `backend/middleware.py` — 认证中间件,校验session cookie(itsdangerous签名)
- `backend/authClient.py` — 企业微信OAuth封装(access_token缓存 + code换userId)
- `backend/database.py` — SQLite操作(WAL模式),users + tasks 两张表
- `backend/config.py` — 全局配置,集中管理路径常量和环境变量
- `backend/routes/` — 三组API路由:authRoutes(登录)、taskRoutes(上传/状态/下载)、historyRoutes(历史)
### 算子层(两套副本,根目录 + backend/operators/)
- `mineruClient.py` — MineRU API封装(uploadFiles / waitForResults / downloadAndExtract)
- `llmClient.py` — OpenAI兼容API封装,两轮调用:extractPaperInfo(文本模型)+ selectKeyImage(视觉模型)
- `pptBuilder.py` — python-pptx生成幻灯片,基于母版占位符索引填充内容
### 前端
- `frontend/` — 纯HTML/CSS/JS,login.html + index.html + app.js + style.css
### 存储
- `storage/uploads/{taskId}/` — 上传的PDF文件
- `storage/output/{taskId}/` — MineRU解析结果 + 生成的PPT
- `storage/app.db` — SQLite数据库
- `templates/母版.pptx` — PPT母版文件
## 环境变量(.env)
- `MINERU_API_TOKEN` — MineRU 的 Bearer Token
- `OPENAI_API_KEY` — LLM API 密钥
- `OPENAI_BASE_URL` — 可选,自定义 API 地址(兼容中转站/国产模型)
- `WECOM_CORP_ID` / `WECOM_AGENT_ID` / `WECOM_APP_SECRET` — 企业微信OAuth配置(Web模式必需)
- `SESSION_SECRET` — cookie签名密钥
- `SERVICE_BASE_URL` — 服务外部访问地址,用于OAuth回调URL拼接
## 关键设计细节
- LLM两轮调用:第一轮用文本模型(textModel)提取结构化JSON,第二轮用视觉模型(visionModel)从候选图片中选GA图
- PPT通过占位符索引(phTitle=11, phImage=16等)定位母版中的文本框和图片框,修改母版后需同步更新索引
- Web模式认证链:企微OAuth → code换userId → itsdangerous签名cookie → 中间件校验注入request.state.userId
- 任务进度分5步:1-上传PDF → 2-解析PDF → 3-提取文字 → 4-选择图片 → 5-生成PPT,前端轮询 progressStep 展示进度
知识层需要给LLM足够多的内容,包括文件路径、项目逻辑、代码规范等等。这一部分文件是会直接加入上下文中的,因此要简短;但是像代码规范这种内容放不下,就要单开一个文件告诉它路径。
对于LLM来说,看不见的东西就是不存在的。
2.约束层与流程层
Anthropic的做法是拆成了Planner、Generator、Evaluator三个角色,每个人各司其职按顺序完成各个部分。一方面这种做法有助于分离角色上下文提高表现,另一方面能够让不同的角色对其他智能体完成的部分做出应对避免越写越嗨的情况发生。
在实际的工程检验中,甚至可以用不同的模型,比如用codex去检验claude生成的代码;不同的模型扮演不同的角色完成不同的工作。
3.反馈与运行时层
其实主要就是Evaluator要做的工作,比较典型的是装一个Playwright去让多模态模型看前端的真实情况,找到哪个按键位置错了,哪个区域没有填满,点击哪个按钮后爆了错误。然而,单一的模型经常会出现偷懒的情况,它会自己欺骗自己说这种情况是合理的然后自说自话的就通过验证,因此需要不断地手动更新和强化提示词,才能真正的达到反馈有效的情况。
四、为什么现在才出现Harness工程?
难道之前的开发工程师们没有想到AI写代码可以主动约束和规范吗?
有的兄弟,有的,不过不是没有,而是做不到。
早期的 Agent 纯靠 Prompt 让模型输出 JSON 来调用工具。模型经常出现格式幻觉(少个括号)、陷入死循环,或者像“无头苍蝇”一样乱试。开始的时间点是2022年11月30日,GPT-3.5刚刚发布。
后来,2023年6月,GPT-4/GPT-3.5-trubo才原生支持了Function Calling功能,带来的标准化的Json Schema工具定义格式。而在11月份,OpenAI推出了Json Mode,通过技术手段保证输出一定是合法的Json。开发者们尝试多智能体编排,开始尝试用沙盒和代码解释器来让AI自己操作。
再后来,2024年11月24日,连带着Claude Sonnet 3.5 ,Anthropic提出了MCP协议的概念,提供了一个标准化的协议,能够让AI应用动态发现、调用外部工具。而在两个月后,DeepSeek-R1才正式发布。
2025年10月17日,Skill作为产品功能正式上线,当时一起推出的模型是Claude Sonnet 4.5。
这些工程上的进化,本质是模型一步步的变强。而在当下这让大模型输出json就如喝水一般简单的时间点,是三年前的AI不可企及的高峰。当Opus4.5能够顺着Skill自己做事情的时候,一年前才推出的MCP协议就永远坐上了冷板凳。如果在未来,真的有那么一个真正超级强的模型能够完全顺着人类的意图完整的开发时,那么Harness工程也会同样失去所有意义。
不过很显然,那一天还很遥远。
五、没有银弹
1987年,弗雷德里克布鲁克斯(图灵奖获得者)在《人月神话》里跨时代的提出了多个规则:
- 没有任何单一的技术或管理方法,能够使软件生产率在十年内提高一个数量级。
- 人月不可交换(9个女人不能1个月生出孩子)。
- 软件复杂性是本质问题。
我认为这些话放在AI大行其道的今天依然有效。
Harness工程不是变出来的,远没有看上去那样美好(Openclaw就是一个很好的例子),软件开发依然需要有经验的工程师大量的纠偏,才能让Harness工程自己从零开始长出来。任何所谓“自我进化”的框架都是嘘头,只有真正能够落地的耗时耗力的工程才有价值。
Talk is cheap, show me your code. -- linus
如果你只是想要简单的用一个AI每天主动找你聊聊天,那你可以像我一样用Astrbot:


一个项目的二次元数量决定了它的质量。
如果你想要在硬件里接入AI,可以看看tinyclaw,把AI放到树莓派里面。
如果你觉得OpenClaw太重了,那你可以换成用rust重写的Ironclaw,速度更快也更安全。
但如果你真的需要一个属于自己的远程写代码的AI助手,那就用ACP协议自己把AI接入社交工具里;如果你不希望他在服务器里大杀四方,那就自己给他配置好权限、沙盒和运行目录;如果你想要他永远变成一只猫娘,那就写好Soul文件和调整Memory,永远不忘记自己是谁。听上去有点像重复造轮子,但那些被泄露秘钥清空E盘的人就是活生生的反面教材。
软件开发没有银弹,至少现在没有。
Comments
评论
Loading comments...
登录后可以评论。 Login