OpenAI Background Mode Research Report Generator Case Study
This is a composite implementation case, not a claim about one customer. It answers a common builder question: how do I build a background processing AI system using OpenAI background mode?
The example product is a research report generator. A user submits a topic, uploads or selects source material, asks for a structured report, and returns later to read or approve the result. The task can take minutes, may need citations, and should not fail just because the browser tab closes.
Quick answer
Section titled “Quick answer”Use OpenAI background mode for the long-running model response, but treat it as one execution step inside a product-owned job workflow:
| Layer | What the product owns | Why it matters |
|---|---|---|
| Job record | Internal job ID, user scope, report type, provider response ID, status, timestamps | The report needs a durable handle outside the API response |
| Source package | Uploaded files, selected URLs, internal records, citation requirements | Research quality depends on source boundaries |
| Status worker | Polling, terminal-state handling, retry classification, timeout policy | The job must continue after the client disconnects |
| Result store | Report artifact, citations, source notes, structured JSON, reviewer comments | Completion must be recoverable and auditable |
| Review gate | Ready for review, approved, rejected, returned for revision | A completed model response is not always a publishable report |
| Control actions | Cancel, retry, revise, approve, archive, expire | Long-running work needs explicit user and operator controls |
If those layers are missing, the product is not a background processing system. It is only a long API call with a delayed answer.
Case profile
Section titled “Case profile”| Attribute | Case design |
|---|---|
| Product feature | User-triggered AI research report generator |
| User | Analyst, founder, product marketer, sales engineer, or research operator |
| Input | Topic, audience, source URLs, uploaded files, report template, deadline sensitivity |
| Output | Structured report with executive summary, evidence table, recommendations, and citations |
| Runtime lane | OpenAI background mode for one tracked report job |
| Review boundary | Human review before publishing, sending, or using the report in customer-facing material |
| Poor fit | Thousands of independent rows or records that do not need per-user job status |
This is a good fit for background mode because one person cares about one report after the live request ends.
The wrong version
Section titled “The wrong version”The weak implementation looks like this:
- User submits a report request.
- Frontend starts a synchronous model call.
- The UI shows a spinner for several minutes.
- The browser tab closes or the connection drops.
- The product cannot tell whether the report finished, failed, or produced partial evidence.
- Support has no job ID to inspect.
This is the failure mode that background mode can help avoid, but only if the product owns job state around it.
Target architecture
Section titled “Target architecture”The healthier flow is:
| Step | System action | User-visible state |
|---|---|---|
| 1. Submit | Create internal report job before calling the model | Report queued |
| 2. Prepare | Validate sources, template, permissions, and report scope | Preparing sources |
| 3. Execute | Start OpenAI background response and store provider response ID | Generating report |
| 4. Poll | Worker retrieves status until terminal state | Still working, last checked time |
| 5. Store | Save report, citations, source notes, model metadata, and cost fields | Ready for review |
| 6. Review | Human approves, edits, rejects, or requests revision | Approved or needs revision |
| 7. Deliver | Make the final report available in the product | Complete |
The provider handles long-running response execution. The product handles trust, visibility, recovery, and business completion.
Minimal data model
Section titled “Minimal data model”Start with one durable report_jobs table or collection:
| Field | Purpose |
|---|---|
id | Product-owned job identifier shown in dashboards and support tools |
workspace_id and requested_by | Scope, permissions, billing, and audit attribution |
report_type | Market scan, vendor comparison, technical brief, due diligence, or customer memo |
input_summary | Support-safe summary of the request |
source_manifest_id | Links to uploaded files, URLs, internal records, or retrieval set |
provider_response_id | Connects the job to the OpenAI background response |
status | queued, preparing, running, needs_review, completed, failed, canceled, expired |
failure_class | timeout, provider_error, source_error, policy_block, validation_error, unknown |
result_pointer | Location of report artifact, JSON, citations, and evidence bundle |
review_state | not_required, pending, approved, rejected, revision_requested |
cost_metadata | model, service tier, token use, tool use, retry count, total runtime |
Keep provider state as one field inside your product workflow. Do not make provider state the workflow.
Progress UI contract
Section titled “Progress UI contract”The progress UI should not expose raw provider status alone. It should explain what the product is doing and what the user can do next.
| Product state | User copy | Available actions |
|---|---|---|
| Queued | Your report is queued. You can leave this page and return later. | Cancel |
| Preparing sources | We are validating sources and report instructions. | Cancel, edit request if not locked |
| Generating report | The report is running in the background. Last checked time is visible. | Cancel, view source list |
| Needs review | A draft is ready and needs human review before use. | Review, approve, request revision |
| Completed | The final report is ready. | Open, export, archive |
| Failed | The job stopped before completion. The failure class is visible. | Retry if retryable, contact support, revise input |
| Canceled | The job was stopped and will not continue. | Start a new report |
| Expired | The job missed the useful window or result-retention boundary. | Re-run with current sources |
Users trust long-running jobs more when they can see that the product still has a handle on the work.
Polling and cancellation behavior
Section titled “Polling and cancellation behavior”OpenAI’s background mode documentation supports creating a background response, polling response status, canceling an in-flight response, and streaming with a cursor when the response was created with streaming enabled. The product should translate those primitives into rules:
| Product rule | Implementation decision |
|---|---|
| Polling cadence | Poll frequently at first, then back off while showing last checked time |
| Terminal state | Store final output or failure class before changing product status |
| Cancellation | Make cancellation idempotent in the UI and clean up downstream artifacts |
| Dropped client | Treat browser close as normal; the worker owns progress |
| Partial evidence | Store source notes and partial artifacts only when they are safe to show |
| Retry | Retry provider or transient source failures; do not blindly retry policy or validation failures |
Cancellation deserves special care. If the user cancels twice, the UI should still show the same final canceled state. If downstream processing has already created draft files, decide whether they are deleted, retained for audit, or hidden from the user.
Source quality and review
Section titled “Source quality and review”A research report generator should not treat “model completed” as “report is trusted.” The review step should inspect:
- whether the cited sources exist and support the claims;
- whether source dates are appropriate for the topic;
- whether the report distinguishes facts from recommendations;
- whether the report used only authorized internal material;
- whether the output includes unsupported legal, medical, financial, or security claims;
- whether the report is safe for the intended audience.
Use deep research source quality and citation policy for the source layer and human escalation thresholds when the report needs expert review.
When Batch is the better answer
Section titled “When Batch is the better answer”Do not use this case pattern for every asynchronous workload.
| Workload shape | Better lane |
|---|---|
| One user asks for one report and wants status | Background mode plus product job state |
| Thousands of independent summaries or enrichments | Batch or another bulk processing lane |
| Short summary that finishes while the user is actively steering it | Interactive request |
| Report that can change records, send emails, or publish content | Background mode plus explicit approval gate |
If the workload is many independent records, compare OpenAI Batch API vs background mode before building a user-facing job system.
Cost and capacity checks
Section titled “Cost and capacity checks”Report generation can become expensive because it combines long context, retrieval, reasoning, retries, and review. Track:
- cost per completed report;
- p50 and p95 runtime;
- queued time before execution;
- model calls per report;
- source count and source retrieval failures;
- retry rate by failure class;
- review time and rejection rate;
- abandoned jobs;
- export or downstream-use rate.
These metrics show whether the feature is producing useful reports or only moving work into a hidden queue.
Failure modes to design out
Section titled “Failure modes to design out”| Failure mode | Prevention |
|---|---|
| The user loses the report after leaving the page | Create the job before execution and make the report retrievable |
| Support cannot inspect a failed job | Store internal job ID, provider response ID, timestamps, and failure class |
| A draft is treated as final | Add needs_review before completed for consequential reports |
| Retried jobs duplicate downstream artifacts | Make output writes idempotent and tied to job version |
| The report cites weak or missing sources | Store citation evidence and require source review for sensitive topics |
| A canceled job still appears active | Make product cancellation state authoritative and visible |
The best background systems are boring to operate. Every job has a state, owner, history, and next action.
Launch checklist
Section titled “Launch checklist”Before shipping this feature, answer:
- What internal job record is created before the OpenAI call?
- Which users can see, cancel, retry, or archive the job?
- What source material is allowed?
- What product states appear in the UI?
- How does polling continue after the browser closes?
- What failures are retryable?
- What counts as a completed report?
- Which reports require human review?
- How are citations, source notes, and artifacts stored?
- Which metrics prove the report was useful after completion?
If the team cannot answer these, the implementation is not ready for production use.
Compare next
Section titled “Compare next”Source note
Section titled “Source note”This case was checked on June 1, 2026 against OpenAI’s background mode guide and Responses API reference. The page translates the API primitives into a product workflow for one tracked research report job.