Iterative Prompt Optimization and Model Selection for Nutritional Calorie Estimation

taralli · Healthcare · 2025 · source Agentic: no · promotional bias: low · source-backed · extracted with prompt 0.5.6 (schema v2)

Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.

Problem

Domain: Nutritional calorie estimation from free-text meal descriptions

Taralli needed to improve LLM-based calorie and nutrition estimation without relying on subjective vibe tests. The task required predicting total calories and macronutrients from messy food descriptions, measuring whether predictions were close enough to ground truth, comparing prompt optimization methods and model choices, and supporting both cloud fallback and offline iOS inference.

Constraints:

Architecture

Taralli's improvement loop starts from a measured evaluation dataset and DSPy metric rather than vibe testing. The developer mixed 107 examples from NutriBench and a prior golden dataset, defined an Accuracy@10% calorie metric, and tested vanilla DSPy prompting, bootstrap few-shot variants, MIPROv2, and GEPA across Gemini 2.5 Flash, Gemini 3 Flash, and DeepSeek v3.2. The winning production update used Gemini 3 Flash with a 16-example few-shot prompt, improving accuracy by about 15% over Gemini 2.5 Flash. Production inference uses OpenRouter with Gemini 3 Flash as primary, DeepSeek v3.2 as fallback, temperature 0.0, and an iOS path that can fetch or bundle an OpenAI-compatible prompt template for on-device LLM inference.

Diagram confidence: reconstructed (reconstructed from prose).

flowchart LR
  NutriBench_dataset["NutriBench dataset"] --> Taralli_evaluation_dataset["Taralli evaluation dataset"]
  Previous_golden_dataset["Previous golden dataset"] --> Taralli_evaluation_dataset
  Taralli_evaluation_dataset --> DSPy_Accuracy10_metric["DSPy Accuracy10 metric"]
  DSPy_Accuracy10_metric --> Prompt_optimizer_experiments["Prompt optimizer experiments"]
  Model_candidates["Model candidates"] --> Prompt_optimizer_experiments
  Prompt_optimizer_experiments --> Selected_few_shot_program["Selected few-shot program"]
  Selected_few_shot_program --> OpenRouter_model_gateway["OpenRouter model gateway"]
  OpenRouter_model_gateway --> DeepSeek_fallback_model["DeepSeek fallback model"]
  Selected_few_shot_program --> Template_converter["Template converter"]
  Template_converter --> Template_endpoint["Template endpoint"]
  Template_converter --> Bundled_prompt_template["Bundled prompt template"]
  Template_endpoint --> iOS_on_device_LLM["iOS on-device LLM"]
  Bundled_prompt_template --> iOS_on_device_LLM
Drag to pan · scroll or use +/− to zoom · reconstructed from the source's described component topology

Components

Component Role Interacts with
NutriBench dataset Research dataset of meal descriptions and nutritional labels used as one source for Taralli evaluation examples. Taralli evaluation dataset
Previous golden dataset Taralli's prior curated examples mixed with NutriBench data for local evaluation. Taralli evaluation dataset
Taralli evaluation dataset 107 examples of food descriptions, total calories, food groups, and source attribution. NutriBench dataset, Previous golden dataset, DSPy Accuracy10 metric, Prompt optimizer experiments
DSPy Accuracy10 metric Evaluation function that scores predictions by whether total calories fall within 10% of ground truth. Taralli evaluation dataset, Prompt optimizer experiments
Prompt optimizer experiments Vanilla, bootstrap few-shot, MIPROv2, and GEPA experiments over the evaluation dataset. Taralli evaluation dataset, DSPy Accuracy10 metric, Model candidates, Selected few-shot program
Model candidates Gemini 2.5 Flash, Gemini 3 Flash, and DeepSeek v3.2 variants evaluated for calorie estimation. Prompt optimizer experiments, Selected few-shot program
Selected few-shot program Gemini 3 Flash with a 16-example few-shot prompt selected as the best reliable production configuration. Prompt optimizer experiments, OpenRouter model gateway, Template converter
OpenRouter model gateway Routes production calls to Gemini 3 Flash with DeepSeek v3.2 as backup and temperature 0.0. Selected few-shot program, DeepSeek fallback model
DeepSeek fallback model Second-best model configured as a fallback in OpenRouter. OpenRouter model gateway
Template converter Transforms the optimized DSPy program into OpenAI-compatible messages for on-device use. Selected few-shot program, Template endpoint, Bundled prompt template
Template endpoint Receives a food description and returns populated OpenAI-compatible messages for iOS inference. Template converter, iOS on-device LLM
Bundled prompt template Backup path that lets the iOS app skip the template-fetching API call. Template converter, iOS on-device LLM
iOS on-device LLM Runs nutritional analysis offline using the optimized prompt template. Template endpoint, Bundled prompt template

Data flow

The developer builds a 107-example dataset from NutriBench v2 and a previous golden dataset, each with food description, calories, food groups, and source. A DSPy evaluation function computes whether the predicted calories are within 10% of ground truth and returns score plus feedback. Multiple prompt optimizers and model candidates are evaluated against that metric. The selected DSPy program is served through an OpenRouter-backed API with a fallback model, and a cached template converter turns the optimized DSPy program into OpenAI-compatible messages that the iOS app can use with an on-device model or bundle directly as a backup.

“I created a new dataset of 107 examples of food descriptions and their corresponding total calories”article, stated
“In short, we want the predicted calories to be within 10% of the ground truth calories. Which means our metric will then be Accuracy@10%.”article, stated
“The iOS app calls this endpoint, receives the populated template, and uses it with the on-device model.”article, stated

Why this architecture

The architecture separates measurement, optimization, production fallback, and edge inference. DSPy forces an explicit Accuracy@10% metric, optimizer experiments compare prompts and models reproducibly, OpenRouter gives model-switching and fallback flexibility, and the iOS template path moves inference offline while still reusing the server-optimized few-shot program.

4 supporting quotes
“One of the nice things about DSPy is that it forces you to write down your evaluation metric explicitly.”article, stated
“The few-shot approach is the most reliable one. It is model agnostic, performs well, and follows the styles of examples in a faithful manner.”article, stated
“Since I'm using OpenRouter, I can also define our 2nd best performing model as a back up”article, stated
“As a backup, we can bundle the template directly in the app to skip the API call entirely.”article, stated

Models used: Gemini 2.5 Flash · Gemini 3 Flash · DeepSeek v3.2 · GPT-4o · DSPy · MIPROv2 · GEPA · BootstrapFewShotWithRandomSearch · on-device LLM

Scale

Alternatives considered (roads not taken)

Continue vibe testing

Rejected because: The author argues that improvement requires numerical measurement before and after changes.

“I call bullshit. How are you supposed to improve something if you can't even measure it? How do you know you didn't just make it worse?”article, stated
“Vibes are useless:** You can't improve something you can't measure.”article, stated

Use GEPA-optimized prompts for production across models

Rejected because: GEPA worked respectably on Gemini 2.5 Flash but failed output formatting on other models, indicating model-specific overfitting.

“the GEPA prompt actually fails to provide the correct response format when used with any other model. In other words, the prompt was overfit to the model it was trained on.”article, stated

Use the incumbent Gemini 2.5 Flash production model

Rejected because: Gemini 3 Flash with the same optimizer and few-shot approach was about 15% more accurate.

“So, I decided to update Taralli to use Gemini 3 Flash with the few-shot approach.”article, stated
“This approach is ~15% more accurate when compared to the old version, which was running on Gemini 2.5 Flash, with the exact same optimizer.”article, stated

Rely only on cloud inference

Rejected because: Taralli added offline on-device inference, with a bundled template backup to avoid the API call entirely.

“One of the best new features is the ability to use Taralli completely offline with an on-device LLM for nutritional analysis.”article, stated
“As a backup, we can bundle the template directly in the app to skip the API call entirely.”article, stated

Patterns

eval-driven-development (evaluation)

Taralli defines an explicit Accuracy@10% metric, evaluates multiple prompt optimizers and models against a 107-example dataset, and chooses updates based on measured accuracy.

“One of the nice things about DSPy is that it forces you to write down your evaluation metric explicitly.”article, stated
“Measure first, understand how the current system is performing, try to improve it, and then measure again.”article, stated

model-routing (architecture)

The production configuration uses OpenRouter with Gemini 3 Flash as the primary model and DeepSeek v3.2 as a fallback model.

“Since I'm using OpenRouter, I can also define our 2nd best performing model as a back up”article, stated
“"models": ["deepseek/deepseek-v3.2:nitro"],”article, stated

cost-aware-routing (optimization)

The experiment explicitly compares cheap and fast closed/open models and later moves inference on-device to remove per-call API dependence for offline use.

“As for models, I chose some that were cheap and fast - some closed (Gemini) and other Open (DeepSeek).”article, stated
“One of the best new features is the ability to use Taralli completely offline with an on-device LLM for nutritional analysis.”article, stated

structured-output-contract (interface)

The calorie estimator expects structured nutritional outputs and the on-device path converts the optimized DSPy program into OpenAI-compatible message templates.

“the prompt was overfit to the model it was trained on. As a result, you only see one GEPA score in the results graph.”article, stated
“The code snippet below transforms a DSPy optimized program into OpenAI-compatible messages.”article, stated

rag-retrieval (retrieval)

RAG is not the chosen production update, but the source treats NutriBench RAG and possible future web/RAG augmentation as a candidate path for better nutritional estimation.

“Retrieval-Augmented Generation (RAG): A system that uses a retrieval database (which they called Retri-DB), to aid the LLM in estimating carbs.”article, stated
“I still believe that in order to get the best performance possible, we would probably need some sort of connection to the outside world (web search, RAG, or the likes).”article, stated

Tradeoffs

Use a 107-example eval set.

Chose a small mixed NutriBench/golden dataset for fast experiments over a larger but slower evaluation set.

Rationale: The developer wanted enough measurement to compare approaches while keeping iteration fast.

“I created a new dataset of 107 examples of food descriptions and their corresponding total calories”article, stated
“I could have used more, but wanted to keep things fast”article, stated

Choose few-shot Gemini 3 Flash for production.

Chose Gemini 3 Flash with 16 few-shot examples over GEPA, vanilla, MIPROv2, and the incumbent Gemini 2.5 Flash setup.

Rationale: This configuration had the best measured score while remaining reliable and model-agnostic in output formatting.

“The best performing model is Gemini 3 Flash with a set of 16 examples in the prompt. It achieves a score of around 60%.”article, stated
“The few-shot approach is the most reliable one. It is model agnostic, performs well, and follows the styles of examples in a faithful manner.”article, stated

Use OpenRouter for model fallback.

Chose Gemini primary with DeepSeek backup through OpenRouter over a direct single-model API integration.

Rationale: The abstraction makes it easy to configure a second-best fallback model without changing the application path.

“Since I'm using OpenRouter, I can also define our 2nd best performing model as a back up”article, stated
“"models": ["deepseek/deepseek-v3.2:nitro"], }, )` ## Running on the edge”article, stated

Run inference on-device for iOS.

Chose offline on-device LLM using an OpenAI-compatible prompt template over requiring cloud API inference for every nutrition estimate.

Rationale: The app can work in airplane mode, avoid a network dependency, and optionally skip even the template endpoint by bundling the prompt.

“One of the best new features is the ability to use Taralli completely offline with an on-device LLM for nutritional analysis.”article, stated
“As a backup, we can bundle the template directly in the app to skip the API call entirely. Long story short, Taralli now works on airplane (mode).”article, stated

Gotchas (what bit them)

Vibe testing cannot tell whether an LLM nutrition change helped or hurt.

Root cause: Without a numerical metric and baseline, prompt/model changes are judged subjectively.

Resolution: Define Accuracy@10%, create a test dataset, measure current performance, change one thing, and measure again.

“I call bullshit. How are you supposed to improve something if you can't even measure it? How do you know you didn't just make it worse?”article, stated
“Whenever you are improving a system, try to be scientific about it. Measure first, understand how the current system is performing, try to improve it, and then measure again.”article, stated

Small eval sets make results fast but less statistically settled.

Root cause: The developer used 107 examples to keep experiments fast, not because 107 was necessarily optimal.

Resolution: Treat the 60% result as a pragmatic benchmark and acknowledge room for larger or more rigorous evaluation.

“I created a new dataset of 107 examples of food descriptions and their corresponding total calories”article, stated
“descriptions and their corresponding total calories2.”article, stated

Prompt optimizers can overfit to model-specific behavior.

Root cause: GEPA optimized a prompt that worked with Gemini 2.5 Flash but failed output formatting on other models.

Resolution: Prefer the more model-agnostic few-shot approach for production portability.

“the GEPA prompt actually fails to provide the correct response format when used with any other model. In other words, the prompt was overfit to the model it was trained on.”article, stated
“The few-shot approach is the most reliable one. It is model agnostic, performs well, and follows the styles of examples in a faithful manner.”article, stated

Model upgrades can produce large gains with tiny code changes, but that also reveals model dependency.

Root cause: Changing only the model string from Gemini 2.5 Flash to Gemini 3 Flash improved accuracy about 15%.

Resolution: Evaluate model updates explicitly and keep a fallback model configured through OpenRouter.

“This approach is ~15% more accurate when compared to the old version, which was running on Gemini 2.5 Flash, with the exact same optimizer.”article, stated
“In conclusion, all I changed was a model string.”article, stated

Cloud-only nutrition inference can fail privacy, cost, or connectivity goals.

Root cause: A mobile calorie tracker may need to work without internet and avoid calling an API for every prediction.

Resolution: Convert the optimized DSPy program to OpenAI-compatible messages for an on-device LLM, with the prompt template bundled as backup.

“The iOS app calls this endpoint, receives the populated template, and uses it with the on-device model.”article, stated
“As a backup, we can bundle the template directly in the app to skip the API call entirely.”article, stated

Evaluation

Taralli evaluates nutrition estimation with a DSPy Accuracy@10% function over a 107-example dataset. The experiments compare prompt optimizers and models, track whether calorie predictions fall within 10% of ground truth, use feedback text for incorrect and correct predictions, and report the winning configuration's approximate 60% score plus a 15% improvement over the previous Gemini 2.5 Flash setup.

Metrics: Accuracy@10% for total calorie prediction · score 1 for within threshold and 0 for incorrect · feedback text for incorrect predictions · 107 examples · 16 few-shot examples in the winning prompt · around 60% score for Gemini 3 Flash few-shot · ~15% improvement over Gemini 2.5 Flash · NutriBench Acc@7.5g 66.82% carb baseline · NutriBench ~99% response rate for GPT-4o CoT

4 supporting quotes
“In short, we want the predicted calories to be within 10% of the ground truth calories. Which means our metric will then be Accuracy@10%.”article, stated
“The best performing model is Gemini 3 Flash with a set of 16 examples in the prompt. It achieves a score of around 60%.”article, stated
“This approach is ~15% more accurate when compared to the old version, which was running on Gemini 2.5 Flash, with the exact same optimizer.”article, stated
“The best performer is GPT-4o with a Chain-of-Thought prompt. It responds to ~99% of prompts (models can refuse to answer) and achieves an [email protected] of 66.82%”article, stated

Outcomes

The experiments used 107 local evaluation examples from NutriBench v2 plus a prior golden dataset. NutriBench itself has roughly 12,000 meal descriptions and tested 4 prompting techniques across 12 LLMs. The selected Taralli configuration uses 16 few-shot examples, reaches around 60% Accuracy@10%, and improves about 15% over the previous Gemini 2.5 Flash setup.

4 supporting quotes
“So, I decided to update Taralli to use Gemini 3 Flash with the few-shot approach.”article, stated
“This approach is ~15% more accurate when compared to the old version, which was running on Gemini 2.5 Flash, with the exact same optimizer.”article, stated
“the GEPA prompt actually fails to provide the correct response format when used with any other model.”article, stated
“One of the best new features is the ability to use Taralli completely offline with an on-device LLM for nutritional analysis.”article, stated