项目: https://github.com/vercel/eve
定位: filesystem-first framework for durable AI agents
核心哲学: "The filesystem is the authoring interface"
一、一句话定位
eve 不是又一个配置驱动的 Agent 框架。它做了一件事:把 Agent 的所有组成部分(指令、工具、技能、通道、子代理)映射到文件系统的约定位置,然后自动发现、编译、运行。
你不需要写注册表、不需要维护配置文件、不需要手动把工具挂到 Agent 上。创建文件就是定义能力,删除文件就是移除能力。
二、项目结构即 Agent 定义
一个典型 eve 项目的结构:
my-agent/
├── package.json
└── agent/
├── agent.ts # 模型和运行时配置(可选)
├── instructions.md # 系统提示词(必需)
├── tools/ # 工具函数
│ └── get_weather.ts
├── skills/ # 按需加载的技能
│ └── plan_a_trip.md
├── channels/ # 消息通道(HTTP/Slack/Discord)
│ └── slack.ts
├── subagents/ # 子代理
│ └── stock-analyst/
├── schedules/ # 定时任务
│ └── weekly_recap.ts
├── hooks/ # 生命周期钩子
├── connections/ # 外部 MCP 连接
└── sandbox/ # 文件沙箱配置
关键设计:路径即身份。
agent/tools/get_weather.ts 自动注册为名为 get_weather 的工具。没有单独的 name 字段,没有注册表,没有手动装配。移动文件 = 重命名工具。删除文件 = 移除工具。
三、核心架构:发现 → 编译 → 运行
eve 的运行时分为三个阶段:
1. 发现(Discovery)
discoverAgent() 扫描 agent/ 目录,按约定结构识别各组成部分:
| 目录 | 发现的内容 |
|---|---|
instructions.md |
系统提示词 |
agent.ts |
Agent 配置(模型、温度、最大步数等) |
tools/*.ts |
工具定义 |
skills/*.md |
技能说明文档 |
channels/*.ts |
通道适配器 |
subagents/*/ |
子代理项目 |
schedules/*.ts |
定时任务 |
hooks/*.ts |
生命周期钩子 |
connections/*.ts |
外部 MCP 连接 |
发现阶段不导入模块,只做文件系统遍历和路径分析。这保证了:
- 编译错误不会阻塞发现
- 可以快速生成诊断信息
- 支持内存源(用于测试)
2. 编译(Compilation)
compileAgent() 将发现结果写入编译产物:
- Manifest:Agent 的完整能力清单
- Diagnostics:发现阶段的错误和警告
- Artifacts:构建产物路径
编译后的 Manifest 包含所有工具、技能、通道、子代理的元数据,但不包含实际的执行代码——代码在运行时按需加载。
3. 运行(Runtime)
运行时的核心是一个 Workflow-backed 的执行引擎:
workflowEntry (长期运行的 driver)
└── 每个 turn 启动一个 turnWorkflow (子工作流)
└── 调用 LLM → 执行工具 → 保存状态 → 流式返回
为什么用 Workflow?
eve 依赖 Workflow SDK(Vercel 开源的另一个项目)实现三个核心特性:
| 特性 | Workflow 提供的机制 |
|---|---|
| 持久化 | 每个 step 的结果是持久化边界,崩溃后可恢复 |
| 可恢复 | resumeHook() 允许在任意 step 边界暂停和恢复 |
| 事件流 | NDJSON 流式输出,支持中间状态推送 |
具体来说:
- 一个 session 对应一个 Workflow run
- 每个 turn(一次 LLM 调用+工具执行)是一个子 Workflow
- Session 状态在每个 step 结束后自动持久化
- 支持
deploymentId: "latest"路由,新部署的代码可以处理旧 session 的后续 turn
四、工具系统:类型安全的函数调用
定义工具
import { defineTool } from "eve/tools";
import { z } from "zod";
export default defineTool({
description: "获取城市天气",
inputSchema: z.object({ city: z.string().min(1) }),
async execute({ city }) {
return { city, condition: "Sunny", temperatureF: 72 };
},
});
defineTool() 做了几件事:
- 打上
TOOL_BRAND标记,运行时验证这不是一个原始对象 - 基于 description 生成 definition key(用于结果窄化)
- 规范化
auth配置(如果有)
工具上下文
工具执行时接收的 ToolContext 包含:
getToken():获取工具的认证 token(支持 OAuth、API Key 等)requireAuth():强制触发认证流程approvedTools:当前 session 中已批准的工具集合
审批机制
import { once } from "eve/tools/approval";
export default defineTool({
description: "执行危险操作",
needsApproval: once, // 每个 session 只审批一次
// needsApproval: always // 每次调用都审批
// needsApproval: never // 无需审批
async execute(input, ctx) { ... }
});
审批是阻塞式的:工具调用暂停,等待用户在 UI 上点击"批准",然后通过 resumeHook() 恢复执行。
动态工具
import { defineDynamic, defineTool } from "eve/tools";
export default defineDynamic({
events: {
"session.started": async (event, ctx) => ({
export: defineTool({ ... }),
}),
"turn.started": async (event, ctx) => ({
analyze: defineTool({ ... }),
}),
},
});
动态工具在运行时根据事件动态生成。这在需要根据上下文条件暴露不同工具的场景非常有用。
五、技能系统:按需加载的上下文
技能(skills)是 eve 的上下文压缩策略。
agent/skills/plan_a_trip.md
# 旅行规划技能
当用户提到旅行、航班、酒店时,加载此技能。
## 步骤
1. 询问目的地和日期
2. 搜索航班
3. 推荐酒店
4. 生成行程表
技能不会被自动注入系统提示词。相反,运行时生成一个"可用技能列表":
Available skills
Listed skills are available in this run. Do not claim a listed skill
is inaccessible unless activation or workspace inspection actually fails.
If the user names a skill or the request clearly matches one of the
descriptions below, call load_skill before proceeding.
- plan_a_trip: 旅行规划助手 (path: /workspace/skills/plan_a_trip/SKILL.md)
模型通过 load_skill 工具显式加载技能,技能内容作为工具结果返回。这保持了系统提示词的稳定性,有利于 prompt caching。
六、通道系统:平台无关的通信层
通道(channels)是 eve 的通信抽象:
import { defineChannel } from "eve/channels";
export default defineChannel({
async fetch(request, ctx) {
// 处理 HTTP 请求
return new Response("Hello");
},
});
通道的核心职责:
- 接收:把平台特定的输入(HTTP request、Slack message、Discord event)转换为 eve 消息
- 发送:把 eve 事件流转换为平台特定的输出
- 认证:验证请求来源(通过
auth配置)
默认的 HTTP 通道是无状态的——它只是一个 discriminator,用于在 Workflow 恢复时重新路由到正确的适配器。
七、子代理系统:任务委派
子代理(subagents)是 eve 的任务分解机制。
agent/subagents/stock-analyst/
├── instructions.md
├── tools/
└── agent.ts
父代理通过 call_subagent 工具委派任务:
// 父代理视角
await callSubagent({
subagentName: "stock-analyst",
description: "分析特斯拉股票",
input: { ticker: "TSLA" }
});
子代理的运行特点:
- 独立的 session,独立的 Workflow run
- 继承父代理的 sandbox state(如果配置了)
- 结果返回父代理后,子代理 session 结束
- 支持 HITL(Human-in-the-loop):子代理可以暂停等待用户输入
子代理的 continuation token 格式:<parentSessionId>:<callId>,支持跨 session 的根追踪。
八、持久化机制:Workflow SDK 的利用
eve 的持久化不是简单的数据库读写,而是建立在 Workflow SDK 的 step 语义上:
// Workflow 伪代码
async function turnWorkflow(input) {
const session = await readDurableSession(state); // step 1
const result = await callModel(session); // step 2
const toolResults = await executeTools(result); // step 3
const updatedSession = await updateSession(...); // step 4
return updatedSession; // 自动持久化
}
关键特性:
- Step 边界即持久化边界:每个
await后的状态自动保存 - 崩溃恢复:Workflow 崩溃后,从最后一个完成的 step 恢复
- 暂停/恢复:
resumeHook()可以在任意 step 边界暂停,等待外部事件 - 版本兼容:持久化状态携带 version 字段,支持向前兼容的迁移
Session 状态结构:
interface DurableSession {
sessionId: string;
rootSessionId?: string; // 顶级 session 的追踪
continuationToken: string; // 恢复用的 token
history: ModelMessage[]; // 对话历史
state?: SessionStateMap; // 用户自定义状态
sandboxState?: SandboxState; // 沙箱文件状态
agent: { system: string }; // 系统提示词快照
compaction?: { ... }; // 上下文压缩状态
}
九、Vercel 平台集成
eve 与 Vercel 平台深度集成:
部署模型
- Production:
deploymentId: "latest"路由,新部署自动接管旧 session - Preview:固定到当前部署,隔离测试
- Local:dev server 模式,文件变更热重载
环境感知
function shouldRouteToLatestDeployment(): boolean {
return process.env.VERCEL_ENV === "production";
}
Production 环境使用最新部署的代码处理 session 的后续 turn,Preview 和本地环境保持固定部署。
十、与其他 Agent 框架的对比
| 维度 | eve | LangChain | AutoGen | CrewAI |
|---|---|---|---|---|
| 配置方式 | 文件系统约定 | Python 代码 | Python 代码 | Python 装饰器 |
| 持久化 | Workflow SDK(内置) | 需手动实现 | 需手动实现 | 需手动实现 |
| 平台绑定 | Vercel(深) | 无 | 无 | 无 |
| 类型安全 | TypeScript(强) | Python(弱) | Python(弱) | Python(弱) |
| 工具发现 | 自动(文件系统) | 手动注册 | 手动注册 | 手动注册 |
| 子代理 | 文件系统隔离 | 代码级 | 代码级 | 代码级 |
| HITL | 内置(审批机制) | 需手动实现 | 需手动实现 | 需手动实现 |
eve 的独特之处:
- 文件系统即接口:无注册表、无配置同步问题
- 持久化原生:不是可选项,是核心设计
- 类型安全:Zod schema 全程验证
- Vercel 生态:一键部署、latest 路由
十一、潜在限制
- 平台绑定:Workflow SDK 的持久化依赖 Vercel 基础设施(或兼容实现),自建部署需要额外工作
- TypeScript 限定:纯 TypeScript 项目,Python/Java 生态不可用
- Beta 阶段:API 可能变化,pre-1.0
- 学习曲线:Workflow SDK 的 step 语义需要理解
- 调试复杂度:持久化执行流的调试比单次请求更复杂
十二、适用场景
适合:
- 需要长期运行、可恢复的 Agent(客服、工作流自动化)
- 团队需要清晰的代码组织和权限边界
- 已经在 Vercel 生态中的项目
- 重视类型安全和可维护性
不适合:
- 单次调用、无状态的简单 API
- 需要多语言支持的场景
- 不想绑定云平台基础设施
十三、核心代码量
| 模块 | 文件数 | 核心职责 |
|---|---|---|
discover/ |
~15 | 文件系统扫描、路径分析 |
compiler/ |
~20 | Manifest 生成、代码规范化 |
execution/ |
~25 | 工作流编排、session 管理 |
channel/ |
~15 | HTTP/WebSocket 适配 |
client/ |
~12 | SDK 客户端、消息流处理 |
public/ |
~20 | 用户-facing API(defineTool 等) |
总代码量约 ~15K LOC(不含测试和文档)。
总结
eve 的核心理念是 "约定优于配置"的极致化——不是把配置写进代码,而是把配置放进文件系统的约定位置。
这种设计的好处:
- 项目结构即文档
- 无需注册表维护
- 版本控制友好(每个组件独立文件)
- 权限控制简单(文件系统权限)
代价是与 Vercel 平台深度耦合,以及 TypeScript 生态的限定。
如果你正在 Vercel 上构建需要持久化、多轮对话、人类介入的 Agent,eve 是目前最原生的选择。
参考:github.com/vercel/eve | beta.eve.dev/docs
#AgentFramework #Vercel #TypeScript #Workflow #DurableExecution #小凯
讨论回复
加载中...正在加载回复...
推荐
智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。