
vercel 发布了 github.com/vercel/eve , 一个新的 agent 开发框架.
eve 采用和 nextjs 一脉相承的设计思路: filesystem as agent structure------目录结构本身就是 agent 的结构.
初步印象
前身 ai-sdk
vercel 本来就有了这样一个 agent 框架: ai-sdk, 也是 eve 的底层框架 (负责接入 ai provider, agent loop, hook).
这个也是 vercel 在前三年持续投入资源的主力 ai 框架.
ai-sdk 的职责很明确: 接入大模型 API, 统一配置差异, 然后在 v6 版本引入了 AgentLoop. 和同一时期出现的 langgraph, llamaindex 等框架不同, 它专注于底层操作的抽象, 不搞过度的封装.
eve 能干的所有事情, 基于 ai-sdk 写代码都能干. 我已经用它搓了很多对话/agent 项目, 也尝试过其它框架 (pi / claude agent sdk), 最终长期选择 ai-sdk, 可以说 ai-sdk 在构建效率 和开发体验上做到了最佳.
脏活成本抽掉
到了 2026 年年中, 用 ai-sdk 开发 agent 项目的过程中, 一些工作已经开始重复:
- Skills: 实现
load_skill tool - 工具封装: 把搜索 REST API 封装成 tool, 或者 await MCP server 加载之后转换为 tool
- 手动调试链路: 暴露一个 Openai-compatible API 接入到 Cherry Studio / Kelivo 这类工具, 或者直接搓一个对话 web 页面
- 设计 schema 与实现对话持久化: conversation(or session) - message
虽然这些都可以让 codex / claude code 来写, 但还是要自己测试调试, 模型的不确定性偶尔会让你卡住. 这些边缘工作的整体成本依然很高.
第一眼看到 eve 时, 我的猜想就是: 它的设计目的就是为了把这些脏活的成本归零.
One more layer---only now.
Vercel 没有在 2024/2025 就推出一款像 langchain / langgraph / llamaindex / mastra 那样的 all-in-one, 过度抽象的框架, 然后最终变成很重, 带很多过时包袱, 积重难返的笨重东西.
而是在今天 (2026 年 6 月), agent 形态已经形成了一套统一共识 (api call loop until finish_reason:stop, workspace, skills, tools, subagent) 的情况下,
才推出这个 **优雅, 一眼就吸引人, 目标是开发体验最好 / 最佳实践合理抽象 ** 的框架.
eve 的优势
封装常需功能
skills, subagents 这些, 本质是很简单的东西, 只要你懂它的原理, 就能容易实现, 但也要花一些功夫.
在 eve 中直接开箱即用, 而且比手动实现的更加优雅.
比如 skills, 手动实现的话:
- 要么把 skills 内容作为字符串写死在代码中
- 要么用 fs 库加载文件, 还要修改打包配置把 skill 文本文件打包进 dist 中
而有了 eve:
- 可以直接像openclaw/codex中一样在
skills/目录下创建静态的.md和代码文件 (会被直接打包进运行时的 workspace/skills 目录下) - 也可以在一个
skills/skill-a.ts文件中export default defineSkill({description, markdown, files})构建动态 skill 内容
方便调试
bash
#npm run dev
eve dev
开发时直接通过 TUI 进行对话, tool_call, turn 完整显示, 并且支持改动后热重启 / 热加载, 不用 exec a .ts 或者通过额外的 web 界面对话.
实际测试就这个 TUI 的对话入口就节省了大量时间.
Channel
没错, 就是 xxClaw 类产品的 Channel 概念, 但是 Eve 的 Channel 更简单轻量, 职责单一, 无论是接入还是扩展开发, 用户体验都极佳.
它是事件驱动型:
- slack @ 了一个 bot
- github 发布了一个 issue 或者 comment @bot (通过 github app webhook)
通过 curl POST 暴露的 Openai-compatible API 或者前端发送消息也是一个 Channel. 没错, channel 被设计为统一 trigger 入口.
实现一个 Channel, 你只需要 adapt 以下 hook:
ts
import { defineChannel, GET, POST } from "eve/channels";
export default defineChannel({
routes: [
POST("/message", async (req, { send }) => {
const body = await req.json();
const session = await send(body.message, {
auth: null,
continuationToken: body.token,
});
return Response.json({ sessionId: session.id });
}),
GET("/sessions/:sessionId/stream", async (_req, { getSession, params }) => {
const session = getSession(params.sessionId);
const stream = await session.getEventStream();
return new Response(stream, {
headers: { "content-type": "application/x-ndjson; charset=utf-8" },
});
}),
],
events: {
"message.completed"(event, channel, ctx) {
// deliver completed messages back to the surface that owns this channel
},
},
});
它可以在接收到事件后回复, 本质是通过 ctx + channel 的信息组合执行具体行为, 比如收到 github issue 这个事件后的处理流程:
txt
github webhook eve runtime
┌───────┐ ┌──────────────────┐
│ issue created trigger──▶ │ channel: gh │
└───────┘ └────────┬─────────┘
│
ctx = { issueId, repo, ... }
│
▼
┌──────────────────┐
│ LLM generate │
└────────┬─────────┘
│
credentials (channel)
│
▼
┌──────────────────┐
│ POST comment to │
│ issue(ctx.id) │
└──────────────────┘
但 不具备 openclaw 那种定时触发任务后主动向 channel 发送消息的能力, 不过可以把定时任务的结果"搭便车"发送到某些 channel:
ts
export default defineSchedule({
cron: "0 9 * * 1-5",
async run({ receive, waitUntil, appAuth }) {
waitUntil(
receive(slack, {
message: "Summarize yesterday's activity and post the digest.",
target: { channelId: "C0123ABC" },
auth: appAuth,
}),
);
},
});
eval of agent
这个功能非常强大. 以往想要对开发的 agent 功能进行 eval, 往往是大量的手动工作:
- 把暴露的 openai-compatible api 接入到 langfuse 等平台, 再在平台内手动创建一堆测试用例
- 只能 evaluate 最终回复, agent 执行过程还要手动查看日志 / 查看 trace
- 往往到最后还是回归了手动 chat, 手动检查执行步骤
而 eve 提供了:
- 约定的 evaluations 存放目录结构
php
evals/
├── evals.config.ts
├── smoke.eval.ts
└── weather/
├── weather-tool.eval.ts
└── seoul-forecast-result-judge.eval.ts
- eval CLI
bash
eve eval # 跑全部
eve eval weather smoke # 按 id 或目录前缀筛选
有了 eval, 终于可以开箱即用的评测构建的 agent 了!
示例代码:
ts
import { defineEval } from "eve/evals";
import { includes } from "eve/evals/expect";
export default defineEval({
description:
"Weather agent calls get_weather (after approval) and surfaces the forecast.",
async test(t) {
await t.send("首尔天气如何?");
t.calledTool("get_weather"); //assert: 必须调用这个 tool
t.completed();//assert: 必须正常结束
t.check(t.reply ?? "", includes("72")); //assert: 结果中 text 必须包含 "72" 字符串
t.judge.autoevals.closedQA('必须是72°F的, 必须包含首尔') //llm judge: 是否完成目标, 输出 "Y" or "N"
// t.judge.autoevals.factuality('xxx') //llm judge: 完成程度, 输出小数
},
});
Sandbox 支持
我尝试过手搓类似的功能, 但是和 skills, subagent 这些可以几句话让 claude 直出的功能不同, 这一块的实现目前 (2026 年 6 月) 还是一个成本黑洞, 很难凭借 codex / claude 稳稳搞定. 想要实现一套稳定 / 健壮的 Agent 隔离运行模式, 没有可预测的排期, 也很容易推倒设计重来.
eve 的 Sandbox 在设计上非常合理:
- agent build 后运行在一个后端 (因为只有 HTTP Server 的职责, 所以无需隔离)
- tool_call 运行在 sandbox 中 (通过 key 隔离, key 是标识符, 比如 github issue id, slack 对话 id)
并且有硬安全 (目前仅 vercel sandbox, microsandbox 两种 sandbox 环境支持):
- credentials 不注入 sandbox 的环境变量 (xxClaw 现在做的, 安全隐患很大), 而是给 sandbox 发出的 HTTP 请求加上 Authorization 头
当前的 sandbox 一共支持四种 backend (运行环境):
- vercel sandbox (自家云服务生态)
- docker
- microsandbox
- just-bash (本机直接运行, 模拟的假 sandbox)
tool 在 sandbox 中运行是必须的, 底层设计就是必须在一个 sandbox 环境中运行, 默认的 backend 是从上方列表中的 4 个从上到下选择一个能用的.
Sandbox 想一想就知道底层实现非常复杂. microsandbox 应该是未来的刚需和第一支持 (只有它支持细粒度网络配置和 auth 隔离), 但是现在用起来有点问题. 现在 docker 和 just-bash 用着没什么问题. 还有一个目前的问题是: 现在的 docker 和 microsandbox backend 都不支持自动结束, 启动后就会一直运行.
eve 中的难受之处
单agent入口
如果是用 ai-sdk 在 nextjs 项目中开发 agent, 因为是自己手搓的, 所以可以开发多个同时存在. 但是 eve 在设计上就是一个项目一个入口, 所以无法支持一个项目暴露三个 path 作为三个不同 agent 的入口.
能想到的方法:
- 通过 subagents 区分: 虽然 subagents 的构建过程和主 agent 完全一模一样 (没有阉割, 不像 claude code 中只是一个提示词文件 😵💫), 但是也要过一遍主 agent 的对话再由主 agent 分配给子 agent 执行
- turborepo monorepo: 增加了复杂度
step hooks 模式变更
在 ai-sdk 的 streamText() 中, 可以直接控制各种 hook 做很多细粒度的控制:
chat.ts
ts
// 透明直控: 在 streamText() 调用前后随意编排 DB / 鉴权 / 上限 / 落库
chatRoute.post("/", async (c) => {
const { message, conversationId: incomingId } = await c.req.json();
const userId = c.get("userUuid");
// 1. 取/建会话
const { id: conversationId, isNew } = await ensureConversation({
conversationId: incomingId,
userId,
});
// 4. 按 session id 查库拉全历史 -> ModelMessage (关键步骤: exec 前完成)
const history = await getMessages({ conversationId, userId });
const modelMessages = await convertToModelMessages(history);
// 5. streamText 透明拿到 messages / tools / prepareStep / onFinish
const result = streamText({
model: deepseekV4Flash,
system: SYSTEM_PROMPT,
messages: modelMessages,
tools: { search: crateBraveSearch() },
stopWhen: stepCountIs(MAX_STEPS + 1),
onFinish: ({ finishReason, totalUsage }) => {
// lastFinishReason = finishReason;
// lastUsage = totalUsage;
},
// 细粒度 step 控制: 达到上限 step 强制 toolChoice:none + 注入收尾指令
prepareStep: ({ stepNumber, messages: stepMessages }) => {
if (stepNumber >= MAX_STEPS) {
return {
toolChoice: "none",
messages: [
...stepMessages,
{ role: "assistant", content: "工具调用已达上限, 直接出最终回复." },
],
};
}
},
});
return result.toUIMessageStreamResponse({
originalMessages: history,
messageMetadata: ({ part }) => {
if (part.type === "start") return { conversationId, isNewConversation: isNew };
if (part.type === "finish")
return { finishReason: part.finishReason, totalTokens: part.totalUsage?.totalTokens };
},
onFinish: async ({ messages: finalMessages, isAborted }) => {
//.......
},
});
});
但是由于 eve 是新的架构, 这些操作不得不变成了"全局旁路"的方式, 没有原来直接操作底层 streamText() 那么透明:
ts
import { defineHook } from "eve/hooks";
export default defineHook({
events: {
async "session.started"(_event, ctx) {
console.info("session started", { sessionId: ctx.session.id });
},
async "message.completed"(event) {
console.info("model finished", { length: event.data.message?.length ?? 0 });
},
},
});
对比
vs mastra, langchain, langgraph, deepagents
mastra / langchain / langgraph 太重了, 把所有东西都塞进去.
eve 显得很轻量, 抽象的恰到好处.
langchain.js / langgraph.js / deepagents.js 只是python主项目 的 javascript 复刻, 有一种"非原生"的使用感觉, 缺少 ai-sdk / eve 那种轻量感. 然后它们的前后端交互协议 相比 vercel 出品的那肯定也是差远了.
vs xxClaw, hermes
相当大一部分人在 xxClaw 和 hermes 上构建出了他们需要的 agent 功能, 主要通过扩展 skill 的方式. 这种模式现在的问题是太混沌了:
- skill 提供的 cli 或者 bash 命令很容易运行失败
- 想要扩展新功能, 调试跑通成本很高
- 所有功能都放在一起, token wasting machine
对于开发者和有一定 vibe coding 能力的非技术人员来说, eve 是可以完美替代 xxClaw, hermes 功能的开发框架. 这种开发框架相比这些支持扩展的成品:
- 非常清晰, 开发体验极度舒适, 极低开发调试成本的 build 过程
- build 出来的功能运行更加稳定
vs pi, opencode
pi-coding-agent ➕ 开源 web 界面 或者 opencode (比 claude code 开放太多, 自带一个成熟的 web 界面支持远程访问), 可以通过扩展的方式定制为一个特定功能的 agent, 相比 ai-sdk 从零手搓节省了不少搭建 agent core 的初始成本, 可以直接本地运行也可以打包为镜像作为一个 build 成品 (打包意味着可复制可规模化).
但是这种套壳方式不支持更 advanced 的定制化功能, 比如:
- 自定义 tool execution 的可视化展示
- 作为一个侧边栏, 嵌入区域而不是完整的页面
- 给 tool 传入 ctx
有了 eve, 完全没必要使用 pi-coding-agent 或者 opencode 来节省基础设施搭建成本了. eve 自带这些基础设施且是可以任意开发的操作代码的东西.
至于 pi-agent-core , 适合和 ai-sdk 类似定位但完全不同架构的东西.
vs claude-agent-sdk
claude-agent-sdk 是和 ai-sdk 类似的定位, 但是更加简单易用 (傻瓜式) 意味着更少的可开发空间.
vs claude code or codex
不是同类定位. claude code or codex 是让人使用的成品工具, eve 是开发框架.