如何為需時數分鐘的 AI 生成產品設計非同步等待體驗
Designing the Wait: Async AI Generation UX for Products That Take Minutes
作者以 Burning Bridges Studio 為例,分享為需時數分鐘的 AI 生成工作設計非同步等待體驗的方法,建議把生成流程保存為可持續追蹤的任務。介面應如實顯示預計耗時和任務階段,並提供可再次查找的任務清單;失敗時自動退還點數或配額。提交後若連線中斷,可用 20 分鐘恢復窗口查找既有任務,避免重複提交,生成結果亦應支援預覽與下載。
A photo goes in. A video comes out. In between, roughly ten minutes of nothing — and that gap is where AI products tend to lose people.
I build Burning Bridges Studio, a single-purpose tool that turns one photo into a short party video. Generation takes about ten minutes, so waiting had to become a designed part of the product instead of a spinner. This post is the pattern I settled on. It applies to any slow AI job — image upscaling, voice cloning, long-form writing — not just video.
1. Model the work as a task, not as a request
An HTTP request that stays open for ten minutes is fragile. Proxies time out, phones sleep, tabs close, and the user has no idea whether the work survived.
Store the work as a record that outlives the request:
type GenerationTask = {
id: string;
status: "queued" | "running" | "ready" | "failed";
createdAt: string;
updatedAt: string;
outputUrl?: string; // only when ready
errorCode?: string; // only when failed
};
Two consequences follow immediately:
- The UI can poll or subscribe to
statusinstead of holding a connection. - The user can close the tab and find the same task later, because the task belongs to the account, not to the page.
If your product charges per generation, attach the task id to the charge. That single foreign key makes refunds, support and duplicate-detection possible later.
2. Be honest about time
Never show a fake percentage. A progress bar that moves without meaning is worse than a plain statement, because users plan around it.
What has worked better:
- Say the expected duration in plain language: "About 10 minutes. Busy periods may take longer."
- Show the current stage, not a number: queued, generating, ready.
- Show when the task was last updated, so a stalled task is visible rather than mysterious.
- Keep polling cheap and idempotent; refresh should never create a second task.
The honest version sets a low expectation that is usually beaten. The optimistic version sets a high expectation that is usually missed.
3. Design for the second visit
Most of the ten minutes happen off-screen. That is the normal case, not an edge case.
Questions to answer in the UI:
- Can the user find the task from a list, not from a bookmark?
- Does the list show enough to identify the photo they used?
- Can they delete a finished or failed task without contacting support?
- Does the empty state explain what will appear there?
A task list also gives you a natural place to explain failures. "Failed" with no reason is a support ticket; "Failed — credits returned" is a resolved moment.
4. Make failure refund the user automatically
Slow jobs fail more often than fast ones, because there are more moving parts and longer windows in which something can break.
Decide the failure contract before launch:
- Credits or quota are returned automatically when the task fails.
- The task stays visible with a clear reason, not silently disappearing.
- Retrying creates a new task rather than mutating a failed one.
The third point matters for auditing. If a failed task can be edited into a successful one, you lose the record of what actually happened.
5. Return a file, not a walled garden
For anything with a visible output, let people take it with them. In my case the result is a 15-second, 16:9 MP4 the user previews and then downloads. Preview before download matters: it lets someone decide whether the result is worth keeping without leaving the product.
If results are only viewable inside your app, you are competing with a screenshot. A downloadable file is a small feature that changes how the product spreads.
6. Handle the interrupted submission
There is a nasty case between "task created" and "response received". If the network drops after the server accepted the work, the client cannot tell whether it should retry.
Two rules keep this from turning into double charges:
- Give the client a short recovery window (I use 20 minutes) in which it can look up the existing task instead of submitting again.
- Tell the user explicitly not to resubmit while recovery is running.
This is a small amount of state to track, and it prevents the most expensive support category: "I paid twice and got one video."
A short checklist
Before shipping a slow AI feature, check that:
- [ ] Work is stored as a task with explicit states.
- [ ] The expected duration is stated honestly.
- [ ] The task survives a page reload and is listed somewhere findable.
- [ ] Failure returns the user's credits or quota automatically.
- [ ] Results can be previewed and downloaded.
- [ ] Interrupted submissions cannot create duplicate charges.
None of these are novel. They are just easy to skip when the model demo works on the first try, and the demo never waits ten minutes.
I build Burning Bridges Studio, so I am describing my own product rather than reviewing it independently. The site publishes its terms, privacy, refund and support pages if you want to check how the pieces above are handled in practice. The ten-minute and 15-second figures are the product's stated estimates, not measured benchmarks.
來源:DEV Community · dev.to