Bunship 上线了:把 AI 产品背后的重复工作,做成一套起点

Bunship 上线了:把 AI 产品背后的重复工作,做成一套起点

Bunship AI SaaS 模板上线记录:把图片生成、任务队列、积分计费、管理后台和项目文档接成一条完整流程,说明适用场景、已实现能力与启动方式。

—次点击8分钟阅读

Bunship 正式上线了。

做 AI 产品时,我越来越在意一个场景:用户输入提示词,点下生成按钮,然后呢?如果图片迟迟不出来,用户要去哪里找这次任务?刷新页面以后,进度还在不在?这次已经扣掉的积分,失败后怎么处理?

这些问题在演示的时候不显眼,但只要真的让别人使用,就会陆续出现。首页、登录框和一次成功的模型调用,可以很快做出来;把它们接成一个有账户、有任务记录、有计费,也能处理失败的产品,要补的事情多得多。

我做 Bunship,就是想把这部分反复出现的工作整理下来。它是一套面向独立开发者和小团队的 AI SaaS 启动模板,把前台应用、业务 API、管理后台和文档放在同一个项目里,让下一个产品能从一条已经组织好的业务流程开始。

想先看看实际界面,可以直接打开 Bunship 官网、图片生成 Demo 和 中文文档。这篇记录的是 2026 年 3 月上线时的设计与功能,配图也来自当时的文档版本;后续变化以官网和文档为准。

为什么从图片生成开始

我没有把第一条主流程做得特别宽,而是选择了图片生成。它足够直观:输入描述、选择模型、调整参数,最后得到一张图。第一次打开页面的人,不需要先理解整个系统,就能知道自己可以做什么。

但对开发者来说,这个过程又足够完整。图片模型往往需要等待,可能排队,可能失败;不同模型的参数和成本也不一样。有的接受参考图,有的按尺寸或数量改变费用,生成结果还需要存储和展示。把这一条流程做好,账户、队列、状态、文件和积分就都有了具体的落点。

Bunship 上线同期的图片生成页面:提示词、模型选择与参数控制放在同一个操作区。
Bunship 上线同期的图片生成页面:提示词、模型选择与参数控制放在同一个操作区。

页面里的提示词输入框只是入口。模型选择、参数表单、费用预估和任务历史,才是我希望一起交付的部分。开发者接入自己的产品时,可以替换默认模型、提示词预设和业务界面,同时保留后面的任务管理方式。

例如,做电商素材工具时,用户关心的可能是产品图、背景和尺寸;做头像工具时,关心的则是参考图、风格和生成数量。两个产品的页面可以很不一样,但任务从创建到完成、失败后的处理、生成结果的归属,不应该每次都重新设计。

一次点击之后,任务要有去处

上线前花时间最多的地方之一,是任务状态。

只在页面上放一个 loading 很容易,难的是回答它到底在等什么。任务还在队列里,还是已经交给供应商?是执行慢,还是运行进程已经不在了?任务明明超时了,页面为什么仍然显示“排队中”?如果恢复任务时又执行了一次,怎样避免重复处理已经结束的记录?

这些都是 3 月 10 日到 12 日开发记录里实际修过的问题:卡住的排队任务、超时状态展示、失败重试、结束状态保护,以及恢复扫描对数据库的压力。它们让我更确定,任务不能只活在某个浏览器页面的一次请求里。

因此,Bunship 把生成请求先变成一条可查询的任务记录,再交给队列执行。用户侧可以查看状态和历史,业务侧可以围绕同一条任务处理执行结果、取消和重试。页面刷新以后,仍然有记录可以追踪,而不是只剩一句“刚才好像提交过”。

对接模型时,上线版本已经整理了 fal、Replicate 和 KIE 的供应商接入。不同供应商仍然有不同参数和返回方式,适配层负责处理这些差异。接入一个新模型时,需要确认参数、输出和价格规则;不能只加一个模型名称,就假设它和其他模型完全一样。

我希望模板能节省的是这套组织方式,而不是把外部服务的不确定性隐藏起来。失败应该是一个明确状态,有原因、有后续动作,用户也应该知道接下来可以做什么。

队列怎么选,取决于应用跑在哪里

队列部分,上线版本保留了 Trigger.dev 和 BullMQ 两条路径。

最初很容易把“网站部署成功”和“后台任务能一直运行”当成同一件事。实际拆开来看,前端页面可以放在一个部署平台上,长时间执行的生成任务却需要另一个合适的运行位置。

如果使用 Trigger.dev,任务交给它的运行环境执行;如果自己有持久运行的服务,就可以选择 BullMQ,并配置 Redis。两种方式背后的运维工作不同,所以我把选择放到适配层,尽量让生成业务不必跟着部署方式一起重写。

部署方式

上线版本提供的队列路径

希望把后台任务托管出去

Trigger.dev,单独配置和部署任务运行环境

已有可以持续运行的服务

BullMQ + Redis,自行维护 worker 和运行资源

这里还有个容易漏掉的细节:前台有环境变量,不代表任务运行环境也有。数据库连接、供应商配置和对象存储权限,都要在真正执行任务的地方准备好。否则网站能打开,生成按钮也能点击,任务却没有条件完成。

恢复机制也需要跟着运行环境走。托管任务和自建 worker 可以采用不同的扫描方式,但最终要回答的是同一件事:一个长时间没有进展的任务,何时结束,如何通知用户,积分如何处理。详细配置放在 任务队列文档 中,文章里就不把所有环境变量再抄一遍了。

积分不能只剩一个余额数字

AI 生成会产生成本,所以计费从一开始就参与了这条流程。

我把订阅额度和钱包余额放到同一个使用场景里考虑:用户获得了多少可用额度,什么时候扣减,任务失败以后怎样补偿,每一笔变化能否查到来源。余额只是结果,后面的交易记录才让这个结果有办法解释。

上线时的实现包括订阅积分、钱包记录、任务费用预估和失败补偿。订阅额度与长期钱包余额有不同的使用规则,用户在界面上需要看得懂,后台也要有对应记录。否则一个“为什么少了几分”的问题,就会变成临时查数据库、猜执行顺序的排障。

价格同样不能写死在按钮旁边。模型不同,参数不同,消耗可能就不同。3 月 12 日补进来的分档参数定价和模型搜索,也是为了让模型选择、参数表单与实际费用更接近,而不是页面显示一个价格,执行时再按另一套规则计算。

支付侧,上线版本已经围绕 Stripe 组织了订单、订阅和 webhook 处理。接入自己的产品时,仍然需要用自己的测试环境验证付款成功、重复通知、退款以及权益变化。这些结果关系到账户的真实权益,一张结账成功页面不能代替完整验证。

我更希望开发者把这里当作可以继续核对和扩展的业务实现。每个产品的赠送额度、订阅规则、退款政策都可能不同,源码里有基础流程,并不意味着自己的商业规则可以省略。

后台和文档,也是产品的一部分

如果生成出了问题,开发者最终会需要一个地方查看它。只做用户页面,后面往往还要临时补订单查询、钱包记录、模型开关和内容管理。

Bunship 的 Admin 把用户、订单、商品、钱包、模型配置、限流和 CMS 放在一起。这样运营侧遇到问题时,至少有明确的入口可以查,而不是每件事都先找开发者写一条查询语句。

我也把模型参数与定价配置放进了后台。对已经支持的参数结构来说,调整模型配置不必总是从改页面开始。需要新能力时,仍然要扩展适配和校验逻辑,这个边界值得保留:后台能配置的内容应当有明确含义,不能靠一个任意 JSON 输入框把复杂性全部交给使用者。

内容侧则有文章、分类、标签和封面编辑。上线前,保存、发布与前台可见性的关系也反复修过。文章出现在编辑器里,和它已经能够被读者访问,是两个不同状态;做产品的介绍页和文档时,这种细节很容易被忽略。

中英文文档与演示入口放在站点里,是为了让拿到模板的人能沿着实际流程阅读。先看图片生成,再看队列和供应商,接着理解钱包与订阅,比打开一个巨大功能清单之后自己找连接更容易。

源码里,哪些东西放在一起

工程上,Bunship 使用 Bun workspace 和 Turborepo 管理项目。Web 基于 Next.js 16、App Router 和 React 19,API 使用 Elysia,认证接入 Better Auth,数据层使用 PostgreSQL 与 Drizzle,生成文件通过 S3 兼容对象存储保存。

对我来说,这些工具的价值在于让不同部分有清楚的位置。页面负责交互,API 负责业务请求,共享包承载通用的数据与能力;一个账户、一个订单或者一个生成任务,不必在多个应用里各自定义一套含义。

这也影响二次开发的方式。如果只是替换品牌、默认模型和提示词,可以先从配置与界面开始;如果要改变积分扣减规则,就应该进入业务服务和对应记录;如果要加新的生成供应商,就去处理适配与任务结果。知道该去哪里改,比“文件很多,看起来什么都有”更重要。

这套结构更适合已经准备做账户、付费和持续使用流程的 AI 产品。一个只展示静态内容的网站,或者还在验证单次模型调用的小实验,未必需要立刻用上所有模块。选模板时,最好先看自己的第一条用户流程,需要用到其中哪些部分。

如果准备试一试,我建议这样开始

先打开 图片生成页面 看交互,再读 快速开始,确认项目结构和部署要求是否适合自己。版本、购买方式与授权说明,以 官网定价页 为准。

拿到源码并进入项目目录后,基本的本地启动动作是:

bash
bun install
cp .env.example .env
# 按快速开始文档填写数据库、认证和站点配置
bun run db:migrate
bun run dev

这几行只是启动入口。真正开始接入自己的产品时,我会先只选一个模型、一套积分规则和一种队列,让一个用户能够注册、提交任务、看到结果,并查到相应的记录。第一条流程清楚以后,再增加模型和页面,比一开始打开所有开关更容易定位问题。

接着主动走一次失败路径:任务没有成功时,页面怎么说,记录处于什么状态,额度怎么变化。成功流程往往最容易被展示,而这些不顺利的情况,才会影响用户愿不愿意继续使用。

这次上线,对我来说是把反复写过、也反复踩过坑的一部分工作整理成了产品。之后做新的 AI 工具,我希望能把更多时间放在用户为什么需要它、一次操作究竟帮他完成什么上。

如果你也在做类似的产品,可以先从 Bunship 的 Demo 和文档看起。它的价值,最终还是要落在你准备交付的那条真实流程里。