类比一下来记忆,整篇文章所讲的知识的体系:

Harness是操作系统——管所有资源的顶层容器;

LLM是CPU——吃进指令吐出结果;

Agent Loop 是内核主调度循环——不停地取任务、调度、等I/O返回、再取下一个;

Two-Stage ReAct是操作系统的模拟执行(dry-run)模式——先试运行看计划,确认了再真正执行;

四个工具是文件系统的几种基本操作——read、write、edit、bash,对应rwx权限模型;

AGENTS.md/Skills/PlanMode是三级存储体系——BIOS、硬盘、内存+磁盘持久化。


一、Agent Loop:内核主调度循环

所有Agent的本质就是一个while(!done)

while not terminated:
    1. 组装上下文(system prompt+历史+工具声明+本次观测)
    2. 把上下文丢给LLM
    3. 解析LLM返回:
       3.1 文本段 → 追加进上下文历史
       3.2 有tool_calls → 逐个执行,结果写回历史,continue
       3.3 无tool_calls → 终止循环,返回文本

就像操作系统内核的主调度循环:

从就绪队列取进程 → 分配 CPU 时间片 → 等 I/O 中断返回 → 再调度下一个。

Agent Loop是:

不停地组装上下文 → 丢给 LLM → 等返回 → 执行工具(I/O)→ 写回历史 → 再循环。

是整个系统的心脏。

跑稳这个循环要想清楚三件事:

  1. 结束条件:无tool_call、命中max_turns、用户取消、校验器判完成。没有明确的终止条件,loop会一直转,token烧到破产。
  2. 验证方法:别信模型自己说做完,而是通过跑测试、diff检查、断言脚本。
  3. 持久化状态:上下文历史、PLAN.md/TODO.md、工具调用日志。上下文压缩会丢吞掉早期信息,要写在磁盘上。

适合上Agent Loop的场景

  • 高频(每周至少跑1次),一次性任务没必要别上Agent。
  • 几乎无需人工介入。
  • 失败可以重跑。

二、Two-Stage ReAct:先Dry-run,再真正执行

直接把工具声明丢给LLM,它会非常冲动地去调用工具,而不是先思考该怎么做。

Two-Stage ReAct把“想”和“做”拆成两次独立的LLM调用(让LLM克制一下欲望),物理上隔离:

Stage 1(无工具prompt):只给任务+上下文,不暴露任何工具
    → LLM输出计划/推理链/假设(dry-run)
Stage 2(带工具prompt):把Stage1的输出拼回去,再暴露工具声明
    → LLM按计划调read/bash/edit...

就像操作系统的dry-run模式——apt-get install -skubectl apply --dry-runmake -n

第一次调用是模拟执行,不碰任何系统状态,只输出打算做什么;

第二次才是真正执行,修改状态。

为什么即使模型已经具备“原生思考”能力,这一层依然有工程价值?

  • 介入点:Stage1和Stage2之间可以拦下来——改计划、人工审批、合规审计。原生思考是黑盒,拦不住。
  • 可观测性:Two-Stage让计划显式成文本,能diff、能回滚、能复盘。原生thinking块看得到但很难审计。
  • 多模型兼容:任何程序都能dry-run,不需要程序本身支持什么特殊能力。换一个便宜的小模型也能跑,不必依赖具备原生思考能力的大模型。

什么时候开启思考(不是每轮都开,贵):

  • 新任务目标刚下发时(先 dry-run 出计划)
  • 工具返回非预期结果(执行出错了,重新dry-run想想要不要换方案)
  • 涉及删除、推送、付费、写生产库等高危动作前(大操作先试运行)

三、工具:文件系统的几种基本操作

只给Harness四个基础工具:readwriteeditbash

这正好对应文件系统/权限模型里的几种基本操作:

工具

文件系统操作

作用

read

读文件(open+read)

无副作用,只看不动

write

写文件(覆盖,像>重定向)

整文件覆盖

edit

修改文件内容(像sed -i,精准patch)

只改该改的那几行

bash

执行程序(execute)

跑任何命令,一条顶十个专用工具

为什么有write还要edit:write是整文件覆盖,文件一大,token消耗极其巨大,既慢又贵。而且大模型生成长文本时极易截断,或者不小心引入新的语法错误。edit像sed -i,只动需要改的那几行,diff 可控、可评审、可回滚。

给太多工具等于chmod 777,乱开权限:不是能力更强,而是模型更容易冲动调用不该用的工具,出错面反而更大。而且容易限制聪明模型的主动性(聪明模型本来可以做更好的操作,但看到你已经提供一个现成的某种操作后,根据你给的描述以为它更合适,就用了,但模型并不知道你是怎么实现的,可能并不是模型真正想要的操作)。四个基础操作加上bash的万能执行能力,已经能覆盖绝大多数任务。

edit的唯一性校验(必做):模糊匹配若命中超过1处,工具绝对不能盲目替换——就像sed匹配到多行时如果不指定行号就全局替换,会把不该改的行一起改掉。必须抛出错误,要求大模型提供更多的上下行代码以精确定位。这是防止Agent改代码时"顺手改错另一个相似片段"的措施。

def apply_edit(text, old, new):
    cnt = text.count(old)
    if cnt == 0:
        raise ToolError("old_text not found")
    if cnt > 1:
        raise ToolError("ambiguous match (>1); provide more surrounding context")
    return text.replace(old, new, 1)

四、Harness执行效率的提升:只读并发,涉写串行

模型一轮推理可能吐出多个tool_call,如果harness都一个一个串行执行,效率就低了,但harness也不应该无脑串行——要有合适的调度策略:一般如果都是只读工具,就可以并行。

func dispatch(calls []ToolCall) {
    var readonly, writable []ToolCall
    for _, c := range calls {
        if isReadOnly(c) {
            readonly = append(readonly, c)
        } else {
            writable = append(writable, c)
        }
    }
    if len(writeable)==0:
        // 只读批:并发 goroutine
        fanOut(readonly)
    else:
        // 涉写批:严格顺序执行
        for _, c := range calls {
            exec(c)
        }
}

这个策略以极低的复杂度,在绝大多数场景下同时保证了性能与正确性。


五、三级记忆:AGENTS.md/Skills/PlanMode

1. AGENTS.md

解决的是“当前项目是什么样”的问题。可以类比于操作系统BIOS信息——启动即加载,告诉系统这台机器什么配置、什么目录结构、有什么禁区。Agent启动时读一次,就知道自己在哪个项目里干活。

注:claudecode目前还是固执地读CLAUDE.md,它的作用跟AGENTS.md是一样的。

2. Skills

解决的是“特定任务该怎么做”的问题。可以类比于硬盘上按需加载的二进制程序,命中对应场景才加载进上下文(CPU)。AGENTS.md告诉机器是什么配置,Skills告诉这个任务该调哪个“程序”。

3. PlanMode

  • PLAN.md:宏观路由表,战略方向。保证Agent在跨越几十轮对话的长任务中不跑偏。
  • TODO.md:调度队列,每完成一项划掉一项。

上下文压缩就像内存回收会丢数据——早期对话历史被compact掉就没了。所以得定期flush到磁盘:把进展写进PLAN.md/TODO.md,防止掉电(压缩)丢失。Agent醒来重新读磁盘,就知道该接着干啥。

ThinkingPhase(慢思考)是 CPU 的流水线级纠错:哪怕TODO.md里已经写了新任务,如果没有每一轮的慢思考约束,模型仍可能在选择具体实现路径时走捷径——跳过边界条件验证、不加权衡地选第一个能跑的方案。慢思考是每一步的即时纠偏,PlanMode是磁盘上的状态兜底,两者互补。


六、串成一句话

Harness(操作系统)
 ├── LLM(CPU算力核心)
 │    └── Agent Loop(内核主调度循环)
 │         └── Two-Stage ReAct(dry-run模拟执行 → 真正执行)
 ├── 工具集(文件系统基本操作:read/write/edit/bash)
 └── 三级记忆(BIOS/硬盘/内存+磁盘持久化)

跑得稳的Agent不是模型最猛的那个,是:Loop有终止条件、工具有边界约束、读写操作有并行串行优化、长任务有磁盘持久化兜底的那一个。


附:可直接参考的Loop伪代码

def agent_loop(task, max_turns=30):
    ctx = bootstrap(task)          #AGENTS.md+Skills发现+历史
    for turn in range(max_turns):
        if need_plan(ctx):         #PlanMode介入
            ctx = two_stage_plan(ctx)
        resp = llm(ctx)            #Stage2(带工具)
        ctx.append(resp.text)
        if not resp.tool_calls:
            return resp.text       #终止条件
        batch = group_by_readonly(resp.tool_calls)
        for r in concurrent_run(batch.readonly):
            ctx.append(r.result)
        for w in sequential_run(batch.writable):
            if w.name == "edit" and match_count(w) != 1:
                ctx.append(edit_ambiguity_error(w))
                break
            ctx.append(w.result)
    raise Timeout("max_turns reached")
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐