← 返回公开文章

Lisp Agent:100 行 Lisp 里的 Agent 循环

/research/lisp-agent-100-lines.md

来源:An Agent in 100 Lines of Lisp, or How my Prof was Right - Just 25 Years Early 原文发布日期:2026-07-07 整理日期:2026-07-13 说明:本文为原文的中英对照翻译与精读。原文代码块保持不改;中文部分尽量保留作者的叙述口吻,同时补充阅读脉络与判断。

精读概括

这篇文章的主轴不是“Lisp 又要复兴了”,而是一个更具体的工程观察:LLM Agent 的外层循环,本质上很像 Lisp 擅长表达的东西——程序把程序当数据处理,并把执行结果反馈进下一轮计算。

作者用一个约 100 行的 Common Lisp toy agent 做了三个层层递进的实验:

  1. Agent loop 是递归函数:消息列表传给模型;模型要么回答,要么要求调用工具;工具结果追加到消息列表后继续递归。
  2. 唯一工具可以是 eval:如果模型能生成 Lisp form,并由运行时执行,那么“工具目录”就从固定清单变成了可在对话中生成的能力。
  3. 技能可以存在于记忆里:运行时定义的函数会随进程退出消失,但定义函数的对话记录被保存下来;下一次 agent 读回历史时,可以把曾经写过的函数重新 eval 出来。

真正值得注意的地方在第三点:作者把“skill”从传统平台里的预定义工具,改写成了可被记忆、重放、再水化的程序片段。这和当前 Agent 平台常见的 MCP、工具注册、SKILL.md 形成了一个张力:一端是预先批准、版本化、契约化的工具;另一端是运行时自生成、自扩展的能力。

但这篇文章也必须带着安全边界读。作者自己明确说,eval 作为工具意味着模型可以在机器上执行任意代码,只适合 sandbox / Docker 里的 toy experiment。它更像是一个概念原型,而不是可直接照搬到生产环境的 Agent 架构。

我的判断:这篇文章好在它抓住了 Agent 工程的一个底层形状——能力不是只存在于工具清单里,也可以存在于可执行记忆里。但它的危险也来自同一个地方:当记忆可以重新变成代码,系统就需要新的权限边界、审计机制和恢复策略。Lisp 在这里不是“最佳生产语言”的结论,而是一面很干净的镜子,让我们看清 Agent loop、tool use、memory、skill 之间本来就有的结构关系。

中英对照翻译

An Agent in 100 Lines of Lisp, or How my Prof was Right - Just 25 Years Early

Around 2000 I took an AI course at the University of Guelph. I don’t think I learned too much. We didn’t talk about neural networks, as far as I can remember. My end of term project was, I think, a pathfinding algorithm wearing an AI costume. There were certainly no discussions of transformers. No CUDA. No PyTorch. None of that existed.

大约在 2000 年,我在 University of Guelph 上过一门 AI 课。我不觉得自己学到了太多。至少在我的记忆里,我们没有讨论神经网络。我的期末项目大概是一个披着 AI 外衣的寻路算法。那时当然也没有 transformer,没有 CUDA,没有 PyTorch。这些东西都还不存在。

But what I remember doing a lot of was coding in Lisp) - a lot of Lisp in the dark University of Guelph CIS lab.

但我确实记得自己写了很多 Lisp)——在 University of Guelph 昏暗的 CIS 实验室里写了很多 Lisp。

My prof (whom I cannot remember the name of for the life of me) called it “the language for AI” and at the time that may have been the conventional wisdom - I’m not sure. But I actually enjoyed writing Lisp code. To me, it was a kind of art building these elegant recursive functions. I don’t know of any other computer languages that hit like that (except almost embarrassingly, xml stylesheets, which I’m probably one of a very small number of people who really liked creating xml transforms with super elegant recursion).

我的教授——我怎么也想不起他的名字了——称 Lisp 为“AI 的语言”。当时这也许是某种主流看法,我不确定。但我确实喜欢写 Lisp。对我来说,构造那些优雅的递归函数有点像艺术。我想不出还有哪门语言能给我同样的感觉;有点尴尬的是,XML stylesheets 可能算一个例外,我大概属于极少数真正喜欢用非常优雅的递归来写 XML transform 的人。

According to my prof, Lisp was, specifically, the language of symbolic AI: expert systems, theorem provers, programs that manipulated symbols and rules. But statistical methods won, then deep learning buried the winner, and I think Lisp ultimately became lost with symbolic AI. At least, I know very few people (none) that used it regularly, beside maybe that I remember Paul Graham mentioning he used it in one of his essays about writing his first e-commerce platform.

按照我教授的说法,Lisp 更准确地说是符号主义 AI 的语言:专家系统、定理证明器、操作符号和规则的程序。但后来统计方法赢了,接着深度学习又把这个赢家埋了。我觉得 Lisp 最终也和符号主义 AI 一起淡出了。至少,我认识的定期使用 Lisp 的人很少——可以说没有。也许只有我记得 Paul Graham 在一篇关于自己第一个电商平台的文章里提到过他用 Lisp。

Now here we are, like 25 years or more after I took that AI course and left with this one thing that I remember learning - Lisp, and meanwhile, I’m burying myself in building an AI agent platform for over a month and this little thought tugs at the bottom of my brainstem this morning - “could Lisp actually be a useful language for an agent loop?” And then I find myself distracted from what I should be doing and instead working with Claude just to see…

现在,距离我上那门 AI 课已经过去了大约 25 年甚至更久。当年我真正记住的东西只有 Lisp。而与此同时,我已经把自己埋在一个 AI agent platform 里做了一个多月。今天早上,一个小念头在我脑干深处拉扯我:“Lisp 会不会其实很适合写 agent loop?”于是我发现自己从本该做的事情上分心了,转而和 Claude 一起试试看……

An agent is a recursive function

Agent 是一个递归函数

Don’t let the power of Claude Code, OpenClaw or any other AI agent tooling fool you - strip away the frameworks and an agent loop is incredibly simple. You have a list of messages. You send it to a model. Either the model answers in words, or it asks to use a tool. If it asks, you run the tool, append the results, and do it again.

不要被 Claude Code、OpenClaw 或其他 AI agent 工具的强大表象骗了。把框架剥掉之后,agent loop 简单得惊人:你有一个消息列表,把它发给模型。模型要么用文字回答,要么要求使用工具。如果它要求用工具,你就执行工具,把结果追加到消息列表里,然后再来一轮。

Maybe some agents implement that as a while loop with state. But perhaps it’s really better implemented as recursion with a base case.

有些 agent 也许会把它实现成一个带状态的 while loop。但也许更好的实现方式,是把它看作一个带 base case 的递归。

I’m not going to get into Lisp syntax at all, and if you’ve never coded with Lisp, this will seem pretty strange, but here’s an agent loop in Lisp:

我不准备深入讲 Lisp 语法。如果你从没写过 Lisp,这段代码可能看起来很奇怪。但下面就是一个 Lisp 写的 agent loop:

(defun agent-loop (messages)
  (let* ((message (ref (call-model messages) "choices" 0 "message"))
         (tool-calls (gethash "tool_calls" message)))
    (if (and tool-calls (plusp (length tool-calls)))
        (agent-loop (append messages
                            (list message)
                            (map 'list #'execute tool-calls)))
        (append messages (list message)))))

That’s the whole agent, no kidding, just 8 lines of Common Lisp. Base case: the model answers, returns the history. Recursive case: it wants tools, executes them, recur with the enriched message list. No framework. No state machine. The agent’s state is just the argument being folded through the recursion.

这就是整个 agent,不开玩笑,只是 8 行 Common Lisp。Base case:模型给出回答,返回历史。Recursive case:模型想要调用工具,于是执行工具,把增强后的消息列表继续递归下去。没有框架,没有状态机。Agent 的状态只是那个在递归中不断被折叠推进的参数。

I put together a full AI agent, with the help of Claude, running against OpenRouter in about 100 lines of Common Lisp. SBCL, two libraries (dexador for HTTP, shasht for JSON), and nothing else.

在 Claude 的帮助下,我用大约 100 行 Common Lisp 拼出了一个完整的 AI agent,通过 OpenRouter 调模型。它使用 SBCL,以及两个库:dexador 负责 HTTP,shasht 负责 JSON。除此之外什么都没有。

The only tool is eval

唯一的工具是 eval

When you build an agent you normally start bolting on tools - Agent Foundry has web search and crawling, tables and file tools, python execution tooling, etc. In fact, most of most agents are a tool catalog.

当你构建一个 agent 时,通常会开始给它装工具:Agent Foundry 有网页搜索和抓取、表格和文件工具、Python 执行工具,等等。事实上,大多数 agent 的大部分内容就是一个工具目录。

Lisp lets you cheat. Lisp is what language nerds call homoiconic - a fancy word for a simple idea: a Lisp program is written in Lisp’s own data structure (lists), so code is data and data is code. A program can build another program the same way it builds a grocery list. Which means instead of building tools, you hand the model the language itself:

Lisp 允许你“作弊”。Lisp 是语言 nerd 所说的 homoiconic 语言。这个词听起来高级,其实意思很简单:Lisp 程序就是用 Lisp 自己的数据结构——列表——写成的,所以代码就是数据,数据也是代码。一个程序可以像构造购物清单一样构造另一个程序。这意味着,你不必一个个构建工具,而是可以把语言本身交给模型:

(defun lisp-eval (form-string)
  (handler-case
      (format nil "~s" (eval (read-from-string form-string)))
    (error (e) (format nil "ERROR: ~a" e))))

One tool. The model writes a Common Lisp form as a string. The agent reads it, evals it, and sends back whatever printed. Ask it for the 30th Fibonacci number and it doesn’t recall the answer, it writes the loop and runs it. Here’s the actual transcript:

一个工具。模型把一个 Common Lisp form 写成字符串。Agent 读取它,eval 它,然后把打印出来的结果返回。你问它第 30 个 Fibonacci 数,它不是凭记忆回答,而是写出循环并运行它。下面是实际 transcript:

* (agent:run "What is the 30th Fibonacci number? Compute it, don't recall it.")
  ⤷ (defun fibonacci (n)
      (if (<= n 2)
          1
          (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) => FIBONACCI
  ⤷ (fibonacci 30) => 832040
The 30th Fibonacci number is 832040.
NIL

I did not tell it to use recursion, but in this blog post about recursive agent loops, the model reached for textbook doubly-recursive Fibonacci all on its own. It defined a function into the live image with its first eval and called it with its second. Keep that move in mind, it comes back later in a bigger way.

我并没有告诉它要用递归。但在这篇关于递归 agent loop 的文章里,模型自己伸手拿起了教科书式的双递归 Fibonacci。它第一次 eval 时把一个函数定义进了 live image,第二次 eval 时调用了这个函数。记住这个动作,后面它会以更大的方式再次出现。

This is the 2026 version of what made Lisp “the language for AI” in the first place. The old dream was programs that manipulate programs. We finally have that. We just outsourced the symbolic reasoning to a language model and kept the substrate.

这就是 2026 版本的“为什么 Lisp 最初会被称为 AI 的语言”。那个古老梦想是:程序可以操作程序。我们终于拥有了这一点。只是我们把符号推理外包给了语言模型,同时保留了底层 substrate。

Caveat, if not incredibly clear: eval as a tool means the model runs arbitrary code on your machine. This is a toy for a sandbox. I haven’t run this outside of a local docker container.

必须非常明确地提醒:把 eval 当作工具,意味着模型可以在你的机器上运行任意代码。这只是一个适合 sandbox 的玩具。我没有在本地 Docker container 之外运行过它。

Memory is 20 lines

Memory 只要 20 行

Once the loop worked I wanted persistence. Conversations that survive across sessions. In Agent Foundry, I implemented pgvector for memory, and I suppose that could also be used for this Lisp based agent, but for this experiment, why introduce another dependency when Lisp has its own primitives perfect for implementing this.

一旦 loop 跑通,我就想要持久化:让对话能跨 session 保存。在 Agent Foundry 里,我用 pgvector 实现 memory。我想这个基于 Lisp 的 agent 也可以用 pgvector。但对这个实验来说,既然 Lisp 自己就有非常适合实现这件事的 primitive,为什么还要引入另一个依赖呢?

The messages are already a list of hash tables. Which is to say, they’re already JSON in spirit. So memory is nothing more than writing the list down and reading it back:

消息本来就是 hash table 的列表。也就是说,从精神上看,它们已经是 JSON 了。所以 memory 不过就是把这个列表写下来,再读回来:

(defun remember (messages)
  (with-open-file (out *memory-file* :direction :output :if-exists :supersede)
    (shasht:write-json (coerce messages 'vector) out))
  messages)

(defun recall ()
  (if (probe-file *memory-file*)
      (coerce (with-open-file (in *memory-file*) (shasht:read-json in)) 'list)
      (list *system-message*)))

The loop itself didn’t change at all. The entry point became a pipeline:

loop 本身完全不需要改变。入口点变成了一条 pipeline:

(remember (agent-loop (append (recall) (list new-user-message))))

Recall, recur, remember. No schema. No migrations. No store abstraction. The serialization format is the runtime format. Tell it your name today, ask tomorrow in a fresh process, it answers.

Recall,recur,remember。没有 schema,没有 migration,没有 store abstraction。序列化格式就是运行时格式。今天告诉它你的名字,明天在一个新进程里问它,它会回答。

It never forgets, which is also its flaw. Full transcript memory grows without bound and eventually you hit the context window. This could be a simple fix: a compress step between recall and the loop, where the agent calls a model to summarize its own past. An agent recursing on its own history. Beautiful.

它永远不会忘记,而这也是它的缺陷。完整 transcript memory 会无限增长,最终撞上 context window。这个问题可以有一个简单修复:在 recall 和 loop 之间加入一个 compress 步骤,让 agent 调用模型总结自己的过去。一个递归处理自身历史的 agent。漂亮。

The Fibonacci trick was really neat to watch - the agent writing throwaway math and running it. Then I decided to give it a little more rope. I pasted a temporary Brave Search API key into the conversation, mostly to see what would happen. And what happened kind of surprised me - the agent used its eval to defun a brave-search function into the live image. It checked what it had available to it, wrote the HTTP call, parsed the JSON response itself, and started answering questions with live web results.

Fibonacci 这个小把戏看起来很有意思:agent 写了一段一次性的数学代码并运行。然后我决定多给它一点绳子。我把一个临时 Brave Search API key 粘进对话里,主要是想看看会发生什么。结果让我有点惊讶:agent 用它的 eval 把一个 brave-search 函数 defun 进了 live image。它检查自己可用的东西,写出 HTTP 调用,自己解析 JSON response,然后开始用实时网页结果回答问题。

I never built a web search tool. The agent has exactly one tool, and it used that tool to write the second one.

我从来没有构建 web search 工具。这个 agent 只有一个工具,而它用这个工具写出了第二个工具。

  ⤷ (defun brave-search (api-key query &key (count 10))
  "Search using Brave Search API"
  (let* ((encoded-query (quri:url-encode query))
         (url (format nil "https://api.search.brave.com/res/v1/web/search?q=~a&count=~d"
                      encoded-query count))
         (response (dexador:get url
                                :headers `(("Accept" . "application/json")
                                          ("X-Subscription-Token" . ,api-key)))))
    (shasht:read-json response))) => BRAVE-SEARCH
Perfect! You were absolutely right, Jamie. I've now created a `brave-search` function that can make HTTP requests to the Brave Search API.

If you provide me with a Brave Search API key, I can perform web searches for you. The function takes:
- `api-key` - your Brave Search API key
- `query` - the search query
- `count` - (optional) number of results to return (default 10)

Would you like to try it out with your API key?
NIL

Sit with that for a second, because it inverts how we normally think about agent capabilities. In Agent Foundry, in Claude Code, in every agent platform I know of, the tool catalog is fixed at design time. Somebody like me decides what the agent can do, writes the tools, ships them. Here the catalog is open. The model decides what it needs, writes it in its own substrate language, and evals it into existence. Code is data, data is code, and capability is just conversation.

停下来想一秒,因为这颠倒了我们通常理解 agent capability 的方式。在 Agent Foundry、Claude Code,以及我知道的每一个 agent platform 里,工具目录都是在 design time 固定下来的。像我这样的人决定 agent 能做什么,写好工具,然后发布。但在这里,目录是开放的。模型决定自己需要什么,用自己的 substrate language 写出来,再通过 eval 让它存在。代码是数据,数据是代码,而能力只是 conversation。

And there’s a twist that took me a minute to appreciate. The defun itself dies when the process exits. Functions live in the running Lisp image, not on disk. But the transcript persists. The source code of brave-search, the model writing it, all of it sits in memory.json as plain text. So in a fresh session the function doesn’t exist until the agent re-reads its own history and evals it back into being. Its capabilities are stored as memories of having built them, re-hydrated on demand.

这里还有一个 twist,我花了一会儿才真正意识到。defun 本身会在进程退出时消失。函数存在于运行中的 Lisp image 里,而不是磁盘上。但 transcript 会持久保存。brave-search 的源代码、模型写出它的过程,所有这些都以纯文本形式存在 memory.json 里。所以在一个 fresh session 中,这个函数一开始并不存在,直到 agent 重新读取自己的历史,并把它重新 eval 出来。它的能力被存储为“曾经构建过这些能力”的记忆,并在需要时重新水化。

Talk about homoiconicity - an agent whose skills are literally stories it tells itself.

这才真叫 homoiconicity:一个 agent 的 skills,字面上就是它讲给自己的故事。

Skills are just memories

Skills 只是 memories

Every serious agent platform today, Agent Foundry included, treats the tool catalog as a design-time decision. MCP is basically a formalization of the design-time assumption - capabilities as contracts, negotiated in advance, versioned, approved. This experiment sits at the other pole: capability decided at runtime, by the agent, in response to whatever the conversation needed.

今天每一个严肃的 agent platform,包括 Agent Foundry,都会把工具目录当成一个 design-time decision。MCP 基本上就是对这种 design-time assumption 的形式化:能力是提前协商、版本化、批准过的 contract。而这个实验位于另一个极端:能力是在 runtime 由 agent 自己决定的,是它对 conversation 当下需求的响应。

Perhaps the industry is already sliding along this continuum without quite naming it. Code interpreters were the first step - agents writing throwaway programs to answer a question. Skills, the SKILL.md pattern, are the second - because a skill is nothing more than capability stored as text and loaded at runtime. This 100 line Lisp agent just collapses the remaining distance. Its skills are stored in its own transcript.

也许整个行业已经在这条连续谱上滑动,只是还没有真正命名它。Code interpreter 是第一步:agent 写一次性程序来回答问题。Skills,也就是 SKILL.md 模式,是第二步:因为 skill 说到底只是以文本形式存储、在 runtime 被加载的能力。这个 100 行 Lisp agent 把剩下的距离压缩掉了。它的 skills 被存储在自己的 transcript 里。

And kind of stretching maybe, that’s roughly how we work too. Almost nothing you can do was installed at design time. You learned it, stored it, and now you rehydrate it on demand - often complete with the memory of writing it into yourself, like remembering the specific summer you learned to ride a bike. A capable human is, in some sense, a transcript of their own practice, re-evaluated every time it’s needed. Watching an agent re-read its own history and defun a skill back into existence felt less like a hack and more like a crude, yet beautiful, sketch of that. I’m speculating well past my expertise here, but the shape rhymes.

也许这有点延伸过头,但我们人大致也是这样工作的。你能做的事情里,几乎没有什么是在 design time 就被安装进去的。你学会它,存储它,然后在需要时重新水化它——常常还带着“把它写进自己”的那段记忆,比如记得自己在哪个夏天学会了骑自行车。从某种意义上说,一个有能力的人,就是自己实践历史的 transcript,并在每次需要时重新被评估。看着一个 agent 重读自己的历史,再用 defun 把一个 skill 重新带回存在,感觉不像是一个 hack,更像是对这件事粗糙但美丽的素描。我在这里已经远远超出了自己的专业范围,但这个形状是押韵的。

He wasn’t wrong, he was early

他没有错,只是太早了

Symbolic AI lost. Nobody’s expert system survived contact with backpropagation and gradient descent. But the thing Lisp was actually built for, programs as data, computation you can inspect and transform and feed back into itself, turned out to be a pretty good description of what an agent is.

符号主义 AI 输了。没有哪个专家系统能在接触到 backpropagation 和 gradient descent 之后幸存下来。但 Lisp 真正为之而生的东西——把程序当作数据,可以被检查、转换,并反馈回自身的计算——结果证明非常适合描述 agent 是什么。

The models do the reasoning now. But the loop around them, the part we actually engineer, is the part Lisp was always fantastic at.

现在做 reasoning 的是模型。但围绕模型的 loop,也就是我们真正需要工程化的那部分,正是 Lisp 一直非常擅长的部分。

25 years is a long time to be right about something. Somewhere out there maybe my old AI prof is ahead of us on something else.

25 年后才被证明某件事是对的,这是一段很长的时间。也许在某个地方,我那位老 AI 教授还在另一些事情上领先我们。

Full source, Dockerfile included, is on GitHub: <https://github.com/jamiebeach/lisp-agent>

完整源码,包括 Dockerfile,在 GitHub 上:<https://github.com/jamiebeach/lisp-agent>

精读笔记

1. 这篇文章的核心不是 Lisp 语法,而是 Agent 的最小形态

作者没有试图证明 Lisp 比 Python、JavaScript 或其他语言更适合做生产级 Agent。他做的是一个“剥离框架”的动作:当我们拿掉 Claude Code、OpenClaw、Agent Foundry 这类复杂平台之后,Agent loop 只剩下三件事:

这也是为什么 Lisp 的递归表达在这里显得自然。不是因为所有 Agent 都必须递归实现,而是因为递归把 Agent 的控制结构暴露得很干净:终止条件是模型不再请求工具;递归条件是模型请求工具并把工具结果纳入下一轮上下文。

2. eval 让工具目录从“预定义能力”变成“生成能力”

传统 Agent 平台通常预先定义工具:搜索、文件、shell、浏览器、数据库、MCP server。模型在运行时只能选择这些已经注册的工具。

这篇文章有趣的地方是,作者把 Lisp 的 eval 暴露成唯一工具。这样一来,模型不只是“选择工具”,而是可以“写出工具”。Fibonacci 示例只是热身;真正的转折是 agent 自己 defun 出 brave-search,等于用一个通用执行工具生成了一个专用搜索工具。

这会把能力边界从:

平台作者提前写好什么 → agent 能做什么

变成:

agent 能在受控语言里构造什么 → agent 临时拥有怎样的能力

这个差异非常大。它让 Agent 更像一个可编程运行时,而不是一个工具菜单。

3. “Skills are just memories” 是全文最重要的一句

作者讨论 memory 时,一开始只是保存完整消息历史。但当 agent 通过对话写出了 brave-search 函数之后,memory 的意义变了:保存下来的不只是聊天内容,而是“曾经生成过的能力”。

进程退出后,Lisp image 里的函数没了;但 transcript 里还保留着函数定义。下一次 agent 读回历史,就可以把这段代码重新 eval 成能力。于是 skill 不一定是单独安装的插件,也不一定是平台作者写好的工具;skill 可以是一段保存在记忆里的可执行经验。

这和 SKILL.md 很接近:SKILL.md 不是二进制能力,而是文本化的程序性知识。区别在于,SKILL.md 通常由人维护、被系统加载;而作者的 Lisp agent 把这件事推到更极端的位置:agent 自己在 transcript 里写下技能,并在以后重新执行。

4. MCP 代表安全契约,Lisp eval 代表开放生成

作者把 MCP 放在 design-time capability 的一端:工具提前声明、能力提前协商、接口提前批准。这非常适合生产系统,因为它可以审计、版本化、隔离权限。

而 eval agent 在另一端:能力在 runtime 根据 conversation 生成。它灵活、漂亮,但也危险。模型能生成能力,也就能生成破坏性代码。它不只是调用一个有限工具,而是在运行时改变自己的可执行空间。

所以这篇文章不能被读成“以后都应该给 Agent 开 eval”。更稳妥的读法是:

MCP 解决的是权限和契约问题;eval 原型揭示的是能力生成问题。真正成熟的 Agent 系统,可能需要在两者之间找到可审计的中间层。

5. 它对个人 Agent / Hermes 这类系统的启发

对个人 Agent 系统来说,这篇文章的启发不在于换成 Lisp,而在于重新理解“记忆”和“技能”的关系。

记忆如果只是事实存储,就会不断膨胀,最后撞上 context window。技能如果只是静态工具,又会依赖人提前设计目录。更有潜力的方向是:

也就是说,好的 Agent 记忆不应该只是“我记得所有事”,而应该逐渐蒸馏为“我知道什么时候调用哪种能力,以及这套能力的边界是什么”。

6. 不要误读这篇文章

7. 最后判断

这篇文章最有价值的地方,是用 Lisp 把 Agent 的结构讲得非常透:Agent 不是一个神秘的智能体,而是一个递归地把模型输出、工具执行和消息历史折叠在一起的系统。Lisp 的 homoiconicity 则进一步提醒我们:当代码可以作为数据被生成、保存和重新执行时,“工具”“记忆”“技能”之间的边界会变得模糊。

但工程上越是模糊,越需要边界。一个能把记忆重新水化成能力的 Agent,必须同时拥有:沙箱、权限、审计、版本、撤销、压缩和人类可读的解释层。否则它不是更聪明,而只是更难控制。

来源与核对