---
title: "Build a Recipe Finder Agent: Ingredient Matching, Dietary Filters, and Cooking Instructions"
description: "Build an AI-powered recipe finder agent that matches recipes to available ingredients, respects dietary restrictions, provides step-by-step cooking instructions, and suggests ingredient substitutions."
canonical: https://callsphere.ai/blog/build-recipe-finder-agent-ingredient-matching-dietary-filters
category: "Learn Agentic AI"
tags: ["Recipe Finder", "AI Agent", "Python", "Ingredient Matching", "OpenAI Agents SDK"]
author: "CallSphere Team"
published: 2026-03-17T00:00:00.000Z
updated: 2026-05-08T06:39:37.751Z
---

# Build a Recipe Finder Agent: Ingredient Matching, Dietary Filters, and Cooking Instructions

> Build an AI-powered recipe finder agent that matches recipes to available ingredients, respects dietary restrictions, provides step-by-step cooking instructions, and suggests ingredient substitutions.

## The Problem With Finding Recipes

You open the fridge, see half a dozen ingredients, and then spend twenty minutes scrolling through recipe websites filled with ads trying to find something that uses what you already have. A recipe finder agent solves this by taking your available ingredients, applying dietary filters, and returning matching recipes with full cooking instructions — all through a single conversational prompt.

This tutorial builds a complete recipe finder agent with an in-memory recipe database, fuzzy ingredient matching, dietary filtering, substitution suggestions, and step-by-step guidance.

## Project Structure

```bash
mkdir recipe-agent && cd recipe-agent
python -m venv venv && source venv/bin/activate
pip install openai-agents pydantic
mkdir -p src
touch src/__init__.py src/recipes_db.py src/matcher.py src/agent.py
```

## Step 1: Build the Recipe Database

We store recipes as structured Pydantic models with ingredients, tags for dietary info, and ordered cooking steps.

```mermaid
flowchart LR
    INPUT(["User intent"])
    PARSE["Parse plus
classify"]
    PLAN["Plan and tool
selection"]
    AGENT["Agent loop
LLM plus tools"]
    GUARD{"Guardrails
and policy"}
    EXEC["Execute and
verify result"]
    OBS[("Trace and metrics")]
    OUT(["Outcome plus
next action"])
    INPUT --> PARSE --> PLAN --> AGENT --> GUARD
    GUARD -->|Pass| EXEC --> OUT
    GUARD -->|Fail| AGENT
    AGENT --> OBS
    style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
    style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
    style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
    style OUT fill:#059669,stroke:#047857,color:#fff
```

```python
# src/recipes_db.py
from pydantic import BaseModel

class Ingredient(BaseModel):
    name: str
    amount: str
    unit: str
    optional: bool = False

class Recipe(BaseModel):
    id: str
    title: str
    tags: list[str]  # e.g., ["vegetarian", "gluten-free"]
    prep_time: int    # minutes
    cook_time: int
    servings: int
    ingredients: list[Ingredient]
    steps: list[str]
    substitutions: dict[str, str]  # ingredient -> substitute

RECIPE_DB: list[Recipe] = [
    Recipe(
        id="r001",
        title="Garlic Butter Pasta",
        tags=["vegetarian"],
        prep_time=5, cook_time=15, servings=2,
        ingredients=[
            Ingredient(name="spaghetti", amount="200", unit="g"),
            Ingredient(name="garlic", amount="4", unit="cloves"),
            Ingredient(name="butter", amount="3", unit="tbsp"),
            Ingredient(name="parmesan", amount="50", unit="g"),
            Ingredient(
                name="red pepper flakes",
                amount="1", unit="tsp", optional=True,
            ),
        ],
        steps=[
            "Boil salted water and cook spaghetti until al dente.",
            "Mince garlic and saute in butter over medium heat.",
            "Toss drained pasta with garlic butter.",
            "Top with grated parmesan and pepper flakes.",
        ],
        substitutions={
            "butter": "olive oil for dairy-free",
            "parmesan": "nutritional yeast for vegan",
            "spaghetti": "gluten-free pasta",
        },
    ),
    Recipe(
        id="r002",
        title="Chicken Stir Fry",
        tags=["gluten-free", "high-protein"],
        prep_time=10, cook_time=12, servings=3,
        ingredients=[
            Ingredient(name="chicken breast", amount="400", unit="g"),
            Ingredient(name="broccoli", amount="2", unit="cups"),
            Ingredient(name="soy sauce", amount="3", unit="tbsp"),
            Ingredient(name="garlic", amount="3", unit="cloves"),
            Ingredient(name="ginger", amount="1", unit="tbsp"),
            Ingredient(name="sesame oil", amount="1", unit="tbsp"),
        ],
        steps=[
            "Slice chicken into thin strips and season with salt.",
            "Heat sesame oil in a wok over high heat.",
            "Stir-fry chicken until golden, about 5 minutes.",
            "Add broccoli, garlic, and ginger; cook 4 minutes.",
            "Pour soy sauce over everything and toss to coat.",
        ],
        substitutions={
            "chicken breast": "tofu for vegetarian",
            "soy sauce": "coconut aminos for soy-free",
        },
    ),
    Recipe(
        id="r003",
        title="Black Bean Tacos",
        tags=["vegan", "gluten-free"],
        prep_time=10, cook_time=10, servings=4,
        ingredients=[
            Ingredient(name="black beans", amount="400", unit="g"),
            Ingredient(name="corn tortillas", amount="8", unit="pieces"),
            Ingredient(name="avocado", amount="2", unit="whole"),
            Ingredient(name="lime", amount="2", unit="whole"),
            Ingredient(name="cumin", amount="1", unit="tsp"),
            Ingredient(name="salsa", amount="1", unit="cup"),
        ],
        steps=[
            "Drain and rinse black beans, heat in a pan with cumin.",
            "Warm corn tortillas in a dry skillet.",
            "Mash avocado with lime juice and salt.",
            "Assemble tacos with beans, guacamole, and salsa.",
        ],
        substitutions={
            "corn tortillas": "flour tortillas (not gluten-free)",
            "black beans": "pinto beans or lentils",
        },
    ),
]
```

## Step 2: Build the Ingredient Matcher

The matcher scores recipes by how many of the user's available ingredients overlap with what each recipe needs. It supports partial matching and dietary filtering.

```python
# src/matcher.py
from src.recipes_db import Recipe, RECIPE_DB

def normalize(name: str) -> str:
    return name.lower().strip()

def match_recipes(
    available: list[str],
    dietary: list[str] | None = None,
    max_missing: int = 2,
) -> list[dict]:
    available_set = {normalize(i) for i in available}
    results = []

    for recipe in RECIPE_DB:
        # Dietary filter
        if dietary:
            if not all(
                d.lower() in [t.lower() for t in recipe.tags]
                for d in dietary
            ):
                continue

        required = [
            ing for ing in recipe.ingredients if not ing.optional
        ]
        required_names = {normalize(i.name) for i in required}
        matched = required_names & available_set
        missing = required_names - available_set

        if len(missing)  str:
    lines = [f"# {recipe.title}"]
    lines.append(
        f"Prep: {recipe.prep_time}min | Cook: {recipe.cook_time}min "
        f"| Servings: {recipe.servings}"
    )
    lines.append(f"Tags: {', '.join(recipe.tags)}")
    lines.append("\nIngredients:")
    for ing in recipe.ingredients:
        opt = " (optional)" if ing.optional else ""
        lines.append(f"  - {ing.amount} {ing.unit} {ing.name}{opt}")
    lines.append("\nSteps:")
    for i, step in enumerate(recipe.steps, 1):
        lines.append(f"  {i}. {step}")
    return "\n".join(lines)
```

## Step 3: Build the Agent

```python
# src/agent.py
import asyncio
import json
from agents import Agent, Runner, function_tool
from src.matcher import match_recipes, format_recipe

@function_tool
def find_recipes(
    ingredients: str,
    dietary_filters: str = "",
    max_missing: int = 2,
) -> str:
    """Find recipes matching available ingredients.
    ingredients: comma-separated list of what you have.
    dietary_filters: comma-separated dietary tags.
    """
    avail = [i.strip() for i in ingredients.split(",")]
    dietary = (
        [d.strip() for d in dietary_filters.split(",")]
        if dietary_filters else None
    )
    matches = match_recipes(avail, dietary, max_missing)
    if not matches:
        return "No matching recipes found."
    output = []
    for m in matches:
        output.append(format_recipe(m["recipe"]))
        output.append(f"Match: {m['match_pct']}%")
        if m["missing"]:
            output.append(f"Missing: {', '.join(m['missing'])}")
            sub_lines = [
                f"  {k} -> {v}"
                for k, v in m["substitutions"].items()
            ]
            output.append("Substitutions:\n" + "\n".join(sub_lines))
        output.append("---")
    return "\n".join(output)

recipe_agent = Agent(
    name="Recipe Finder",
    instructions="""You are a helpful cooking assistant.
Use the find_recipes tool to search for recipes based on
the user's available ingredients and dietary needs.
Present results clearly with cooking instructions.
Suggest substitutions for missing ingredients.
Ask clarifying questions about allergies or preferences
if the user hasn't specified them.""",
    tools=[find_recipes],
)

async def main():
    result = await Runner.run(
        recipe_agent,
        "I have spaghetti, garlic, butter, and parmesan. "
        "What can I make? I'm vegetarian.",
    )
    print(result.final_output)

if __name__ == "__main__":
    asyncio.run(main())
```

## Running the Agent

```bash
python -m src.agent
```

The agent identifies the garlic butter pasta as a perfect match, shows the full recipe with steps, and notes that no ingredients are missing.

## Extending the Project

**Scaling the database.** Replace the in-memory list with SQLite or PostgreSQL. Add a `search_by_tag` tool that queries recipes by cuisine type or cooking method.

**Fuzzy matching.** Use `difflib.SequenceMatcher` or the `rapidfuzz` library to handle misspellings — matching "parmesean" to "parmesan" automatically.

**Nutritional info.** Add a `calories`, `protein`, `carbs`, and `fat` field to each recipe and create a `get_nutrition` tool so the agent can factor macros into recommendations.

## FAQ

### How would I add hundreds of recipes without defining them all in code?

Store recipes in a JSON file or database and load them at startup. You can also build a scraper tool that pulls recipes from public APIs like Spoonacular or Edamam and converts them into your `Recipe` model format. The matcher works the same regardless of how many recipes are in the database.

### Can the agent handle ingredient amounts and adjust servings?

Yes. Add a `scale_recipe` tool that takes a recipe ID and target servings, then multiplies each ingredient amount by the ratio of target to original servings. The agent can call this tool after finding a match to present adjusted quantities.

### How do I make substitution suggestions smarter?

Replace the static substitutions dictionary with an LLM-based tool. When an ingredient is missing, the agent can call a `suggest_substitution` tool that sends the recipe context and missing ingredient to the model, getting back contextually appropriate alternatives based on flavor profiles and cooking chemistry.

---

#RecipeFinder #AIAgent #Python #IngredientMatching #OpenAIAgentsSDK #AgenticAI #LearnAI #AIEngineering

---

Source: https://callsphere.ai/blog/build-recipe-finder-agent-ingredient-matching-dietary-filters
