<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kristian-Roopnarine</title>
    <description>The latest articles on DEV Community by Kristian-Roopnarine (@kristianroopnarine).</description>
    <link>https://dev.to/kristianroopnarine</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F516047%2F2f72c573-8a48-469d-b8da-4e23acda2f84.jpeg</url>
      <title>DEV Community: Kristian-Roopnarine</title>
      <link>https://dev.to/kristianroopnarine</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kristianroopnarine"/>
    <language>en</language>
    <item>
      <title>Kitchen Nightmares: LangChain agents edition</title>
      <dc:creator>Kristian-Roopnarine</dc:creator>
      <pubDate>Thu, 25 Jun 2026 12:55:00 +0000</pubDate>
      <link>https://dev.to/kristianroopnarine/kitchen-nightmares-langchain-agents-edition-45co</link>
      <guid>https://dev.to/kristianroopnarine/kitchen-nightmares-langchain-agents-edition-45co</guid>
      <description>&lt;p&gt;TLDR?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Health application to parse recipes, create meals and meal plans&lt;/li&gt;
&lt;li&gt;Implemented agents using LangChain and LangSmith for agent observability, FastAPI and React for web app&lt;/li&gt;
&lt;li&gt;How using LangSmith can help diagnose agent bugs&lt;/li&gt;
&lt;li&gt;I fired the idiot sandwich agent&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who doesn't love a good home cooked&amp;nbsp;meal?
&lt;/h2&gt;

&lt;p&gt;Over the last couple of years, cooking has been something I've grown to love. I enjoy cooking great food for my fiancé and finding recipes that I can share with my family and friends. The hard and annoying part sometimes is sharing that recipe, either I can't find the link or I changed something I did in the recipe and I've forgotten. Maybe its a memory problem instead…&lt;/p&gt;

&lt;p&gt;Oh well, I'm an engineer so the only solution I know of is to buy a domain, build a side project and never ship it.&lt;/p&gt;

&lt;p&gt;At first I created a script that will fetch the recipe details and save them in a Postgres database. It solved the problem of finding these recipes again, it was just a select query to get the information, but another problem I had was handling different "recipe components". Some recipes included multiple dishes like a main, side, sauces etc. The parsed recipe contents would provide a list of the ingredients and instructions for ALL the components. There were times where I only made the main dish of one recipe, and the side dish of another so this automation still didn't solve the problem, that's where I had an idea that I GUARANTEE nobody else has had.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if I throw AI at this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Genius right? Claude thought so too.&lt;/p&gt;

&lt;p&gt;The idea is a FastAPI/React project that uses LangChain for agent invocation, and LangSmith for observability. The backend programmatically parses a recipe, then passes that in a prompt to a grouping agent which will find the different recipe components such as main, side, veggie, sauce etc and will group those components with their respective ingredients and instructions. There's a second structuring agent that will take the output from the grouping and create a structured response sent to the UI. I can then create a meal and/or meal plan using those components, calculate calorie information, mix and match components to create different meals and share the components or meal plan with others. Example of the UI shown below. It includes the inconsistent output. Notice the main dish doesn't have instructions!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe7w9thwzvmnvqlx812xf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe7w9thwzvmnvqlx812xf.png" alt="UI of proof of concept with bug" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The idiot sandwich&amp;nbsp;agents
&lt;/h2&gt;

&lt;p&gt;I am using 2 agents for the recipe extraction. One agent is responsible for grouping and generating the components, the other is responsible for just providing the structured output from the grouping agent. These are the bones of the dual agent execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ParsedRecipeComponentResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;tracker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AgentMetadataTracker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;grouping_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;grouping_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-haiku-4-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;recipe_fetch&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;grouping_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grouping_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grouping_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;callbacks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tracker&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;structuring_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-haiku-4-5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
        &lt;span class="n"&gt;response_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ParsedRecipeComponentResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;structuring_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;

    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;structuring_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;structuring_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grouping_result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;callbacks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tracker&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;sr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;structured_response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sr&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I already know what you're thinking. Why two agents? At first, when I tried to use one agent to do the grouping and produce the structured output, it was very unreliable. Sometimes the agent would generate duplicate components, two main dishes with one having all the ingredients and the other all the instructions. Sometimes the agent would forget the instructions in the output all together (shown in picture above), and other times it would just combine the entire recipe into one component.&lt;/p&gt;

&lt;p&gt;I then split it into two focused agents, one to group the recipes and one to just create the structured output. The funny thing is that this worked perfectly for the first day. After splitting the agent execution it worked really well, but when I went to implement the API call into the UI the NEXT DAY, the inconsistencies started showing up again. I was using print statements to try and debug the issues, which got quite annoying and that's when I learned about LangSmith. It's an observability platform that is agentic framework agnostic but integrates really easily with LangChain agent invocation.&lt;br&gt;
Using LangSmith, I am able to track the token cost, input/output per agent execution. Which is perfect because I created a "tracker" shown in the code above to try and monitor these metrics already, and its no longer needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvcslchx66zo601pxubam.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvcslchx66zo601pxubam.png" alt="LangSmith traces" width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the LangSmith tracing, it shows the latency, tokens and even cost! This will help when I try to optimize agent execution, can't improve what you don't measure. From the agent input/output I was able to assess that the grouping agent was working as expected. I saw the exact markdown output with the instructions and ingredients for each component, example shown below parsed from &lt;a href="https://nickskitchen.com/halal-chicken-recipe/:" rel="noopener noreferrer"&gt;https://nickskitchen.com/halal-chicken-recipe/:&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;Based on the recipe I retrieved, here are the distinct components of the Halal Chicken and Rice recipe&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;

&lt;span class="c1"&gt;## MAIN DISH: Marinated Halal Chicken&lt;/span&gt;

&lt;span class="c1"&gt;### Ingredients:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;½ cup plain whole-milk yogurt&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3 tablespoon neutral oil (canola or avocado)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 tablespoon white vinegar or lemon juice&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;6 clove garlic (finely grated)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;2 teaspoon ground cumin&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;2 teaspoon ground coriander&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;2 teaspoon dried oregano&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1½ teaspoon smoked paprika&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 teaspoon black pepper&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;2 teaspoon kosher salt&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;½ teaspoon ground turmeric&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;½ teaspoon ground ginger&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;2 pound boneless, skinless chicken thigh&lt;/span&gt;

&lt;span class="c1"&gt;### Instructions:&lt;/span&gt;
&lt;span class="s"&gt;1. In a large bowl, whisk together the yogurt, oil, vinegar or lemon juice, garlic, spices, and salt until smooth.&lt;/span&gt;
&lt;span class="s"&gt;2. Add the chicken and toss to coat completely.&lt;/span&gt;
&lt;span class="s"&gt;3. Cover and refrigerate for at least two hours, preferably overnight.&lt;/span&gt;
&lt;span class="s"&gt;4. Heat a cast-iron skillet or grill over high heat.&lt;/span&gt;
&lt;span class="s"&gt;5. Cook the chicken in batches for five to seven minutes per side until deeply browned with slight charring. Cook until the internal temperature reaches 165°F (74°C).&lt;/span&gt;
&lt;span class="s"&gt;6. Transfer to a cutting board and rest for 10-15 minutes.&lt;/span&gt;

&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;## SIDES: Yellow Rice&lt;/span&gt;

&lt;span class="c1"&gt;### Ingredients:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;2 cup long-grain white rice&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;2 cup chicken stock&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 tablespoon butter&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;½ teaspoon ground turmeric&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 teaspoon cumin seeds&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 bay leaf&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;¼ teaspoon garlic powder (optional)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 teaspoon kosher salt&lt;/span&gt;

&lt;span class="c1"&gt;### Instructions:&lt;/span&gt;
&lt;span class="s"&gt;1. Rinse the rice in a fine mesh strainer until the water runs mostly clear.&lt;/span&gt;
&lt;span class="s"&gt;2. Add the rice, chicken stock, butter, turmeric, cumin seeds, bay leaf, garlic powder, and salt to a rice cooker or pot.&lt;/span&gt;
&lt;span class="s"&gt;3. Cook using the white rice setting or simmer covered until tender.&lt;/span&gt;
&lt;span class="s"&gt;4. Fluff with a fork and keep warm.&lt;/span&gt;

&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;## SAUCES: White Sauce (Garlic Yogurt)&lt;/span&gt;

&lt;span class="c1"&gt;### Ingredients:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 cup mayonnaise&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;½ cup plain Greek yogurt&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;2 tablespoon lemon juice&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;2 tablespoon white vinegar&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;4 clove garlic (finely grated)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 tablespoon sugar&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 teaspoon black pepper&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 teaspoon salt&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 teaspoon dried dill&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 teaspoon dried tarragon&lt;/span&gt;

&lt;span class="c1"&gt;### Instructions:&lt;/span&gt;
&lt;span class="s"&gt;1. Whisk all ingredients together in a bowl until smooth.&lt;/span&gt;
&lt;span class="s"&gt;2. Add a little cold water if needed to thin to a pourable consistency.&lt;/span&gt;
&lt;span class="s"&gt;3. Transfer to a squeeze bottle (optional) and refrigerate for at least two hours, preferably overnight.&lt;/span&gt;

&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;## SAUCES: Red Sauce (Hot Chile)&lt;/span&gt;

&lt;span class="c1"&gt;### Ingredients:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;6-8 dried red chiles (chile de árbol or similar)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;4 clove garlic&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 tablespoon white vinegar&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1½ teaspoon paprika&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;½-1 teaspoon cayenne pepper (to taste)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;1 teaspoon kosher salt&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;½ cup neutral oil&lt;/span&gt;

&lt;span class="c1"&gt;### Instructions:&lt;/span&gt;
&lt;span class="s"&gt;1. Soak the dried chiles in boiling water for ten minutes.&lt;/span&gt;
&lt;span class="s"&gt;2. Add softened chiles, garlic, vinegar, paprika, cayenne, and salt to a blender and blend until smooth.&lt;/span&gt;
&lt;span class="s"&gt;3. With the blender running, slowly stream in the oil to emulsify.&lt;/span&gt;
&lt;span class="s"&gt;4. Add soaking liquid as needed to thin.&lt;/span&gt;
&lt;span class="s"&gt;5. Transfer to a squeeze bottle and chill for at least two hours.&lt;/span&gt;

&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;## SALADS: Lettuce and Tomato Salad&lt;/span&gt;

&lt;span class="c1"&gt;### Ingredients:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;iceberg lettuce (finely shredded)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ripe tomatoes (thinly sliced)&lt;/span&gt;

&lt;span class="c1"&gt;### Instructions:&lt;/span&gt;
&lt;span class="s"&gt;1. Finely shred the lettuce and thinly slice the tomatoes.&lt;/span&gt;
&lt;span class="s"&gt;2. Refrigerate until ready to serve to keep crisp.&lt;/span&gt;

&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="c1"&gt;## BREAD: Pita Bread&lt;/span&gt;

&lt;span class="c1"&gt;### Ingredients:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pita bread (warmed)&lt;/span&gt;

&lt;span class="c1"&gt;### Instructions:&lt;/span&gt;
&lt;span class="s"&gt;1. Warm the pita in a dry pan or oven until soft and lightly toasted.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is EXACTLY what I expect from the grouping agent and the structure agent receives this input too, but somehow doesn't consistently produce the correct output. Here is the output from the structuring agent with the above input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"components"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Marinated Halal Chicken"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"cuisine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Middle Eastern"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://nickskitchen.com/halal-chicken-recipe/`, "&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Yellow Rice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"cuisine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Middle Eastern"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://nickskitchen.com/halal-chicken-recipe/`, "&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"White Sauce (Garlic Yogurt)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"cuisine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Middle Eastern"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://nickskitchen.com/halal-chicken-recipe/`, "&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Red Sauce (Hot Chile)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"cuisine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Middle Eastern"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://nickskitchen.com/halal-chicken-recipe/`, "&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lettuce and Tomato Salad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"cuisine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Middle Eastern"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://nickskitchen.com/halal-chicken-recipe/`, "&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pita Bread"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"cuisine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Middle Eastern"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://nickskitchen.com/halal-chicken-recipe/"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example the instructions and ingredients are COMPLETELY missing, when this is the expected structured response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecipeComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Parsed Recipe Information&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Name of the recipe component&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cuisine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cuisine type inferred from the recipe &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(e.g. &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Indian&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Mexican&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Italian&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;). &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Unknown&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; if it cannot be determined.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;default_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;List of instructions for this recipe component&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ingredients&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;default_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;List of ingredients for this recipe component&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Source of where this recipe component was parsed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ParsedRecipeComponentResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;RecipeComponent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;List of components parsed from the recipe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have to fix these idiot sandwiches now, and it's definitely my fault. Thankfully with LangSmith I can help identify which agent is causing the issue, and whether I even need 2 agents at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First I want to fix the agent reliability - I noticed that the structured output contains a cuisine field that isn't part of my original prompt for the grouping agent, and isn't included in the markdown output. I wonder if this causes the structuring agent to become an idiot sandwich.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Adding LLM validation - I'm familiar with the LLM-as-a-judge pattern for output verification, but I feel like what would be overkill in this situation. I should be able to create a python function to validate the outputs, ensure the markdown is in the correct format and that the structured response does not contain duplicates etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improving Observability - I want a metric that links all agent executions to a parsing event. When a user triggers some parsing event, I want to be able to trace every aspect of that request.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to separate your test, development and production databases using NODE_ENV.</title>
      <dc:creator>Kristian-Roopnarine</dc:creator>
      <pubDate>Fri, 27 Nov 2020 18:22:42 +0000</pubDate>
      <link>https://dev.to/kristianroopnarine/how-to-separate-your-test-development-and-production-databases-using-nodeenv-anl</link>
      <guid>https://dev.to/kristianroopnarine/how-to-separate-your-test-development-and-production-databases-using-nodeenv-anl</guid>
      <description>&lt;h1&gt;
  
  
  Why should you separate your test, development and production databases?
&lt;/h1&gt;

&lt;p&gt;As your applications become more complex you're going to incorporate different methods of testing to help ensure that your application works as intended. Of course this doesn't make your application 100% bullet proof, which is why proper testing is important, but why is it important to separate our testing environment from development and production? When running test suites, there is usually some degree of changes made to the database in the form of updating entries, adding, deleting, forcing errors etc. We want to make sure that when we run our tests, they don't rely on previous data to ensure that one test doesn't influence another. An easy way to do this is to implement some clean up method before and after a test is run, which usually means clearing a database and filling it with the same dummy data. &lt;br&gt;
Running a test suite on a production database would be irresponsible because a test might have unwanted side effects and alter the state of our database, or worse it would reveal information about our tests and source code. The data inside of the production database is always changing as well, which means that a test suite might work one day, but fail another day because the same data was altered causing our tests to fail.&lt;/p&gt;
&lt;h1&gt;
  
  
  How to separate application environments using NODE_ENV
&lt;/h1&gt;

&lt;p&gt;We can store environment variables in the node process (highly encourage you to read up on this if you're not familiar). Then we can access any of these variables in any part of our program. These variables are also secure so it is common to store API keys, credentials and other secrets inside of the node process. When running our node applications we can set the NODE_ENV and conditionally change the applications settings based on this NODE_ENV. It is a common practice to store these variables as key=value pairs inside of a .env file shown below. &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The environment is set to development by default and one implementation of this is found below by changing our the URI to our database. &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This does not have to be used with mongoose, it was just an example. But depending on the environment our application will use a different database. This can be used to change the settings of other features as well, maybe you want to enter a testing environment for stripe, or sandbox environment to test an SDK.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to set NODE_ENV
&lt;/h1&gt;

&lt;p&gt;Now that we know how to conditionally render settings using NODE_ENV, how do we set NODE_ENV when running our application? A common approach is to set them in &lt;code&gt;package.json&lt;/code&gt; scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  ...
  "scripts": {
    "start": "NODE_ENV=production node ./app"
  }
  ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way you can start an app in either a test, development or production environment.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>backend</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Add docker to your NodeJS workflow in just 4 simple steps</title>
      <dc:creator>Kristian-Roopnarine</dc:creator>
      <pubDate>Wed, 18 Nov 2020 09:13:17 +0000</pubDate>
      <link>https://dev.to/kristianroopnarine/add-docker-to-your-nodejs-workflow-in-just-4-simple-steps-1ggn</link>
      <guid>https://dev.to/kristianroopnarine/add-docker-to-your-nodejs-workflow-in-just-4-simple-steps-1ggn</guid>
      <description>&lt;h1&gt;
  
  
  What is docker and why should you use it?
&lt;/h1&gt;

&lt;p&gt;Docker is a platform as a service which allows you to isolate an entire operating system via Linux containers. The files we create below are instructions for how Docker should build the Linux container. Dockerizing (is that a word?) your application should be the first step in your workflow as it provides a good base for your development and production environments. Onboarding new members to the project is easy too, just provide them the respective &lt;code&gt;Dockerfile&lt;/code&gt; and they’re good to go. Docker can become extremely complicated and you can add a lot of configuration to your application with Docker alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You will definitely benefit from spending time researching complex features of Docker!&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Add docker to your NodeJS app in 4 steps
&lt;/h1&gt;

&lt;p&gt;I don’t explain what the following code does, but docker has great documentation on it, &lt;a href="https://docs.docker.com/engine/reference/builder/" rel="noopener noreferrer"&gt;https://docs.docker.com/engine/reference/builder/&lt;/a&gt; .&lt;br&gt;
All of the following config files will be at the root of your project. These files will work for probably 90% of your NodeJS applications, barring specific configuration.&lt;br&gt;
If this is an application that will be shipped to production, create a separate &lt;code&gt;Dockerfile.prod&lt;/code&gt; that contains configuration for your production application. These config settings can be googled because there are many people who have used Docker in production. This helps separate dev vs prod configuration with ease.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;Dockerfile.dev&lt;/code&gt; with the following code:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;docker-compose.yml&lt;/code&gt; with the following code:&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;.dockerignore&lt;/code&gt; and add &lt;code&gt;node_modules&lt;/code&gt; to it. Any files/folders in the &lt;code&gt;.dockerignore&lt;/code&gt; will not be copied over to the Docker container. Since &lt;code&gt;node_modules&lt;/code&gt; is usually a large directory, adding this to a &lt;code&gt;.dockerignore&lt;/code&gt; this will speed up your build times. &lt;strong&gt;Add other files/directories you do not want to be copied into your docker container here!&lt;/strong&gt; &lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Execute the following commands in the root directory of your project depending on what you need:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;docker-compose up -d --build&lt;/code&gt; : Builds the container using Dockerfile.dev and starts your docker container in detached mode&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;docker-compose up -d&lt;/code&gt; Starts your docker container in detached mode&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;docker-compose down&lt;/code&gt; &lt;strong&gt;ALWAYS&lt;/strong&gt; run this command when stopping your container&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;docker ps&lt;/code&gt; Lists your current active containers&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the initial build is successful execute &lt;code&gt;docker ps&lt;/code&gt; and ensure that your container is running. If so, head on over to &lt;code&gt;localhost:5000&lt;/code&gt; where your application is hosted locally. You can change this port through the &lt;code&gt;port&lt;/code&gt; setting in the &lt;code&gt;docker-compose.yml&lt;/code&gt; .&lt;/p&gt;

</description>
      <category>docker</category>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
