GalleyGraph is a production-shaped reference implementation for an AI Engineer working on maritime procurement and catering. It combines a domain ontology, a typed knowledge graph, semantic ingredient substitutions, an explainable planning agent, and constraint optimization.
The demo solves a constrained weekly menu problem:
- uses only inventory that is available and not expired;
- respects dietary, religious, allergy and cultural constraints;
- finds ingredient substitutions only when their semantic role and cooking behavior are compatible;
- balances nutrition, cost, waste and menu diversity;
- returns a decision trace so a product user can see why every menu item was selected.
py -3.11 -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev,graph,agents]"
uvicorn app.main:app --reloadOpen http://localhost:8000. The UI calls the offline deterministic agent, so an LLM key is not needed for the demo. The API is available at http://localhost:8000/docs.
To run with Neo4j:
docker compose up --buildNeo4j is an optional persistence adapter. The default runtime uses the same typed graph contract in memory, which keeps local development and tests fast.
inventory + crew profile + recipe catalog
|
context retrieval
|
semantic substitution engine
|
recipe variants + hard filters
|
OR-Tools CP-SAT optimization
|
validation + explainability trace
|
API / web demo
The agent is implemented as explicit typed nodes in app/agents/menu_agent.py. This is inspectable and can be compiled into LangGraph when that optional package is installed. The LLM is not allowed to invent a final menu: it may propose candidates, while ontology constraints and the optimizer remain authoritative.
app/domain/ontology.py defines the vocabulary: Ingredient, Recipe, Cuisine, Restriction, Nutrient, CookingMethod, IngredientRole and InventoryLot. app/graph/store.py stores typed nodes and edges and supports indexed lookup, neighborhood inspection and JSON-LD export. The relation vocabulary includes HAS_INGREDIENT, PLAYS_ROLE, COMPATIBLE_WITH, USED_IN_CUISINE, SATISFIES_RESTRICTION and SUBSTITUTES_FOR.
app/services/substitutions.py applies hard gates first (role, allergen, dietary compatibility, cooking feasibility), then produces a weighted score with a human-readable breakdown. This prevents a language model from casually replacing a binding ingredient with something that only looks similar lexically.
app/optimization/solver.py creates a CP-SAT model with one recipe variant per meal slot, inventory consumption, budget, nutrition minimums, repeat limits and a diversity objective. A deterministic greedy fallback is included for environments where OR-Tools is not installed; production and Docker use CP-SAT.
Every result includes feasibility filters and rejection reasons, substitution scores and hard-gate decisions, selected recipe cost/nutrition/inventory consumption, optimizer summary, and agent node trace.
Invoke-RestMethod http://localhost:8000/api/demo-plan | ConvertTo-Json -Depth 20POST a MenuRequest to /api/plan. GET /api/ontology exposes the ontology contract. GET /api/graph exposes the graph for inspection. POST /api/substitutions returns ranked alternatives for one recipe.
- Persist the graph through the Neo4j adapter and use RDFLib/SHACL validation in CI for ontology changes.
- Replace the in-memory catalog with event-driven inventory lots and expiration events.
- Add graph-neighborhood retrieval plus document retrieval for GraphRAG.
- Add LangGraph checkpointing, human approval and tool-call audit logs.
- Add historical menu feedback, waste observations and price volatility to objective weights.
The key design boundary is deliberate: probabilistic retrieval and agents suggest; deterministic domain validation and CP-SAT decide.