我最近在琢磨一件事:怎么把 AI agent 真正塞进一个产品里,而不是在页面右下角挂个聊天框了事。Builder.io(做可视化建站那家)这个月刚开源的 Agent-Native 给了一个挺直接的答案——它不把 agent 当外挂助手,而是把"能力"定义成应用的一等公民,Agent 和 UI 平等地共用同一套东西。我 clone 下来读了源码、也把它的 CLI 跑了一遍,下面是我的判断。
项目地址:https://github.com/BuilderIO/agent-native(GitHub,MIT,2026-03 建仓,当前 5.2k★)
它到底解决什么问题
常见的"AI 产品"是两条平行的线:后端有个 agent 能调工具,前端有个 UI 能点按钮,两边各写一套逻辑、各存一份状态。结果就是 agent 不知道用户在看什么,用户也不知道 agent 改了什么,要同步就得一堆胶水代码。
Agent-Native 的核心就一句话:把每个能力定义成一个 action,agent 把它当工具用,UI 从代码里直接调同一个函数。两边走的是同一份校验、同一份权限、同一份实现。agent 不"点击"UI,它和 UI 一样,都是穿过 action 层去干活。
一个 action,六张面孔
框架里一个 action 用 defineAction 定义,放在 actions/ 目录里自动被发现。它同时是:agent 的工具、React 里 useActionQuery 调用的函数、HTTP 接口、MCP tool、A2A(agent 对 agent)接口、以及 CLI 命令。下面这段是仓库里 chat 模板自带的 hello action,一字未改:
// templates/chat/actions/hello.ts
import { defineAction } from "@agent-native/core/action";
import { z } from "zod";
export default defineAction({
description: "Return a friendly greeting.",
mcpTool: true, // 同时注册成 MCP 工具
schema: z.object({
name: z.string().default("world").describe("Name to greet"),
}),
http: { method: "GET" }, // 顺手暴露成 GET 接口
run: async ({ name }) => {
return { message: `Hello, ${name}!` };
},
});
这就是为什么 README 敢说"定义一次,到处能用"。我翻了 packages/core/src/action.ts 里 defineAction 的真实签名(第 1040 行起),它除了 schema/run,还带着几个很"生产向"的字段:
// 来自 action.ts 的真实字段(节选)
readonly needsApproval?:
| boolean
| ((args, ctx?) => boolean | Promise<boolean>); // 人工审批门,默认关
readonly allowPersistentApproval?: boolean; // 已批准的偏好可复用
readonly access?: ActionAccessConfig; // 声明式权限契约
readonly authorize?: (args, ctx?) => Promise<void>; // 鉴权在输入校验"之内"
最后这点我觉得是踩过坑才有的设计:authorize 被包在输入校验里面,所以鉴权函数拿到的是已经 parse、已经 coerce 的合法值,而不是调用方原样扔过来的 attacker-shaped 输入。源码注释写得很直白——把它放在外面,每个守卫都会读到"看起来像已校验、其实没校验"的数据。
Agent 不点 UI,它读写"应用状态"
光有共享 action 还不够,agent 还得知道用户在看什么、能驱动 UI 跳到哪。Agent-Native 把 UI 状态也存进 SQL 的 application_state 表。还是 chat 模板里的两个真实 action:
// templates/chat/actions/view-screen.ts(节选)
export default defineAction({
description: "See what the user is currently looking at on screen.",
schema: z.object({}),
http: false,
readOnly: true, // 标成只读,agent 不会误改状态
run: async () => {
const navigation = await readAppState("navigation");
if (!navigation) return "No application state found. Is the app running?";
return { navigation };
},
});
// templates/chat/actions/navigate.ts(节选)
export default defineAction({
description: "Navigate the UI to a specific view or path.",
schema: z.object({
view: z.string().optional().describe("View name to navigate to"),
path: z.string().optional().describe("URL path to navigate to"),
}),
http: false,
run: async (args) => {
// 写一条 navigate 指令进应用状态,UI 读完后自动删除
await writeAppStateForCurrentTab("navigate", nav);
return `Navigating to ${args.view || args.path}`;
},
});
agent 调 view-screen 就等于"看一眼屏幕",调 navigate 就"让 UI 跳过去"——但全程不碰 DOM,只是读写那张共享状态表。前端轮询 useDbSync() 把状态映回界面。这套机制让"人在回路里审阅、agent 后台改"变成框架级能力,而不是你自己拼。
图:Agent 与 UI 通过同一张 SQL 应用状态表形成闭环,不需要 agent 去模拟点击。
框架硬塞给你的四条约束
图:AGENTS.md 要求的四个面,缺一功能就不完整。
本地跑一遍
环境:macOS,Node 22.22.2,pnpm 10.29.1。我先照 README 的 npx @agent-native/core@latest create ... 走,结果在第一步就撞墙:
npm error code EPERM
npm error syscall unlink
npm error path /Users/aaron/nodejs/node_cache/_cacache/tmp/21a88ed4
npm error Your cache folder contains root-owned files,
npm error due to a bug in previous versions of npm.
这是本机 npm 缓存被早期 npm 写成 root 属主导致的老 bug,npx 想清理临时文件却被拒。正经修法是 sudo chown -R 501:20 那个缓存目录,但我这台没 sudo 权限。退一步,我把缓存指到自己的目录就绕过去了:
export npm_config_cache="$HOME/.npm_cache_agentnative"
npx --yes @agent-native/core@latest --help
# → agent-native v0.182.1
# dev / build / start / action <name> / agent "prompt"
# agents list / invoke <app> "prompt" / mcp <cmd> / code / doctor ...
能跑出 help 说明包本身没问题。但我没把完整 app boot 起来——它要 PostgreSQL(本地用 PGlite)或一个 LLM key(Anthropic / OpenAI / 本地 Ollama),create 还会跑 pnpm install 拉一整套 React + Nitro + Drizzle 依赖(chat 模板的 e2e 测试就专门验证 install 后 pnpm action hello 能过)。这篇就先停在源码级 + CLI 级,不假装跑通了业务流。
仓库长什么样
它是个 pnpm monorepo,根目录 21 个 packages/(core、dispatch、scheduling、embedding、toolkit、desktop-app、mobile-app、vscode-extension…)和 17 个开箱即用的模板 app(Clips 录会议、Design 出设计稿、Slides 做 PPT、Analytics 查数据、Calendar、Mail、Content、Plan…)。技术栈是 TypeScript + React + shadcn/ui + Nitro 部署 + Drizzle 操作 Postgres,License MIT。
AGENTS.md 里有两条契约我印象很深:"All AI work goes through the agent chat"(UI 不直接调 LLM)和 "The agent can modify app code"(agent 能改应用代码,所以 UI 和数据流要按这个前提设计)。另外它自带一套 doctor 静态检查和 pnpm guards 门禁,连"失败时别把错误 coerce 成正常值"都写进了仓库纪律——这是被反复踩坑逼出来的。
值不值得上
| 场景 | 结论 |
|---|---|
| 适合 | 要做"人 + agent 协作"的知识工作产品(会议纪要、设计、内容、数据分析类),且愿意接受它整套全栈约定(React + Nitro + Postgres)。shared action 层能省掉大量 agent/UI 状态同步的胶水。 |
| 不适合 | 只想在后端点个 LLM、或要轻量 CLI 工具——它偏重,强绑定前端栈与 SQL。还很早期(v0.182.1,2026-03 才建仓),虽已 5.2k star、commit 极活跃,但 API 仍在快速变动,不适合追求稳定契约的生产系统。 |
Agent-Native 的卖点不是"又一个 agent 框架",而是把 agent 写进应用的契约里,让能力和状态成为 UI 与 agent 共享的事实源。适合从它的模板 app 起步改造成自己的产品;想完全自己掌控技术选型的话,它这套强约定会是负担而不是助力。