论文链接:Harness as a Language: A Minimalist Agent Framework With Maximal Expressivity 代码仓库:jaz-lang/jaz(框架)|jaz-lang/jaz-evals(评测) 发表时间:2026年9月 机构:MIT CSAIL(8 人)+ Independent Researchers(2 人) 领域标签:cs.AI / 智能体框架 / 程序合成

一、论文背景

要读懂这篇论文,先得搞清楚三个层层递进的概念:agent loop(智能体循环)、harness(运行时脚手架),以及为什么"极简 harness"会成为一个值得检验的科学问题。

Agent loop 是什么? 现代 LLM 智能体的基本形态是一个循环:模型观察环境 → 采取一个动作(调用工具)→ 看到结果 → 再决定下一步。2022 年的 ReAct 给了模型每一步自由选择动作的能力;2024 年的 CodeAct 把表达能力升级为"模型直接在 Python REPL 里写可执行代码",工具与子智能体都变成代码里可以引用的普通函数。表达能力每升一级,就解锁一批新能力——这是一个已被反复验证的趋势。

Harness 是什么? agent loop 之外、为特定能力专门加装的工程层。最典型的两类:一是记忆系统——上下文窗口装不下几千轮交互,于是有了 MemGPT(后更名为 Letta)这类借鉴操作系统"虚拟内存"思想、在多层存储间换页的方案;二是自改进系统——让智能体从任务反馈中沉淀经验,比如 ACE 用"生成器-反思器-策展人"三角色把经验蒸馏进不断演化的 playbook。可以粗略理解为:agent loop 是发动机,harness 是针对特定路况外加的变速箱与悬挂。

问题出在哪? 这些专门 harness 越垒越高,但一个反例一直悬而未决:2025 年底的 RLM(Recursive Language Models)证明,CodeAct 循环加上递归子智能体、不给任何外部工具,就能在长上下文任务上打败长上下文模型本身。也就是说,某些"必须靠专门系统"的能力,也许只是 loop 本身的表达能力没被榨干。于是论文提出核心问题:一个只比 agent loop 多一点点的极简 harness,究竟能不能涌现出记忆与自改进这些 traditionally 需要专门系统的能力? 这是对"能力来自专门工程"这一默认假设的直接挑战。

二、论文定位和关联工作

这篇论文不是凭空出现的,它站在一条清晰的谱系上,同时用两大类专门系统作为对照面。

谱系一:agent loop 表达能力的演进(本文是这条线的新终点)

工作核心思想与本文的关键区别
ReAct (2022)推理与行动交替,每步自由选动作动作空间受限,无法组合工具
CodeAct (ICML 2024)用可执行代码统一动作空间用户提示与 REPL 历史只是消息列表,不是代码变量
RLM (2025, arXiv:2512.24601)递归子智能体 + 输入作为 REPL 变量,处理超长上下文只把"输入"变成变量;本文进一步把提示与交互历史也变成变量,并推向长程与自改进
JAZ invoke(本文)一切可见之物皆为代码环境变量两条定义性质统一前述所有循环

RLM 是本文最直接的前驱——一作 Alex Zhang、导师 Omar Khattab 均为 RLM 作者,RLM 已证明"把输入当变量"威力巨大,JAZ 把这个思想推到极致:连 REPL 历史本身 __history__ 也是变量。

谱系二:专门 harness 阵营(本文的对照面)

  • 记忆系统线:MemGPT/Letta (arXiv:2310.08560) 把上下文当"内存"、外部存储当"磁盘",通过 conversation_search 等预定义检索工具访问历史;compaction(摘要压缩)则是工业界主流(Claude Code 等在上下文约 70% 时触发)。本文证明这两类都是 __history__ 变量的特例。
  • 自改进线:ACE (arXiv:2510.04618) 用固定三角色工作流优化提示词;GEPA、Voyager 技能库、Meta-harness 等各有优化对象。本文让顶层 invoke 直接充当 meta-agent,优化"传给子 invoke 的一切输入"。

定位结论:JAZ 不与任何专门系统比拼功能丰富度,而是问一个更根本的问题——当你给模型一个图灵完备的执行环境,并把它看到的一切都变成可编程对象时,多少"专门能力"会自然涌现?答案是:至少记忆与自改进这两大类。

三、问题定义

论文的抽象方式非常"程序合成"(这毫不意外,二导师 Armando Solar-Lezama 正是程序合成权威):不把 harness 当成一组功能模块,而是把它当成编程语言里的一个原语。

具体来说,给定任意一个图灵完备的语言(论文用 lambda 演算给出形式化定义),给它加一个新原语:

invoke(x1 := e1, ..., xk := ek)

它语法上就是一个函数调用,语义上是:把所有输入序列化成字符串喂给 LLM,LLM 生成的代码就是这个函数的、仅本次调用有效的函数体,随后在给定输入上执行。普通 LLM 原语是 str -> str,invoke 推广为"基础语言中的任意对象 -> 任意对象"。

这个定义精妙在哪? 两条性质不是设计出来的,而是定义的直接推论:

  1. 递归 invoke(子智能体)是默认的——模型输出的语言就是增强后的语言,天然包含 invoke,写代码时随手就能调子智能体;
  2. 模型看到的一切都是代码环境里的变量——所有输入(不区分提示/工具/数据)以及 REPL 历史本身。

形式化上,闭环 agent loop 等价于 invoke 的尾递归形式;实际实现中由 harness 自动做尾调用优化,得到 REPL 形态的"命令式 invoke"。加一点:由于每次调用的函数体都是新生成的,不存在"复用",因此动态作用域(而非传统的静态作用域)在这里反而是正确的选择。

给定这个定义,论文检验的假设可以形式化为:约束:不加任何手工工具、不加外部系统(无文件系统、无记忆模块)、提示与任务无关(防止过拟合)。求:仅靠 invoke 循环 + 提示,能否在长程记忆与持续自改进两类工作流上达到或超过专门 harness。

四、问题解法

JAZ 框架 = invoke 原语 + 三个使能系统。整个解法可以概括为"一个原语管表达,三个系统管工程"。

4.1 invoke 原语:一切能力的第一因

从外界看,invoke(task="分析数据画图", df=df, web_search=web_search) 就是一次函数调用;内部发生的事是:LLM 拿到所有输入的紧凑字符串表示,写出函数体——这段代码可以对 df 做任意操作、调用 web_search,也可以再 invoke 递归派生子智能体(比如为每种图型派一个),并把上一轮 REPL 输出 __history__[0].repl_output 作为提示传下去。子智能体不是被"设计"出来的功能,而是语言自带的能力。

4.2 tail-recursive delegation:统一的上下文管理模式

这是长程任务的核心机制。上下文快满时(由 ContextWindowWarning hook 在 70% 阈值提醒),当前智能体执行:

return invoke(
    instructions=instructions,        # 按引用传递,无损
    guidance=guidance,
    prev_history=globals().get("prev_history", []) + __history__,  # 完整历史接力
    prev_progress_summary="So far, ...",
    next_steps="Your next step is to ...",
)

关键在于按引用传递 vs 手工复制:instructions 是变量,传递零损耗;而 CodeAct 系只能让模型把提示硬编码成字符串抄进子智能体,几十层委托后必然有损。

论文特别指出,这个模式统一了现有所有上下文管理为特例:compaction ≈ 只传 prev_progress_summary;过滤式管理(如 Chroma Context-1)≈ 传过滤后的 __history__;而完整传递则是无损上限。这就像发现了"各种变速箱其实都是同一个传动系统的特殊档位"。

4.3 动态作用域 scope:工具的继承机制

with scope(web_search=web_search): 让顶层智能体和所有递归子智能体自动拿到这个工具,不必层层显式传参。理由在 4.1 已述:invoke 无静态实现、无复用,动态作用域才是语义正确的。

4.4 Hooks:可组合的监控与约束层

hooks 在生命周期事件(Invoke/LLMQuery/REPLExec 的 Enter/Send/Complete/Exit)上发出可组合的静态效应,采用 blackboard 模式通信。内置 hooks 覆盖四类能力:

类别内置 hooks作用
可观测性PrintLogger、TrajectoryRecorder、LangfuseTracing 等记录、回放轨迹
资源控制BudgetPool、RecursionLimit、ContextWindowWarning 等预算、递归深度、上下文预警
校验ReturnType、ValidateReturn、ValidateREPLCode返回类型/代码校验
可恢复性TrajectoryReplay断点续跑

hooks 同样分局部(位置参数传入,仅作用于本次 invoke)与作用域(上下文管理器,作用于整棵递归树),如 with BudgetPool(max_cost=5): 让 $5 预算在所有子 invoke 间共享。

4.5 实验设计的关键工程:受控消融

为公平对比,团队用 hook 移除 __history__ 与用户提示变量、并做最小提示适配,在 JAZ 内复刻出 CodeAct 与 CodeAct+subagents——因为既有实现(如 smolagents 的系统提示缺陷"这位团队成员是真实人类")会引入混淆变量。评测协议还严格切分"方法提供 guidance(任务无关)“与"环境提供 instructions(方法无关)",防止把任务知识偷运进提示。

五、评估指标与实验证据

论文用两个基准分别检验两个核心主张,实验设计针对性极强。

5.1 StuLife:长程记忆检验

基准特性:模拟大学生一学期的 1284 个有序任务,939 个计分任务中 207 个属于"far recall"子集——需要回忆 50+ 个任务之前 delivered 的信息。典型 episode 需 7000–8000 次环境交互、3000–5000 次 LLM 调用,历史会超出上下文窗口多倍。指标:Pass rate(满分任务占比)、Score(部分得分)、Cost(美元/次运行,3 次独立运行取均值)。

方法far-recall Pass (%)far-recall Score (%)全集 Pass (%)成本 ($)prompt-only
CodeAct_JAZ(逐任务,无记忆基线)24.825.852.54.4✓
CodeAct+subagents(smolagents)20.622.030.29.4✓
CodeAct+subagents_JAZ(RLM 式)32.033.960.013.1✓
Letta Agent(专门记忆系统)61.867.070.942.1✗
JAZ invoke69.973.672.618.3✓

怎么读这张表:far recall 是唯一能区分"有记忆"与"无记忆"的子集——无记忆基线(24.8%)与有记忆方法间存在 30+ 点的断层。JAZ 比 Letta 高 8.1 个百分点,成本却只有其 43%($18.3 vs $42.1)。CodeAct+subagents 委托机制与 JAZ 相同,唯独缺"历史与提示是变量”,far recall 就从 69.9 掉到 32.0——这正是受控消融的力量:单一变量差异对应 38 个百分点。

案例深挖(任务 #1282):期末考试题考虚构协议,正确选项 D 对应的授课内容出现在 497 个任务之前。JAZ 此时已递归委托 69 次(深度 70),但每层都完整接力 prev_history,一轮代码搜索(精确子串匹配)即命中授课记录、答对。CodeAct+subagents 因提示只能硬编码复制,几十层委托后"这是虚构协议、需回忆授课内容"的关键指令漂移丢失,只能靠现实知识猜错;Letta 的 conversation_search(BM25+向量混合检索)返回的是题目本身或名字相似的其他协议——需要精确子串匹配时,预设检索接口无能为力。

5.2 AppWorld:持续自改进检验

基准特性:模拟 9 个常用 App 的 API 接口,取 test-challenge 全部 417 个任务按固定种子打乱成序列,带完整测试反馈。指标:TGC(任务完成率)、SGC(子目标完成率)、成本拆分为 meta(元智能体)与 solver(解题智能体)。自改进方法跑 6 次(方差更大),其余 3 次。

方法TGC (%)SGC (%)总成本 ($)meta / solver ($)prompt-only
CodeAct 官方基线(逐任务)48.220.416.6— / 16.6✗
CodeAct_JAZ(逐任务)67.543.410.2— / 10.2✓
CodeAct+subagents_JAZ71.147.621.67.3 / 14.3✓
ACE(专门自改进 harness)69.947.130.617.1 / 13.5✗
JAZ invoke74.251.120.99.9 / 10.9✓

怎么读这张表:自改进的增量清晰可见——无跨任务学习的逐任务 CodeAct 是 67.5%,JAZ invoke 的 74.2% 中约 6.7 点来自持续学习。对比 ACE:JAZ 高 4.3 点 TGC,成本低 32%(注意 ACE 的 reflector/curator 极其昂贵,团队只让它在前 42 个任务上学习后冻结,否则成本估计超 $180,约为 JAZ 全量学习的 9 倍)。元智能体行为也体现了代码级自由度:批量派发任务、批间诊断失败轨迹、自适应调整批大小、让子智能体直接 return __history__ 以获取完整轨迹——这些都是 ACE 固定工作流做不到的。

5.3 指标如何支撑主张

两组实验构成互补的证据闭环:StuLife 证明"记忆不必是系统"(对比最强记忆 harness),AppWorld 证明"自改进不必是系统"(对比最强自改进 harness);而两次受控消融(CodeAct+subagents_JAZ 与 JAZ 的唯一差异就是两条定义性质)把胜负手精确锁定在 invoke 的表达力本身,而非提示工程或实现细节。

六、效果优势的根源解释

6.1 根源机制与证据链

因果链一:按引用传递 → 信息无损接力 → far recall 翻倍

  • CodeAct 系的根本局限:提示与历史不是变量,跨层传递只能靠模型手工复制内容 → 复制是有损压缩,几十层委托后关键指令漂移丢失(论文 #1282 案例中"虚构协议"警告彻底丢失)→ far recall 崩至 32.0%。【论文实验已支持】
  • JAZ 的结构改变:变量传递 = 引用语义,零损耗 → 69 次委托后历史仍完整 → 一轮代码搜索答对 497 任务前的信息。【论文实验已支持】
  • 外部佐证:context rot 研究(Chroma “Context Rot” 测得 18 个模型全部随上下文增长退化;Liu et al. “Lost in the Middle”)证明"把一切塞进上下文"本身有代价,无损接力 + 按需程序化检索恰好绕开这一点。【阅读者推断,机理自洽】

因果链二:图灵完备的程序化访问 vs 预设检索接口 → 检索表达力差距 → Letta 败北

  • Letta 的 conversation_search 是预设接口(BM25 + 向量混合检索),遇到"精确子串匹配虚构协议名"这种长尾需求即失效——检索回来的常是题目自身或相似协议。【论文实验已支持,#1282 案例】
  • JAZ 的 __history__ 是原始数据 + 完整 Python:str.find() 精确匹配、正则、逐条过滤皆可编程实现。预设接口是"菜单点菜",程序化访问是"进后厨"。【论文实验已支持】
  • 这是论文反复强调的一般规律:专门系统把假设编码进接口,环境一旦打破假设系统就变刚性;代码环境不预设假设,故不失效于长尾。【论文论证 + 阅读者认同】

因果链三:meta-agent 的自由度 → 逼近最优工作流 + 成本骤降 → 胜过 ACE

  • ACE 把"何时反思、反思什么、如何入库"焊死在固定三角色流水线里,每任务都要跑昂贵的 reflector+curator;JAZ 的 meta-agent 是自由代码:批量派发摊薄元调用成本、按需选读轨迹片段而非全量载入、能同时优化提示和技能(ACE 只优化提示)。【论文实验已支持:$20.9 vs $30.6,TGC +4.3】
  • 换言之,ACE 是"给定传动比序列的变速箱",JAZ 是"让司机自己换挡"。【类比,阅读者表述】

反事实推理:若去掉"历史是变量"(消融组 CodeAct+subagents_JAZ),far recall 从 69.9% → 32.0%,甚至低于逐任务无记忆基线在全集的表现——说明递归委托若无无损历史接力,反而会成为负担(信息层层衰减)。这反证了性质 2 的必要性。【论文实验已支持】

6.2 相关工作检索与对照

研究(可核验链接)相似尝试相关结论与本文的差异与适用边界对根源解释的影响
RLM(arXiv:2512.24601)输入作为 REPL 变量 + 递归子调用,处理超长输入递归 + 程序化访问在长上下文上中位数提升 130%(vs CodeAct+子调用)、26%(vs compaction)只处理"输入"这一变量;任务为单次长上下文,非跨任务长程/自改进支持:同团队前驱,验证了因果链一在长输入场景同样成立
MemGPT(arXiv:2310.08560)虚拟内存式分层记忆 + 预设检索工具自管理记忆显著优于固定上下文基线检索是预设接口;在需要精确匹配的场景(#1282)失效支持并限定:证明记忆必须超越原生窗口,同时其接口刚性正是 JAZ 胜出的机制切入点
ACE(arXiv:2510.04618, ICLR 2026)反思-策展工作流持续演化上下文结构化增量更新防止"上下文坍缩",AppWorld 上 +10.6%固定工作流、只优化提示;在本文受控对比中成本高、灵活度低支持并限定:自改进确实有效(高于逐任务基线),但"如何改进"的自由度是效率瓶颈——印证因果链三
CodeAct(arXiv:2402.01030, ICML 2024)代码统一动作空间代码动作比 JSON/文本动作成功率高至 20%动作空间升级,但提示与历史仍非变量支持:整个谱系的底层逻辑一致——表达能力每升一级,涌现能力跟着升级,JAZ 是该逻辑的下一站
Chroma Context Rot(2025) / Lost in the Middle(arXiv:2307.03172)18 个模型长上下文退化实测上下文增长 → 全体模型检索精度下降,非均匀退化非 agent 场景,纯模型能力测量补充:为"无损历史应放在可编程变量里按需检索、而非全量塞上下文"提供第一性原理依据

检索范围说明:以上以 recursive language models、agentic context engineering、MemGPT memory agent、CodeAct、context rot 等中英文关键词检索并核验 arXiv/官方页;未发现与本文同一受控设定(历史作为 REPL 变量的消融)的直接第三方复现,该缺口如实保留。

6.3 综合判断与未决问题

多研究共同支持的机制:代码级表达能力提升带来涌现能力(CodeAct → RLM → JAZ 三级证据链一致);专门接口在长尾场景的刚性(Letta 与 smolagents 的失败模式均为此类)。

仍属推测的部分:JAZ 优势多大程度依赖 GPT-5.4 系模型的代码能力?论文未测试弱模型——若模型写不出可靠的历史管理代码,性质 2 可能反成负担(RLM 论文"脚手架使用不当导致显著未开发性能"的发现暗示模型与脚手架需要协同进化)。自改进实验中 JAZ 的 rep 5 出现低于 CodeAct 基线的离群点(64.5%),说明该范式的方差与稳定性仍需更多研究。

适用边界:优势成立的前提是"长程依赖不可分解"(可分解任务上逐任务求解更便宜)与"模型代码能力够强";若任务只需常规语义检索(非精确匹配),Letta 类系统的工程成熟度仍有价值。

七、必要知识反推

假设让一个具备基础 ML 功底但对该领域一无所知的人重做这项工作,他最少需要哪些知识?

领域知识层

  • agent loop 的演进史(ReAct → CodeAct → 子智能体):否则无法定位"表达式天花板"在哪里,也就提不出极简性问题。
  • 两大对照系统的机理:MemGPT 的虚拟内存隐喻与检索接口、ACE 的三角色工作流——不知道专门系统强在哪、贵在哪,就无法设计出能赢的对照实验。

方法论知识层

  • 程序语言理论:lambda 演算、CBV 操作语义、尾递归与尾调用优化——这是把"harness"翻译成"语言原语"的形式化工具,也是论文标题 Harness as a Language 的底气。理解动态作用域为何在此语境下正确,同样需要 PL 直觉。
  • 受控消融方法论:用 hook 移除单一变量复刻基线、任务/方法提示正交切分——没有这套实验纪律,“JAZ 更强"的结论会被提示工程混淆击穿。

工程知识层

  • LLM 缓存前缀匹配与成本测量:必须懂得控制 cache key、限制并行度(n=3 的选择来自对 OpenAI 服务端缓存命中率的实测),成本对比才有意义。
  • REPL 沙箱与提示序列化:输入的 LLM 友好紧凑表示(大对象不 dump 原文、callable 显示签名+docstring)直接决定 invoke 的可用性。

知识融合的关键节点:最大的一次化学反应发生在"程序语言视角 × agent 工程”——把"LLM 每次生成函数体"视为语言原语的运行时语义,尾递归 invoke 经尾调用优化就"坍缩"成 REPL 循环,两条定义性质从推论变成必然。第二次融合是"受控消融 × hook 系统设计":hook 不仅是个功能,它本身就是实验仪器——同一框架内复刻基线、剥离变量,让 38 个百分点的差距可以归因于单一条性质。

八、论文中可以提取的通用性灵感

灵感一:把"给能力"换成"给表达能力",让能力成为必然的副产物。 论文证据:两条定义性质均为定义的推论,记忆与自改进是涌现而非设计(far recall +38 点、TGC +6.7 点均为受控消融差异)。 推广场景:工具产品设计(提供可编程接口而非功能清单);教育(教原理而非套路,让解法可推导);组织管理(给一线完整信息访问权而非预制报表,长尾问题自解)。

灵感二:接口的刚性在长尾处致命,原始数据的程序化访问是终极灵活性。 论文证据:Letta 的 conversation_search 在需要精确子串匹配的 #1282 上失效,而 __history__ + str.find() 一轮命中。 推广场景:数据库产品(SQL 全量表达力 vs 固定查询模板);数据分析(给分析师原始表 vs 只给 BI 看板);API 设计(暴露正交原语 vs 暴露场景化端点)。

灵感三:按引用传递优于手工复制——无损接力是多层协作的生命线。 论文证据:69 层递归委托后指令零漂移 vs CodeAct 系几十层后关键指令丢失。 推广场景:组织流程设计(交接文档引用源头系统而非层层转述);分布式系统(传指针/句柄 vs 序列化拷贝);法律文书(引用条款原文 vs 概括转述)。

灵感四:固定的"最优工作流"是隐性税,让执行者自定流程往往更便宜也更好。 论文证据:JAZ meta-agent 自由批处理 + 按需读轨迹,成本比固定工作流的 ACE 低 32%、TGC 反高 4.3 点。 推广场景:研发管理(默认流程 vs 授权团队自定节奏);模型推理策略(手工 pipeline vs 程序化编排);自动化运维(预制 runbook vs 可编程运行时)。

灵感五:统一视角的价值——把已有方法变成新框架的特例,比逐个击败它们更有解释力。 论文证据:compaction、过滤式上下文管理、完整记忆全部被收编为 tail-recursive delegation 传参策略的光谱。 推广场景:理论工作(新框架应包含旧结论为极限情形);产品迭代(新架构兼容旧用例为配置项);科学史(好的范式吸收而非推翻竞争范式)。

附录:术语速查

术语含义
invoke函数体由 LLM 在每次调用时现场生成的语言原语
sub-invoke递归 invoke 调用,即默认可用的子智能体
__history__REPL 历史的魔法变量,可编程检索
tail-recursive delegation上下文将满时委托子智能体并按引用接力完整历史的模式
far recallStuLife 中需回忆 50+ 任务前信息的 207 个任务子集
TGC / SGCAppWorld 任务完成率 / 子目标完成率
prompt-only仅用基准自带工具、提示任务无关的极简设定