数据截至 (上游 commit 0c84ae09499b)
Tambo 是什么 · 全景与阅读地图
30 秒导读: Tambo 是一套给 React 的开源生成式 UI(generative UI)工具包。你把自己写的组件用 Zod schema 注册进去,LLM 会按用户那句话挑出该显示哪个组件,并流式地把 props 填进去,前端就渲染出一个活的、可交互的界面。一句话:让 AI 说你自己的 UI。
1. 这是什么(零基础也能懂)
一句话定义。 Tambo 是"让 LLM 按用户意图调用、更新你自己 React 组件"的一套前后端一体工具包(README.md:44)。
它解决谁的什么问题。 传统聊天式 AI 只会吐一段文字或 Markdown。但很多场景里,用户真正想要的是一个界面:一张图表、一个可勾选的任务板、一个能改的购物车。以前你得手写一堆"如果模型说 X 就渲染组件 Y"的胶水代码;Tambo 把这套胶水标准化了。
- 给谁用: 想在 React 应用里加"AI 生成界面"的前端/全栈开发者。
- 典型例子: 用户说"给我看看各区域的销售额",渲染出你的
<Chart>;用户说"加个任务",更新你的<TaskBoard>(README.md:46)。
它能做什么(功能一览):
| 能力 | 说明 |
|---|---|
| 生成式组件 | 模型按用户消息挑组件、填 props,渲染一次(图表、摘要、可视化) |
| 可交互组件 | 组件持久存在、随对话反复更新(购物车、表格、任务板) |
| 流式 props | props 边生成边流入组件;取消、错误恢复、重连都替你处理好 |
| 内置 Agent | 后端替你跑完 LLM 对话循环,自带你的 API key(OpenAI / Anthropic / Gemini / Mistral 等) |
| 本地工具 & MCP | 组件之外还能注册浏览器里跑的函数,或接 MCP 服务器(Linear、Slack、数据库) |
| Cloud 或自托管 | 同一套后端既可用官方托管的 Tambo Cloud,也能 Docker 自托管 |
用起来什么样(最小示例)。 三步:注册组件 → 包一层 Provider → 用 hook 读消息。下面是 README 里的真实用法(README.md:95-141,示意精简):
// ① 用 Zod schema 把你的组件描述成"AI 能理解的东西"
const components: TamboComponent[] = [
{
name: "Graph",
description: "用 Recharts 把数据画成图表", // 这段描述会喂给模型,决定它何时选这个组件
component: Graph,
propsSchema: z.object({
data: z.array(z.object({ name: z.string(), value: z.number() })),
type: z.enum(["line", "bar", "pie"]),
}),
},
];
// ② 包一层 Provider(必须给 userKey 或 userToken 标明 thread 归属)
<TamboProvider apiKey={API_KEY} userKey={currentUserId} components={components}>
<Chat />
</TamboProvider>;
// ③ 在任意子组件里用 hook 读消息和流式状态
const { messages, isStreaming } = useTambo();
一句话直觉/类比。 把你的每个 React 组件想成一个**"按钮",按钮上写着"我能显示天气"。Tambo 把这排按钮的说明书递给模型;模型看用户想要啥,就去按对应的按钮**(内部叫 show_component_天气),同时把该显示的数据从按钮的插槽塞进去。你不再写"if 模型说 X"的分发逻辑,模型自己会按。
2. 顶层全景(它大概怎么转)
Tambo 是一个 Turborepo monorepo,同时装着"框架"(给开发者用的 SDK)和"云平台"(跑对话的后端)。理解它,先抓住一条四层主线——从你的浏览器一路到 LLM。
2.1 四层架构图
怎么读这张图: 从上到下是一次请求的流向。虚线是浏览器 / 服务器的边界——上半在用户浏览器里跑,下半在 Tambo Cloud 或你自托管的机器上跑。左边标的是包名。
用户在聊天框里打字 / 点建议
│
┌─────────────▼──────────────────────────────┐
│ ① React 胶水层 @tambo-ai/react │ react-sdk/src/index.ts
│ TamboProvider / useTambo / 组件注册表 │ (当前只导出 v1)
└─────────────┬──────────────────────────────┘
│ 依赖
┌─────────────▼──────────────────────────────┐
│ ② 框架无关内核 @tambo-ai/client │ packages/client
│ TamboClient(状态)+ TamboStream(流) │ Node/Vue/Svelte 也能直接用
└─────────────┬──────────────────────────────┘
│ HTTP / SSE(text/event-stream)
- - - - - - - - -│- - - - 浏览器 ╱ 服务器 边界 - - - - - - - - -
│
┌─────────────▼──────────────────────────────┐
│ ③ HTTP / 流式接口 apps/api (NestJS) │ apps/api/src/v1/v1.controller.ts
│ /v1/threads/runs → SSE 吐 AG-UI 事件 │ Cloud 或自托管
└─────────────┬──────────────────────────────┘
│ 调用 runDecisionLoop()
┌─────────────▼──────────────────────────────┐
│ ④ 决策循环大脑 @tambo-ai-cloud/backend │ packages/backend
│ 把组件变成 show_component_* 工具喂给模型 │ tambo-backend.ts
└─────────────┬──────────────────────────────┘
│
▼
LLM(自带你的 API key)
一句话:react-sdk 是给 React 用的糖,client 是真正的引擎,apps/api 是它对外的 HTTP 门面,backend 是门后决策的大脑。 react-sdk 在依赖上包着 client(react-sdk/package.json:80),client 通过生成的 HTTP SDK 打到 apps/api,apps/api 再调 backend 的 runDecisionLoop(apps/api 依赖 @tambo-ai-cloud/backend,apps/api/package.json:50)。
2.2 每个包 / 应用一句话职责
框架侧(给开发者用的,发到 npm):
| 包 / 应用 | npm 名 | 一句话职责 |
|---|---|---|
| react-sdk | @tambo-ai/react | React SDK:Provider、hooks、组件/工具注册表——开发者主要碰的就是它 |
| packages/client | @tambo-ai/client | 框架无关内核:流式、工具执行、thread 状态,不依赖 React |
| packages/react-ui-base | @tambo-ai/react-ui-base | 无头(headless)基础组件 / 原语,供上层 UI 拼装 |
| packages/ui-registry | @tambo-ai/ui-registry | 预制生成式 UI 组件库(图表、地图、消息线程等)的源 |
| cli | tambo | 脚手架 CLI:初始化项目、生成组件、同 步组件注册表 |
| create-tambo-app | create-tambo-app | npm create tambo-app 的引导器,一键起新项目 |
云平台侧(跑对话的后端,Cloud 或自托管):
| 包 / 应用 | npm 名 | 一句话职责 |
|---|---|---|
| apps/api | @tambo-ai-cloud/api | NestJS 服务:对外的 HTTP / SSE 接口,承载 thread、运行、流式 |
| apps/web | @tambo-ai-cloud/web | Next.js 控制台(项目管理、API key 等仪表盘) |
| apps/docs-mcp | docs-mcp | 把文档暴露成 MCP 服务器,供 AI 查 Tambo 文档 |
| packages/backend | @tambo-ai-cloud/backend | 决策循环大脑:把组件转成工具、跑 LLM、流式吐结果 |
| packages/core | @tambo-ai-cloud/core | 纯工具函数(校验、JSON、UI 工具名前缀等),不碰数据库 |
| packages/db | @tambo-ai-cloud/db | Drizzle ORM schema + 迁移 + 数据库操作 |
2.3 主线走一遍(高层,不进代码)
一次"用户说话 → 界面出现"大致这样流动:
- 用户发消息。 前端
useTamboThreadInput().submit()把这句话交给 client。 - 组件被当成工具喂给模型。 后端把每个注册组件转成一个名叫
show_component_<组件名>的"工具",组件的 props schema 就是这个工具的参数表(packages/backend/src/services/tool/tool-service.ts:100convertComponentsToUITools)。 - 模型决策。 决策循环(
runDecisionLoop)让模型看用户意图,选择调用哪个show_component_X,并按 props schema 生成参数——这就是"选组件 + 填 props"。 - props 流式回传。 生成的内容以 AG-UI 事件(一种标准化的流式事件语言)通过 SSE 一点点推回浏览器;client 的累积器把碎片拼成完整的 thread 状态。
- 前端渲染。 react-sdk 在注册表里按名字找到真正的 React 组件,把流进来的 props 灌进去,渲染成活的、可继续交互的界面。
3. 巧妙之处索引(读后续章节会展开)
这些是 Tambo "值得学"的设计点,先给你一个索引,细节在对应章节:
- 组件即工具(component as tool)。 不发明新协议,直接复用 LLM 原生的 "tool/function calling":一个组件 = 一个
show_component_<Name>函数,props schema = 函数参数(tool-service.ts:100-122)。前缀常量集中在一处UI_TOOLNAME_PREFIX = "show_component_"(packages/core/src/ui-tools.ts:1)。→ 见 01 - 决策循环是可迭代的流。
runDecisionLoop是个 async generator,吐出DecisionStreamItem(既含遗留的组件决策、又含 AG-UI 事件),支持连续调用多个 UI 工 具(decision-loop-service.ts:115、decision-loop-prompts.ts:14)。→ 见 02 - 借 AG-UI 做流式语言。 不自造流协议,直接用生态里的
@ag-ui/core事件类型;累积器把 delta 拼成完整状态(backend / client / react-sdk 三处都依赖@ag-ui/core)。→ 见 03 - SSE 而非 WebSocket。 运行接口是普通的
POST /v1/threads/runs,响应是text/event-stream,每个 AG-UI 事件一行data: <json>(v1.controller.ts:315、:366)。→ 见 04 - 可交互组件靠 HOC 包一层。
withTamboInteractable把普通组件升级成"AI 能反复改状态"的组件(react-sdk/src/v1/index.ts:282)。→ 见 05
4. v1 与遗留:当前 API 边界(读代码前必看)
Tambo 1.0 已发布,v1 是当前唯一对外的 API。这条边界很关键,否则你在 react-sdk/src/providers/ 下会看到一堆同名 provider 而困惑:
- 对外入口只导出 v1。
react-sdk/src/index.ts:7只有一行export * from "./v1/index";凡是从@tambo-ai/react能 import 到的,都在react-sdk/src/v1/index.ts里(约 300 行的导出清单)。 react-sdk/src/providers/下的非 v1 provider 是过渡/遗留实现。 它们中一部分被 v1 复用(如tambo-registry-provider、tambo-client-provider被 v1/index.ts:83-89 重新导出),但顶层的TamboProvider、useTambo等已经是 v1 版本(来自./v1/providers/tambo-v1-provider与./hooks/use-tambo-v1,见 v1/index.ts:75、:126)。读代码时以v1/目录为准,v1-前缀的文件是现役实现。
5. 代码地图(导航索引 · agent 跳转表)
用符号名 grep 比行号更抗漂移;下面每行指向后续章节会深挖的锚点。
| 主题 | 文件 | 符号 |
|---|---|---|
| React SDK 唯一对外入口 | react-sdk/src/index.ts | export * from "./v1/index" |
| v1 公共 API 清单 | react-sdk/src/v1/index.ts | TamboProvider / useTambo / withTamboInteractable |
| 主 Provider(现役) | react-sdk/src/v1/providers/tambo-v1-provider.tsx | TamboProvider |
| 组件/工具注册表 | react-sdk/src/providers/tambo-registry-provider.tsx | registerComponent / TamboRegistryProvider |
| 框架无关内核 | packages/client/src/tambo-client.ts | TamboClient |
| 流式可迭代对象 | packages/client/src/tambo-stream.ts | TamboStream |
| UI 工具名前缀 | packages/core/src/ui-tools.ts | UI_TOOLNAME_PREFIX / isUiToolName |
| 组件 → 工具 转换 | packages/backend/src/services/tool/tool-service.ts | convertComponentsToUITools |
| 决策循环入口 | packages/backend/src/tambo-backend.ts | createTamboBackend / runDecisionLoop |
| 决策循环实现 | packages/backend/src/services/decision-loop/decision-loop-service.ts | runDecisionLoop / DecisionStreamItem |
| 决策循环 system prompt | packages/backend/src/prompt/decision-loop-prompts.ts | UI tools 说明(:14) |
| 组件流式追踪 | packages/backend/src/util/component-streaming.ts | COMPONENT_TOOL_PREFIX / isComponentTool |
| HTTP / SSE 运行接口 | apps/api/src/v1/v1.controller.ts | @Post("threads/runs")(:315) |
想深入某一块,顺着上表的符号名跳进克隆源码;想系统学,按 frontmatter 的
chapters顺序读 01 → 05。