使用指南
高级

工作台技术说明

工作台是怎么跑起来的、清单文件怎么写,以及它能调用的每项 Floatboat 能力(模型、语音识别、Agent、Workflow、连接的服务、日程、自动化、空间)能做什么、怎么调、有哪些限制。

这一页写给想把工作台做深一点的人:你自己写代码,或者想看懂 Agent 替你写的代码。平时用工作台不用读这页,看工作台就够了。

这里的内容对应当前正式版里的工作台 SDK 1.0.0。SDK 就是工作台用来调用 Floatboat 的那套代码接口。

一个工作台由什么组成

先有个整体印象:工作台其实是一个跑在你电脑上的小网页应用,分三块。

部分用什么写做什么
页面React + TypeScript(TSX)你在 Floatboat 里看到、点到的界面
服务端TypeScript,跑在 Node 22 上存取数据、调用 Floatboat 的能力、给页面提供 /api/* 接口
数据库SQLite这个工作台自己的业务数据

Node 随 Floatboat 一起装好了,你不用另外装。每个空间最多放一个工作台,它在窗口里作为一栏显示,和文件浏览器、浏览器、对话并排。

目录结构

想自己改代码、或者让 Agent 改某个文件时,先知道东西都放在哪。用模板新建的工作台长这样:

manifest.json          工作台的身份、版本、要用的能力
package.json           npm 依赖
pnpm-lock.yaml         依赖锁文件
index.html             页面入口
src/ui/                页面代码(React)
src/server/index.ts    服务端入口
src/contracts/         页面和服务端共用的类型
migrations/            数据库迁移,0001_initial.sql 起
tests/                 测试
ENGINEERING.md         写给 Agent 的工程说明
DESIGN.md              写给 Agent 的设计说明

在 Floatboat 里用对话做的工作台,源码在 ~/.floatboat/<空间 ID>/workbench/。用外部 Agent 开发时结构一样,只是放在你自己的仓库里,业务代码在 app/ 下。

构建和运行

改完代码没生效、或者构建报错时,看这一节。每次你保存或 Agent 改完,Floatboat 会依次做四件事:

  1. 检查类型。 用严格模式,不允许显式的 any,也不允许用注释跳过类型检查。
  2. 打包服务端。 用 esbuild 打成 dist/server/index.mjs。
  3. 打包页面。 用 Vite 打成 dist/ui。工作台自己的 Vite、PostCSS 配置和 scripts 不会被执行,所以改这些不会有效果。
  4. 启动服务。 用随包的 Node 运行服务端,只监听本机 127.0.0.1 的一个随机端口,别的电脑连不进来。

页面代码里如果引入了 node:*、服务端代码或 SDK 的服务端模块,构建会报错(WORKBENCH_BROWSER_SERVER_IMPORT)。也就是说,读文件、连数据库这类事要放在服务端做,页面再通过 /api/* 去拿。

任何一步没通过,工作台会继续跑上一个能用的版本。你改坏了也不会把正在用的工作台弄崩。

什么时候在运行

如果你在意后台任务会不会被打断,看这几条:

  • 关掉面板不会停。 点「关闭面板(工作台继续运行)」后,服务还在后台跑,正在做的任务不受影响。
  • 退出 Floatboat 会停。 服务有 3 秒收尾,没做完的任务会标记为中断。
  • 「随 Floatboat 启动」(默认关):打开后,每次启动 Floatboat 都会把工作台跑起来。它只跑上次能用的版本,不会去编译还没检查过的改动。这个开关只在你这台电脑上生效,分享或上架时不会带走。
  • 自动更新(默认关):点「开启自动更新」后,源码一保存就自动检查、构建并换成新版本;检查不通过就继续用原来的版本。

第一次运行一个工作台时,会弹出「信任本地工作台」,写着「此程序及随包依赖可以访问计算机上的文件和网络。请仅运行你信任来源的代码。」点「信任并运行」才会启动。

清单文件 manifest.json

清单写明工作台是谁、哪个版本、要用哪些能力。Floatboat 会严格检查,写了它不认识的字段就会拒绝,所以拼写要和下面完全一致。

{
  "schemaVersion": 1,
  "appId": "workbench.2f1c9a7e-3b8d-4e51-9c0a-6d4f8b2e1a37",
  "registryName": "shop-inventory",
  "name": "网店库存",
  "description": "记录进货和销量,提醒补货",
  "version": "1.2.0",
  "minDesktopVersion": "0.5.11",
  "sdkVersion": "1.0.0",
  "runtime": "node22-sqlite-v1",
  "build": {
    "profile": "typescript-react-v1",
    "server": "src/server/*.ts",
    "ui": "index.html"
  },
  "capabilities": ["llm", "calendar"]
}
字段说明
schemaVersion固定 1
appId本机唯一 ID,Floatboat 新建时生成,不用改
registryName上架后的永久名字,之后改不了。只能用小写字母、数字、- 和 _,见规则一览
name / description / changelog名称(最多 120 字)、简介(最多 2000 字)、更新说明(最多 10000 字)
version版本号,主.次.修订,新建时是 0.1.0
minDesktopVersion可选。需要的最低 Floatboat 版本,低于它会拒绝构建(WORKBENCH_UPDATE_CLIENT_TOO_OLD)
sdkVersion / runtime / build固定为上面示例里的值
migrations数据库迁移目录
capabilities要用的 Floatboat 能力,见下一节,最多 8 项
contributions可选。在工作台里加命令、侧栏、工具栏或面板入口,最多 30 个
dependencies可选。依赖的 Workflow 或 Combo,最多 64 个
resources可选。要用的文件或文件夹,最多 64 个
connectedServices可选。要用的连接服务,最多 32 个;写了它,capabilities 里也要有 connected-services
license可选。许可证,最多 100 字

能调用哪些 Floatboat 能力

写文字、听写、请 Agent 干活、读你的日程这些事,工作台要借 Floatboat 的能力来做。

调用方式是在服务端用 app.host。用哪项,就在 capabilities 里写哪项,没写的调用会被拒绝。写了也不等于一定能用:每次调用 Floatboat 都会再查一遍,比如工作台有没有启用、你有没有登录、账号有没有开通工作台。

capabilities 里写界面上叫能做什么
llm模型调用让模型写一段文字、按格式输出 JSON,或者边写边显示
asr语音识别把对着麦克风说的话实时转成文字
agentAgent 任务把一件要动手的事交给 Agent 在后台做完,或者和 Agent 来回对话
workflows工作流运行你已有的 Workflow
connected-services连接的服务用你在 Floatboat 里连接过的账号调用外部服务
calendar日程查、建、改、删日程
automation自动化创建和管理定时让 Agent 执行的自动化
workspaces—列出、新建、切换空间,或者在空间里打开一个网页

有一个调用不用声明就能用:capabilities.list。它会告诉你每项能力此刻能不能用(available 能用、not-declared 没声明、account-required 需要登录或开通账号),以及每个操作的参数格式。开发时先调它,比看文档更准。

所有调用默认 120 秒超时,单次请求不超过 2 MiB。耗时长的活交给 agent 或 workflows,再用它们的 events 跟进度。

模型调用 llm

需要 AI 帮你写一段话、改写、归类、提取信息时用它。比如老师把全班的作文评语交给它,让它按「优点 / 要改进」整理成固定格式;做市场的把一周的活动数据交给它,让它写成一段周报。

app.route('POST', '/api/summary', async ({ body, host }) => {
  const result = await host.llm.generateText({
    system: '你是网店运营助手,回答简短。',
    prompt: `把今天的入库记录写成一段话:${JSON.stringify(body.records)}`,
    maxOutputTokens: 800,
  });
  return { summary: result.text };
});

三个操作,按你想怎么拿结果来选:

操作用途
generateText一次返回完整文字
generateObject按你给的 JSON Schema 输出,返回结果里带解析好的 object,适合直接存进数据库
streamText一边生成一边返回,适合在页面上逐字显示
  • 输入:prompt 最多 20 万字符,system 最多 3 万字符,maxOutputTokens 1–32768(默认 4096),temperature 0–2。generateObject 的 Schema 最多 5 万字符。
  • 模型:model 可以不填,用平台默认的轻量模型;要填的话,得是你账号能用的模型。
  • 只有单轮文字:不能输入图片,也不能让模型调用工具。它只会「写」,不会「做」:要它读文件、跑命令、上网查资料,用 agent。
  • 用量:和平时对话一样,算在你当前登录的账号上,会用掉积分。返回结果里有 usage,写着输入、输出各用了多少 token。

语音识别 asr

想让工作台「听写」时用它:说话,实时出文字。比如店主边盘货边念「A 款进了 20 件」,直接记进库存;自由职业者开会时把客户的要求实时记下来;学生把课上的要点口述成笔记。

声明了 asr,工作台页面才会被允许用麦克风。流程是三段接力:页面在用户点按钮后用 getUserMedia 录音,把音频交给自己的服务端,服务端再转给 Floatboat 识别。

const { streamId } = await host.asr.start({ sampleRate: 16000, format: 'pcm', hotwords: ['补货', '入库'] });
await host.asr.sendFrame({ streamId, sequence: 0, pcmBase64 });
for await (const event of host.asr.events({ streamId })) {
  // 实时拿到识别出的文字
}
await host.asr.stop({ streamId });
  • 音频格式:16 kHz、单声道、16 位 PCM,每帧不超过 128 KiB,用 base64 传。浏览器录到的音频通常不是这个格式,页面或服务端要先转一下。
  • 热词:最多 100 个,每个最多 100 字。热词是你提前告诉它「这些词会出现」,比如店名、学生名字、产品型号。不常见的词放进去,识别更准。
  • 可选:semanticPunctuationEnabled 自动加标点,speakerDiarizationEnabled 区分不同说话人(适合会议记录)。
  • 限制:同时最多 8 路;60 秒没收到新的音频帧会自动结束。录音中途停掉过,要重新 start 一路。
  • 操作:start、sendFrame、events、get、stop、cancel。

Agent 任务 agent

有些事不是「写一段话」,而是要真的动手:打开文件、跑命令、上网查。这时交给 Agent。比如做销售的让它「读这个文件夹里的报价单,整理成表」;行政让它把一堆发票 PDF 汇总成报销清单。

它在工作台所在的空间里后台运行,用的是和平时对话一样的 Floatboat Agent,能跑命令、改文件、查网页。

const run = await host.agent.start({
  prompt: '把 ~/报价单 里的 PDF 汇总成一张 CSV,按供应商分组。',
  workingDirectory: '/Users/me/报价单',
  idempotencyKey: `quote-${Date.now()}`,
});
for await (const event of host.agent.events({ runId: run.runId })) {
  // 进度和结果
}
  • 两种用法:start 跑一次就结束;conversations.create / send 是和 Agent 来回对话,聊天记录会保存下来。
  • 输入:prompt 最多 10 万字符;workingDirectory 要填一个已存在的绝对路径,Agent 就在这个文件夹里干活。
  • idempotencyKey 必填。 它是你给这次任务起的唯一编号。网络抖了一下、你的代码重试时,Floatboat 认出是同一个编号,就不会把同一件事做两遍。所以每件不同的任务要用不同的编号,同一件任务重试时用同一个。
  • 时长:默认最多 10 分钟,可以设到 60 分钟。同时最多 8 个。耗时很长的活要拆开,或者改用 workflows。
  • Combo:清单里依赖的 Combo 准备好后,会一起加载给 Agent 用;必需的 Combo 没准备好时报 WORKBENCH_CONFIGURATION_REQUIRED。
  • 用量:和平时让 Agent 做事一样,会用掉积分。
  • 操作:start、get、list、findByIdempotencyKey、events、cancel,以及 conversations.create、list、get、messages、send。

工作流 workflows

如果你已经有一条做好的 Workflow,工作台可以直接按一下就跑它,不用重新写一遍。比如做市场的在工作台里放个按钮,一点就跑「每周竞品汇总」那条 Workflow。

  • 清单里写了 dependencies 时,用 dependency 指定依赖的 ID;没写时,可以用 name 按名字找。
  • 可以指定 workspaceId 在别的空间里跑,最长 24 小时。
  • 收费的 Workflow 照常按它的价格收费。
  • cancel 只能取消这个工作台自己发起的运行,你在别处手动跑的它管不到。
  • 操作:start、get、list、findByIdempotencyKey、events、cancel。

连接的服务 connected-services

想让工作台读写你在别处的数据时用它,前提是这个账号已经在 Floatboat 里连接过。比如行政读一份在线表格里的报名名单,产品经理把整理好的需求写进团队的在线表格。

  • 先在清单的 connectedServices 里写要用哪家,比如 { "id": "sheet", "provider": "connector:<名字>" },再在 capabilities 里声明 connected-services。
  • 还没连接时,调 requestConnection 或 connect,Floatboat 会弹出「连接」加服务名的窗口,让你授权。连接请求 10 分钟内有效,过期了要重新发起。
  • 工作台拿不到你的密码或令牌。 账号授权都留在 Floatboat 里,返回的结果也会去掉敏感信息。
  • 写入类的调用失败后不会自动重试,免得同一条数据写两遍。要不要重试,由你的代码自己判断。
  • 想知道有哪些服务、每个服务能做什么,用 searchProviders、search、describe 查目录。
  • 操作:searchProviders、search、describe、listConnections、getConnection、requestConnection、getConnectionRequest、cancelConnectionRequest、connect、call。

日程 calendar

让工作台帮你排时间、查安排。比如自由职业者的接单工作台,客户确认后自动把交付日期放进日程;学生把这学期的考试安排一次性建进日历。

  • 可以操作 Floatboat 日历(默认),也可以操作电脑的系统日历。
  • 新建日程要同时给时间和时区,标题最多 300 字。
  • 删除重复日程时,要说明删这一次、以后的,还是全部。
  • 操作:search、get、create、update、delete。

自动化 automation

让工作台替你设一个定时任务,到点让 Agent 去做。比如店主设「每天早上 9 点检查库存,低于 10 件就列出来」,做市场的设「每周一整理上周的数据」。详见自动化。

  • 新建和修改分两步:先 preview 拿到预览和一个 10 分钟有效的令牌,再用完全相同的内容调 create 或 update。这样能保证真正建出来的,就是用户看过的那一份。
  • Floatboat 不会替你弹确认框。 预览结果要由工作台自己显示给用户,用户点了确认再创建。
  • 要写明信任级别,也就是允许 Agent 动手到什么程度;执行方式默认只读。
  • runs 能查最近的运行记录,默认 30 天内,最多查 366 天、200 条。
  • 操作:preview、create、update、archive、list、get、runs。

空间 workspaces

让工作台帮你管理空间、打开网页。比如产品经理的项目工作台,点一下就为新项目建好空间,再打开项目的需求文档页面。

  • list、create、activate:列出、新建、切换空间。新建时可以指定文件夹,也可以选用独立的浏览器身份。
  • openUrl:在空间里打开一个网页,只支持 http 和 https。
  • 切换空间和打开网页要 Floatboat 窗口正开着,否则返回 WORKSPACE_UI_UNAVAILABLE,所以后台自动跑的代码要处理好这个错误。

不经过 Floatboat 的部分

工作台自己的事,比如给页面提供接口、存数据,都在它自己的服务端里完成,不用声明能力:

接口用途
app.route(method, path, handler)给页面提供接口,路径以 /api/ 开头,支持 GET、POST、PUT、PATCH、DELETE
app.database工作台自己的 SQLite(Node 内置的 node:sqlite)
app.action(name, handler)响应清单 contributions 里加的按钮和命令
app.trackTask(fn) / app.tasks()记录长任务的状态,退出时没做完的会标记为中断
app.resources.path(id, rel)拿到清单 resources 里文件或文件夹的真实路径,不允许跳出这个范围

页面这边用 connectWorkbenchPage() 拿到 page.fetch,它只能请求自己服务端的 /api/*。

数据怎么存

想知道数据会不会丢、换电脑怎么带走,看这一节。

  • 数据库在 <Floatboat 数据目录>/workbench/data/<appId>/data.sqlite,和源码分开放。改代码、重新构建都不会丢数据。
  • 表结构用 migrations/NNNN_名字.sql 管。迁移文件就是一条条「改表」的记录,按编号依次执行。它只能往后加:要改表,就新写一个文件,别去动老的。已经执行过的迁移文件被改了或删了,启动会报错。
  • 分享或导出时,可以选择带不带数据。

和对话里的 Agent 怎么配合

  • Agent 写代码。 你在空间里让 Agent 改工作台,它会用专门的工具新建工作台、读编写指南、检查构建,并用 workbench_runtime 打开、查看日志、停止或重装工作台。
  • Agent 知道你的工作台在哪。 每次对话,Floatboat 都会把当前空间里工作台的源码位置和说明文档告诉 Agent,你不用每次重复。
  • 你可以让 Agent 打开它。 说一句「在旁边打开网店库存」,它会调用 workbench.open,见 Agent 能调用的客户端动作。
  • 方向是单向的。 工作台可以用 agent 能力请 Agent 干活;但工作台不能给对话里的 Agent 加新工具。

依赖与资源

npm 依赖

想在工作台里用别人写好的 npm 包时,注意这几条:

  • 只支持纯 JavaScript 包。带原生二进制(.node、.dll、.dylib、.so、.exe)的包会被拒绝,所以一些要编译的包(常见于图片处理、数据库驱动)用不了,挑包时先看一眼。
  • 锁文件要用 pnpm 的 pnpm-lock.yaml,每个依赖都要带完整性校验。
  • 安装时,Floatboat 用自带的 pnpm 从 registry.npmjs.org 下载,不执行任何安装脚本,也不读你电脑上的 npm 配置。所以你本机设的镜像源、私有源在这里不起作用。
  • 依赖加起来不超过 100 MiB、1 万个文件;源码不超过 100 MiB。
  • 模板预装了 React 19 和 lucide-react 图标库。

依赖的 Workflow 和 Combo

工作台要用到某条 Workflow 或某个 Combo 时,在 dependencies 里声明。每项可以来自三个地方:

  • bundle:直接打包在工作台里,跟着一起走。
  • binding:安装后让用户从自己已有的里面选一个。
  • registry:指定市场上某个确切版本。

用户可以在工作台的「依赖与资源」里查看和调整。

文件和文件夹

工作台要读写某个文件或文件夹(比如一份素材、一个导出目录),在 resources 里声明:

字段取值
kindfile 或 directory
roleasset(只读素材)或 data(读写数据)
locationproject(工作台源码里,只能放素材)、data(数据目录里)、external(用户自己选一个位置)
accessread 或 read-write
transfer分享或导出时,snapshot 带上一份副本,rebind 让对方重新选位置(只有 external 能用)

安全边界

运行别人的工作台之前,值得花一分钟看完这几条:

  • 工作台的服务端是一个普通的 Node 程序。 它能读写你电脑上的文件,也能联网。这也是第一次运行时要你点「信任并运行」的原因:只运行你信任的工作台。
  • 页面被关在框里。 页面只能请求自己服务端的接口,不能直接连外部网站;只有声明了 asr 才能用麦克风。
  • 拿不到你的账号凭据。 Floatboat 的登录信息、模型密钥、连接服务的令牌都不会交给工作台。
  • 每次调用都会重新检查。 退出登录、停用工作台、换账号之后,之前的调用会立刻失效。

上架时「内容详情」里写的是什么

上架时在窗口里展开「内容详情」,会看到几项和本页对应的信息,方便你核对:

内容详情里对应
运行时runtime,即 node22-sqlite-v1
SDK 版本sdkVersion,即 1.0.0
能力capabilities 声明了几项
最低客户端版本minDesktopVersion,写了才显示

上架流程见上架工作台。

不支持的

现在的 SDK 还没有这些:语音合成(把文字念出来)、图片生成、向量和 embedding、给用户发通知、让工作台向对话里的 Agent 提供工具。

真需要的话,有两条路:用 agent 让 Agent 去做,或者在服务端自己接第三方服务。

接下来

本页目录