Harness Engineering:从零讲起

原文链接:https://x.com/santtiagom_/article/2098782814837543075

作者:santi(@santtiagom_)· 布宜诺斯艾利斯

正文为中文,紧随其后的引用块为英文原文对照。

一年前,如果你问别人怎么把 agent 做好,答案几乎总是一样的:换个模型,或者写个更好的 prompt。

A year ago, if you asked someone how to improve an agent, the answer was almost always the same: try another model or write a better prompt.

但那只是一部分。我想告诉你为什么:

But that was only part of it. And I want to show you why:

OpenAI 造出了一整套内部产品:一百万行代码、1500 个 pull request,人类一行都没写。

OpenAI built an entire internal product: one million lines of code, 1,500 pull requests, without a single human writing a single line.

LangChain 把自己那个排在 Terminal Bench 2.0 第 30 名的 coding agent,推进了前 5。没换模型。

LangChain took its own coding agent, which was ranked 30th on Terminal Bench 2.0, and moved it into the top 5. Without changing the model.

Anthropic 记录了类似的事:同一个模型放在不同配置里,要么给你一个看着挺好但跑不起来的 app,要么给你一个真能跑的。

Anthropic documented something similar: the same model, in different configurations, can leave you with an app that looks fine but doesn’t work, or one that does.

这三家都不是靠换模型做到的。他们投的是同一件事:模型外围的那套系统。

None of the three achieved it by changing the model. All three invested in the same thing: the system around the model.

而这件事,开始被称为 Harness Engineering。

And that is exactly what started to be called Harness Engineering.

他们到底造了什么?

What exactly did they build?

这就是我们要从零搭出来的东西:从一个只会返回文本的模型开始,一次加一块,直到变成一个你能把明确目标交给它的 agent。

That’s what we’re going to build here, from scratch: we start with a model that only returns text and add one piece at a time, until we reach an agent you can hand a concrete goal to.

但先得搞清模型和 harness 的区别。

But first, we need to understand the difference between a model and a harness.

模型负责什么、harness 负责什么

What the model does and what the harness does

你给 coding agent(Claude Code、Codex 或别的)派任务时,你看到的只有一样东西:一段对话。你写下需求,agent 就开跑:找文件、打开、写代码、跑测试,再把改动拿给你看。

When you give a coding agent a task — Claude Code, Codex, or any other — what you see is a single thing: a conversation. You type the request and the agent starts. It searches for files, opens them, writes code, runs the tests, and shows you the changes.

看起来这些全是模型在做。其实模型只做一部分:思考、判断该干什么。

It looks like the model does all of that. But in reality, the model does one part: thinking and deciding what’s worth doing.

模型收文本、吐文本,仅此而已。它不打开文件、不执行命令,也没有记忆。

A model takes in text and returns text. That’s all it does. It doesn’t open files, doesn’t run commands, and has no memory either.

那如果不是模型,是谁在找文件?是谁在写代码?一定有另一个组件在管这些事。

So then, if it isn’t the model, who looks for the file? Who writes the code? There has to be another component handling that.

这个组件,我们叫它 harness。

We call that component the harness.

harness 是围绕模型的那套软件系统,它把模型写出的东西变成已完成的工作:组装模型要读的内容、解读模型的回应、执行模型请求的动作、保存过程中发生的事,并判定任务何时算完成。

A harness is the software system that surrounds the model and turns what it writes into finished work: it assembles what the model will read, interprets what it responds, executes the actions it requests, stores what has been happening, and decides when the task is done.

说得更短: 不是模型的一切,都是 harness。

跑起来的那个程序、它提供的 tools、执行这些 tools 的地方、两次调用之间它保存下来的东西。全都是。

Put more briefly: everything that isn’t the model is the harness.

The program that runs, the tools it offers, the place where it executes them, what it keeps between one call and the next. All of that.

可模型只会写文本,它怎么提出请求?

But how does the model ask for something, if all it can do is write text?

harness 递给它一份可用动作清单:搜代码、读文件、改文件、跑测试。这些动作叫 tools。模型不执行它们,只写出想用哪个、带什么参数。这个请求仍然是文本,是 harness 把它变成真实动作。

The harness hands it a list of available actions: search code, read a file, edit it, run the tests. Those actions are called tools. The model doesn’t execute them; it only writes which one it wants to use and with what parameters. That request is still text. The harness is what turns it into a real action.

现在没完全看懂也没关系,后面会带例子细讲。眼下记住一句就够:模型提要求,harness 去执行。

If it isn’t entirely clear yet, no matter. We’ll go deep later, with examples. For now the idea is enough: the model asks, the harness executes.

看个更实际的例子。

Let’s look at a more practical case.

你在做一个能发帖的 app,有点像 Twitter。仓库开着,代码都在里面。

你想给帖子加一个点赞按钮,于是对 agent 说:

You’re building an app where people can publish posts, something like Twitter. You have the repository open, with all the code inside.

You want to add a like button to the posts. So you tell the agent:

「给帖子加个点赞按钮。」

“Add a like button to the posts.”

接下来发生的是:

Here’s what happens from there on:

  1. harness 组装模型将收到的消息:它该怎么干活的说明、你的需求、项目关于自身的文档(团队约定、各部分在哪),以及可用 tools 清单和它们的参数。

    1. The harness assembles the message the model will receive: instructions on how it should work, your request, whatever the project documents about itself (team conventions, where each thing lives), and the list of available tools with their parameters.
  2. 模型用文本回应:「我需要找到每个 post 在哪渲染」,并请求使用搜索(tool)。

    1. The model responds with text: “I need to find where each post is rendered,” and asks to use search (tool).
  3. harness 在你的真实文件上跑这个搜索,返回三个文件:Post.tsx、PostList.tsx、useUserData.ts。(名字不用较真,只是举例)

    1. The harness runs that search over your real files and returns three files: Post.tsx, PostList.tsx and useUserData.ts. (don’t worry about the names, it’s just an example)
  4. 模型判断按钮该放在第一个文件里,请求打开 Post.tsx。

    1. The model decides the button goes in the first one and asks to open Post.tsx.
  5. harness 打开它,把内容发过去。

    1. The harness opens it and sends it the content.
  6. 模型提出改动:在这里加按钮,用这段代码。

    1. The model proposes the change: add the button here, with this code.
  7. harness 把它写到真实文件上。

    1. The harness applies it to the real file.
  8. 模型请求跑测试。

    1. The model asks to run the tests.
  9. harness 跑完返回结果:有一个失败了,附带错误信息。

    1. The harness runs them and returns the result: one failed, along with the error message.
  10. 模型读这个错误,提出下一个改动。循环重新开始。

    1. The model reads that error and asks for the next change. The cycle starts again.

与此同时,你只看到 agent 在干活。

Meanwhile, all you see is the agent working.

注意这个模式:模型从不做事,它只提请求。harness 负责搜、开、改、跑,再把结果回给模型,让它决定下一步。

Notice the pattern: the model never does anything, it asks. The harness searches, opens, edits, executes, and returns what happened so the model can decide the next step.

模型负责什么、harness 负责什么:模型决定并请求,harness 执行

所以这些工具有一种「一个 agent 在电脑上干活」的感觉。模型提供推理,harness 把它接到文件、终端、浏览器、数据库或任何它需要动手的环境上。

That’s why these tools feel like agents working on a computer. The model provides the reasoning. The harness connects it to files, terminal, browser, database, or whatever other environment it has to act in.

落到实处:你用 Claude Code 时,模型是 Claude(Opus、Sonnet,随你选),Claude Code 是 harness。Codex 也一样,Codex 是 harness,Sol 是模型。一个负责想,另一个干剩下全部。

To ground it: when you use Claude Code, the model is Claude (Opus, Sonnet, whichever you pick) and Claude Code is the harness. In Codex it’s the same — Codex is the harness and Sol is the model. One thinks, the other does everything else.

它们就是一些你装上、跑起来的程序,和别的程序没两样。有意思的是里面装了什么——而这正是我们接下来要一块块搭出来的东西。

They’re programs you install and run, like any other. The interesting part is what they have inside — which is exactly what we’re going to build now.

两个角色分清之后,我们就一点点搭一个 harness,目标就用刚才那个需求:让 agent 能把点赞按钮加上,并且你能确信它确实做对了。

With both roles clear, we’ll build a harness bit by bit, with this same request as the goal: that the agent can add the like button, and that you can trust it was done right.

我们从一个只会返回文本的裸模型开始,一次加一块。一共九块,分两组。

We start with a bare model that does nothing but return text, and add one piece at a time. There are nine, in two groups.

前六块是 harness 给模型的东西,让它能干得了活:

The first six are what the harness gives the model so it can do the work:

  1. Tools,让它能动手。

    1. Tools, so it can act.
  2. Loop,把步骤串起来。

    1. A loop, to chain steps together.
  3. 记忆(memory),让它记得自己做过什么。

    1. Memory, so it remembers what it did.
  4. 上下文(context),决定每次调用它看到什么。

    1. Context, to choose what it sees on each call.
  5. 一个干活的地方,与你的环境隔开。

    1. A place to work, separate from yours.
  6. 明确的目标 + 验证,用来判断它做完了没有。

    1. A clear goal and verification, to know whether it’s done.

另外三块是 harness 给你的,让你能信任结果:

The other three are what the harness gives you, so you can trust the result:

  1. 权限与边界,让它不做不该做的事。

    1. Permissions and limits, so it doesn’t do what it shouldn’t.
  2. 可观测性,让你看到发生了什么。

    1. Observability, to see what happened.
  3. Evals,衡量它有没有变好。

    1. Evals, to measure whether it improved.

两组的分工很重要。前六块让 agent 能自主干活、跑出结果;后三块让你能约束它、看懂它做了什么、并衡量它是不是真的管用。

The difference between the two groups matters. The first six let the agent work autonomously and reach a result. The other three let you constrain it, understand what it did, and measure whether it actually works.

harness 给模型的六块能力,以及 harness 给你的三块能力

harness 给模型的东西

What the harness gives the model

  1. Tools,让它能动手

    1. Tools, so it can act

回到那个需求:给帖子加点赞按钮。

Let’s go back to the request: add a like button to the posts.

模型读完,完全明白要做什么,然后用文本回答:「应该在这个 post 组件里加一个按钮。」

The model reads it, understands perfectly what needs to be done, and answers with text: “we’d need to add a button in the post component.”

但你的仓库跟之前一模一样。没打开一个文件,没写一行代码。

But your repository is exactly as it was. Not a file opened, not a line written.

那它只产出文本,怎么去搜到这个组件、打开它、改代码?

So how does it search for that component, open it and change the code, if all it produces is text?

靠 tools。一个 tool 就是 harness 提供给模型的函数:有名字、有它做什么的描述、有入参、有返回值。harness 把可用清单和请求它们的精确格式一起交给模型。

Through tools. A tool is a function the harness offers the model: it has a name, a description of what it does, the parameters it takes and a result it returns. The harness hands it the list of what’s available and the exact format it must use to request them.

我们给它 4 个:

For our task we give it 4:

search_code(text)
read_file(path)
edit_file(path, old_text, new_text)
run_tests()

模型不能执行它们。它只写出想用哪一个:

The model can’t execute them. All it does is write which one it wants to use:

search_code(“post”)

search_code(“post”)

这仍然是文本,但形状是 harness 认得的。harness 读它、在你的文件里跑搜索,并在下一次调用把结果回给它:

That’s still text, but now it has a shape the harness recognizes. The harness reads it, runs the search over your files, and returns the result on the next call:

  • components/Post.tsx

    • components/Post.tsx
  • components/PostList.tsx

    • components/PostList.tsx
  • hooks/useUserData.ts

    • hooks/useUserData.ts

整个机制就是这个来回:模型按约定格式提请求,harness 执行并回话。

That back-and-forth is the whole mechanism: the model asks in an agreed format, the harness executes and answers.

这里有一点很重要:你怎么设计这些 tools,会改变 agent 的行为。edit_file 失败时只返回一句 「error」,和返回「我在 Post.tsx 里没找到这段文本,但第 42 行有一处相似匹配、缩进不同」,完全不是一回事。

要记住精确度是关键。前者模型只能猜,后者它已经知道该去哪改。(OpenAI 甚至是按「agent 会读这些报错」来写自家 linter 报错文案的。)

And here’s something important: how you design those tools changes the agent’s behavior. It’s not the same for edit_file to fail returning just “error”, as to fail saying “I didn’t find that text in Post.tsx, but there’s a similar match on line 42 with different indentation.”

Keep in mind precision is key. With the first, the model has to guess. With the second, it already knows where to fix it. (OpenAI went as far as writing their linters’ error messages thinking the agent will read them.)

有了 tools,模型已经能让你的仓库里发生事情了。这就是模型与环境交互的方式。

With tools, the model can now make things happen in your repository. It’s how the model interacts with the environment.

但看看我们卡在哪:它请求一次搜索,harness 回了三个文件,交换就结束了。一问一答。按钮还是不存在,也没人会去请求下一步。

But look where we’re stuck: it asked for a search, the harness returned 3 files, and the exchange ended there. One request, one answer. The button still doesn’t exist, and nobody will ask for the next step.

  1. Loop,把步骤串起来

    1. A loop, to chain steps

所以必须有人再去调它一次。

That’s why someone has to call it again.

想想加这个按钮它需要做多少事: (1) 找到组件、(2) 读它、(3) 搞清数据怎么存、(4) 写改动、(5) 跑测试、(6) 修失败的地方。至少六步。

Think about everything it needs to add the button: (1) find the component, (2) read it, (3) understand how the data is stored, (4) write the change, (5) run the tests and (6) fix whatever fails. Six steps, minimum.

而且它没法提前规划,因为每一步都依赖上一步的结果。搜索没返回文件名之前,它不知道打开哪个文件;没读到文件之前,不知道写什么代码;没跑测试之前,不知道成没成。

And it can’t plan them upfront, because each depends on the previous result. It doesn’t know which file to open until the search returns the names. It doesn’t know what code to write until it reads the file. It doesn’t know if it worked until it runs the tests.

所以 harness 不会只调它一次,而是调很多次,而且每次都告诉它上一次的结果。

That’s why the harness doesn’t call it once. It calls it many times, and on each call it tells it how the previous one went.

harness 大致这么做:

The harness does something like this:

while 任务未完成:
 response = call_model(需求 + 到目前为止发生的一切)
 result = execute(它请求的那个 tool)
while the task isn't finished:
    response = call_model(the request + everything that happened so far)
    result = execute(the tool it asked for)

换句话说: 问模型该做什么 → 去做 → 告诉它发生了什么 → 再问它。直到做完。(这就是 loop!)

In other words: ask the model what to do, do it, tell it what happened, and ask it again. Until it’s done. (a loop!)

关键在于那第二部分——「到目前为止发生的一切」。第一轮模型只有你的需求;第二轮它知道有哪些文件,因为 harness 告诉它搜索结果了;第三轮它已经读过其中一个;第四轮它知道某个测试失败了、以及为什么。

The important part is that second piece, “everything that happened so far”. On the first turn the model only has your request. On the second it knows which files exist, because the harness told it the search result. On the third it has already read one. On the fourth it knows a test failed and why.

每一轮开始时都比上一轮知道得更多。所以它比「一次尝试」能走得远得多。

Each turn starts knowing more than the last. That’s why it gets further than in a single attempt.

这个模式通常和 ReAct 联系在一起:推理 → 行动 → 观察结果 → 再推理。它是如今很多 agent 的核心。

This pattern is usually associated with ReAct: reason, act, observe what happened, and reason again. It’s the heart of many agents today.

这时缺的那个词就出现了:模型和 harness 在这个循环里一起工作、朝一个目标推进——那就是 agent。

And here’s the word that was missing: when the model and the harness work together inside this cycle, chasing a goal, that’s an agent.

LangChain 用一个公式概括了它:

LangChain sums it up in a formula:

agent = 模型 + harness

agent = model + harness

它不是又加了一块零件,而是整个系统运转起来之后的名字。

It’s not a new piece added to the other two. It’s the name of the whole system, running.

有一点值得注意:没人预先规定第二步必须打开 Post.tsx,是模型看到搜索结果之后自己选的。如果那次搜索只返回一个文件、或者一个都没返回,下一步就会不一样。

And something worth noticing: nobody decided in advance that step two had to be opening Post.tsx. The model chose it after seeing the search result. If that search had returned one file, or none, the next step would have been different.

在 agent 里,每一步都源自上一步的结果。所以它能解决你搭它时没预料到的任务。

In an agent, each step comes out of what happened in the previous one. That’s why it can solve tasks that weren’t foreseen when you built it.

有个问题还悬着:循环什么时候停?目前是「模型说做完了就停」。而这正是后面必须解决的问题。

One question remains open: when does the loop stop? For now, when the model says it’s done. Which is exactly the problem we’ll have to solve later on.

现在 agent 能连续走很多步了。但在两轮之间,模型会把一切忘干净。

Now the agent can work across several steps. But between one turn and the next, the model forgets everything.

  1. 记忆,让它记得自己做过什么

    1. Memory, so it remembers what it did

如果模型在两次调用之间忘光一切,它怎么继续干活?

If the model forgets everything between one call and the next, how can it keep working?

答案其实藏在 loop 里,就在我们一带而过的那句「到目前为止发生的一切」。

The answer was hidden in the loop, in something we said quickly: that “everything that happened so far”.

模型怎么知道发生过什么?这些信息存在哪?

How does the model know everything that happened? Where does that information live?

不在模型里。每次调用都是独立的(stateless):进一段文本、出一段文本,就结束了。什么都不留。

Not in the model. Each call is independent (stateless): text goes in, text comes out, and that’s it. Nothing is kept.

在任何聊天窗口里都能看出来。你连发三条消息,模型回答时会顾及第一条,看起来它记得这段对话。其实没有:每一轮都把完整历史从头再发一遍。看上去像记忆的东西,是 harness 每次把整份历史重发而已。

You can see it easily in any chat. When you write three messages in a row and the model answers taking the first one into account, it looks like it remembers the conversation. It doesn’t: on every turn the full history is sent again, from the beginning. What looks like memory is the harness resending the entire history each time.

agent 也一样,只是重发的不是聊天消息,而是工作记录。如果第 3 轮模型发现偏好是用 X 函数存的,到第 4 轮它就不知道了——除非有人再告诉它一遍。

With an agent it’s the same, except what gets resent isn’t chat messages but the work log. If on turn 3 the model discovered the preferences are stored with function X, on turn 4 it no longer knows, unless someone tells it again.

那个「有人」就是 harness。所以我们加上记忆:把状态存在模型之外,每次调用时再喂回去。

That someone is the harness. That’s why we add memory: it keeps the state outside the model and passes it back in on every call.

状态可以包括:

The state can include:

  • 已经看过哪些文件;

    • which files it has already reviewed;
  • 应用了哪些改动;

    • which changes it applied;
  • tools 返回了什么;

    • what the tools returned;
  • 出现了哪些错误;

    • which errors came up;
  • 还差什么没做完;

    • what’s still left to do;
  • 已经尝试了几次。

    • how many attempts it has made.

循环的每一轮——也就是对模型的一次调用加上由此产生的动作——都会留下新信息。harness 把它记下来。

Each turn of the loop — that is, each call to the model plus the action that comes out of it — leaves new information. The harness writes it down.

三四轮之后,我们 agent 的状态大概长这样:

After three or four turns, our agent’s state might look like this:

目标:给帖子加点赞。
已看文件:Post.tsx、useUserData.ts。
已应用改动:在 Post.tsx 加了按钮。
待办:持久化偏好并验证 UI。
最近错误:useUserData 的 mock 里缺 likePost。
Goal: add likes to posts.
Files reviewed: Post.tsx, useUserData.ts.
Change applied: button added in Post.tsx.
Pending: persist the preference and verify the UI.
Last error: likePost is missing from the useUserData mock.

这些不存在模型里,而是活在 harness 里:由它维护更新,并用它组装下一次调用。

That isn’t stored in the model. It lives in the harness, which keeps it up to date and builds the next call with it.

还有一点:

长任务还需要跨会话的连续性。Anthropic 处理这个问题的做法是:让每个会话留下一个进度文件和清晰的 commit。下一个会话读它们,搞清做到哪了,然后接着往下做。

And one more thing:

On long tasks you also need continuity between sessions. Anthropic worked on this problem by having each session leave behind a progress file and clear commits. The next session reads them, understands what was done, and continues from there.

这是对某个具体问题的简单解法:让接手任务的 agent 看到一个整洁的桌面——之前做过什么、下一步做什么,都摆在明面上。

It’s a simple solution to a specific problem: that the agent picking the task back up finds a tidy desk, with the previous work and the next steps in view.

现在 agent 记得自己做过的一切了。而这恰好带来下一个问题:东西太多,不可能每次调用都整包发过去。

Now the agent remembers everything it did. And that’s exactly the next problem: it’s too much to send whole on every call.

  1. 上下文,决定每次调用它看到什么

    1. Context, to choose what it sees on each call

模型每次调用能接收的文本量有上限。

The model has a limit on how much text it can receive per call.

每次调用都必须塞进上下文窗口(context window)——也就是模型一次能读的最大文本量。它用 token 计量,token 是词的小片段,大约三四个字符一个。

Each call has to fit inside the context window, which is the maximum amount of text the model can read at once. It’s measured in tokens, which are word chunks of roughly three or four characters each.

今天的窗口大得惊人。Sol 能处理大约一百万 token,Claude 也在同一量级。听着很多,也确实很多——相当于好几本完整的书。

Today’s windows are enormous. Sol handles around a million tokens, and Claude is in similar territory. It sounds like a lot, and it is: it’s equivalent to several whole books.

但真实仓库可能比这还大。代码、测试、文档加其他文件,一个大型 codebase 轻松超过一百万 token。

But a real repository can be bigger than that. Between code, tests, documentation and other files, a large codebase can easily exceed a million tokens.

就算塞得进去,还有另一个问题:上下文更多 ≠ 上下文更好。为了加一个按钮把整个项目发过去,真正重要的东西会淹没在几千行无关代码里。而且要看的东西越多,模型盯错地方的概率越大。

And even if it fit, you’d have another problem: more context isn’t better context. If you send the whole project just to add a button, what matters gets lost among thousands of lines that have nothing to do with the task. And the more there is to read, the likelier the model focuses on the wrong part.

所以 harness 必须挑选每次调用带什么进去。选错了两头都贵:发太多,白烧窗口还加噪音;压太狠,模型丢掉重要决策、把做过的活重做一遍。

So the harness has to choose what goes into each call. And choosing badly is expensive both ways: send too much and you burn window and add noise; summarize too much and the model loses important decisions and redoes work it had already done.

那它怎么选?两招。

And how does it choose? With two moves.

第一招:给它一张项目地图,而不是整个项目。几行字告诉它各部分在哪,比如:

The first is giving it a map of the project instead of the whole project. A few lines telling it where each thing is, for example:

  • 帖子渲染在 components/Post.tsx。

  • 偏好用 hooks/useUserData.ts 保存。

  • 组件测试和组件放在一起。

    • Posts are rendered in components/Post.tsx.
    • Preferences are stored with hooks/useUserData.ts.
    • Component tests live next to each component.

有这些,模型一行代码都没读就知道该去哪儿。

With that, the model already knows where to go without having read a single line of code.

第二招:只在需要时才把剩下的取进来。如果它要搞懂 useUserData,就请求搜它的使用处、打开那些文件,仅此而已。仓库的其余部分永远不会进来。

The second move is bringing the rest only when it’s needed. If it needs to understand useUserData, it asks to search for its usages, opens those files, and nothing more. The rest of the repository never comes in.

这就是 agent 内部的 retrieval:到当前上下文之外去找信息,只把对下一步有用的取回来。Anthropic 在这里详细展开,包括他们判断「什么该进、什么不该进」的策略。

That’s retrieval inside an agent: looking for information outside the current context and bringing in only what’s useful for the next step. Anthropic develops it in detail here, with the strategies they use to decide what goes in and what doesn’t.

这种工作方式——先给一点、剩下的边走边取——叫 progressive disclosure(渐进披露)。后面你还会再见到它。

That way of working — start with little and bring the rest as you go — is called progressive disclosure. You’ll see it show up again later.

所以上下文不是开头组装一次就固定的块,它在整个任务过程中一直在变:

Context, then, isn’t a fixed block assembled once at the start. It keeps changing throughout the task:

初始需求
→ 项目地图
→ 搜索 Post.tsx
→ 组件内容
→ useUserData 的使用处
→ 某个测试的错误
initial request
→ project map
→ search for Post.tsx
→ component contents
→ usages of useUserData
→ a test error

每个动作都会产生新信息。好的 harness 会过滤它、保留重要的、避免用旧结果把上下文塞满。但这有代价:模型会缓存已处理过的内容以免重复付费,所以每当 harness 重写一段本来就在的内容,从那里往后的缓存就失效了。

Each action produces new information. A good harness filters it, keeps what matters and avoids filling the context with stale results. Though that has a cost: since the model caches what it already processed so as not to pay for it again, every time the harness rewrites something that was already there, that cache is lost from that point on.

那如果对话还是变长、塞不下了呢?两条出路。一是 compaction:就地总结旧内容,让 agent 接着做同一件事但占用更少。二是彻底断开、开一个新会话,并给它留一条「做到哪了」的记录。

And if the conversation gets long anyway and starts not fitting? There are two ways out. One is compaction: summarize the old part right there, so the agent continues with the same thing but taking up less. The other is cutting it off entirely and starting a new session, with a note of where it left off.

这一切(发什么、何时取、总结什么、丢掉什么)有自己的名字:context engineering。它是当下讨论最多的东西之一,有时被当成全部问题。但它只是 harness 的一块,和本文开头那个 prompt engineering 一样:依然重要,依然只是更大整体的一个部分。

All of this (what to send, when to bring it, what to summarize, what to discard) has its own name: context engineering. It’s one of the most talked-about things today, and sometimes it’s treated as if it were the whole problem. But it’s one more piece of the harness, just like the prompt engineering this article started with: it still matters, and it’s still part of something bigger.

它已经知道做什么、用什么信息。还缺一个我们一直默认的前提:这一切发生在哪里。

It now knows what to do and with what information. One detail is missing that we’ve taken for granted so far: where all this is happening.

  1. 一个干活的地方,与你的环境隔开

    1. A place to work, separate from yours

agent 做的一切都发生在某个地方。它改文件、跑测试,都是在真实文件、真实电脑上发生的。

Everything the agent does happens somewhere. When it edits a file or runs the tests, that happens on real files, on a real computer.

问题是:哪一台?

The question is which one.

如果是你的电脑,agent 的每个失误就是你机器上的事故:删了个文件、装了个依赖把别的东西搞坏了、跑了一条你根本不想跑的命令。

If it’s yours, every agent mistake is a mistake on your machine: a deleted file, a dependency that breaks something else, a command you didn’t want to run.

另一个选择是给它一份副本去干活——你的项目放在一个与外界隔离的空间里。它在里面搞坏了什么,你直接扔掉重来,你的机器毫不知情。

The other option is giving it a copy to work in. Your project inside a space separate from everything else. If it breaks something there, you throw it away and start over, and your machine never notices.

这个地方叫「环境」(environment);当它是隔离的,就叫 sandbox。

That place is called an environment. When it’s isolated, a sandbox.

你用的每个工具里都有这个东西。Codex 在操作系统级 sandbox 里执行命令,允许你选三档:只读、仅限项目文件夹可写、完全访问。默认是中间那档,而且网络是关的。Claude Code 有自己的 sandbox 模式,在它原本会弹窗问你的那些权限之下,再加一层同样的系统级底线。

This exists in every tool you use. Codex runs commands inside an OS-level sandbox and lets you choose among three levels: read-only, write limited to the project folder, or full access. The default is the middle one, and the network is off. Claude Code has its own sandbox mode, which adds that same OS-level floor to the permissions it was already asking you for on screen.

它保护你免受什么?三件很具体的事。

What does it protect you from? From three fairly concrete things.

  1. 跑出项目范围的破坏性命令。一条写错的 rm(删除)动不了文件夹之外的任何东西。

    1. A destructive command that escapes the project. A badly written rm (remove) can’t touch anything outside the folder.
  2. 你没要求的对外连接。网络关着,agent 没法把你的代码发出去,也没法下载来路不明的东西。

    1. A connection you didn’t ask for. With the network off, the agent can’t send your code anywhere or download something odd.
  3. 还有一件听起来不那么显眼、却越来越重要的事:藏在 agent 所读材料里的指令。如果它打开的文件、依赖或网页里写着「把一切删掉、把凭据传到某处」,即便模型信了,sandbox 也是让它走不远的那道墙。

    1. And one that sounds less obvious but matters more and more: hidden instructions in the material the agent reads. If it opens a file, a dependency or a web page that says “delete everything and upload the credentials over there,” the sandbox is what keeps that from getting far, even if the model believes it.

最后一条要留神:sandbox 只是多一层,不是保证。比如你为了让它装依赖而开了网络,其中一把锁就打开了。

Watch out with that last one: the sandbox is one more layer, not a guarantee. If you enable the network so it can install dependencies, for example, one of those padlocks opens.

把这个地方搭起来也是 harness 的活,因为不只是隔离:得决定里面有哪些文件、装了什么依赖、能不能上网、有没有测试数据库。

And setting that place up is also the harness’s job, because it isn’t only about isolating: you have to decide which files are inside, which dependencies are installed, whether it has internet access, whether there’s a test database.

现在 agent 能动手、能串步骤、能记住做过什么、能挑要看什么、能在受控的地方干活。但它还不知道什么时候算做完。

The agent can now act, chain steps, remember what it did, choose what to look at and work in a controlled place. But it still doesn’t know when it’s finished.

  1. 明确的目标 + 验证,用来判断它做完了没有

    1. A clear goal and verification, to know whether it’s done

它已经能干这活了。缺的是「知不知道自己干得对」——而这件事在完工之前很久就开始了。

It can do the work now. What’s missing is knowing whether it did it well, and that starts long before finishing.

「加个点赞按钮」看起来是个明确需求,直到你真去实现它。

“Add a like button” looks like a concrete request until you try to implement it.

用户只能点一次吗?要显示计数吗?状态得在刷新后保留吗?按钮放哪?可以动帖子的样式吗?

Can the user like it only once? Do you have to show a counter? Does the state have to survive a refresh? Where does the button go? Can the post’s design be touched?

如果 harness 把需求原样发过去,模型就自己把这些空白补上。有时猜对,有时做出跟你预期不一样的东西。

If the harness sends the request exactly as it arrived, the model fills those gaps on its own. Sometimes it gets it right. Other times it builds something different from what you expected.

这些谁来写?两条路。

And who writes that? There are two paths.

(1)你自己写:写在需求里,或者写在 agent 启动时会读的仓库文件里,比如多个工具都采用的 AGENTS.md、或 Claude Code 的 CLAUDE.md。

(1) One is that you write it: in the request itself, or in a file in the repository that the agent reads on startup, like the AGENTS.md several tools adopted or Claude Code’s CLAUDE.md.

(2)让 harness 生成:开工之前单独调一次模型,把你的两行需求变成一份完整规格。Anthropic 就是这么试的,专门用一个 agent 干这件事。

(2) The other is that the harness generates it. Before starting the work it makes a separate call to the model, asking it to turn your two-line request into a complete specification. Anthropic tested it this way, with an agent dedicated to just that.

无论哪种,写下来的东西是这样:

In either case, what gets written down is this:

目标:
每个帖子加一个点赞按钮。

限制条件:
保持列表现有设计。
使用现有的用户偏好系统。

验收标准:
- 按钮出现在每个帖子上。
- 点击后状态变化。
- 刷新后状态保留。
- 现有测试继续通过。
Goal:
Add a like button on each post.

Constraints:
Keep the list's current design.
Use the existing user-preferences system.

Acceptance criteria:
- The button appears on each post.
- It changes state when tapped.
- The state persists after a reload.
- The existing tests keep passing.

验收标准是关键部分,因为它们之后会变成验证清单。

The acceptance criteria are the key part, because they later become the verification checklist.

为什么需要这份清单?因为到某个时刻模型会说:

And why is that checklist needed? Because at some point the model will say:

「好了,点赞按钮已经能用了。」

“Done. The like button works now.”

而这句话说的是模型「以为」发生了什么,不是实际发生了什么。

And that sentence tells you what the model believes happened, not what happened.

所以验证要去模型之外找证据。在我们的例子里:

That’s why verification looks for evidence outside the model. In our case:

  1. 打开应用。

    1. Open the application.
  2. 确认每个帖子上都出现按钮。

    1. Confirm the button appears on each post.
  3. 点它,确认状态发生变化。

    1. Tap it and check that it changes state.
  4. 刷新页面,确认仍是已点赞状态。

    1. Reload the page and check it’s still marked.
  5. 跑测试。

    1. Run the tests.

每一条都直接来自前面定义的验收标准。

Each item comes straight out of the acceptance criteria we defined earlier.

视任务不同,证据也可以是别的形式:一套测试、一张截图、一个 API 响应,或一次数据库查询。

Depending on the task, the evidence can take other forms: a test suite, a screenshot, an API response or a database query.

让它更可靠的一种做法是把「造」和「审」分开。一个 agent 实现改动,另一个拿到验收标准、检查结果、找问题。Anthropic 称之为 generator 和 evaluator:一个产出,另一个以独立视角评估。两个角色可以是同一个模型,变的是每次执行的上下文和目标。

One way to make it more reliable is separating who builds from who reviews. One agent implements the change and another receives the criteria, inspects the result and looks for problems. Anthropic calls them generator and evaluator: one produces, the other evaluates with an independent eye. It can be the same model in both roles; what changes is the context and the goal of each run.

到这里,agent 干活需要的东西齐了。接下来看 harness 给你的那部分。

With this, the agent has everything it needs to work. Now let’s go to what the harness gives you.

harness 给你的东西

What the harness gives you

  1. 权限与边界,让它不做不该做的事

    1. Permissions and limits, so it doesn’t do what it shouldn’t

到目前我们一直在给它加能力。现在这个 agent 能搜、能读、能改文件、能跑命令,还能独立把一件事扛很久。

So far we’ve been giving it capabilities. By now the agent can search, read, edit files, run commands and sustain a task for a long while, on its own.

而这恰恰就是问题。能做这些事的 agent,也能删掉一个不该删的文件、装一个把别的东西搞坏的东西,或者把命令跑到错误的数据库上。

And that very thing is the problem. An agent that can do all that can also delete a file it shouldn’t, install something that breaks something else, or run a command against the wrong database.

前面那个 sandbox 限制的是「破坏能走多远」。权限是另一回事:它定义模型能请求什么、以及做之前必须先问你什么。

The sandbox we saw earlier limits how far the damage goes. Permissions are something else: they define what the model may ask for, and what it has to check with you before doing.

这套东西叫权限系统,实际定义三件事:

That’s called the permission system, and in practice it defines three things:

  • 有哪些 tools 存在。如果没有「删文件」这个 tool,模型再怎么请求也删不了。

    • Which tools exist. If there is NO tool for deleting files, the model has no way to delete one, no matter how much it asks.
  • 哪些能自己执行。搜代码、读文件不需要谁批准。

    • Which ones run by themselves. Searching code or reading a file doesn’t need anyone’s approval.
  • 哪些会先问你。改文件、装依赖、对数据库执行东西:这时 harness 会停下,等你的确认。

    • Which ones ask you first. Editing a file, installing a dependency, running something against a database: there the harness stops and waits for your confirmation.

你会看到这类东西被叫 guardrails(护栏),不过这个词通常用得更宽:还包括对 agent 能说什么、能交付什么做过滤,而不只是它能执行什么。

You’ll see all this called guardrails, though the term is usually used more broadly: it also includes filters on what the agent may say or deliver, not only what it may execute.

这里最重要的一条:关键限制必须落在权限系统里,而不是写在指令里。「不要删重要的东西」这种指令,取决于模型每一刻都正确理解它。反过来,如果「删除」这个 tool 从来就没给过,就没有任何需要解释的东西:删不了,完事。

And here’s the idea that matters most: important limits have to live in the permission system, not in the instructions. An instruction like “don’t delete anything important” depends on the model interpreting it correctly at every moment. If instead the delete tool was never available, there’s nothing to interpret: you can’t delete, and that’s that.

还有另一半:万一还是出错了怎么办。

Then there’s the other half: what to do when something fails anyway.

出错不一定要中断执行。harness 可以让 agent 重试,并回给它一条更清楚的报错。

An error doesn’t always have to cut execution. The harness can let the agent retry and return a clearer message.

但也需要天花板:重试多少次、多少时间、多少花费。两个例子:

But it also needs ceilings: how many retries, how much time, how much cost. Two examples:

  • agent 把函数名写错了,测试挂了。它读报错、改那一行、再跑测试。这种重试正是你想要的。

    • The agent misspells a function name and the test fails. It reads the error, fixes that line and runs the tests again. Retrying is exactly what you want to happen.
  • agent 想修同一个测试,修了五次还是失败。它已经不是在修东西了。harness 中断执行,把每一轮试了什么给你看,决定权交回你手里。系统停下来把控制权还给你,这叫 human in the loop。

    • The agent tries to fix the same test five times and it fails all five. It’s no longer fixing anything. The harness cuts execution, shows you what it tried on each turn, and leaves the decision to you. When the system stops and hands control back to you, that’s called human in the loop.

现在 agent 出错不会弄坏东西了。还差「能搞懂它为什么出错」。

Now the agent can fail without breaking anything. What’s missing is being able to understand why it failed.

  1. 可观测性,让你看到发生了什么

    1. Observability, to see what happened

任务出问题时,agent 的最终回答说明不了什么。要搞懂问题,得把执行过程重建出来:

When a task goes wrong, the agent’s final answer says very little. To understand the problem you have to reconstruct the run:

  • 模型收到了什么上下文;

    • what context the model received;
  • 它选了哪个 tool;

    • which tool it chose;
  • 用什么参数调的;

    • with what parameters it called it;
  • 得到了什么结果;

    • what result it got;
  • 在哪一步改变了方向。

    • at which step it changed direction.

这些 trace 会告诉你真正的故障在哪:也许模型从没拿到某个关键文件;也许某个 tool 的描述写得不清楚;也许最有用的那条报错被挤出了上下文。

Those traces show you where the real fault is. Maybe the model never received a key file. Maybe a tool’s description was confusing. Maybe the most useful error stayed outside the context.

没有可观测性,一切都像是「模型不行」。有了它,你能看到该修系统的哪一块。

Without observability, everything looks like “the model failed.” With observability, you see which part of the system needs fixing.

现在你知道该改什么了。还差「知道改进了没有」。

Now you know what to improve. What’s missing is knowing whether the improvement worked.

  1. Evals,衡量它有没有变好

    1. Evals, to measure whether it improved

改完 harness 的一块之后,你得知道系统是变好了,还是修好一个又弄坏一个。

After changing a piece of the harness you need to know whether the system got better, or whether you fixed one thing and broke another.

Evals 就是这个:跑一组固定的任务,用既定标准衡量结果。这样你就能比较两版 harness 并发现回归。

That’s what evals are: running a stable set of tasks and measuring the result against defined criteria. That way you can compare two versions of the harness and catch regressions.

举个例子:

你改了 harness 组装上下文的方式:现在除了模型要的那个文件,还把邻近的文件一起发过去。

An example:

You change how the harness assembles context: now, in addition to the file the model asked for, it also sends the ones around it.

你用一个人为复杂的任务测试——需要同时改好几个文件的那种——结果比以前好很多。看起来是个明显的改进。

You test it with a complicated task, one that requires touching several files at once, and it comes out much better than before. It looks like a clear improvement.

但在简单任务上它变差了。现在模型会收到不需要的文件,有时还改错了文件。

But on simple tasks it got worse. Now the model receives files it didn’t need and sometimes ends up editing the wrong one.

光测一个任务看不出来。要改动前后跑同样那二十个任务、再比对结果,才看得出来。

You don’t see that by testing one task. You see it when you run the same twenty tasks before and after the change, and compare the results.

合在一起

All together

嗯……信息量是不是很大?是。

好消息是你不需要把这些全背下来,你只需要开始认出这些模式。

回到开头,这次用完整的 harness。你提的需求和第一次一模一样:给帖子加一个点赞按钮。

Well… is it a lot of information? Yes.

The good news is you don’t need to memorize all of this. You just need to start recognizing these patterns.

Let’s go back to the beginning, now with the complete harness. You ask it exactly the same thing as the first time: add a like button to the posts.

发生的是:

Here’s what happens:

  1. harness 把你的需求变成带验收标准的任务:按钮出现在每个帖子上、点击后状态变化、刷新后仍在、测试继续通过。

    1. The harness turns your request into a task with acceptance criteria: the button appears on each post, changes state when tapped, survives a reload, and the tests keep passing.
  2. 它用任务、项目地图和可用 tools 组装第一次调用。

    1. It assembles the first call with the task, the project map and the available tools.
  3. 模型请求搜索帖子在哪里渲染。harness 在 sandbox 里跑这个搜索,返回那三个文件。

    1. The model asks to search where the posts are rendered. The harness runs that search inside the sandbox and returns the three files.
  4. 它把这个结果存进状态,再调一次模型——这次带的信息比上次多。

    1. It saves that result in the state and calls the model again, now with more information than before.
  5. 模型请求编辑 Post.tsx。这个动作需要确认,于是 harness 停下问你。

    1. The model asks to edit Post.tsx. That action needs confirmation, so the harness stops and asks you.
  6. 你同意。harness 应用改动、跑测试,有一个失败了。

    1. You accept. The harness applies the change, runs the tests, and one fails.
  7. 模型读报错、修正、重试。这次全过了。

    1. The model reads the error, fixes it and retries. This time all of them pass.
  8. harness 按验收标准验证:打开应用、点按钮、刷新页面、确认仍是已点赞。

    1. The harness verifies against the criteria: it opens the application, taps the button, reloads the page, confirms it’s still marked.
  9. 到这时它才判定任务完成。而且整个过程都有记录,方便回头查。

    1. Only then does it consider the task done. And everything that happened along the way is recorded, in case you need to review it.

我们加的每一步都有它存在的理由——少了它就会有东西坏掉:模型动不了任何东西、不知道该看哪里、忘了自己做过什么、弄坏了不该弄的、没验证就说「好了」、或者错了却不留任何线索。

Every step we added exists because, without it, something failed: the model couldn’t touch anything, didn’t know where to look, forgot what it had done, broke something it shouldn’t, said “done” without checking, or failed leaving no trace of why.

而模型还是开头那个模型。变的只是我们在它周围搭起来的东西。

And the model is the same one from the start. The only thing that changed is what we built around it.

之后才出现的那些零件

The pieces that show up later

这个 harness 已经能解决一个完整任务了。任务变大之后,更先进的系统会再加上一些组织知识与工作的方式。

That harness already solves a complete task. When tasks grow, more advanced systems add other ways of organizing knowledge and work.

Skills。它把某一类任务的指令、标准、资源打包。一个前端 skill 可以告诉 agent 怎么检查设计、遵循哪些约定、做完要展示哪些截图。harness 按需加载它,而不是一直放在上下文里——还是前面那个 progressive disclosure,只不过对象从代码变成了指令。我另外写过一篇文章讲这个,在这里。

Skills. They package instructions, criteria and resources for a type of task. A frontend skill can tell the agent how to review the design, which conventions to follow and which screenshots to show when it finishes. The harness loads it when needed, instead of always having it in context: the same progressive disclosure as before, applied to instructions instead of code. I wrote a separate article about this, here.

MCP。它把 agent 发现和使用外部工具/数据源的方式标准化。通过一个通用接口,可以把它接到 GitHub、数据库、内部文档或工单系统上。用 harness 的话说,它扩大了「能从哪拿上下文」和「能执行哪些动作」。

MCP. It standardizes how an agent discovers and uses external tools or sources. It can connect it to GitHub, a database, internal documentation or a ticketing system through a common interface. In harness terms, it widens where it can get context from and which actions it can execute.

Subagents(子代理)。一个大任务可以拆到多个上下文和目标不同的执行里去:一个调研仓库、一个实现、一个验证。好处不来自「多加了几个模型」,而来自拆分本身减少了上下文、分开了职责、或者让复审能独立进行。而且一旦这样拆,你就可以给每个角色用不同的模型——简单的用便宜的、难的用贵的:这就是 model routing。

Subagents. A big task can be split across runs with different contexts and goals: one investigates the repository, another implements, another verifies. The advantage doesn’t come from adding models; it comes when the split reduces context, separates responsibilities or allows independent review. And once you split that way, you can use a different model in each role — a cheap one for the simple part and an expensive one for the hard part: that’s model routing.

长期记忆。状态维持的是单个任务的线索;长期记忆则跨任务复用信息:架构决策、团队偏好、反复出现的错误。由 harness 决定存什么、什么时候取回、以及怎么避免旧信息污染新的执行。

Long-term memory. State keeps the thread of one task. Long-term memory reuses information across tasks: architecture decisions, team preferences, recurring mistakes. The harness decides what to store, when to retrieve it, and how to keep old information from contaminating a new run.

注意这些零件没有一个是新机制,都是先前那些的延伸:skills 是更有条理地管理上下文,MCP 是加 tools 的标准方式,subagents 是多个被协调起来的 loop,长期记忆是比任务活得更久的状态。

Notice that none of these pieces is a new mechanism. They’re the same ones from before, extended: skills are a tidier way of managing context, MCP is a standard way of adding tools, subagents are several coordinated loops, and long-term memory is state that outlives the task.

底层那个模式——模型提请求、harness 去执行——始终没变。

The underlying pattern — the model asks, the harness executes — is still the same.

那么,什么是 harness engineering?

So what is harness engineering?

这两个词值得拆开看。

It’s worth separating the two words.

Harness 在英语里就是「马具、挽具」:一套套在某个东西身上、既借用它的力量又不让它失控的皮带。由此引申出动词 to harness——把已经存在的东西导向对你有用的方向。

Harness, in English, is the harness: the set of straps you put on something to use its strength without letting it get out of hand. From there comes the verb, to harness: to take something that already exists and direct it where it serves you.

在软件里这个词还有自己的历史。几十年来,人们把「围绕被测部件的代码」叫做 test harness:它执行被测对象、喂输入、看返回、检查对不对。

In software the term also has its own history. For decades, test harness has been the name for the code surrounding a piece you want to test: it runs it, feeds it inputs, looks at what it returns and checks whether it’s right.

而这也正是我们全文一直在搭的东西:一个围绕模型的系统,喂它输入、执行它的请求、观察返回、并检查工作结果对不对。

Which is exactly what we’ve been building throughout this article. A system that surrounds the model, feeds it inputs, executes what it asks for, observes what comes back and checks whether the work turned out right.

Engineering 是另一半,也是最常被跳过的那一半。搭一次不算完:得测量它、找到它在哪失效、改掉、再测。

Engineering is the other half, and it’s the one usually skipped. Building it once isn’t enough: you have to measure it, find where it fails, change it and measure again.

把两者合起来:

Putting the two together:

Harness engineering 是设计、衡量并改进「让模型能完成真实任务的那套系统」的工作。

Harness engineering is the work of designing, measuring and improving the system that allows a model to complete real tasks.

有意思的是,harness 依赖装在里面的那个模型。今天必须的某条规则,等模型变强之后可能就没用了;为某个模型设计的 tool,换一个模型可能就难用。每出一代新模型,都得重新审视:哪些还有用、哪些是多余的、失效点又变到了哪里。

The interesting part is that the harness depends on the model inside it. A rule that’s necessary today may stop contributing when the model improves. A tool designed for one model can be awkward for another. Every new generation forces you to review what helps, what’s surplus, and where different failures show up.

还有一点:模型是和 harness 一起训练的。Claude Code 和 Codex 是在带着自家 harness 的情况下做后训练的,所以模型会习惯那套 harness 的具体形态。之后你改了某个 tool 的逻辑,性能可能反而下降——哪怕新 tool 同样合理。

And there’s more: models are trained alongside a harness. Claude Code and Codex post-train their models with the harness in place, so the model gets used to that harness’s concrete shapes. If you later change a tool’s logic, performance can drop, even if the new tool is just as reasonable.

但这不代表「原厂 harness」总是最好。LangChain 测过:把 Opus 4.6 放在 Claude Code 里,与同一个模型放在别的 harness 里相比,在 Claude Code 里的得分明显更低。

But that doesn’t mean the native harness is always the best. LangChain measured Opus 4.6 inside Claude Code against the same model in other harnesses, and in Claude Code it scored considerably lower.

所以 harness engineering 不是「给模型套一层壳」就完了,它是迭代的活:

That’s why harness engineering isn’t building a layer around the model once. It’s iterative work:

跑任务
→ 看 trace 和结果
→ 找到反复出现的失效
→ 调整 harness
→ 再跑一遍 evals
run tasks
→ review traces and results
→ find a repeating failure
→ adjust the harness
→ run the evals again

模型提供能力,harness 创造「把这份能力用好」的条件。

The model brings the capability. The harness creates the conditions to use it well.

当这两部分协同起来,你才得到一个真的可以托付工作的 agent。

And when those two pieces work together, you get an agent you can genuinely delegate work to.

结尾

To close

下次你打开 Claude Code 或 Codex 提要求时,希望你看到的东西不一样了。

Next time you open Claude Code or Codex and ask it for something, hopefully you’ll see something else.

当界面上出现一行「正在你的仓库里搜索」,你会知道:是模型请求了一个 tool,harness 正在执行它。

当它只打开三个文件而不是整个项目,你会知道是有人决定了什么进上下文。当它回到十步之前做过的事,你会知道那不是模型记得——是 harness 在告诉它。

当它在动文件之前停下来问你要许可,你会明白那是权限系统。当它跑测试并修掉失败项时,你能在脑子里跟完整个 loop。

When a line shows up saying it’s searching your repository, you’ll know the model asked for a tool and the harness is executing it.

When it opens three files and not the whole project, you’ll know someone decided what goes into the context. When it comes back to something it did ten steps ago, you’ll know the model doesn’t remember that: the harness is telling it.

When it stops to ask your permission before touching a file, you’ll understand that’s the permission system. And when it runs the tests and fixes what failed, you’ll be able to follow the whole loop in your head.

那些感觉「很顺」的东西,其实都是零件拼出来的——现在你认识它们了,你能看懂里面是怎么回事。

All that stuff that feels fluid is made of pieces, and now you know them. You can understand what’s inside.

希望你喜欢这篇文章,也希望它对你继续学习有帮助。

I hope you enjoyed the article and that it helps you keep learning.

抱一个。

A hug.

santi (:

santi (: