铭鸿体育资讯网

把 Agent 搬进代码里:从 RLM 到 Harness as a Langu

把 Agent 搬进代码里:从 RLM 到 Harness as a Language
我在今年 RLM 出来之后,就一直在思考一个问题:如何设计一个 ever-running 的 Agent,也就是它不仅仅是长程,而是一直持续运行下去。这里我可能要说明一下,我说的“长程”不像 Openclaw 那种。虽然看起来你是在一个会话中、在一个 Channel中连续跟它聊天,但它其实会自动切分会话。我这里更像是一个永远不会终止的会话。但是,天然由于语言模型上下文的限制,这件事情其实特别困难。 所以,才会出现了那么多关于如何在长程任务中管理上下文的方法,例如各种工具输出卸载的方案,还有最近出现的各种压缩上下文的方法(比如 Sol-Pi,CliffCompaction)。但是我一直觉得其实还有另外一种思路:为什么不能把所有跟语言模型相关的 context 都放在代码环境中呢?不仅仅是历史、还有系统提示词、工具、环境(编码为状态)等等。 不过我一直有些问题一直没想明白,怎么递归,还有怎么解决 PTC 或者 CodeAct 这种思路的一些问题。比如如何让工具既能面向 LLM,也能面向代码。如何在代码中实现语义分支。最近看到 Jev,我倒是觉得似乎可以补上这一环了。
RLM 出来的时候,我就觉得这个范式就非常适合,解决了很多我之前的困惑。它不仅仅可以用来解决 OOLONG PAIR 那种需要检索海量上下文的推理场景,我们完全可以把 Agent 本身放进代码环境中。我当时的设想是编写一系列的原语或者工具来扩展这种架构,让 Agent 能够在代码环境看到自己的上下文、工具、动态的环境、递归调用自己等,但是一直没有时间去实践。
今天看到了这篇论文 ,有一种醍醐灌顶的感觉,比我当初的设想要优雅很多简洁很多。
论文的核心其实很简单,它把 Agent Harness 本身当成了一种语言,而核心原语只有一个 invoke。LLM 能看到的东西,包括 prompt、历史、工具、数据,全部都变成代码环境中的变量;而 invoke 又可以递归调用 invoke。这样一来,subagent、context management、memory 这些原来需要 Harness 单独实现的东西,都可以变成代码本身。有意思的是 invoke 并不是一个静态函数,而是每次都由 LLM 根据签名生成的,这一点是我之前完全没有想过的。
这个思路我觉得非常漂亮。因为一旦上下文也变成可以被代码操作的对象,长程 Agent 的问题就不一定非要靠“不断往 context 里塞东西”来解决了。它可以自己搜索、压缩、保存自己的历史,也可以把状态传给下一次递归调用。某种意义上,这和我之前想的“把 Agent 本身放进代码环境”已经非常接近了,只是它把这件事情抽象得更彻底。而且,每个 invoke 都是独一无二的,所以可以适应各种不同的任务范式。
题外话:如果我们要把所有东西都搬到代码中,我觉得现在最缺的是这个语义分支。我不认为基于正则的匹配或者搜索就足够面向所有通用的场景了。如果在 if 语义的条件上能使用基于模型的理解,那么就能扩大代码的语义表示空间。直接使用 LLM 推理的问题是太慢了,Jev 看起来刚好能补这个缺口。或者特意为 LLM 设计一个新的DSL?