最近在AI Coding圈子里逛,发现一个挺有意思的现象:不少人拿同一个模型、同一套提示词去跑同一个需求,最后产出的质量却差得离谱。有人甩锅给模型,有人怪工具不行,但真正拉开差距的,往往是藏在工具链最底层的那层骨架——Agent Harness。模型只是负责“想”,而“怎么想、想完怎么动、动完怎么复盘、下一步怎么决策”这一整套循环,全都由Harness在背后控制。这篇博文我就把它放上解剖台,一层层拆开看:它由哪些子系统组成、主流实现做了什么取舍、以及如果你打算自己动手搭一套最小可用的Harness,关键节点在哪里。
1. 为什么Agent的智能一半写在外壳里
1.1 模型只是大脑,Harness才是躯干和神经系统
很多人对AI Coding Agent的理解就是“API调用”:把用户的需求拼进system prompt,扔给模型,拿到回复就完事。但在真实工程里,一次完整的编码任务远不止一轮对话。模型的每一次输出只是“一个念头”,这个念头要变成真实动作——读文件、搜代码、改代码、跑测试、看报错,再决定下一轮怎么办——中间必须有一层执行框架帮它完成“把念头变成行动”的闭环。
这层执行框架就是Harness。你可以把模型想象成一个特别聪明但完全不能动的人,Harness就是给他装的机械臂、传感器和神经系统。模型负责做决策,Harness负责执行决策,并把执行结果“翻译”回模型能理解的语言。没有这层外壳,模型再聪明也只能对着空气输出文本,无法真正完成一项多步骤的编码任务。
所以我在项目里一直强调一个观点:**模型能力决定Agent的天花板,Harness决定Agent的地板。**两者是乘法关系,不是加法。一个90分的模型跑在一个20分的Harness上,效果大概率不如一个75分的模型跑在80分的Harness上。
1.2 “裸奔”的Agent与“穿盔甲”的Agent
刚接触Agent开发的时候,大多数人写出来的第一个版本其实都是“裸奔式”的:一个while循环,把用户消息发给模型,打印回复,结束。这种实现跑“聊天”没问题,但一旦面对真正的工程任务,比如“帮我写一个Python脚本处理这批数据,然后运行它,如果报错就自动修复”,裸奔版几乎必崩。
原因很简单:裸奔式Agent没有记忆管理、没有工具调用闭环、没有失败处理机制。模型第一次回答可能给了脚本代码,但它不会自己把代码保存成文件,不会执行,更不会看到执行结果后做第二轮修改。它只是“说了”,但没有“做”。
穿上Harness之后,整套行为就变了。Agent能够走完这个闭环:模型生成工具调用指令 → Harness解析并执行(保存文件、跑命令)→ 把执行结果(如报错信息)回填给模型 → 模型基于新信息再决策 → 循环直到任务完成。差异很直观:
| 能力维度 | 裸奔Agent | 带Harness的Agent |
|---|---|---|
| 多步工具调用 | 不支持或极不稳定 | 原生支持,可连续调用 |
| 执行结果反馈 | 无法自动获取 | 自动回填观察结果 |
| 失败重试 | 基本靠运气 | 有重试与分支决策 |
| 上下文管理 | 消息一长就乱 | 结构化预算与裁剪 |
| 可调试性 | 黑盒 | 全轨迹可重放 |
1.3 Harness这个词在AI Coding语境下的真实含义
Harness这个词,老工程师应该不陌生,原本意思是“马具、安全带”,后来在软件工程里常指“测试夹具”(test harness),用来把被测系统包起来,给它喂输入、收输出。到了AI Coding语境下,意思进一步演化:把Agent模型包起来,替它管理整个执行过程的那层基础设施。
它和Framework、Orchestration、SDK这些概念有本质区别。Framework是给你复用代码用的,你调它的接口;SDK是给你接入某个服务用的;Orchestration(编排)偏重多服务、多步骤的流程调度;而Harness更贴近模型本身——它规定模型“每轮能看到什么、能调用什么、调用结果怎么回填、循环什么时候结束”。一个Agent可以没有Framework,但绝对不能没有Harness。
现在圈子里讨论比较多的DeepSeek Harness、Codex Harness,本质上都是围绕特定模型/场景打造的Harness实现。它们没有改变模型本身,而是改变了模型“被使用的方式”,效果却能天差地别,这正是这篇文章要拆解的核心。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解剖台:Harness的四个核心子系统
2.1 事件循环与状态机:Agent的“心跳”
Harness最底层的骨架是一个事件循环。Agent不是“调用一次模型就结束”的程序,它持续不断地在几个状态之间切换:等待用户输入 → 调用模型 → 执行工具 → 处理结果 → 再调用模型 → 直到任务结束。
我会建议用显式状态机来管理这个过程,不要靠散落的if/else硬撑。一个典型的Agent状态机至少包括这几个状态:
idle:空闲,等待任务触发thinking:模型正在推理/生成回复executing_tool:正在执行某个工具调用observing:接收并整理工具返回结果finished:任务完成error:出现无法恢复的错误
每个状态有明确的进入条件、处理逻辑、退出条件。为什么要这样做?因为真实任务里,工具调用是会嵌套的:Agent先调用“读取目录结构”的工具,看到文件列表后又调用“打开某个文件”,看完内容再调用“编辑文件”。如果没有状态机,一旦某一步工具超时或返回格式异常,整个Agent的流转就会乱套,模型可能在一个错误的状态假设下继续决策。
事件循环的核心点在“循环”二字:模型输出不一定是最终答案,它可能是一个工具调用指令。Harness的任务就是识别这一点,不把工具调用当答案返回给用户,而是转入执行、回填、再循环。这一步搞对了,Agent才真正“活”起来。
2.2 上下文管理器:记忆的组织方式决定Agent的下限
Harness的第二个核心子系统是上下文管理器。很多人把上下文简单理解成“消息数组”,往里面append就完事。这是天真的做法。真实Agent跑到第20步时,系统提示词、用户目标、工具定义、中间产物、历史观察结果全堆积在一起,token很快就超了,就算不超,模型也会在长文本里迷失重点。
合格的上下文管理器要做几件事:
- Token预算分配:给系统提示词、工具定义、执行历史、观察结果分别设置预算比例。比如系统提示词占10%-15%,工具定义按需动态加载,历史消息做裁剪,观察结果做压缩摘要。
- 关键信息固定:用户的核心目标、当前任务状态这类信息必须始终保留,不能因为滑动窗口被挤出上下文。
- 消息层级结构化:不是平铺的字符串列表,而是带元数据的分组,例如
{role: "tool", content: "...", summary: "...", token_count: 231}。
我见过很多Agent项目跑着跑着效果变差,排查半天发现是上下文管理器完全没做——所有历史工具输出原封不动堆在消息列表里,模型到后面根本分不清哪些是用户需求、哪些是旧的工具输出。好的上下文管理器,目标是让模型在每一步都看到“当前最需要的信息”,而不是“所有信息”。它的实际效果是给Agent扩容,甚至比直接换更大上下文窗口的模型更管用。
2.3 工具执行器:模型与外部世界的接口层
工具执行器是Harness里最接地气的部分,也是“Agent能不能真正干活”的关键。它的职责很清晰:接收模型输出的结构化工具调用指令,做参数校验,在安全边界内执行,然后把结果整理回填给模型。
这里有几个容易忽略的设计点:
工具定义要模型友好。工具不是写给人看的函数,而是写给模型看的“说明书”。工具名称、描述、参数Schema都要足够清晰,让模型在生成调用时尽量少犯错。比如一个工具叫search_symbol_definition,描述写清楚“在代码库中查找某个符号的定义位置,返回文件路径和行号”,比泛泛的search好用太多。
返回值要“模型友好”。工具执行后,不应该把原始输出一股脑塞回上下文。一个工具可能输出上千行日志,但模型真正需要的可能只是最后三行报错信息,Harness要做的是对工具输出做截断、摘要、结构化,减轻模型负担。这个环节做得越好,Agent的多步执行能力越强。
安全边界是硬约束。模型不是你写的,它会生成任意工具调用,包括删除文件、安装依赖、执行未知命令。Harness必须建立白名单机制、沙箱环境、资源限制、超时控制。尤其你做编码Agent时,执行脚本是刚需,但直接让Agent在没有约束的环境里跑任意shell命令,风险极大。后面第5章我会专门讲工程化实践,这里先记住一个原则:工具的权限边界必须显式声明,而不是靠模型的自觉。
2.4 内省与重放子系统:可调试性是工程化的生命线
第四个子系统,也是最容易被低估的,是内省与重放。简单说,Harness必须完整记录Agent的一举一动:每一步模型收到了什么输入、输出了什么内容、调用了哪个工具、工具返回了什么、上下文在那一刻是什么状态。
为什么说这是生命线?因为Agent是概率性的,同一个任务跑十次可能出十种不同的中间路径。线上跑挂了,你问模型“你为什么要这么做”,它自己都说不清楚。Harness如果没记录轨迹,排错就只能靠猜,这在工程上是完全不可接受的。
有了完整轨迹记录,就能做重放(Replay):把一段历史任务的所有事件序列在本地重新执行一遍。不需要模型重新“思考”,只需要把当时的输入原样复现,你就能在本地逐步观察Agent每一步的决策依据,定位是哪一步的上下文出了问题,还是某个工具的输出格式误导了模型。
现在DeepSeek Harness、Codex Harness这类成熟实现,内部都已经把轨迹记录、状态快照、重放调试做成了标配。自研Harness时,这个模块看似不直接产生业务价值,但踩过一次线上事故的坑就会明白,它是最值得先做的基础设施。
3. 三款主流Harness的解剖对比:DeepSeek Harness、Codex Harness与自研方案
3.1 DeepSeek Harness的设计取向与安装排查
DeepSeek Harness是社区里围绕DeepSeek模型体系构建的一套Agent执行框架,核心思路是把模型调用、上下文组装、工具编排、结果回填做成紧密耦合的单条管线。它的一个明显取向是对DeepSeek模型做了深度适配,模型输出的工具调用格式、上下文偏好都针对性优化过,所以在DeepSeek模型上跑代码任务,稳定性通常比通用框架更好。
但实际部署安装时,很多人在某个环节卡住,比如社区里常见的反馈“deepseek harness卡在pnpm dsh web”。我的排查经验是,这种问题多半不是框架本身坏了,而是环境三个点不对:
- Node版本不匹配:Harness类项目通常对Node版本有明确要求,版本太低或太高都会导致依赖编译失败。先确认项目文档要求的Node版本,再用
nvm切到对应版本。 - pnpm workspace依赖安装不完整:代码仓库通常是一个monorepo,子包之间用workspace关联。如果只装了根依赖没装子包依赖,启动web界面就会卡住。正确做法是先
pnpm install完整安装,再检查node_modules是否存在于所有子包目录。 - 环境变量缺失:很多Harness在启动前需要配置模型API地址、密钥、本地服务端口等环境变量。缺了不会报清晰错误,而是直接卡在某个启动阶段不动。
遇到“卡住”类问题,不要急着重装。先开一个调试终端,用--verbose模式启动,看它最后停在哪一步;再对照文档检查环境变量;最后确认端口是否被占用。这样绝大多数安装问题都能快速定位。
3.2 Codex Harness的强约束与执行模型
Codex Harness(指Codex CLI编码工具背后那套执行编排逻辑)的设计哲学和DeepSeek Harness很不一样,核心是强约束执行。它把编码任务拆解成一系列受控动作:读取文件、编辑文件、执行命令、检查测试结果,每一步都限定在预定义的动作空间里,模型不能自由发挥。
这种“把Agent关进笼子里”的思路,对代码类任务其实非常有效。原因很朴素:人类工程师写代码的流程本来就是“先探索现状 → 再动手修改 → 再编译测试 → 根据反馈迭代”。强约束Harness把这条流程固化成了模型必须遵守的执行协议,模型随时知道自己处于流程的哪个阶段,下一步只能做什么。
代价是灵活性降低。Codex Harness擅长代码仓库级别的任务,但它不适合开放式自由创作(比如“帮我头脑风暴一个营销方案”)。选型时一定要确认你的核心场景是“结构化任务”还是“开放式任务”,这决定了Harness的设计取向。
3.3 商业Harness与自研Harness的取舍清单
很多团队问我一个问题:直接用现成的Harness,还是自己写一个?我的回答通常是:看你的核心诉求是“跑通场景”还是“完全掌控”。两者各有一套取舍:
| 决策维度 | 现成Harness | 自研Harness |
|---|---|---|
| 上手成本 | 低,开箱即用 | 高,需要从零搭 |
| 可定制性 | 受限 | 完全可控 |
| 调试能力 | 依赖项目维护者 | 自己定义轨迹格式 |
| 生态兼容 | 通常较好 | 需要自己维护 |
| 私有化/合规 | 视开源协议而定 | 完全自主 |
| 长期维护成本 | 跟随上游升级 | 自己扛 |
我的建议是:先用现成工具把业务场景跑通,验证价值后再决定是否自研。 很多团队一上来就想造轮子,结果真实任务还没跑通,时间全花在框架抽象上。Harness是工程基础设施,它的价值只有在真实任务的长期运行中才能体现,过早投入是在赌一个你还没验证的需求。
4. 手写一个最小Harness:关键代码与设计决策
4.1 核心数据结构:消息、工具、结果的三元闭环
手写最小Harness前,先想清楚数据流。一个Agent的多步执行,本质是“模型消息 → 工具调用 → 工具结果 → 回填模型消息”的闭环。我建议先用三个核心数据结构把这个闭环显式化:
python复制# 消息:模型侧的输入输出单元
@dataclass
class Message:
role: str # "system" / "user" / "assistant" / "tool"
content: str # 文本内容
tool_calls: list[ToolCall] | None = None
tool_call_id: str | None = None
metadata: dict = field(default_factory=dict)
# 工具调用:模型发出的一道指令
@dataclass
class ToolCall:
id: str # 唯一标识,供结果回填时匹配
name: str # 工具名称
arguments: dict # 解析后的参数对象
# 工具结果:工具执行后返回给模型的对象
@dataclass
class ToolResult:
tool_call_id: str # 指向哪次调用
content: str # 整理后的观察结果
raw_output: str # 原始输出(用于调试)
success: bool # 执行是否成功
这三个结构形成了闭环:模型输出包含tool_calls列表 → Harness逐个执行 → 为每个ToolCall生成ToolResult → 把ToolResult以Message(role="tool", tool_call_id=...)形式追加进消息列表 → 再次调用模型。tool_call_id的匹配是关键,没有它,模型无法知道哪段观察结果对应哪个工具调用。
4.2 事件循环实现:从“一轮对话”到“多步执行”
有了数据结构,就可以写最核心的循环了。一个最小Harness的主循环可以精简成下面这个伪代码形态:
python复制def run_agent(task: str, tools: list[dict], max_steps: int = 20):
messages = [{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": task}]
for step in range(max_steps):
# 1. 调用模型
response = llm_call(messages, tools=tools)
# 2. 如果没有工具调用,说明模型给的是最终答案
if not response.tool_calls:
return response.content, messages
# 3. 有工具调用时,先把assistant消息加入历史
messages.append({
"role": "assistant",
"content": response.content or "",
"tool_calls": [format_tc(tc) for tc in response.tool_calls]
})
# 4. 逐个执行工具,并把结果回填
for tc in response.tool_calls:
result = execute_tool(tc.name, tc.arguments)
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": result.content
})
return None, messages # 超过最大步数
这个循环有几个边界情况必须处理:模型返回的空tool_calls列表、模型生成但未执行完就中断、某个工具执行异常后模型是否还能继续。我在实际项目中,把max_steps设为硬限制防死循环,同时在每轮循环开头检查消息总token数,超过阈值就触发裁剪逻辑,避免跑着跑着把上下文撑爆。
4.3 工具调用与状态回填:容易翻车的几个细节
最小Harness的代码量不大,但真正让它“跑得稳”的是几个细节。第一个是参数解析容错。模型生成的arguments经常是残缺JSON,直接在execute前做一次json.loads失败就崩,这是最常见的翻车点。我的做法是套一层容错解析,失败时把“参数解析失败+原始字符串”作为工具结果回填给模型,让它自己修正,而不是抛异常终止整个任务。
第二个细节是结果回填的角色。不同模型API对工具结果的格式要求不同,有些要求role="tool",有些要求role="user",还有些要求带name字段。写Harness时,最好在模型适配层做一次封装,屏蔽这些差异。
第三个细节是并发工具调用的结果匹配。有些模型一次会返回多个工具调用,如果并发执行,回填时必须严格按tool_call_id对齐结果,绝不能按顺序想当然地拼装。错位一个,整个Agent后续决策就全错了。
第四个细节是工具执行的超时。一个工具卡死会让整个Harness事件循环卡死。每个工具都要有自己的超时上限,超时后把“超时”本身作为观察结果回填给模型——很多时候模型看到超时后会主动换一个更轻量的方案,这比直接失败要优雅得多。
4.4 最小Harness的测试与验证
写完最小Harness后,怎么验证它能干活?我最常用的测试任务是:准备一个故意写错的小型Python脚本,要求Agent“读取脚本内容、运行它、根据报错修复、再运行直到通过”。
这个任务能验证整条链路:读取文件(工具调用)→ 运行脚本(工具调用)→ 观察报错(结果回填)→ 修改文件(工具调用)→ 再运行(结果回填)→ 输出成功。任何一个环节有bug,这个测试都会暴露出来。
常见失败模式有三种:
- 模型不调用工具:直接输出一段“解决方案”然后结束。通常是工具定义写得不清不楚,模型根本没理解这工具是干嘛的。
- 工具参数错误:比如把文件内容当成文件路径传进去。这时候看回填的“参数解析失败”消息模型能不能自我纠正。
- 模型观察结果后“装死”:工具报错回填后,模型不做修改动作,而是给出一段分析。这时要考虑是不是工具结果格式不清晰,模型没理解那是错误。
跑通这个闭环,说明你的最小Harness已经具备了多步执行能力。但要注意,这只是最小可用版本,距离生产环境还有不小距离,下一章讲的坑,全都是我在真实项目里踩过的。
5. Harness工程化中那些文档里不写的坑
5.1 “the agent execution provider did not respond in time”背后的超时设计
“the agent execution provider did not respond in time”这个报错在AI Coding社区里出现的频率很高。很多人看到第一反应是网络问题或服务商故障,但我排查过几次后发现,这个报错暴露的往往是Harness层超时设计的问题。
一个Agent任务里其实存在三层超时:模型推理超时、工具执行超时、外部依赖(如API请求)超时。很多Harness偷懒,全网统一设一个超时时间,结果模型偶尔推理要30秒,30秒一到整个任务被当作失败,用户看到的就是“execution provider did not respond”。
正确做法是三层分开设置,而且处理策略不能“一刀切”:
- 模型推理超时:超时后重试一次,仍超时则把“超时”作为observation回填给模型,让模型决定收缩问题范围或换方案。
- 工具执行超时:按工具类型区分,编译类工具给长超时,文件读取类给短超时。超时后终止该工具调用,并回填超时信息。
- 外部依赖超时:HTTP请求层面加指数退避重试,但重试次数要有上限,避免拖垮整个Harness。
配置示例:
json复制{
"timeouts": {
"model_inference": { "initial_ms": 30000, "retry_times": 1 },
"tool_execution": {
"default_ms": 10000,
"overrides": { "run_build": 120000, "read_file": 5000 }
},
"http_request": { "initial_ms": 5000, "max_retries": 3, "backoff_base_ms": 1000 }
}
}
5.2 上下文爆炸:怎么给Agent“减负”
多步执行的Agent跑着跑着,上下文就会像雪球一样越滚越大,这是Harness工程化里最普遍的问题。上下文爆炸带来的不只是token成本增加,更严重的是模型在超长上下文里的行为质量会明显下降——它开始忘记前面几步做了什么,甚至复制粘贴出重复的工具调用。
解决上下文爆炸,核心思路是“三步走”:
第一步:裁剪旧历史。 保存最近N轮消息,更早的做截断或省略。风险是模型可能忘记早期的重要信息,所以“用户核心目标”这类关键消息必须固定在上下文里,不允许被裁剪。
第二步:摘要压缩。 对工具观察结果做摘要,保留关键结论,丢弃过程细节。例如“脚本运行报错,traceback最后一行是IndexError: list index out of range,位置在main.py第12行”比粘贴整个traceback更高效。
第三步:外部化存储。 大块内容(如文件内容、完整日志)写到磁盘,上下文中只保留“路径+摘要”。模型如果后续需要完整内容,可以再调用读取工具。这是目前编码类Agent比较成熟的落地方案。
我见过不少团队的Agent,任务越来越复杂后效果直线下降,一查上下文管理器还是最原始的“全量append”。花一个下午把三步走实现进去,效果立竿见影。
5.3 并发任务与资源隔离
当Agent从“一个人偶尔用用”变成“团队都在用”时,并发问题就来了。多个Agent任务同时跑,如果共享同一个全局消息列表或同一个工作目录,任务之间会互相污染,出现“这个任务怎么跑着跑着多出另一个任务的代码”这种诡异现象。
Harness必须为每个任务做资源隔离:
- 独立上下文:每个任务拥有独立的消息列表和状态机实例。
- 独立工作目录:每个任务在自己的临时目录里操作文件,任务结束清理或归档。
- 独立工具执行器:工具执行环境互不干扰,最好通过沙箱或容器隔离。
并发控制层面,最简单的方案是用信号量限制最大并发任务数,再用优先级队列做任务调度。例如核心代码:
python复制import asyncio
async def worker(semaphore: asyncio.Semaphore, task):
async with semaphore:
await run_agent(task)
async def main(tasks, max_concurrency=3):
semaphore = asyncio.Semaphore(max_concurrency)
await asyncio.gather(*(worker(semaphore, t) for t in tasks))
资源问题坑起来很隐蔽。有一次我同事的Agent任务总是莫名其妙写出重复文件,查了好几天,最后发现是两个并发任务共用了同一个缓存目录。从那以后,所有Harness的路径配置我都要求带上任务ID。
5.4 可观测性:日志、tracing、重放三件套
Agent类应用有一个让人非常头疼的特点:它的行为路径不固定,这次跑挂的原因,下次可能不会复现。所以Harness的工程化程度,衡量标准就看可观测性做得怎么样。我的做法是三个层面:
日志:记录每次模型调用的时间、prompt摘要、token数、耗时、响应摘要。日志不是给模型看的,是给人排错看的,所以必须简洁、结构化、带任务ID。
Tracing:记录完整事件流,从任务开始到结束,每一步的事件类型、父子关系、耗时。定位卡点用它最好使——一看就明白是模型推理耗时占比高,还是某个工具调用堵住了。
重放:把整个执行轨迹(包括每一步的模型输入输出、工具调用、上下文快照)序列化保存。出问题后,在本地加载轨迹,逐步回放,定位是哪一步开始偏离预期。
这个模块看起来不产生“业务价值”,但它能救命。有一次生产环境的Agent在某个特定任务上连续失败,我们靠重放轨迹发现是某次工具返回的超长输出把上下文撑爆,后续所有决策都建立在不完整信息上。修复成本很低,但如果没做重放,可能要花几周去猜。
5.5 小型企业部署Harness的现实路径
最后聊一下小型企业的情况。没有专门的AI基础设施团队,怎么落地Agent Harness?我的建议是不要一开始追求自研,走“成熟工具打底 + 渐进式掌控”的路径。
第一步,选一个社区活跃、文档齐全的Harness(比如DeepSeek Harness这一类有本地部署能力的开源实现),用默认配置跑通一到两个真实业务场景。这阶段的目标是验证价值,而不是追求极致性能。
第二步,梳理核心场景对工具集、上下文管理、安全边界的需求,在Harness的现有扩展点上做定制。大多数成熟Harness都支持自定义工具注册,把团队内部的数据接口、构建命令挂进去,业务价值会立刻放大。
第三步,当团队已经有了一定的Agent运维经验,再评估是继续深挖现有Harness的源码,还是基于这段时间沉淀的需求自研一套。到了这一步,你已经知道哪些地方是现有实现的瓶颈,哪些是自己的核心需求,决策就有依据了。
硬件条件有限的小企业,可以先用API模型跑通流程,再根据数据安全要求逐步迁移到本地模型。这涉及成本与隐私的权衡,没有标准答案,但有一条经验值得参考:先让业务跑起来,再谈优化。
最后再分享一条我自己的体会。做Harness最忌讳的是“过早抽象”:项目还没跑起来,就先搭一堆接口、抽象层、插件机制。我自己踩过这个坑,花了三周搭了一个看起来很美的框架,结果真实任务一跑,发现核心循环的处理逻辑根本不对,又推倒重来。现在我的原则是先写最小闭环,跑一个真实任务,遇到哪里痛再针对性补工程化能力。还有一个小技巧是给Harness加一个人工确认的暂停点,在关键工具调用(比如删除文件、安装依赖)前停下来让用户确认。这个“人肉安全锁”成本极低,但能拦住大部分灾难性失误。
