The client
Health data people wanted to act on
A consumer health-testing and nutrition company that helps people understand their own health data. Its customers take tests, read their results and want to know what to do next. For most of them, the next thing is what to eat.
The company had the results, the profiles and a recipe library. What it did not have was a way to connect them for one person.
The challenge
Generic advice on top of personal results
A user could see exactly what their tests said and still get the same meal suggestions as everyone else. Profiles, test data, recipe PDFs and ingredient data lived apart, so nothing linked a result and a goal to a specific dish.
What had to be connected
Personal results with generic guidance is the gap where customers lose interest. They had paid for insight and received a list.
Constraints
What we had to design around
- Health contextA meal plan built on someone’s test results is not a playlist. A nut-free user cannot get a recipe with almonds in it, however well it scores. Restrictions had to behave as rules, not preferences.
- Data shapeProfiles and test data, recipe PDFs, images and ingredient lists — in different formats and different places. The connections between them, not the records themselves, were what a recommendation needed.
- ExplanationPeople change what they eat when they understand why. Every suggestion had to come with a reason a user could read, tied to their own goals and results.
- IntegrationThe company already had an app its customers used. The capability had to arrive as an API that app could call, not as a separate product.
- Speed to valueThree weeks from kick-off to meal plans served through that API — so the foundations had to be small, clean and ready to grow.
Our approach
Model the relationships, then retrieve them
A recommendation is a path: this person, this goal, this result, this restriction, this recipe, these ingredients. Plain vector search finds recipes that sound similar. It cannot follow that path or prove a recipe respects every rule on it.
So we built the path first. A small ontology of users, goals, recipes, ingredients and dietary preferences, filled by triplet generation from the raw data. Graph-RAG then retrieves the user’s subgraph and hands the language model only what is true for that person — which is also what makes each answer explainable.
The solution
Five layers, from a test result to a plate
- Data processing — Profile and test data, images and recipe PDFs land in file storage. Feature extraction and embedding extraction run on the way in, with quality checks on critical fields such as recipe names and ingredient quantities.
- Graph construction — A prompt-templated triplet generator turns each record into subject–relation–object facts — a user, a weight goal, a value — which are indexed into the knowledge graph. The ontology covers recipes, ingredients, users and dietary preferences.
- Knowledge base — Three stores behind one interface: the knowledge graph on Amazon Neptune, a vector store on Aurora PostgreSQL, and conversation history, so a follow-up question knows what came before.
- Graph-RAG retrieval — A query becomes a vector, then a KNN and hybrid search over the graph. The matching subgraph and its linked documents go to the language model on Amazon Bedrock, which generates the answer from them.
- Agents and API — Context understanding, report analysis, meal recommendations and an explainer share the context engine. A FastAPI service exposes recommendation endpoints that take structured inputs from the app.


Responsible by design
Four rules for AI that tells people what to eat
Ground
Meals come from the graph, not the model’s memory.
Every recipe in a plan exists in the graph and connects to the user’s own profile and results. The language model writes; it does not invent food.
Constrain
A restriction is a filter, never a weight.
Dietary restrictions and preferences sit in the graph as relationships, so a recipe that breaks one is not retrieved at all. Guardrails check the output before it reaches the user.
Explain
No recommendation without a reason.
A dedicated explainer agent says why each meal fits — which goal, which result, which preference — in language a user can act on.
Learn
Feedback flows back into the context.
A feedback module and usage tracker capture how users respond to their plans, and feed it into the context engine for the next plan.
The second rule matters most. A ranking model can trade a restriction for a better score. A graph that never retrieves the recipe cannot.
Results
What changed for the customers
- Up to 40% higher customer satisfaction and retention — meal plans built on each user’s own data give people a reason to come back to the app.
- Real-time retrieval of personalised meal plans, pulled from the user’s subgraph rather than assembled from scratch on every request.
- Low-carb and vegan plans from one ontology, with relationships ready for new diets and use cases without a redesign.
- A reason attached to every recommendation, written by the explainer agent and tied to the user’s goals.
- Delivered in 15 working days — three epics, ending in tested recommendation endpoints and documentation for the API and its workflows.
Test results stopped being the end of the journey and became the start of a plan.
Beyond the numbers
What else changes
Every new test, recipe or diet becomes another set of nodes, not another feature. Add a recipe and it is immediately reachable for every user it fits. Add a new marker and report analysis can reason about it on the next request.
And because the answer is a subgraph, the company can see exactly why the system suggested what it did. That makes every plan easy to check and easy to trust.
If your customers get personal data and generic advice
The first question is which connections your data already holds. That is answerable from a sample of your records, before anything gets built.