---
author: QinIndexCode
tags: AI, Agent, PromptEngineering, ContextEngineering, HarnessEngineering, Cursor, 经验分享
---

## 2026-06-10 从零开始写 Agent，我在 Prompt、Context 和 Harness 三层工程上踩过的坑

这篇博客聊聊我这一年多接触 AI 辅助编程和 Agent 编写的真实经历。从去年中旬偶然发现 Cursor 官网，到十月份之后接触 TraeCN，再到后来尝试 Cursor、OpenCode、Codex、OpenClaw，最后自己动手写 Agent。整个过程走了不少弯路，也推翻了很多最初想当然的认识。

在写这篇文章时，我也翻了一些资料——从 Anthropic 的官方工程博客，到 TMLR（Transactions on Machine Learning Research）正在评审的《Agent Harness Engineering: A Survey》综述论文，再到 harn.app 上整理的实践框架和掘金社区的讨论。这些资料让我把之前零散的经验串联成了一条更清晰的线，也补充了一些我自己实践中还没有注意到的维度。

---

## 起点，一次偶然的发现

去年中旬，我偶然点进了 Cursor 的官方网站。当时正在准备竞赛培训，时间很紧，只是大概看了下产品介绍，知道这是个 AI 编程助手，能做代码补全和生成。心里想着挺有意思，但手头事情太多，没空深入了解，就这么搁下了。

竞赛培训结束后，时间空出来一些。去年十月份之后，我开始接触 TraeCN。那时候我的用法很初级，主要是让它帮忙写一些简单的函数，或者解释看不懂的代码片段。TraeCN 确实能省不少时间，尤其是一些 boilerplate 代码，再也不用自己手敲了。

但用了一段时间后，我开始不满足于这种浅层辅助。我想让 AI 做更复杂的事，比如理解整个项目的结构，或者帮我做跨文件的改动。这时候我开始尝试 Cursor、OpenCode、Codex、OpenClaw 这些工具。（顺便提一嘴，Codex 是真好用）

---

## 工具尝试阶段，各家有各家的脾气

Cursor 给我的第一印象是快。代码补全几乎没有延迟，而且它能理解我当前打开的文件上下文，生成的代码和项目风格比较一致。但 Cursor 的问题也很明显，它更像是一个超级加强版的 IDE 插件，擅长单文件或者邻近文件的改动。一旦涉及复杂的跨模块重构，它就有点力不从心了。

OpenCode 和 Codex 的集成度很高，尤其是在特定生态里。Codex 配合 GitHub 用很方便，能直接读取仓库信息。但它们的自由度相对较低，很多时候只能按照预设的套路来，遇到非常规需求就卡住了。

OpenClaw 是我用过的工具里自主性最强的。它能执行 shell 命令、读写文件、甚至自己规划任务步骤。刚开始用的时候很惊艳，感觉像雇了一个真正的程序员。但很快我就发现了问题，它太自由了，经常在一些边界条件上出错，而且错误会连锁传播，越到后面越难收拾。

这一轮工具尝试让我明白一件事。现有的 AI 编程工具，要么太死板，要么太放任。它们解决的是特定场景的问题，但没有一个能真正按照我的想法去工作。于是我萌生了自己写 Agent 的念头。

---

## 自己写 Agent，推翻了一个想当然的认识

刚开始写 Agent 的时候，我走了最直观的一条路。把 Prompt 写得尽可能详细，给 Agent 规定死每一步该干什么，能调什么工具，不能干什么，输出格式必须怎样。甚至在代码里写了一大套硬编码的门禁逻辑，Agent 每做一步都要过一遍检查清单。

最开始的效果似乎还不错。Agent 按照我规定的步骤走，输出也很规范。但我很快发现了问题。

第一个问题是僵化。Prompt 写得越细，Agent 的应变能力越差。遇到我预设之外的情况，它完全不知道怎么处理，要么报错退出，要么机械地套用不合适的步骤。

第二个问题更隐蔽。当我换一个更强的模型时，效果反而下降了。因为 Prompt 里那些为了约束弱模型而写的详细规则，对强模型来说变成了多余的束缚。强模型本可以做出更合理的判断，却被我的硬编码规则限制住了。

这其实就是后来我在 Anthropic 的工程博客里看到的"高度"问题（Right Altitude）：系统提示词存在一个 Goldilocks Zone（黄金区）——**太规定（Too Prescriptive）**会写出像流程图一样僵硬的 if-else 逻辑，难以适应真实情况的变化；**太模糊（Too Vague）**又会缺少具体的信号，让 Agent 误以为存在共享上下文而偏离任务。**恰到好处（Just Right）**的提示词应该具体到足以有效引导行为，但又足够灵活以提供强大的启发式判断，用最小的信息集完整描述预期行为。

这个发现让我挺意外的。我原以为提示词越清晰越多越好，结果在实践中恰恰相反。过于详细的指令不仅没帮助，还可能成为 Agent 能力的上限。

---

## Anthropic 的一篇文章，让我换了思路

就在我纠结怎么改进 Agent 的时候，我读到了 Anthropic 的一篇关于 Agent 工程的文章。里面有一个观点直接击中了我。

好的 Agent 工程，重点不在于指导 Agent 该干什么，也不在于用一套硬编码的门禁去限制它。重点在于给 Agent 提供一个可运行的环境，让它在这个环境里有足够的信息和工具去自主决策。

这句话把我之前的做法完全推翻了。我原来在做的是 micromanagement，每一步都要管。而正确的做法应该是提供土壤和工具，让 Agent 自己长。

文章里提到的思路和我之前的经验也对得上。OpenClaw 之所以容易失控，不是因为它的模型不够强，而是因为它的运行环境缺乏有效的约束和反馈机制。Cursor 之所以安全但死板，也是因为它把环境限制得太死了。

从这时候开始，我的关注点从 Prompt 本身转移到了 Prompt 背后的整个系统。

---

## 从 Prompt Engineering 到 Context Engineering

理解了 Anthropic 的思路后，我做的第一个改变是精简 Prompt。把那些为了约束弱模型而写的详细规则大量删除，只保留最核心的目标描述和边界条件。Prompt 从原来的几百字压缩到了几十字。

但光精简 Prompt 不够，因为 Agent 做决策需要信息。如果信息给少了，Agent 就会瞎猜。如果信息给多了，Agent 就会在噪声里迷路。

这就是 Context Engineering 要解决的问题。用 Andrej Karpathy 的话说：**"上下文工程是一门微妙的艺术与科学——在正确的时间，用正确的信息填充上下文窗口。"** 它和 Prompt Engineering 的区别在于：Prompt Engineering 问的是"**什么是正确的词？**"，而 Context Engineering 问的是"**模型在执行的每个节点上应该拥有的最优信息集是什么？**"

我开始认真对待这件事。每次调用模型之前，我会根据当前任务筛选出最相关的信息。Agent 在处理 bug 修复时，只给它看相关模块的代码和最近的提交记录，其他无关信息一律不放入上下文。同时，我把信息按结构化方式组织，用清晰的标题分隔不同来源的内容。

在翻资料的时候，我发现关于上下文工程有几种成熟的技术，值得单独记录一下：

**1. Just-In-Time 上下文检索（即时检索）**

这是最推荐给 Agent 使用的策略。Agent 不预先加载所有可能相关的信息，而是维护轻量级的标识符（文件路径、存储的查询等），在需要时通过工具动态加载数据。这样做的好处是让 Agent 的工作记忆中只保留当前真正需要的内容，避免了"上下文腐烂"（Context Rot）——即随着上下文窗口中 token 数量增加，模型准确回忆和推理信息的能力会下降的现象。由于 Transformer 架构中每个 token 都要关注其他所有 token，token 数 n 意味着 n² 对关系，上下文越长，模型的注意力焦点被拉伸得越稀薄。

**2. 上下文压缩（Compaction）**

当对话接近上下文窗口限制时，让模型总结当前对话内容，然后用摘要重新开启一个新的上下文窗口。这个过程的关键是先最大化召回率（确保捕获所有相关信息），再迭代消除冗余内容（清理重复的工具调用和中间输出），保留关键的架构决策、bug 定位和实现细节。

**3. 结构化笔记（Agentic Memory）**

Agent 定期将中间笔记写入持久化存储（位于上下文窗口之外），在后续需要时再将其拉回上下文窗口。这相当于给 Agent 配备了一个"外置硬盘"，用来记录 ID、过滤器、早期决策和已验证的事实。

**4. 子代理架构（Sub-agent Architectures）**

使用专业化的子代理处理特定焦点任务，每个子代理使用干净的上下文窗口进行深入探索，然后只返回一个精炼、浓缩的摘要给主代理。这在处理长任务时特别有效，因为它防止了工具调用的噪声在主上下文中积累。LangChain 的 LangGraph 框架就是围绕这个思想设计的——它通过一个状态对象来隔离不同来源的上下文，LLM 只在需要时才能访问特定上下文字段。

这些技术背后有一个共同的核心原则：**找到最小的高信号 token 集合，以最大限度提高期望结果的可能性。** 效果提升很明显，Agent 的决策准确率提高了，响应速度也更快了，因为上下文变精简了。这个经历让我体会到，给模型喂多少信息不重要，喂什么信息、怎么组织信息才重要。

---

## Harness Engineering，把认知再升一级

今年我读到一份关于 Harness Engineering 的调研报告，里面有个公式让我印象很深。**Agent = Model + Harness。** Model 是模型本身，Harness 是模型之外的一切——系统提示词、工具接口、沙箱环境、编排逻辑、反馈循环、观测体系等等。

报告里提到了一组数据让我非常震撼。同一模型，仅改变 Harness 设计，编码基准测试分数可以从 6.7% 跃升到 68.3%。另一个例子是，通过系统提示词重构、中间件上下文注入和自我验证钩子，有人把一个固定的 GPT-5.2-Codex Agent 在 Terminal-Bench 2.0 上从 52.8% 提升到了 66.5%——13.7 个百分点的增益完全通过基础设施改变实现。还有一个 Meta-Harness 的工作通过自动化 Harness 优化达到了 76.4%，超过了所有手工设计的方案，但没有修改任何模型权重。这些 Harness 层面带来的改进，每一项都超过了同一基准上模型代际进步通常报告的 2 到 4 个百分点。这个差距太惊人了，它直接说明了一件事：**模型能力的提升往往不是 Agent 表现不佳的瓶颈，Harness 的设计质量才是决定性因素。**

TMLR 的综述论文把这个现象称为"绑定约束命题"（Binding Constraint Thesis）：对于跨可比前沿模型评估的长时任务，基准测试的方差可能由执行 Harness 和模型本身共同驱动。

这让我回顾自己写过的 Agent，发现很多稳定性问题确实出在 Harness 层，而不是模型层。比如 Agent 在两个文件之间来回修改，改完 A 发现 B 有问题，改完 B 发现 A 又不对，陷入死循环。这不是模型不够聪明，而是 Harness 缺少断路器机制。后来我给 Agent 加了最大迭代次数和超时检测，这个问题就彻底消失了。

再比如 Agent 把一段合法的解构赋值改成了错误的形式。这也不是模型的问题，而是 Harness 缺少验证步骤。后来我在写入文件前强制运行测试，失败就回滚，准确率立刻上去了。

Harness Engineering 把 Prompt Engineering 和 Context Engineering 当成基础层，在此基础上搭建执行环境、工具管理、状态记忆、观测评估和故障恢复。它的核心思想是：**Agent 的可靠性取决于整个系统的设计，而不是单次模型调用的质量。**

关于 Harness 的系统分层，不同资料有不同的归纳方式，放在一起看反而更容易理解全貌：

**harn.app 提出的 CAR 框架（三层）：**

- **Control（控制层）**：约束与规范。不要让 Agent 写好代码，而是机械地强制执行好代码的样子——通过 AGENTS.md、linters、类型检查、测试即契约、架构规则来实现。**语言约束是建议，代码约束是法律。** Prompt 里写"请不要修改数据库 schema"并不可靠，因为当上下文过长时上下文腐烂几乎不可避免；但把规则写入 CI 检查、pre-commit hooks 或策略守卫，模型就无法绕过。
- **Agency（工具层）**：工具与接口。定义模型被允许如何行动——限定工具范围，而不只是限定知识。MCP 服务器、子代理委托、浏览器/GUI 访问、权限边界都属于这一层。
- **Runtime（运行层）**：执行与恢复。管控工作随时间的展开方式——生命周期钩子、重试与回滚、上下文压缩、追踪收集作为"反射弧"自动触发安全检查或格式化操作，不需要 AI 干预。

**juejin 上一篇文章归纳的七层架构，更偏实践视角：**

1. 认知层（Context Layer）
2. 工具层（Tool Layer）
3. 契约层（Contract Layer）
4. 编排层（Orchestration Layer）
5. 记忆与状态（Memory & State）
6. 评估层（Evaluation Layer）
7. 约束与恢复（Constraint & Recovery）

**TMLR 综述论文提出的 ETCLOVG 七层分类法，更学术系统化：**

1. **Execution environment**（执行环境）：sandbox、workspace、container、隔离执行
2. **Tool interface**（工具接口）：文件系统、git、浏览器、数据库、API
3. **Context management**（上下文管理）：检索、压缩、动态注入、token 预算
4. **Lifecycle/Orchestration**（生命周期/编排）：多步骤任务串联、状态流转
5. **Observability**（可观测性）：日志、追踪、中间结果审计
6. **Verification**（验证）：测试、静态分析、自我检查、行为验证
7. **Governance**（治理）：权限层级、安全边界、人工介入点

不管用哪种分类法，核心信息都是一致的：早期系统把能力集中在单个模型循环里，而后期系统越来越把可靠性视为跨层的基础设施问题。

我现在把 Harness 拆成几块来设计。信息边界层，定义 Agent 该知道什么、不该知道什么。工具系统层，控制 Agent 如何与外部交互。执行编排层，把多步任务串起来。记忆与状态层，管理中间结果。评估与观测层，让 Agent 能自我检查。约束与恢复层，出错时怎么拦截和回滚。

这样拆分之后，调试 Agent 变得清晰多了。出问题的时候，我能快速定位是哪一层的问题，而不是对着模型的输出发呆。

---

## 工具设计要克制

我犯过的另一个错误是给 Agent 塞了太多工具。有一次写项目管理 Agent，集成了十几种工具。查代码、改代码、查文档、发邮件、创建任务、搜索知识库、读取数据库。结果 Agent 表现很糟糕，经常在不该调用工具的时候调用，或者连续调用多个无关工具，把简单问题搞得复杂无比。

后来我砍掉了大部分工具，只保留最核心的三个。读取文件、写入文件、执行命令。效果反而更好了。Agent 的决策路径变清晰了，出错率也大幅下降。

这个教训让我对工具设计有了新的认识。工具数量和控制精度之间存在权衡。工具越多，Agent 的选择空间越大，但也越容易迷失。对于特定场景的 Agent，工具集应该保持精简，每个工具都要有明确的职责边界。

另外，工具的命名也很关键。我早期有个工具叫 file_processor，Agent 经常搞不清楚什么时候该用它。改成 read_file 和 write_file 之后，调用准确率明显提升。命名原则很简单，动词加名词，一看就知道干什么。

关于这一点我在资料里看到一条很实用的规则：**如果一个人类工程师都不能明确地说出在某个情境下该用哪个工具，就不能指望一个 AI Agent 能做到。** 工具应该自包含（single purpose）、对错误健壮（handle edge cases gracefully）、极度清晰（intended use is unambiguous）、token 高效（returns relevant info without bloat），并且参数命名具有描述性（例如 user_id 而非 user）。

---

## 一个实际的重构案例

今年三月份，我接手了一个遗留项目的维护工作。代码库里充斥着各种过时写法，手动重构估计要花两周。我决定写个 Agent 来辅助完成。

这个 Agent 的逻辑很简单。遍历项目目录找出目标文件，逐个读取内容，让模型按照预设规则重构，比如把 var 改成 const 和 let，把回调函数改成 async 和 await，然后把重构后的代码写回文件，最后运行测试验证结果。

整个过程分成两个阶段。第一阶段是探索，Agent 先扫描项目结构，生成待修改文件清单，让我确认。第二阶段是执行，Agent 按清单逐个处理，每处理完一个就运行一次测试。

实际运行中遇到了不少问题。有一次 Agent 把一段合法的解构赋值改成了错误的形式，测试立刻失败了。好在我在设计阶段就加入了测试检查点，Agent 发现测试失败后会回滚代码，然后跳过这个文件继续处理下一个。最终在三天的间歇性运行后，Agent 帮我重构了大概百分之七十的代码，剩下的百分之三十因为逻辑过于复杂，还是需要人工处理。

这个案例让我体会到 Agent 的现实定位。它擅长处理大量重复、模式化的工作，但在涉及复杂业务逻辑的时候，人的判断依然不可替代。把 Agent 当成一个不知疲倦的初级程序员来用，期望设定合理了，反而更容易获得满意的结果。

---

## 调试 Agent 的一些经验

写 Agent 最痛苦的部分不是写代码，而是调试。Agent 的执行流程涉及多个步骤，每个步骤都可能出错，而且错误会连锁传播。

我总结了几条经验。

日志要详尽。Agent 的每一步决策、每一次工具调用、每一个中间结果都应该记录下来。出了问题之后，翻日志是最快的方式。TMLR 综述把可观测性（Observability）列为独立的架构关注点，强调中间步骤必须可读——计划、追踪、差异、失败记录都应该存在 Agent 和人类可以审计的文件中。

设置断路器。给 Agent 设置最大迭代次数和超时时间，防止陷入死循环。加了迭代上限之后，至少能保证程序不会跑飞。

保留人工介入点。在关键节点暂停执行，让人确认后再继续。比如文件写入操作前弹出确认框，显示变更内容摘要。这在处理重要代码库的时候尤其必要。harn.app 称之为 Governed（治理）——自主性必须有边界，不可逆操作受到权限层级、沙箱、验证门和人工审查的约束。

反馈要闭环。Agent 完成任务后，系统需要自动判断它是否做对了，并把结果反馈给 Agent，驱动它自我修复。这在 juejin 的文章里被称为反馈层——功能验证（代码能跑吗？逻辑对吗？）和行为验证（Agent 的行为本身符合预期吗？）都是这个循环的一部分。行为验证甚至可以写成测试，比如"变更行数不应超过 50 行"、"不应引入新依赖"，这些断言能防止 Agent 过度工程化。

---

## 写在最后

从最初偶然发现 Cursor 官网，到接触 TraeCN，再到尝试各种工具，最后自己动手写 Agent，这一路的认知升级挺明显的。最开始我以为重点是写好 Prompt，后来发现 Context 更重要，再后来意识到整个 Harness 的设计才是根本。

这段时间我翻资料时发现，整个社区的认知演进也是按同样的顺序：2022-2023 年是 Prompt Engineering，大家关心的是措辞；2024 年是 Context Engineering，大家开始意识到信息选择和组织的重要性；从 2025 年开始，随着 Agent 开始真正修改代码库、调试系统、连续运行数小时，Harness Engineering 成为了新的焦点——构建一个让 AI Agent 可以安全、可预期、可审计地运行的系统。这个三代演进的脉络和我自己踩坑的顺序高度吻合，也让我对自己当前的方向更有信心。

最大的感触是 Agent 没有魔法。它的本质依然是大语言模型加循环加工具调用。那些看起来很炫酷的 Agent 应用，背后都是大量的工程细节和边界情况处理。

但写到这里我想多说一句。**Agent 并不是 LLM 应用的最终形态，它只是一个过渡态。**

当前的 Agent 本质上是在用工程手段弥补模型能力的不足。Harness 越复杂、钩子越多、约束越严密，恰恰说明模型本身还不够可靠——我们需要一个庞大的外部脚手架来防止它犯错。而理想的方向，应该是模型自身就能更稳定地理解任务、管理状态、处理边界，从而让 Harness 简化，而不是无限膨胀。

再往深看一层，Prompt Engineering 是在教模型"怎么说"，Context Engineering 是在教模型"看什么"，Harness Engineering 是在教系统"怎么管"。这三层工程加起来，其实是在回答同一个问题：**当模型还不够聪明的时候，我们怎么让它把事情做对？** 但如果未来模型本身具备了更强的长期规划、工具理解、状态记忆和错误恢复能力——这些能力从外部 Harness 内建到模型内部——那么今天我们精心设计的 Agent 框架就可能变得多余，就像当初详细的 Prompt 规则在更强的模型面前失去意义一样。

另一个角度是应用范式本身。当前的 Agent 仍然是"有人指挥的自动化"——人定义任务、人确认结果、人兜底异常。真正的下一代 LLM 应用可能不是"Agent"这个词暗示的"代理执行"，而是模型作为系统的一个原生组件嵌入到应用逻辑里，和传统代码、数据库、用户界面无缝协作，不需要显式的工具调用循环和人工检查点。那时我们写的不再是 Agent，而是**具备原生理解和推理能力的新型应用**。

所以我对自己的定位很清楚：今天用心写好 Agent，不是因为我相信 Agent 是终点，而是因为在通往终点的路上，这是最有价值的练兵场。理解 Agent 的痛点，就是在理解下一代 LLM 应用需要解决什么问题。

如果你也想在日常工作中引入 Agent，建议从一个具体的小问题开始。不要想着一步到位搭建全能助手，先解决一个实际的痛点。等这个小 Agent 跑顺了，再逐步扩展能力范围。同时保持一份清醒——你在做的可能不是未来，而是通往未来必经的一段路。

技术本身并不复杂，复杂的是把技术落地到真实场景中的过程。希望这篇博客能给正在尝试写 Agent 的你一些参考。
