DEV Community

Zhe
Zhe

Posted on

Designing a Multi-Model Answer Grid Without Hiding Uncertainty

A multi-model interface sounds simple: send one prompt, render several answers, and let the user compare them. The difficult part is not the columns. It is representing independent, asynchronous work without implying that agreement equals correctness.

This article sketches an interface contract for that problem. It is an illustrative design exercise based on public behavior, not a description of any private implementation.

Model each panel independently

If three providers receive a prompt, they will not finish together. One may stream immediately, one may pause, and one may fail. A single global loading boolean cannot represent those outcomes.

Start with a per-panel state:

type PanelStatus =
  | "queued"
  | "streaming"
  | "complete"
  | "error"
  | "cancelled";

type AnswerPanel = {
  panelId: string;
  modelLabel: string;
  status: PanelStatus;
  text: string;
  errorMessage?: string;
  startedAt?: number;
  completedAt?: number;
};
Enter fullscreen mode Exit fullscreen mode

The collection can now contain two complete answers and one error without pretending that the entire request failed. The UI can preserve readable results while offering a retry only on the failed panel.

Keep prompt identity outside the panels

Comparison is meaningful only when the displayed answers belong to the same prompt version. Store the prompt as an immutable turn record and associate every panel with that turn.

type ComparisonTurn = {
  turnId: string;
  prompt: string;
  createdAt: number;
  panels: AnswerPanel[];
};
Enter fullscreen mode Exit fullscreen mode

If the user edits the prompt, create a new turn. Do not silently replace the text above old responses. A tiny “edited” badge is not enough when the main purpose is comparison.

Design the grid for partial progress

The grid should answer four questions at a glance:

  1. Which model is represented by this panel?
  2. Is it still working?
  3. Is the visible text complete?
  4. What action is available next?

Skeleton loaders are poor once real tokens exist. Render the available text, retain a visible streaming indicator, and announce status changes to assistive technology without reading every token aloud. When a response completes, move focus only if the user initiated an action that requires it.

On narrow screens, columns become stacked cards. Preserve the shared prompt above them and keep model labels sticky or repeated. “Answer 1” and “Answer 2” are insufficient after cards move vertically.

Avoid a false consensus feature

It is tempting to count matching phrases or display “3/3 models agree.” That indicator can overstate what the system knows. Similar wording is not independent fact checking, and different wording is not necessarily substantive disagreement.

A safer comparison layer helps users inspect rather than declares a verdict. Possible features include:

  • manual highlighting of claims;
  • a user-created verification checklist;
  • per-answer copy controls that retain the model label;
  • a prompt for “What assumption differs across these answers?”;
  • a clear reminder to verify consequential claims with primary sources.

The public multi-model chat at Wikis AI demonstrates the core interaction: a shared prompt goes to selected models, responses stream independently in separate panels, and the reader can continue with a useful model. This public behavior is enough to motivate the state model above; it does not expose the service's internal architecture.

Separate discovery from focused follow-up

A broad question often needs orientation before conversation. A topic guide can provide the vocabulary, common distinctions, and paths for follow-up.

The public AI Wiki is presented as a collection of structured guides with source-answer comparison and follow-up options across AI topics. From a product-design perspective, that suggests two entry modes:

  • browse mode: select a topic and inspect organized perspectives;
  • question mode: send a specific prompt and compare live responses. Keep those modes connected but distinct. A guide is not merely a frozen chat, and a chat is not automatically a maintained reference page.

Make failure local and recoverable

Provider errors, timeouts, and cancellations should not erase successful answers. Give each panel its own recovery action and preserve the original turn.

function retryPanel(turn: ComparisonTurn, panelId: string) {
  return {
    ...turn,
    panels: turn.panels.map((panel) =>
      panel.panelId === panelId
        ? { ...panel, status: "queued", text: "", errorMessage: undefined }
        : panel
    ),
  };
}

Enter fullscreen mode Exit fullscreen mode

In production, retry semantics also need an idempotency strategy, cancellation support, and protection against duplicated billing or duplicated events. Those responsibilities belong in the real service boundary, not in a copy-pasted client helper.

Test transitions, not screenshots alone

A visual snapshot of three completed panels misses the risky states. Test the timeline:

  • all panels queued;
  • one streaming while another completes;
  • one fails after emitting partial text;
  • user cancels one panel;
  • retry affects only its target;
  • prompt editing creates a new turn;
  • mobile stacking preserves labels and reading order;
  • keyboard navigation reaches every panel action;
  • status announcements are concise.

Also test the product language. “Compared” is accurate. “Verified” is not, unless a separate verification process actually occurred.

The best multi-model grid does not choose a winner by decoration. It keeps provenance, progress, failure, and uncertainty visible enough that a person can make the next decision deliberately.

Top comments (0)