Inspiration

Every group chat has the same thread: "where should we eat?" Three people, three tastes, and the loudest person wins. Ask a general-purpose LLM and you get "something for everyone", which really means nothing for anyone in particular. The model cannot know how much you, a Bon Iver and Parasite person, will like a specific restaurant or film. Qloo can, and it can answer that separately for each person in the group. That is what turns "group recommendation" from a guess into something you can actually make fair.

What it does

Each person enters a name and two to five favourites: artists, films, shows, books, places, brands. You pick an occasion (dinner, night out, movie night, TV night or weekend trip), optionally a city and constraints (budget, vegetarian/vegan/gluten-free/halal, wheelchair access, family-friendly), and press Find common ground.

The agent then:

  1. resolves every favourite to a real entity in Qloo's taste graph,
  2. turns constraints like "vegetarian" or "wheelchair accessible" into real Qloo tags,
  3. builds a candidate pool from the group's combined taste and from each person alone, so a minority taste still gets candidates,
  4. asks Qloo how much each person would like every candidate, and which of their own favourites drove that score,
  5. ranks candidates by fairness: it maximises the satisfaction of the least-satisfied member (0.6 × minimum + 0.4 × mean, with a diversity penalty so the three options differ in kind).

You get three picks. Each one shows a satisfaction bar per person, a sentence for each person explaining why it fits them ("Your love of Bon Iver and Radiohead is what Qloo connects this film to"), and the Qloo links behind it. If one person is compromising, the app says so.

It also shows what a plain "average taste" ranking would have chosen and who it would have left behind. In our movie-night example, averaging picks Lady Bird and leaves Marco at 92%. Common Ground picks Captain Fantastic and keeps everyone at 93% or above.

An optional panel runs the same request through the LLM without Qloo. The difference is easy to see: the LLM-only answer mostly echoes the group's own favourites back and once invented a "film adaptation" of a TV series. There are no per-person scores and nothing is verified.

Finally, How the agent decided lists every agent step (and whether the LLM or the deterministic autopilot took it), every Qloo request with its key parameters, and how each favourite was resolved.

How we built it

  • Runtime: a single Cloudflare Worker serves the UI (plain HTML/CSS/JS, no build step) and the /api/plan endpoint.
  • Agent: a tool-using agent on Workers AI (Llama 3.3 70B with function calling). The tools are resolve_favourites, resolve_constraints, find_candidates, score_pool, rank and relax. The LLM drives the loop when budget allows; a "light" tier lets the LLM classify favourites and phrase explanations while a deterministic autopilot runs the Qloo plan; with no LLM budget the whole thing runs deterministically with templated text. The product never breaks when the free AI allocation runs out.
  • Qloo usage:
    • /search with type hints to resolve free-text favourites,
    • /v2/tags with filter.query and filter.parents.types to map constraints to tags,
    • /v2/insights with signal.interests.entities, filter.location.query, filter.tags, filter.price_level.max and filter.content_rating to build candidates,
    • and the core: /v2/insights with filter.results.entities + feature.explainability=true, called once per person, to score the same pool for every member and learn which favourites drove each score.
  • Parameter safety: Qloo silently ignores parameters that are invalid for an entity type, so every request goes through an allowlist transcribed from the Entity Type Parameter Guide and fails loudly instead of degrading quietly.
  • Fairness scoring: pure, unit-tested functions (normalisation per member, maximin score, regret, diversity, compromise flags). 31 unit tests run against a synthetic mock of Qloo, so the repo works without an API key.
  • Honest narration: the LLM may only rephrase facts derived from Qloo (satisfaction, linked favourites, shared tags). It is told never to invent venues, plots or prices.

Challenges we ran into

  • Cross-type signals. In a live run the LLM classified "Pride and Prejudice" and "Little Women" as books for a movie night. Qloo accepted the request but returned candidates without an affinity for that person, so they scored 0% everywhere. We now detect this, re-resolve that person's favourites as the occasion's own type, score again and say so in the notes.
  • Response shapes differ from the docs in small ways. For example, the resolved city comes back under query.localities.filter. We probed the live API endpoint by endpoint before trusting any field.
  • Free-tier limits. Workers AI's free daily allocation covers roughly 60 Llama-3.3-70B calls a day, so the agent counts calls in KV and degrades through three tiers instead of failing.
  • Speed. One run makes about 15–20 Qloo calls plus a few LLM calls and takes 20–60 seconds. The UI shows progress, and the trace makes the wait legible.

Accomplishments that we're proud of

  • The ranking is genuinely different from "average taste", and the app shows exactly when and why.
  • Every explanation is traceable to a Qloo response. Nothing in a pick's explanation is invented.
  • It runs end to end on free tiers, live, with a deterministic fallback.

What we learned

  • Per-person scoring of a fixed candidate pool (filter.results.entities) is the Qloo feature that makes group fairness possible; everything else is plumbing around it.
  • Restaurant and bar affinities cluster tightly, so fairness trade-offs show up most clearly for films and TV. Normalising per person matters.
  • Building with an AI coding agent was fastest when every assumption about the API was checked against a live response before it reached the code.

What's next

  • A shareable link per group, so each person adds their own favourites from their phone.
  • Learning from the group's final choice ("we went with option 2") to tune the fairness weights per group.
  • More occasions Qloo already covers: podcasts for a road trip, books for a book club, brands for a group gift.

Built With

Share this project:

Updates

Submission history