A working journal of applied engineering Beta

jcousins/2026.04.002

NutriPlan

Personalised meal planning by vector retrieval over a curated database, with LLM optimisation against macro targets.

J. Cousins

Independent · London, UK

Submitted  2025-08 Revised  2026-04 Status  Beta
Abstract. We describe NutriPlan, a meal-planning system that combines vector similarity search over a curated meal database (pgvector with text-embedding-3-small, 1536 dimensions) with downstream optimisation by GPT-4o against user-specified calorie and macro targets. A separate, cheaper model (GPT-4o-mini) handles user feedback ingestion. The retrieval-then-optimise architecture is a deliberate alternative to pure LLM generation, which we found tends toward repetition and hallucinated nutritional content. The system meets calorie targets within ±10% and produces a full weekly plan in under two seconds end-to-end. The backend is a deployed FastAPI service on Render with 99.8% uptime; a SwiftUI iOS client is in beta.

Keywords retrieval-augmented generation · pgvector · FastAPI · GPT-4o · iOS · nutrition science

1Introduction

Meal planning is a constrained optimisation problem dressed as a creative one. Users have explicit constraints (calorie targets, macro splits, allergies, time budget) and implicit constraints (taste, variety, cuisine preferences) that they cannot or will not articulate as rules. Most existing tools are template-based: a fixed catalogue of plans tweaked at the margins. We argue that the right architecture is to separate retrieval (which meals are plausible candidates given preferences and history) from optimisation (which subset of candidates best meets the day's targets), and to keep both surfaces narrow enough to test.

2Method

2.1Retrieval over generation

Pure GPT-4o generation tended to produce repeated meals across days within a week and was difficult to ground against accurate nutritional data. We instead retrieve approximately 100 candidate meals via pgvector cosine similarity (text-embedding-3-small, 1536 dimensions) over a curated meal database, then ask the LLM to optimise within that candidate set. The retrieval step also gives us a natural diversity knob: we constrain candidate selection by 14-day meal history.

2.2Two-model pipeline

Generation uses GPT-4o for quality. Feedback analysis (parsing free-text user responses into preference signals) uses GPT-4o-mini for cost efficiency. The two are abstracted behind LiteLLM so we can swap models per-task without touching application code. This was a small decision with a large compounding payoff: most of the cost optimisation in the system has come from picking the right model for the right step rather than from any prompt engineering.

2.3Preference embeddings

Rather than capturing preferences as explicit rules ("user dislikes mushrooms"), we update a per-user preference embedding from positive and negative meal feedback. This generalises across cuisines and ingredients in ways an explicit rule set does not. The trade-off is that the system is harder to introspect: "why was this meal suggested" becomes a vector-distance question rather than a rule-trace.

2.4Nutrition engine

Daily energy and macro targets are computed from the Henry/Oxford equations per UK SACN guidelines, supporting user-defined macro splits (e.g., 40% carbohydrate, 30% protein, 30% fat). The optimiser hits calorie targets within ±10% and macro splits with under 5% variance.

3Implementation

LayerChoiceWhy
ClientSwift / SwiftUI · iOS 26Native performance, Liquid Glass design system.
BackendFastAPI · asyncHigh throughput, automatic OpenAPI, Pydantic validation.
DBSupabase (Postgres 15)Managed Postgres with pgvector, RLS for security.
Embeddingstext-embedding-3-small (1536d)Cosine similarity for meal retrieval, low cost-per-call.
GenerationGPT-4o (meals), GPT-4o-mini (feedback)Quality where it matters, cost efficiency where it does not.
AbstractionLiteLLMSwap models per-task without code changes.
HostingRenderSimple deploy from GitHub, env vars, free tier sufficient for MVP.

4Results

  • Calorie accuracy: within ±10% of target.
  • Macro targeting: user-defined ratios with under 5% variance.
  • End-to-end latency: under 2 seconds (retrieval + optimisation).
  • API uptime: 99.8% on Render.
  • Preference coverage: 100+ meals embedded into the user-feedback corpus.

5Discussion

The architectural call we keep returning to is the retrieval-then-optimise split. It is more code than a single LLM prompt, but it makes every other property of the system testable in isolation: nutrition targeting becomes deterministic, candidate diversity is a measurable quantity, and the LLM step is a small constraint-satisfaction problem rather than an open-ended generation task. We expect this pattern to generalise to other domains where the search space is finite and the optimisation surface is well-defined.

Near-term: complete the SwiftUI client and ship a TestFlight beta over summer 2026. Integrate Spoonacular and Edamam for richer recipe coverage. The product roadmap follows a freemium ladder: free calorie tracker, premium meal planning, pro for advanced personalisation and household coordination.

6References

  1. SACN, "Dietary Reference Values for Energy", UK Scientific Advisory Committee on Nutrition.
  2. Henry, C.J.K. (2005), "Basal metabolic rate studies in humans: measurement and development of new equations", Public Health Nutrition.
  3. Lewis, P. et al. (2020), "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks", arXiv:2005.11401.