SnakeEats 技术解剖:扫描器是蛇,文档是它会生长的身体------人机协作的新数据层
核心:Claude Code 的工作不可重跑复用,Dify 的画布是黑盒。SnakeEats 把状态放进文档------扫描循环每次重读流,工具吐出的新标记被自然捕获,文档在执行中自己生长。本文讲架构决策的 WHY,组件级 API 细节见文末关联文章。
三个 AI 工具圈的普遍痛点:
- 记忆管理。对话的状态在模型的黑盒里,丢失不可观测;文档的状态在外部文本里,永不丢失、永远可寻址。区别不在"会不会忘",而在"忘了你是否知道、是否能找回"。
- 画布是黑盒。Dify/n8n 的流程"定义"在画布上,"执行"却在引擎里------中途无法介入,事后无法复现,参数改了为什么结果不对,没人知道。
- 状态管理无人做。LangChain/CrewAI 管"逻辑编排",但"Agent 记住自己做过什么"这个状态层,至今没有标准答案。
AI Agent 领域公认的两大难题------状态管理 和可观测性 ------本质上是同一个问题:人和 AI 之间,缺一个共享的、并发安全的、可寻址的文本数据层。
SnakeEats 的回答:让文档本身成为程序。 文档是程序的载体,扫描器是解释器,工具是标准库,而"执行到什么程度"------就写在这份文档里。
范式映射:为什么是"降维"
| 传统编程 | SnakeEats |
|---|---|
| 源代码 | Markdown 文档 + `@{tool |
| 解释器 / CPU | 扫描循环(scan loop) |
| 标准库 | tool-registry(本机任意可执行脚本) |
| 内存 / 状态 | 文本流(stream) |
| 调试输出 | scan_log 流 |
为什么这个映射是"降维"而不是"等价替换"?三个理由:
- 状态天然可寻址。 对话窗口里的状态在 LLM 的上下文里,不可寻址、不可持久。文档里的状态在文本里,可以搜索、可以回滚、可以被任何工具读取。流的每一次快照,就是系统此刻的完整状态。
- 定义与执行合一。 传统系统要维护"定义层"(代码/画布/配置)和"执行层"(运行时)两套东西。SnakeEats 只有一层:你正在写的文档。改流程 = 改文档,不需要改图、不需要重新部署。
- 人和 AI 用同一个载体。 文档对 LLM 是上下文,对人是你熟悉的 Markdown。不需要为 AI 建一套 API 层、为人建一套 UI 层------两者之间没有阻抗失配。
设计一:扫描循环------"贪吃蛇"式执行模型
这是整个系统最核心、也最容易被误解的机制。核心逻辑:
python
while not self._stop_event.is_set():
self._pause_event.wait() # 暂停门
chunk = stream.read(start=self.position, end=None) # 每次重读流剩余部分
matches, end_pos = self._collect_continuous(chunk, self.position)
if not matches:
break # 没标记了 → 自然结束
# 执行工具 → 工具可 append/insert 新标记
self.position = config["end"] # 推进 → 下一轮读到新内容
关键在那一行 stream.read(start=self.position, end=None)------循环每次从当前 position 重新读到流末尾。 工具在执行期间通过 stream.append() 或 stream.insert_after() 追加的新标记,在下一轮迭代被自然捕获。这不是 bug,是 feature:一个"执行→推进→重读→发现新指令"的闭合反馈环。
这就是 SnakeEats(贪吃蛇) 这个名字的由来:扫描器是蛇,在文档中前进;吃到标记就执行,执行让文档变长,蛇游过自己新长的身体继续吃,直到整份文档不再有标记。整个 Agent 循环的"状态"不在内存里,而在文档里------而文档,是可以被人类随时打开、阅读、编辑、保存的。
暂停不是"停一下"那么简单。 循环顶部的 _pause_event.wait() 是一个暂停门:正常扫描时立即通过,pause() 时阻塞,resume() 时继续。这意味着人类可以在任意两个工具之间介入------改参数、改文档、纠正方向,然后继续。这不是"事后审查",是"执行中协作"。
设计二:位置感知 API------工具知道"我在文档的哪里"
工具进程是被扫描器以 subprocess 方式拉起的,它怎么知道自己的标记在文档的哪个位置?扫描器在调用前自动做两件事:注入环境变量 SCAN_STREAM_NAME,并把标记区间 {"start", "end"} 存入 InternalStore。于是工具获得位置感知能力:
python
stream = system.get(os.environ["SCAN_STREAM_NAME"])
config = stream.get_replace_config() # {"start": N, "end": M}
context = stream.get_text_before() # 标记前的上下文
stream.insert_after("\n@{subtask|{...}}") # 原位插入新标记 → 下轮立即执行
stream.replace_in_range(result_text) # 用结果替换标记自身,标记消失
append vs insert_after 的差异,决定了工作流的灵活性天花板:
append()→ 追加到流末尾 = 排队执行,适合顺序任务链(先扫完中间内容,最后执行)insert_after()→ 插入当前扫描位置 = 立即执行,是"LLM 即时分解任务链"和"条件分支"的工程基础
一个工具可以在运行时重组自己所在文档的后续流程 ------插入新任务、替换自己的标记、修改后续步骤。这在传统工作流引擎里需要改图、改配置、重新部署;在这里,只是往文档里写几行字。这也是 llm_orchestrator 能"就地展开任务"的底层原因:LLM 分解出的子任务不是排队等着,而是插到当前位置马上执行。
设计三:和 function calling 的本质区别
主流 Agent 框架用 function calling:LLM 返回一个 JSON 调用请求 → 系统拦截 → 执行 → 结果塞回上下文。工具调用和文本内容是分离的------对话系统和工具系统在两套空间里来回切换。
SnakeEats 的标记是文本的一部分:
python
@{weather|{"city":"北京"}}
它不是"调用指令",它就是一行文本。扫描器解析文本时发现了它,执行它,然后这行文本变成结果。
这带来三个 function calling 做不到的能力:
- AI 可以像写自然语言一样写工具调用,不需要经过调度器(当然为了避免幻觉,使用LLM自己训练好的形式也可以,需要diy工具去适配)
- 人类可以直接在文本里插入/修改工具标记,不需要任何 UI------改一行字就能改一个参数
- 工具调用的顺序、嵌套、并行完全由文本布局决定,不需要额外的编排配置
设计四:底层引擎(一句话带过)
text-stream 底层是带版本控制的命名文本缓冲区 :双模访问(快照+流)、语义搜索 API、CAS 乐观并发。这些细节我上一篇组件文章已完整写过(《SnakeEats.text-stream:给多 Agent 之间装一条文本通道》),这里不重复------本文想强调的是:这些能力不是为了"做个数据库",而是为了支撑"文档即程序"这个范式。
思路的演进: LLM/工具的平等定位
LLM 不是外挂,而是可以被注册的普通工具。 系统本身不内置任何"智能",它只提供一个载体------智能作为工具流进来,执行作为文档留下来。这跟"做个 LLM 封装"是两种完全不同的哲学。
诚实的局限
文档即程序。 你写下的文字不只是记录,工具调用以 @{工具|{参数}} 的形式嵌入其中------内容与执行合一,一行文字就是一个真实的行动。 工作流即文档。 流程不画在画布上,而是写在文字里:扫描器像蛇一样吃掉标记、让文档在执行中生长,计划、执行、记录、产物是同一份文档的不同时刻。 文档即画布。 它既是人思考的载体,也是 LLM 工作的现场,更是多个 AI 共享的信息空间------人类编辑它,模型驱动它,Agent 协作它,一切协作都发生在这份看得见、改得动、留得住的文档上。
以上,是SnakeEats的理念。
- 当前项目是验证性的,正处于项目初期,未来将根据情况改造,但我希望SnakeEats的理念能传播出去,能让你获得启发,期待体验者、合作者、生态开发者
- 尚未兼容 MCP 、skills等外部工具协议,生态接入靠自建注册表,自建工具
最后
SnakeEats 想回答的根本问题是:当 AI 从"工具"变成"同事",人机之间需要怎样的共享基础设施? 我的答案是:一个并发安全的、可寻址的、人能读 AI 也能写的文本层------文档是程序的载体,扫描器是执行引擎,而这一切都以你熟悉的 Markdown 形式呈现。
关联阅读:
- 《SnakeEats.text-stream:给多 Agent 之间装一条文本通道》------底层引擎细节
- 《SnakeEats.tool-registry:在文本里嵌入可执行代码》------工具注册与执行细节
项目已开源,Apache-2.0 协议:
项目地址:
- GitHub: github.com/heyy259/Sna...
- Gitee: gitee.com/heyy259/Sna...
标签: #架构设计 #可执行文档 #Agent状态管理 #扫描循环 #LLM