跳到主要内容

eve — 架构与原理(总览)

30 秒导读: eve 是 Vercel 出品的「文件系统优先(filesystem-first)」后端 AI agent 框架。你不写一个巨大的配置对象,而是把 agent 的每个部件——指令、工具、技能、频道、定时任务——放进约定好的文件位置;eve 扫描这个目录树,编译成一个能跑在本地、能服务 HTTP、能跨多轮对话持久运行、且进程崩溃后能从断点恢复的 agent。


1. 这是什么(零基础也能懂)

一句话定义。 eve 是一个用「普通 TypeScript 文件」来搭建持久化 AI agent 的框架(packages/eve/package.json:5,description 写得很直白:"Filesystem-first framework for durable backend AI agents that run anywhere")。

它要解决谁的什么问题。 假设你要做一个能接 Slack、能调工具、能跑好几天、中途还能等人审批的后端 agent。常规做法是把模型配置、工具列表、频道路由全塞进一个大对象,越长越难读、越难改。eve 反过来:每个关注点都有一个固定的"家"——指令在一个文件、工具在一个文件夹、频道在另一个文件夹。光读目录树,你就大致知道这个 agent 能干什么。

一个典型 eve agent 长这样(摘自 README.md:24):

my-agent/
└── agent/
├── agent.ts # 可选:选模型、配运行时
├── instructions.md # 必填:always-on 系统提示
├── tools/ # 可选:模型能调的、带类型的函数
│ └── get_weather.ts
├── skills/ # 可选:按需加载的长流程
│ └── plan_a_trip.md
├── channels/ # 可选:消息入口(HTTP / Slack / Discord)
│ └── slack.ts
└── schedules/ # 可选:周期性 cron 任务
└── weekly_recap.ts

用起来什么样(最小示例)。 一条命令起一个新项目(README.md:43):

npx eve@latest init my-agent

它会建目录、装依赖、初始化 Git,并打开一个交互式终端 UI。

写一个工具,只需在 agent/tools/ 下放一个文件——文件路径就是工具名,不需要任何注册表(README.md:71):

// agent/tools/get_weather.ts —— 文件名 get_weather 就是工具名
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
description: "Return mock weather data for a city.",
inputSchema: z.object({ city: z.string().min(1) }),
async execute({ city }) {
return { city, condition: "Sunny", temperatureF: 72 };
},
});

选模型,在 agent/agent.ts 里一行(README.md:87):

import { defineAgent } from "eve";

export default defineAgent({
model: "anthropic/claude-sonnet-4.6",
});

这就是一个能跑的 agent 了。defineTool / defineAgent 这些只是给文件套了类型壳子,真正的"组装"由框架在后台完成。

一句话直觉。 把 eve 想成 agent 界的「约定优于配置」框架——就像 Next.js 把 pages/ 目录下的文件自动变成路由,eve 把 agent/ 目录下的文件自动变成一个 agent 的能力。目录结构就是这个 agent 的接口。


2. 顶层全景(它大概怎么转)

要看懂 eve,先抓住一条主线:目录约定 → discover(发现)→ compile(编译)→ runtime(运行)。前两步在构建/启动时跑一次,把你写的文件变成一份"清单(manifest)";第三步在每条消息到来时跑,驱动模型循环干活。

怎么读这张图

从上到下分三段:约定层(你写的文件)→ 编译层(框架一次性把文件读成 manifest)→ 运行层(每条消息触发的持久化执行)。运行层内部又是一条 channel → turn workflow → harness 循环 → sandbox 的链路。

┌──────────────────────────── 你写的文件(约定层) ────────────────────────────┐
│ agent/instructions.md agent/tools/*.ts agent/skills/* agent/channels/* │
│ agent/agent.ts agent/schedules/* agent/connections/* agent/subagents/* │
└───────────────────────────────────┬───────────────────────────────────────────┘
│ 构建 / 启动时跑一次
┌────────────▼────────────┐
│ ① discover(发现) │ 扫目录,认出每个"槽位"
│ src/discover/ │ (哪些是工具/频道/技能…)
└────────────┬────────────┘
┌────────────▼────────────┐
│ ② compile(编译) │ 规范化成一份 manifest
│ src/compiler/ │ (模型、工具描述、路由…)
└────────────┬────────────┘

▼ ── 运行时(每条消息触发) ──
消息到来 ┌─────────────────────────┐
(HTTP/Slack/cron) ───▶ │ ③ channel(前门) │ 验签、定身份、转成统一消息
│ src/channel/ │
└────────────┬────────────┘
┌───────────▼─────────────┐
│ ④ turn workflow │ 把"这一轮"包成持久化工作流
│ src/execution/ │ 逐 step 落 checkpoint,崩溃可恢复
└───────────┬─────────────┘
┌───────────▼─────────────┐
│ ⑤ harness(默认循环) │ 喂指令/工具/历史给模型,
│ src/harness/ │ 跑 tool-loop,做上下文压缩
└───────────┬─────────────┘
│ bash / read_file / write_file …
┌───────────▼─────────────┐
│ ⑥ sandbox(隔离工作区) │ 模型的 shell/文件操作落在这里
│ src/sandbox/ │ /workspace 隔离,无 secrets
└──────────────────────────┘

主线走一遍(高层,不进代码)

  1. 写文件。 你在 agent/ 下按约定摆好指令、工具、频道等。
  2. discover + compile(一次性)。 discoverAgent(src/discover/discover-agent.ts:59)扫描目录认出每个槽位,compileAgent(src/compiler/compile-agent.ts:62)把它们规范化成一份运行时清单(模型选择、工具描述、频道路由等)。
  3. 消息进来。 不管来自 Web、终端还是 Slack,走的是同一条流程(docs/introduction.mdx:65):channel 把平台输入转成统一消息。
  4. 包成一轮持久化工作流。 每一轮(turn)作为一个 durable workflow 运行——turnWorkflow(src/execution/turn-workflow.ts:32)。
  5. harness 驱动模型。 默认 harness 把指令、技能、工具、历史喂给模型,跑 tool-loop——createToolLoopHarness(src/harness/tool-loop.ts:347),按需调工具和子 agent。
  6. shell/文件落到 sandbox。 模型的 bash/read_file/write_file 操作被代理进隔离的 /workspace,碰不到 process.env 和密钥。
  7. 保存 + 流式返回。 会话被持久化、事件被流式推送,结果以平台期望的形式送回。

关键收获:channel→turn→harness→sandbox 这条链对每个平台都一样。你的天气工具不需要知道问题是从浏览器还是 Slack 来的(docs/introduction.mdx:67)。


3. 部件一句话职责

下面这张表是 eve 的"零件清单"。左边是你在 agent/ 下能写的槽位,右边是它干什么、用哪个 define* 助手、源码在哪。

部件干什么你写的文件 / 助手关键源码符号
agent 配置选模型、配 compaction、配运行时(Workflow world 等)agent/agent.ts · defineAgentdefineAgent(src/public/definitions/agent.ts:37)
instructionsalways-on 系统提示,定 agent 的稳定身份agent/instructions.md.ts · defineInstructionsdefineInstructions(src/public/definitions/instructions.ts:34)
tools模型能调的、带 zod 类型的函数;执行在 app 运行时agent/tools/<name>.ts · defineTooldefineTool(src/public/definitions/tool.ts:193)
skills按需加载的长流程,平时不进 prompt,匹配到才注入agent/skills/*.md*/SKILL.md · defineSkilldefineSkill(src/public/definitions/skill.ts:29)
channelsagent 的"前门":入站验签、定身份、转成统一消息agent/channels/*.ts · defineChanneldefineChannel(src/public/definitions/defineChannel.ts:210)
schedules周期性 / 定时任务(cron)agent/schedules/*.ts · defineScheduledefineSchedule(src/public/definitions/schedule.ts:104)
connections接外部 MCP / OpenAPI 服务,把它们的工具引进来agent/connections/*.tseve/connections 导出(package.json:114)
subagents专精子 agent,根 agent 可委派,各自独立上下文agent/subagents/*src/execution/subagent-*.ts
state会话级持久化状态,跨 step 边界存活defineStatedefineState(src/public/definitions/state.ts:43)
dynamic按调用者(团队/租户/计划)在运行时解析指令或技能defineDynamicdefineDynamic(src/public/definitions/tool.ts:258)
sandbox模型 shell/文件操作的隔离工作区agent/sandbox/* · eve/sandboxeve/sandbox 导出(package.json:129)

补一句容易混的点:tool 和 sandbox 的信任级别不同。工具的 execute 跑在受信的 app 运行时(能读 process.env、调 Stripe);而模型的 shell 命令跑在隔离的 sandbox(没有密钥、没有回到 app 的路)。这条边界是 eve 安全模型的核心(docs/concepts/security-model.md:10),详见 05 章


4. 本组阅读地图

这一组文档把 eve 由浅入深拆成五章。建议按顺序读:1→2 打通"文件怎么变成运行的 agent、为什么不丢状态";3→4 深入默认行为和上下文控制;5 收尾在边界和安全。

顺序章节讲什么什么时候该读
101-filesystem-discovery.md文件系统即接口:discover 怎么扫目录认槽位,compile 怎么规范化成 manifest想搞懂"为什么放个文件就能加工具"
202-execution-durability.mdsession / turn / step 三级模型,Workflow SDK 怎么让会话崩溃可恢复、可暂停可续想搞懂"为什么进程挂了对话不丢"
303-harness-tool-loop.md默认 harness:agent 主循环、内置工具集、上下文压缩(compaction)想搞懂"开箱即用的那套循环和工具"
404-context-skills-subagents.md上下文控制:always-on instructions、按需 skills、隔离 subagents想搞懂"怎么控制模型每轮看到什么"
505-channels-connections-security.mdchannels 前门、connections 凭证、app/sandbox 双信任域、失败即关闭想搞懂"边界在哪、安全怎么兜底"

巧妙之处提要(精华预告)

这些是读完整组后能带走的设计点,先列在这里建立期待:

  • 路径即身份(filesystem-first)。 工具名 = 文件名,移动/重命名文件,它的身份跟着走;没有要同步的注册表(docs/introduction.mdx:61)。这是 01 章的主题。
  • turn = 一个持久化工作流。 每轮对话被包成 durable workflow,在每个 step 边界落 checkpoint。崩溃/超时/重新部署后从最后一个完成的 step 续跑,已完成的 step 不重跑(docs/concepts/execution-model-and-durability.md:43)。这是 02 章的主题。
  • "停下来等"也是持久的(parked work)。 等人审批、等 OAuth、等子 agent——工作流挂起且不占算力,输入到了再原地续(docs/concepts/execution-model-and-durability.md:51)。
  • compaction 不只压历史,还保护框架自己的工具状态。 压缩会重置 read-before-write 跟踪、并重新注入 todo 列表,让模型跨摘要不丢任务(docs/concepts/default-harness.md:21)。这是 03 章的主题。
  • 内置工具靠"同名覆盖 / sentinel 禁用"来改。agent/tools/ 放一个同 slug 文件就覆盖内置;导出 disableTool() 就移除——文件名写错会在构建时报错而不是悄悄失败(docs/concepts/default-harness.md:80)。
  • skills 默认不进 prompt。 框架只广告技能描述并挂一个 load_skill 工具,匹配到才把技能 markdown 注入当轮(docs/concepts/context-control.md:36)。这是 04 章的主题。
  • 双信任域 + 失败即关闭。 密钥只在 app 运行时,sandbox 永远看不到;路由默认拒绝匿名流量,放开匿名要显式 none()(docs/concepts/security-model.md:76)。这是 05 章的主题。
  • frontmatter 是数据,不是代码。 skill/schedule 文件的 YAML frontmatter 被严格当数据;会 eval() 的代码引擎(---js)被禁用,这类 fence 直接抛错(docs/concepts/security-model.md:73)。

5. 边界与本章范围

本章只讲 Layer 0(这是什么)+ Layer 1(顶层全景)+ 阅读地图,不深入任何子系统的实现细节。具体机制——发现/编译的算法、Workflow 的 step 语义、tool-loop 的内循环、压缩的触发、channel 验签——分别落在 01–05 各章。

eve 当前处于 beta(README.md:124),API 和行为可能变;本章所有引用 as-of sourceCommit: ed8a935


6. 代码地图(跨 src 顶层目录的导航索引)

eve 源码在 packages/eve/src/ 下,按"发现 → 编译 → 运行"的生命周期组织。下表是顶层目录的跳转表,带真实符号名(行号会随上游漂移,符号名更抗漂移,可直接 grep)。

主题文件路径(相对 packages/eve/src/)关键符号
对外入口(re-export)index.tspublic/index.tsexport * from "#public/index.js"
agent 配置助手public/definitions/agent.tsdefineAgent
工具定义助手public/definitions/tool.tsdefineTool · defineDynamic
指令 / 技能 / 定时 / 频道 / 状态助手public/definitions/defineInstructions · defineSkill · defineSchedule · defineChannel · defineState
① 发现:扫目录认槽位discover/discoverAgent(discover/discover-agent.ts:59) · filesystem.ts · slots.ts · manifest.ts
② 编译:规范化成 manifestcompiler/compileAgent(compiler/compile-agent.ts:62) · normalize-*.ts
③ 频道:入站前门、路由、验签channel/routes.ts · adapter.ts · schedule.ts · send.ts
④ 持久化执行:turn 工作流 / sessionexecution/turnWorkflow(execution/turn-workflow.ts:32) · session.ts · workflow-entry.ts · subagent-*.ts
⑤ harness:主循环、内置工具、压缩harness/createToolLoopHarness(harness/tool-loop.ts:347) · compaction.ts · advertised-tools.ts
内置工具实现(编译进来的)runtime/framework-tools/bash.ts · glob.ts · grep.ts · ask-question.ts · connection-search-dynamic.ts
⑥ sandbox:隔离工作区后端sandbox/(后端适配:docker / just-bash / microsandbox / vercel)
运行时解析图(把 manifest 连成可执行图)runtime/resolve-agent.ts · resolve-channel.ts · resolve-tool.ts · graph.ts
CLI(eve init / dev / deploy)cli/cli/commands/init.ts · cli/run.ts · cli/dev/
客户端 / 前端框架绑定client/ · react/ · vue/ · svelte/对应 package.json./client ./react 等导出
评测evals/package.json./evals 导出

想直接从源码入手:先读 discover/discover-agent.ts 看"文件怎么被认出来",再读 compiler/compile-agent.ts 看"怎么变成 manifest",最后读 execution/turn-workflow.ts + harness/tool-loop.ts 看"一轮对话怎么跑"。这三处串起来就是 eve 的主干。各子系统细节见 0105 章。