<?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: rosidotidev</title>
    <description>The latest articles on DEV Community by rosidotidev (@rosidotidev).</description>
    <link>https://dev.to/rosidotidev</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F597573%2F7196bb7a-1d95-468f-8afc-a12a54ec9ceb.jpeg</url>
      <title>DEV Community: rosidotidev</title>
      <link>https://dev.to/rosidotidev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rosidotidev"/>
    <language>en</language>
    <item>
      <title>In-Depth Comparison: Workflow Control with LangGraph and CrewAI</title>
      <dc:creator>rosidotidev</dc:creator>
      <pubDate>Fri, 01 Aug 2025 15:47:07 +0000</pubDate>
      <link>https://dev.to/rosidotidev/in-depth-comparison-workflow-control-with-langgraph-and-crewai-ae3</link>
      <guid>https://dev.to/rosidotidev/in-depth-comparison-workflow-control-with-langgraph-and-crewai-ae3</guid>
      <description>&lt;p&gt;(Originally published on my blog: &lt;a href="https://roby73.hashnode.dev/in-depth-comparison-workflow-control-with-langgraph-and-crewai" rel="noopener noreferrer"&gt;https://roby73.hashnode.dev/in-depth-comparison-workflow-control-with-langgraph-and-crewai&lt;/a&gt;)&lt;br&gt;
Choosing between &lt;strong&gt;CrewAI&lt;/strong&gt; and &lt;strong&gt;LangGraph&lt;/strong&gt; for multi-agent orchestration isn’t trivial, especially for developers balancing rapid prototyping with future scalability.&lt;/p&gt;

&lt;p&gt;Personally, I gravitate toward &lt;strong&gt;CrewAI&lt;/strong&gt; for its straightforward setup and developer-friendly abstractions. It lets you build production-ready agent flows in minutes, staying focused on business logic rather than complex orchestration architecture. That ease of use and quick iteration cadence make CrewAI a great fit for many projects.&lt;/p&gt;

&lt;p&gt;That said, &lt;strong&gt;LangGraph&lt;/strong&gt; has quickly become the go-to framework for large, stateful projects in production, thanks to its expressive graph-based DSL and wide adoption among major tech players. It offers granular control over state, dependencies, and memory, which is often necessary for complex or long-running workflows.&lt;/p&gt;
&lt;h3&gt;
  
  
  Absolute Control Over Agent Steps: LangGraph vs. CrewAI
&lt;/h3&gt;

&lt;p&gt;One of LangGraph’s undeniable strengths is the &lt;strong&gt;absolute control it offers over every single step executed by agents&lt;/strong&gt; in the workflow. Thanks to its explicit graph-based architecture, you precisely define nodes, edges, and state transitions. This granular orchestration lets you monitor, intervene, and debug the entire flow of execution with full visibility.&lt;/p&gt;

&lt;p&gt;In contrast, &lt;strong&gt;CrewAI’s abstraction via agents and tasks simplifies setup and speeds development&lt;/strong&gt;, but sometimes this comes at the cost of &lt;strong&gt;less direct visibility and control over internal step execution&lt;/strong&gt;. The orchestration logic is more implicit and "black-boxed" inside the Crew abstractions, which can make fine-grained intervention more challenging.&lt;/p&gt;

&lt;p&gt;That said, with the introduction of &lt;strong&gt;Flows&lt;/strong&gt; in CrewAI—explicitly defined workflows coordinating agents and tasks—you can reclaim a similar level of control and transparency over execution. The Flows feature lets you model sequences, conditions, and branching explicitly, reducing the "black box" effect while still keeping CrewAI’s ease of use.&lt;/p&gt;

&lt;p&gt;The Java Verifier examples below provide a clear demonstration of this: while LangGraph exposes every node and edge explicitly, CrewAI Flows allow similarly controlled stepwise execution and monitoring inside a more developer-friendly environment.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example: The Java Verifier
&lt;/h3&gt;

&lt;p&gt;To illustrate the difference in abstraction and workflow style between CrewAI and LangGraph, here is a minimal “Verifier” agent implementation in both frameworks. The goal of this verifier is to validate, correct, and optimize small Java code snippets. The workflow is designed with a loop: it first checks the code for syntax errors. If an error is found, it attempts to correct the code and then re-enters the verification step. This "verify-correct" loop continues until the code is deemed syntactically correct. Only then does the workflow proceed to the final step of optimizing the code for readability and performance. You can find all the code shown in this post on this &lt;a href="https://github.com/rosidotidev/Java-Verifier-LangGraph-CrewAI" rel="noopener noreferrer"&gt;Github repo (Java-Verifier-LangGraph-CrewAI)&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  1. CrewAI: Java Verifier with Flow
&lt;/h4&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.amazonaws.com%2Fuploads%2Farticles%2Fnivzj4tyo6ig5fwrcw0q.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.amazonaws.com%2Fuploads%2Farticles%2Fnivzj4tyo6ig5fwrcw0q.png" alt="This image has been generated using the functionality at the end of the provided Python code)" width="800" height="388"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(This image has been generated using the functionality at the end of the provided Python code)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;CrewAI Flows allow you to define a multi-agent workflow in a class-based structure that feels familiar to developers. You declare agents and then use decorators (&lt;code&gt;@start&lt;/code&gt;, &lt;code&gt;@router&lt;/code&gt;, &lt;code&gt;@listen&lt;/code&gt;) to map out the flow. This structure keeps the logic contained and easy to read. For this particular example, we chose to orchestrate the individual agents directly within the &lt;code&gt;Flow&lt;/code&gt; rather than using a complete &lt;code&gt;Crew&lt;/code&gt;. This approach gives us more &lt;strong&gt;direct control&lt;/strong&gt; over each agent's step, which was ideal for this straightforward, cyclical process. It's important to note that in more complex scenarios, CrewAI's flexibility allows you to orchestrate entire &lt;code&gt;Crews&lt;/code&gt; of agents, leveraging their collective intelligence for a different level of abstraction.&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&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;Field&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;crewai.agent&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;crewai.flow.flow&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&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;CodeValidationState&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;code&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="sh"&gt;""&lt;/span&gt;
    &lt;span class="n"&gt;syntax_status&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="sh"&gt;""&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JavaCodeValidationFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CodeValidationState&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;

    &lt;span class="n"&gt;analyzer_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Java code syntax analyzer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Receive Java code and reply exactly with &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;correct&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;incorrect&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; based on syntax.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;backstory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a meticulous and precise code quality tool.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;corrector_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Java code corrector&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Receive syntactically incorrect Java code and return corrected code with valid syntax only. Return only Java code with no explanation and no markdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;backstory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are an expert Java programmer who fixes code errors.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;optimizer_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Java code optimizer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Receive syntactically correct Java code and optimize it for readability and performance without changing logic. Return only Java compilable code with no explanation and no markdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;backstory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a senior developer specializing in code optimization.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;try_again&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_analysis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Starts the workflow, sends the code to the analyzer.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting code analysis...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;analyzer_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kickoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;syntax_status&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="n"&gt;raw&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;syntax_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;syntax_status&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Analyzer result: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;syntax_status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_analysis&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;conditional_next_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Decides whether to proceed with correction or optimization.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;syntax_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;syntax_status&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conditional_next_step &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;syntax_status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;syntax_status&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;incorrect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="nd"&gt;@router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;incorrect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;correct_code_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Performs code correction.&lt;/span&gt;&lt;span class="sh"&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;corrector_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kickoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Corrector: code corrected.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&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="n"&gt;raw&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;try_again&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="nd"&gt;@listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;optimize_code_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Performs code optimization.&lt;/span&gt;&lt;span class="sh"&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optimizer_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kickoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&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="n"&gt;raw&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Optimizer: optimization finished.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Workflow complete. Final optimized code:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage of the workflow
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_code_validation_flow&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Initial Java code with a syntax error (missing semicolon)
&lt;/span&gt;    &lt;span class="n"&gt;initial_java_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    public class Test {
        public static void main(String[] args) {
            System.out.println(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, World!&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="n"&gt;flow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JavaCodeValidationFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting CrewAI Java code validation flow...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Start the workflow and get the final result
&lt;/span&gt;    &lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kickoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&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;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;initial_java_code&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;flow&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;run_code_validation_flow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my_flow_plot&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;&lt;strong&gt;Mental Model:&lt;/strong&gt; In CrewAI, you first define the &lt;strong&gt;roles&lt;/strong&gt; and &lt;strong&gt;goals&lt;/strong&gt; of your agents. Then, you use a &lt;code&gt;Flow&lt;/code&gt; to orchestrate them through a series of steps. The flow itself feels like a regular class with methods, where decorators handle the routing logic. This keeps the logic contained and aligned with a developer's class-based thinking. Notice that here we are using default LLM used by CrewAI that at the minute is “gpt-4o-mini“.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. LangGraph: Java Verifier with Graph
&lt;/h4&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.amazonaws.com%2Fuploads%2Farticles%2Fgvqw3ihz191v9t8o5ntu.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.amazonaws.com%2Fuploads%2Farticles%2Fgvqw3ihz191v9t8o5ntu.png" alt="This image has been generated using the functionality at the end of the provided Python code" width="411" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(This image has been generated using the functionality at the end of the provided Python code)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;LangGraph's approach is more explicit and foundational. You define a graph with nodes and edges, where each node is a function. The state of the workflow is passed explicitly between nodes, and conditional edges are used to manage the flow.&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langgraph.graph&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;  &lt;span class="c1"&gt;# Import TypedDict and Annotated
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langgraph.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Command&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;IPython.display&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;display&lt;/span&gt;
&lt;span class="c1"&gt;# Ensure your OpenAI API Key is set in environment variable OPENAI_API_KEY
&lt;/span&gt;&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# Define your state schema
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CodeState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;is_correct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JavaVerifierGraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Initialize LangChain OpenAI wrapper (reads OPENAI_API_KEY from env)
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&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;gpt-4o-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;workflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CodeState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_analysis_node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_analysis_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;optimize_code_node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optimize_code_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_code_node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;correct_code_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Define entry and transitions
&lt;/span&gt;        &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_entry_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_analysis_node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Conditional edges from analyzer node
&lt;/span&gt;        &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start_analysis_node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conditional_next_node&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;optimize_code_node&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;optimize_code_node&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;correct_code_node&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;correct_code_node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="c1"&gt;# Cycle back from corrector to analyzer
&lt;/span&gt;        &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_code_node&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;start_analysis_node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;



    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;llm_check_code_syntax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;code&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="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;prompt&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;Check if the following Java code is syntactically correct. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reply ONLY with &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;correct&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;incorrect&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Java code:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;Answer:&lt;/span&gt;&lt;span class="sh"&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;llm_correct_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;code&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="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;prompt&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;Correct the following Java code to be syntactically valid. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Provide only the corrected code without explanations.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Java code:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;Corrected Java code:&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;llm_optimize_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;code&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="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;prompt&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;Optimize the following syntactically correct Java code &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;for readability and performance. Return only Java code with no explanation and no markdown.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Java code:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;Optimized Java code:&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# The analyzer node sets 'is_correct' in state to guide conditional branching,
&lt;/span&gt;    &lt;span class="c1"&gt;# no explicit goto inside the node function.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_analysis_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CodeState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Analyzer: Checking syntax via LLM...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;is_correct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;llm_check_code_syntax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Analyzer: Code is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;correct&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_correct&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;incorrect&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&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="nc"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&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;is_correct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;is_correct&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;# Optimizer node - performs optimization and ends the workflow.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;optimize_code_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CodeState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Optimizer: Optimizing code via LLM...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;optimized_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;llm_optimize_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Optimizer: Optimization complete. Ending workflow.&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="nc"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&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;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;optimized_code&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;goto&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Corrector node - fixes syntax errors; no goto, flow cycles via explicit edge.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;correct_code_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CodeState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Corrector: Correcting code via LLM...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;corrected_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;llm_correct_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Corrector: Correction complete. Returning to analyzer.&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="nc"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&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;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;corrected_code&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;# Branching function to decide next node after analyzer based on 'is_correct'.
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;conditional_next_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CodeState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;optimize_code_node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_correct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_code_node&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_workflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;initial_state&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;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_correct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;  &lt;span class="c1"&gt;# 'analyzer' will set this value at the beginning
&lt;/span&gt;        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting the execution of the workflow with invoke()...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Run the workflow and get the final state
&lt;/span&gt;        &lt;span class="n"&gt;final_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&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="n"&gt;initial_state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Workflow completed!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Final Java code (corrected and optimized):&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final_state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Final &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;is_correct&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; state: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;final_state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;is_correct&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_graph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_code_validation_flow&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;

    &lt;span class="n"&gt;initial_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    public class Test {
        public static void main(String[] args) {
            System.out.println(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&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="n"&gt;initial_state&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;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;initial_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_correct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;  &lt;span class="c1"&gt;# 'analyzer' will set this value at the beginning
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting the execution of the workflow with invoke()...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;JavaVerifierGraph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;final_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_workflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_state&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;graph&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;run_code_validation_flow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# This command generates the PNG data as bytes, which works outside of Jupyter
&lt;/span&gt;    &lt;span class="n"&gt;mermaid_png_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_graph&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;draw_mermaid_png&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Specify the filename for the output image
&lt;/span&gt;    &lt;span class="n"&gt;output_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;langgraph_workflow.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Open the file in binary write mode ('wb')
&lt;/span&gt;        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Write the image bytes to the file
&lt;/span&gt;            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mermaid_png_bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Diagram sevaed on &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;output_filename&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error during diagram generation: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&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;&lt;strong&gt;Mental Model:&lt;/strong&gt; With LangGraph, you build the workflow by explicitly defining a &lt;strong&gt;state schema&lt;/strong&gt;, followed by individual &lt;strong&gt;nodes&lt;/strong&gt; (functions). You then connect these nodes with &lt;strong&gt;edges&lt;/strong&gt;. The orchestration logic is literally a graph you construct, giving you a powerful, albeit more complex, low-level tool for state management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I appreciate CrewAI’s lean, quick-to-launch workflows and developer experience, which speed up prototyping and smaller scope projects. The &lt;code&gt;Flow&lt;/code&gt; feature adds a layer of explicit control that bridges the gap with more low-level frameworks. Meanwhile, LangGraph stands out for heavyweight, scalable AI pipelines in enterprise-grade systems with a need for full-control graph orchestration.&lt;/p&gt;

&lt;p&gt;To gain a more complete understanding of each framework's workflow implementation capabilities, other critical aspects must be considered. These include &lt;strong&gt;state management&lt;/strong&gt;, the ability to handle &lt;strong&gt;state persistence&lt;/strong&gt; (saving and resuming a workflow), and the ease of implementing a &lt;strong&gt;Human-in-the-Loop (HITL)&lt;/strong&gt; scenario. These factors are crucial for designing robust, long-running processes that require durability or external intervention.&lt;/p&gt;

&lt;p&gt;For the time being, CrewAI fits my development style best, but I watch LangGraph’s evolution with interest as it appears to be solidifying its place as the go-to framework for complex AI agent orchestration at scale.&lt;/p&gt;

</description>
      <category>langgraph</category>
      <category>crewai</category>
      <category>ai</category>
      <category>openai</category>
    </item>
    <item>
      <title>Crewai</title>
      <dc:creator>rosidotidev</dc:creator>
      <pubDate>Wed, 30 Jul 2025 18:47:56 +0000</pubDate>
      <link>https://dev.to/rosidotidev/crewai-2nkk</link>
      <guid>https://dev.to/rosidotidev/crewai-2nkk</guid>
      <description></description>
    </item>
    <item>
      <title>Spring.ai</title>
      <dc:creator>rosidotidev</dc:creator>
      <pubDate>Sun, 27 Jul 2025 13:19:05 +0000</pubDate>
      <link>https://dev.to/rosidotidev/springai-17al</link>
      <guid>https://dev.to/rosidotidev/springai-17al</guid>
      <description></description>
      <category>spring</category>
      <category>ai</category>
    </item>
    <item>
      <title>crew</title>
      <dc:creator>rosidotidev</dc:creator>
      <pubDate>Sun, 20 Jul 2025 19:40:07 +0000</pubDate>
      <link>https://dev.to/rosidotidev/crew-326m</link>
      <guid>https://dev.to/rosidotidev/crew-326m</guid>
      <description></description>
      <category>discuss</category>
    </item>
    <item>
      <title>CrewAI meets RAG: built-in and custom solutions</title>
      <dc:creator>rosidotidev</dc:creator>
      <pubDate>Sun, 20 Jul 2025 12:55:25 +0000</pubDate>
      <link>https://dev.to/rosidotidev/crewai-meets-rag-built-in-and-custom-solutions-69p</link>
      <guid>https://dev.to/rosidotidev/crewai-meets-rag-built-in-and-custom-solutions-69p</guid>
      <description>&lt;p&gt;(Originally published on my blog: &lt;a href="https://roby73.hashnode.dev/crewai-meets-rag-built-in-and-custom-solutions" rel="noopener noreferrer"&gt;https://roby73.hashnode.dev/crewai-meets-rag-built-in-and-custom-solutions&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Generative AI offers immense possibilities, however to truly be effective in real-world applications, it needs to overcome key hurdles: ensuring &lt;strong&gt;accuracy&lt;/strong&gt; and integrating with &lt;strong&gt;private, up-to-date company information&lt;/strong&gt;. A standard Large Language Model (LLM) on its own often isn't enough for tasks demanding specific facts and deep domain knowledge. LLMs generate responses based solely on their training data. If they lack a direct answer, they might still attempt one, sometimes leading to convincing, yet fabricated, outputs (often referred to as &lt;strong&gt;hallucinations&lt;/strong&gt;). For serious applications that demand reliable, grounded results, a smarter approach is essential.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding RAG: The secret to accurate AI
&lt;/h2&gt;

&lt;p&gt;This is where &lt;strong&gt;Retrieval Augmented Generation (RAG)&lt;/strong&gt; comes in. Think of RAG as giving the LLM a set of &lt;strong&gt;specific notes&lt;/strong&gt; to read &lt;em&gt;before&lt;/em&gt; it answers a question. This makes its responses accurate and based on real data. The RAG process can be broadly divided into two main phases: &lt;strong&gt;Ingestion&lt;/strong&gt; and &lt;strong&gt;Retrieval&lt;/strong&gt;, both crucial for augmenting the LLM's knowledge.&lt;/p&gt;

&lt;h3&gt;
  
  
  RAG Ingestion Phase
&lt;/h3&gt;

&lt;p&gt;This initial phase focuses on preparing your knowledge base.&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2Fwn3t6biojl2s3plkri53.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.amazonaws.com%2Fuploads%2Farticles%2Fwn3t6biojl2s3plkri53.png" alt=" " width="581" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Document Loading:&lt;/strong&gt; Documents from various sources (PDFs, text files, database schemas, etc.) are loaded into the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transformation (Chunking):&lt;/strong&gt; Loaded documents are often too large to be processed all at once. They are broken down into smaller, manageable "chunks" or segments. This process might also involve cleaning or pre-processing the text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embedding:&lt;/strong&gt; Each text chunk is then converted into a numerical representation called an &lt;strong&gt;embedding&lt;/strong&gt;. This transformation is performed by an &lt;strong&gt;embedding model&lt;/strong&gt; (e.g., a Sentence Transformer or a model like OpenAI's &lt;code&gt;text-embedding-3-small&lt;/code&gt;). Embeddings capture the semantic meaning of the text, allowing for comparisons based on context rather than just keywords.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Persistence (Vector Database):&lt;/strong&gt; These embeddings, along with references back to their original text chunks, are stored in a &lt;strong&gt;Vector Database (Vector DB)&lt;/strong&gt;. A Vector DB is optimized for efficiently storing and querying high-dimensional vectors, enabling fast similarity searches.&lt;/p&gt;
&lt;h3&gt;
  
  
  RAG Retrieval Phase
&lt;/h3&gt;

&lt;p&gt;This phase occurs when a user submits a query to the Generative AI application.&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.amazonaws.com%2Fuploads%2Farticles%2Ftbfi3jxxgy4an0gmjgs8.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.amazonaws.com%2Fuploads%2Farticles%2Ftbfi3jxxgy4an0gmjgs8.png" alt=" " width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query Embedding:&lt;/strong&gt; The user's input query is also converted into an embedding using the &lt;strong&gt;same embedding model&lt;/strong&gt; that was used during the Ingestion phase. This ensures consistency in the vector space.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Similarity Search:&lt;/strong&gt; The query embedding is then used to perform a similarity search within the Vector DB. The goal is to find the "closest" or most semantically similar text chunks (and their corresponding original content) to the user's query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contextual Augmentation:&lt;/strong&gt; The relevant text chunks retrieved from the Vector DB serve as &lt;strong&gt;precise, up-to-date information&lt;/strong&gt;. This retrieved context is then used to &lt;strong&gt;enrich the original user query&lt;/strong&gt;, forming a new, more informed prompt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LLM Interrogation:&lt;/strong&gt; Finally, this &lt;strong&gt;augmented prompt&lt;/strong&gt; (containing both the user's original request and the relevant retrieved context) is fed to the Large Language Model. The LLM then generates a factual and grounded response, drawing directly from the specific knowledge extracted from your knowledge base, significantly reducing hallucinations and increasing reliability.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why RAG is a Game-Changer
&lt;/h3&gt;

&lt;p&gt;RAG isn't just about accuracy; it solves critical problems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Precision and Reliability:&lt;/strong&gt; RAG ensures the LLM's answers are &lt;strong&gt;factually correct&lt;/strong&gt; and you can &lt;strong&gt;trace them back&lt;/strong&gt; to your trusted data. This significantly reduces the chance of hallucinations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost Optimization:&lt;/strong&gt; Giving the LLM the right context with RAG means you don't need super long, complex prompts. &lt;strong&gt;Getting data (like for embeddings) is usually much cheaper than writing huge prompts or paying for more LLM tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overcoming Token Limits:&lt;/strong&gt; All LLMs have a maximum amount of text they can handle at once (their &lt;strong&gt;context window&lt;/strong&gt;). RAG smartly gets around this by only giving the most relevant bits of information, instead of trying to stuff an entire knowledge base into the prompt. This lets LLMs work with much bigger and more complex data sets.&lt;/p&gt;
&lt;h2&gt;
  
  
  CrewAI: Orchestrating Smart Agents for flexible RAG
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CrewAI&lt;/strong&gt; is a powerful Python framework. It lets you create and manage &lt;strong&gt;teams of autonomous AI agents&lt;/strong&gt;. With CrewAI, you can define specialized &lt;strong&gt;agents&lt;/strong&gt; (like a "Researcher" or an "Analyst") with specific &lt;strong&gt;roles&lt;/strong&gt;, &lt;strong&gt;goals&lt;/strong&gt;, and &lt;strong&gt;tools&lt;/strong&gt;. CrewAI is key for RAG because it allows these agents to &lt;strong&gt;work together and share tasks&lt;/strong&gt;. This makes the RAG process strong and efficient. The &lt;strong&gt;"Tools"&lt;/strong&gt; are the crucial link, connecting your agents to all your different knowledge sources. &lt;strong&gt;Flexibility is key:&lt;/strong&gt; CrewAI lets you use both &lt;strong&gt;built-in RAG features&lt;/strong&gt; that come with the framework (like &lt;code&gt;PDFSearchTool and Knowledge&lt;/code&gt;) and &lt;strong&gt;custom tools&lt;/strong&gt; you build yourself. This means you can connect to any specific data source you need, which is essential for real-world projects.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementing RAG with CrewAI: Three Practical Approaches
&lt;/h2&gt;

&lt;p&gt;Here's how you can use CrewAI to implement RAG, showing its versatility.&lt;/p&gt;
&lt;h3&gt;
  
  
  Native RAG Tools
&lt;/h3&gt;

&lt;p&gt;This is how CrewAI handles RAG natively using its &lt;strong&gt;built-in tools&lt;/strong&gt;. The &lt;code&gt;PDFSearchTool&lt;/code&gt; is a prime example, designed for &lt;strong&gt;semantic searches&lt;/strong&gt; directly within PDF content. A CrewAI agent can use this &lt;strong&gt;out-of-the-box tool&lt;/strong&gt; to efficiently find and retrieve specific passages based on a search query within a PDF document. By default, it uses OpenAI for both embeddings (to understand meaning) and summarization, though this can be customized. This automates knowledge extraction from your existing PDF archives directly within the CrewAI ecosystem.&lt;/p&gt;
&lt;h3&gt;
  
  
  Knowledge for Document-Based RAG
&lt;/h3&gt;

&lt;p&gt;CrewAI offers a &lt;strong&gt;native "Knowledge" feature&lt;/strong&gt; that allows agents and crews to directly access and utilize various external information sources. This acts as a built-in reference library for your agents. You can provide knowledge sources in formats like raw strings, &lt;code&gt;.txt&lt;/code&gt;, &lt;code&gt;.pdf&lt;/code&gt;, &lt;code&gt;.csv&lt;/code&gt;, &lt;code&gt;.xlsx&lt;/code&gt;, and &lt;code&gt;.json&lt;/code&gt; documents by placing them in specified directories. CrewAI handles the storage (using ChromaDB by default) and embedding automatically. This approach empowers agents with direct access to a curated document set, ensuring their responses are grounded in your specific data.&lt;/p&gt;
&lt;h3&gt;
  
  
  Custom tool that uses Vector Search (FAISS in our case)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;FAISS&lt;/strong&gt; (Facebook AI Similarity Search) is great for very fast searches based on meaning, across huge sets of data (vector embeddings). Here, a &lt;strong&gt;custom tool&lt;/strong&gt; lets CrewAI agents query a FAISS index. They find information that's semantically similar and feed it to the LLM. This provides fast and scalable semantic search for large, changing knowledge bases.&lt;/p&gt;
&lt;h2&gt;
  
  
  Real-World Example: Demonstrating RAG Flexibility with Multi-Crew Setup
&lt;/h2&gt;

&lt;p&gt;In a real-world project, we implemented a system to analyze PDF documents. This setup, whose code is available in this repository: &lt;a href="https://github.com/rosidotidev/CrewAI-RAG-Sample" rel="noopener noreferrer"&gt;CrewAI-RAG-Sample&lt;/a&gt;, effectively demonstrated CrewAI's versatility.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── db
│   ├── 455d85ec-a7f9-4c9c-82d8-d3567d9263aa
│   └── chroma.sqlite3
├── Easy_recipes.pdf
├── knowledge
│   └── Easy_recipes.pdf
├── LICENSE
├── main.py
├── Pipfile
├── Pipfile.lock
├── ragcrew
│   ├── config
│   │   ├── agents.yaml
│   │   └── tasks.yaml
│   ├── faiss_rag_crew.py
│   ├── pdf_knowledge_crew.py
│   ├── tool_rag_crew.py
│   └── tools
│       └── custom_tool.py
├── README.md
├── report.md
└── setup.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We achieved this by employing three distinct crews, executed one after the other, to reach the same analytical goal. What made each crew unique was the specific RAG approach it utilized, while the core agents and tasks remained consistent. This allowed for a direct comparison of RAG strategies in action.&lt;/p&gt;

&lt;p&gt;Each of these three crews was designed with the same set of specialized agents, for instance, a &lt;strong&gt;PDF Researcher&lt;/strong&gt; and a &lt;strong&gt;Content Analyst&lt;/strong&gt;. Similarly, the tasks they performed were identical across all crews: first, Information Retrieval to locate and extract relevant data from the PDF based on a user query; then, Content Refinement to process and summarize the retrieved information for clarity and conciseness; and finally, Output Generation to format and save the final, refined content into a Markdown (.md) file.&lt;/p&gt;

&lt;p&gt;The key differentiator lay in how each crew performed its Information research task declared within the tasks.yaml file. This task relies on pdf_researcher Agent.&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="na"&gt;research_task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;Search for specific information requested in the {topic}.&lt;/span&gt;
  &lt;span class="na"&gt;expected_output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;Most relevant information about {topic},&lt;/span&gt;
  &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pdf_researcher&lt;/span&gt;

&lt;span class="na"&gt;content_task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;Review the context you got.&lt;/span&gt;
    &lt;span class="s"&gt;Make sure the report is detailed and contains any and all relevant information.&lt;/span&gt;
  &lt;span class="na"&gt;expected_output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;A fully fledged report with the main topics. The language to use is the language of the request "{topic}",&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s see how the three crews manage RAG different approaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ToolRagCrew:&lt;/strong&gt; This crew leveraged CrewAI's &lt;strong&gt;out-of-the-box&lt;/strong&gt; &lt;code&gt;PDFSearchTool&lt;/code&gt; for its RAG mechanism. Agents directly queried PDF documents, showcasing a straightforward, native approach to unstructured document RAG. Here a Python code snippet for &lt;strong&gt;tool_rag_crew.py&lt;/strong&gt;&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="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; 
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;crewai_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PDFSearchTool&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="nd"&gt;@CrewBase&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ToolRagCrew&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;agents&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;BaseAgent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;tasks&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;Task&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="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getPDFRagTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_tool&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PDFSearchTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                              &lt;span class="c1"&gt;#chunker=dict(chunk_size=2000,chunk_overlap=50)
&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_tool&lt;/span&gt;
        &lt;span class="nd"&gt;@agent&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pdf_researcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;Agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Agent&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pdf_researcher&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPDFRagTool&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="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How you can see, a built in PDFSearchTool is configured as a tool for the PDF Researcher Agent&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PDFKnowledgeCrew:&lt;/strong&gt; Here, the crew utilized CrewAI's &lt;strong&gt;native "Knowledge" feature&lt;/strong&gt;. PDF documents were pre-loaded into the agents' knowledge base by placing them in a designated directory, allowing agents to access and integrate this curated information during their tasks. Here a Python code snippet for &lt;strong&gt;pdf_knowledge_crew.py&lt;/strong&gt;&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="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; 
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;crewai.knowledge.source.pdf_knowledge_source&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PDFKnowledgeSource&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="nd"&gt;@CrewBase&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PDFKnowledgeCrew&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;agents&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;BaseAgent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;tasks&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;Task&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="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_knowledge_sources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_source&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PDFKnowledgeSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_paths&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_source&lt;/span&gt;

        &lt;span class="nd"&gt;@agent&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pdf_researcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;Agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Agent&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pdf_researcher&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# type: ignore[index]
&lt;/span&gt;                &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;knowledge_sources&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_knowledge_sources&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="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How you can see, it is very simple to use Knowkedge feature with Crew. You have to use the attribute knowledge_sources within the Agent declaration. It accepts an array of instances of PDFKnowledgeSource. That’s it!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FAISSRagCrew:&lt;/strong&gt; For this crew, a &lt;strong&gt;custom tool integrated with FAISS&lt;/strong&gt; was implemented. This represented a more scalable solution for large datasets, where agents used this custom tool to perform semantic searches on vector embeddings derived from the PDF content. I’ve used &lt;strong&gt;FAISS&lt;/strong&gt; (&lt;strong&gt;Facebook AI Similarity Search&lt;/strong&gt;) because this library is very useful for similarity search and clustering of vectors. I also wanted to share how CrewAI framework is “opened” for integration with 3rd party libraries and tools. Here a Python code snippet for &lt;strong&gt;faiss_rag_crew.py&lt;/strong&gt;&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="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pdfplumber&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.text_splitter&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_community.vectorstores&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FAISS&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAIEmbeddings&lt;/span&gt;  
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ragcrew.tools.custom_tool&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PDFFAISSTool&lt;/span&gt;

    &lt;span class="nd"&gt;@CrewBase&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FAISSRagCrew&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

        &lt;span class="n"&gt;agents&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;BaseAgent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;tasks&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;Task&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pdf_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pdf_path&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vector_store&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search_tool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_openai_embedding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&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;text-embedding-3-small&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pdfplumber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract_text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;prepare_rag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pdf_text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;text_splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;chunk_overlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text_splitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf_text&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;FAISS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_texts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;OpenAIEmbeddings&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initFAISS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;pdf_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_pdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vector_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepare_rag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search_tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PDFFAISSTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vector_store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nd"&gt;@agent&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pdf_researcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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;Agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initFAISS&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Agent&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pdf_researcher&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# type: ignore[index]
&lt;/span&gt;                &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search_tool&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="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How you can see, within the Agent declaration the initFAISS() method is invoked. It executes the ingestion phase of the RAG process: loading of the PDF file, persisting embedded data into the vector DB, and initialization of the PDFFAISSTool which is a custom tool defined in the project.&lt;/p&gt;

&lt;p&gt;This multi-crew sample effectively highlights CrewAI's ability to &lt;strong&gt;maintain consistent operational logic (same agents, same tasks) while allowing for flexible and interchangeable RAG strategies&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Takeaways of the reading
&lt;/h2&gt;

&lt;p&gt;In this article, we looked at different ways to set up Retrieval-Augmented Generation (RAG) within a CrewAI agent system. We saw how each method: using a special PDFSearchTool, the built-in Knowledge feature of CrewAI, and making a Custom Tool with FAISS, offers different ways to help our agents find and use outside information. We learned that all three methods aim to give Large Language Models (LLMs) the right information to create accurate answers and avoid making things up. But they are different in their purpose, how the agent uses the data, and how much control you have. What is clear is that CrewAI is a capable framework for building systems with many agents. Alongside other agent frameworks like LangChain, AutoGen, or LlamaIndex, CrewAI provides a valuable alternative. It is easy to use and focuses on how agents work together, what their jobs are, and what they want to achieve.&lt;/p&gt;

</description>
      <category>crewai</category>
      <category>genai</category>
      <category>openai</category>
      <category>ai</category>
    </item>
    <item>
      <title>Trading</title>
      <dc:creator>rosidotidev</dc:creator>
      <pubDate>Fri, 21 Mar 2025 22:53:12 +0000</pubDate>
      <link>https://dev.to/rosidotidev/trading-4lmd</link>
      <guid>https://dev.to/rosidotidev/trading-4lmd</guid>
      <description></description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Simplifying backlog management on Jira with CrewAI</title>
      <dc:creator>rosidotidev</dc:creator>
      <pubDate>Sun, 19 Jan 2025 21:29:19 +0000</pubDate>
      <link>https://dev.to/rosidotidev/simplifying-backlog-management-on-jira-with-crewai-3jmd</link>
      <guid>https://dev.to/rosidotidev/simplifying-backlog-management-on-jira-with-crewai-3jmd</guid>
      <description>&lt;p&gt;One of the key challenges in the Agile development lifecycle is defining &lt;strong&gt;User Stories&lt;/strong&gt; with the right level of detail. During refinement phases, stories can range from being overly generic and high-level to fully detailed and actionable. This variability often leads to inefficiencies and inconsistencies in backlog management.&lt;/p&gt;

&lt;p&gt;By leveraging a workflow of &lt;strong&gt;Generative AI agents&lt;/strong&gt; capable of interacting with &lt;strong&gt;Jira's APIs (tools)&lt;/strong&gt;, we can automate backlog creation and refinement. These agents process requirements, enrich them with best practices, and interact directly with Jira to generate and organize backlog items. The workflow is designed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Break down requirements into structured &lt;strong&gt;Epics&lt;/strong&gt; and &lt;strong&gt;User Stories&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Suggests stories in a structured and formalized format.&lt;/li&gt;
&lt;li&gt;Seamlessly interface with Jira to update or query backlog items dynamically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article we see how &lt;a href="https://docs.crewai.com/introduction" rel="noopener noreferrer"&gt;CrewAI&lt;/a&gt; framework can be used to reach this goal, it is a cutting-edge platform designed to orchestrate autonomous AI agents, enabling them to collaborate effectively on complex tasks.&lt;/p&gt;

&lt;p&gt;Key components of CrewAI include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.crewai.com/concepts/agents" rel="noopener noreferrer"&gt;Agents&lt;/a&gt;&lt;/strong&gt;: Autonomous units with specific roles, expertise, and responsibilities. Each agent can perform tasks, utilize tools, and collaborate with other agents to achieve shared objectives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.crewai.com/concepts/tools" rel="noopener noreferrer"&gt;Tasks&lt;/a&gt;&lt;/strong&gt; Defined objectives assigned to agents, which can be executed sequentially or in parallel. Tasks are the building blocks of the workflow, guiding agents on what needs to be accomplished.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.crewai.com/concepts/tools" rel="noopener noreferrer"&gt;Tools&lt;/a&gt;&lt;/strong&gt; Integrated functionalities that agents can employ to interact with external systems, such as APIs. For instance, agents can use tools to interface with Jira's API, enabling operations like creating issues or retrieving data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.crewai.com/concepts/crews" rel="noopener noreferrer"&gt;Crews&lt;/a&gt;&lt;/strong&gt; A crew in crewAI represents a collaborative group of agents working together to achieve a set of tasks. Each crew defines the strategy for task execution, agent collaboration, and the overall workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By defining these components, CrewAI facilitates the creation of AI teams where each agent has specific roles, tools, and goals, working together to accomplish complex tasks. This structured approach ensures efficient collaboration and effective task execution within the framework. The basic idea is to define the 4 main capabilities using a friendly and basic UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Detailed Backlog Creation from Requirements&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
CrewAI agents process requirement descriptions and generate tasks enriched with &lt;strong&gt;security considerations&lt;/strong&gt;, &lt;strong&gt;architectural patterns&lt;/strong&gt;, and &lt;strong&gt;testing protocols&lt;/strong&gt;. Whether a requirement is sparse or well-documented, the system produces actionable Epics and User Stories, aligning with best practices and reducing manual effort.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Collaboration with Product Owners&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Tasks are automatically grouped into &lt;strong&gt;Epics&lt;/strong&gt; and linked to &lt;strong&gt;User Stories&lt;/strong&gt; with pre-defined acceptance criteria. Product Owners can easily review, adjust, and reprioritize tasks, ensuring alignment with project goals while reducing time spent on refinement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Automated Jira Integration&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The system integrates seamlessly with Jira, creating and organizing Epics and User Stories directly within the tool. This eliminates manual data entry, ensuring consistent and efficient backlog management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Advanced Search and Filtering&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
With natural language queries and advanced filters (e.g., by &lt;strong&gt;priority&lt;/strong&gt;, &lt;strong&gt;status&lt;/strong&gt;, or &lt;strong&gt;assignee&lt;/strong&gt;), the system can quickly navigate large backlogs, locate tasks, and identify gaps or dependencies to optimize task management.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementation overview
&lt;/h2&gt;

&lt;p&gt;In this &lt;a href="https://github.com/rosidotidev/CrewAI-Agentic-Jira/" rel="noopener noreferrer"&gt;github project&lt;/a&gt; there is a basic implementation of these capabilities. This is the project structure&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── agents
│   ├── agile.py
│   └── reporter.py
├── tasks
│   ├── agile.py
│   └── reporter.py
├── tools
│   ├── easy_jira_wrapper.py
│   ├── jira_cleaner_util.py
│   ├── jira_epic_creator_tool.py
│   ├── jira_reader_tool.py
│   └── jira_story_creator_tool.py
├── crews.py
├── LICENSE
├── main.py
├── main_web_gradio.py
├── Pipfile
├── Pipfile.lock
├── README.md
├── setup.txt
├── statememnts_repo.py
└──web_app_gradio.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;main.py&lt;/code&gt;&lt;/strong&gt;: Backend entry point for CrewAI workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;main_web_gradio.py&lt;/code&gt;&lt;/strong&gt;: Entry point for the Gradio-based web interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;web_app_gradio.py&lt;/code&gt;&lt;/strong&gt;: Logic for the web app, handling user inputs and outputs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;crews.py&lt;/code&gt;&lt;/strong&gt;: Defines Crews, collections of agents and tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;statememnts_repo.py&lt;/code&gt;&lt;/strong&gt;: Repository for prompts, queries, or agent instructions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/strong&gt;: Documentation for installation and usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;LICENSE&lt;/code&gt;&lt;/strong&gt;: Project licensing information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Pipfile&lt;/code&gt; &amp;amp; &lt;code&gt;Pipfile.lock&lt;/code&gt;&lt;/strong&gt;: Dependency management with &lt;code&gt;pipenv&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;setup.txt&lt;/code&gt;&lt;/strong&gt;: Instructions for initializing the project.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;agents&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Defines AI agents specialized in specific tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;agile.py&lt;/code&gt;&lt;/strong&gt;: Agents for Agile processes like backlog refinement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;reporter.py&lt;/code&gt;&lt;/strong&gt;: Agents for generating Jira-related reports.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;tasks&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Specifies objectives for agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;agile.py&lt;/code&gt;&lt;/strong&gt;: Tasks for creating Epics and User Stories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;reporter.py&lt;/code&gt;&lt;/strong&gt;: Tasks for generating reports.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;tools&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Utilities for Jira integration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;easy_jira_wrapper.py&lt;/code&gt;&lt;/strong&gt;: Simplified wrapper for Jira API operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;jira_cleaner_util.py&lt;/code&gt;&lt;/strong&gt;: Tool for cleaning outdated issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;jira_epic_creator_tool.py&lt;/code&gt;&lt;/strong&gt;: Automates Epic creation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;jira_reader_tool.py&lt;/code&gt;&lt;/strong&gt;: Reads and filters Jira issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;jira_story_creator_tool.py&lt;/code&gt;&lt;/strong&gt;: Creates and links User Stories.
## User Interface
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Frosidotidev%2FCrewAI-Agentic-Jira%2Frefs%2Fheads%2Fmain%2Fasset%2Fweb1.png" width="800" height="359"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user interface is designed for simplicity and functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Input Area&lt;/strong&gt;:
Located in the &lt;strong&gt;top-left corner&lt;/strong&gt;, this text area allows users to input their requirements or queries for the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output Area&lt;/strong&gt;:
Positioned at the &lt;strong&gt;bottom&lt;/strong&gt;, this section displays the system's response, including generated backlogs or Jira issue details.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dropdown Menu&lt;/strong&gt;:
Found in the &lt;strong&gt;top-right corner&lt;/strong&gt;, the dropdown provides the following options:
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a Backlog and Jira User Stories on Jira&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The user can enter a requirement (even just a few words) into the input area, then the system processes the input, generates a backlog, and saves it in Jira as an &lt;strong&gt;Epic&lt;/strong&gt; with linked &lt;strong&gt;User Stories&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
The output includes the &lt;strong&gt;Type&lt;/strong&gt;, &lt;strong&gt;Key&lt;/strong&gt;, &lt;strong&gt;Summary&lt;/strong&gt;, and &lt;strong&gt;Description&lt;/strong&gt; of all Jira Stories in Markdown format.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a Backlog&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This option allows the user to generate a backlog based on the input requirement.  The user can review and modify the backlog before submitting it to Jira with the next choice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create Jira User Stories on Jira&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Use this option to submit a pre-defined or previously created backlog to Jira, where it will be saved as &lt;strong&gt;Epics&lt;/strong&gt; and &lt;strong&gt;Stories&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Retrieve Jira Issues&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This feature allows users to query Jira and retrieve existing issues based on specific criteria.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The interface provides a streamlined experience, ensuring users can efficiently manage backlogs and interact with Jira. Below an example of what can be created on Jira with this tool.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Frosidotidev%2FCrewAI-Agentic-Jira%2Frefs%2Fheads%2Fmain%2Fasset%2Fjira_view.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%2Fraw.githubusercontent.com%2Frosidotidev%2FCrewAI-Agentic-Jira%2Frefs%2Fheads%2Fmain%2Fasset%2Fjira_view.png" width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This project serves as a concrete example of how &lt;strong&gt;Agentic Generative AI&lt;/strong&gt; can support a specific phase of the &lt;strong&gt;software development lifecycle&lt;/strong&gt;. By automating the backlog creation and refinement process, it showcases the potential of AI agents to reduce manual effort, enhance consistency, and streamline Agile workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CrewAI&lt;/strong&gt; proves to be a strong competitor in the growing landscape of agentic frameworks, standing alongside platforms like &lt;strong&gt;LangGraph&lt;/strong&gt;, &lt;strong&gt;LlamaIndex&lt;/strong&gt;, &lt;strong&gt;AutoGen&lt;/strong&gt;, and many others. Its flexibility in defining agents, tasks, and tools makes it a valuable choice for building advanced AI-driven workflows.&lt;/p&gt;

&lt;p&gt;That said, the project is currently in a &lt;strong&gt;prototypal state&lt;/strong&gt; and has room for improvement in several key areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Integration of a Retrieval-Augmented Generation (RAG) approach&lt;/strong&gt;: To enhance contextual accuracy by combining AI outputs with real-time data retrieval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Input and Output Typing with Pydantic&lt;/strong&gt;: Strengthening data validation and consistency across the workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent and Task Abstraction&lt;/strong&gt;: Introducing support for YAML-based configuration files to simplify the definition and customization of agents and tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expanded Jira Interactions&lt;/strong&gt;: Adding more diverse operations to interact with Jira, such as advanced queries, bulk updates, and custom workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This prototype highlights the immense potential of CrewAI and similar frameworks, demonstrating how they can revolutionize software development processes with intelligent, automated workflows.&lt;/p&gt;

</description>
      <category>crewai</category>
      <category>llm</category>
      <category>genai</category>
      <category>openai</category>
    </item>
    <item>
      <title>GenAI meets Jira: Transforming CSV Exports into Insights</title>
      <dc:creator>rosidotidev</dc:creator>
      <pubDate>Mon, 20 May 2024 19:09:30 +0000</pubDate>
      <link>https://dev.to/rosidotidev/genai-meets-jira-transforming-csv-exports-into-insights-3af</link>
      <guid>https://dev.to/rosidotidev/genai-meets-jira-transforming-csv-exports-into-insights-3af</guid>
      <description>&lt;p&gt;As a passionate developer with many years of experience, I've witnessed the evolution of technology and its impact on the way we handle data. While traditional methods have served us well, the advent of Generative AI (GenAI) presents a transformative opportunity for data analysis. Today, I want to share my journey into this exciting new world by exploring how GenAI can revolutionize the way we interact with and analyze data exported from Jira.&lt;/p&gt;

&lt;p&gt;Jira, a popular project management tool, is widely used to track tasks, bugs, and project progress. It offers the capability to export data into CSV files, which can then be analyzed to gain insights. However, the manual process of sifting through these CSV files can be tedious and time-consuming. This is where GenAI steps in.&lt;br&gt;
Imagine being able to query your Jira exports using natural language, extracting meaningful insights effortlessly. With the combination of LangChain, OpenAI's powerful language model, and the pandas library, we can create an intelligent agent capable of interpreting and executing complex queries on Jira data exports. This not only simplifies the analysis process.&lt;br&gt;
In this article, I'll walk you through how GenAI can be applied to Jira CSV exports, transforming raw data into actionable insights with ease. We'll delve into a project that leverages these cutting-edge technologies to demonstrate the potential of GenAI in revolutionizing our approach to data analysis.&lt;/p&gt;

&lt;p&gt;While it is possible to use a Jira agent developed by LangChain, I chose to work with a CSV file that closely resembles the format of an export from Jira. This decision was made to simplify the demonstration and to avoid to connect to the Jira instance of your Company :). The data in the CSV file used for this project was generated in a nearly random manner to serve as an example.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's Start
&lt;/h2&gt;

&lt;p&gt;To get started with this project, you'll need an OpenAI API key. You can obtain this key by subscribing to the OpenAI service on their website. Once you have your API key, save it in a &lt;code&gt;.env&lt;/code&gt; file at the root of the project. The &lt;code&gt;.env&lt;/code&gt; file should look like this:&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="n"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you need to install the necessary libraries. You can do this using pipenv with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pipenv &lt;span class="nb"&gt;install &lt;/span&gt;pandas numpy python-dotenv langchain langchain-openai openai langchain-experimental tabulate streamlit streamlit-chat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this project, I used PyCharm, but you can use any other Python IDE such as VS Code or any editor of your choice.&lt;/p&gt;

&lt;p&gt;The entire project is available in my GitHub repository &lt;a href="https://github.com/rosidotidev/langchain_pandas_agent"&gt;langchain_pandas_agent&lt;/a&gt;. In this repository, under the csv_dir directory, you will find a CSV file containing tasks for a fictional eCommerce project. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87rm60bqpgdd8cyeauxc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87rm60bqpgdd8cyeauxc.png" alt="Image description" width="800" height="186"&gt;&lt;/a&gt;&lt;br&gt;
The teams Baggio, Buffon, Del Piero, Mancini, Materazzi, and Zola are working on this project, and the file includes both Technical and Functional tasks recorded over three sprints.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Main Script
&lt;/h2&gt;

&lt;p&gt;The core of our project is encapsulated in the main.py script, which orchestrates the interaction between various components. Let's take a closer look at how it's structured:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agent_manager&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;getAgentExecutorChatOpenAI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;df_manager&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;read_df&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;read_df&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;agent_executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getAgentExecutorChatOpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent_executor&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="n"&gt;query&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;response&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_web_app&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;web_app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;build_web_app&lt;/span&gt;
    &lt;span class="nf"&gt;build_web_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;start_web_app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explanation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Imports&lt;/strong&gt;: The script begins by importing necessary modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;load_dotenv&lt;/code&gt; from &lt;code&gt;dotenv&lt;/code&gt; to load environment variables.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getAgentExecutorChatOpenAI&lt;/code&gt; from &lt;code&gt;agent_manager&lt;/code&gt; to create the agent executor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;read_df&lt;/code&gt; from &lt;code&gt;df_manager&lt;/code&gt; to read the DataFrame.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ask Function&lt;/strong&gt;: The &lt;code&gt;ask&lt;/code&gt; function is designed to handle the queries. It reads the DataFrame using &lt;code&gt;read_df()&lt;/code&gt;, initializes the agent executor with &lt;code&gt;getAgentExecutorChatOpenAI(df)&lt;/code&gt;, and invokes the agent with the given query to obtain a response. This function essentially acts as the bridge between the user input and the underlying data processing logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;start_web_app Function&lt;/strong&gt;: This function sets up the web application. It imports &lt;code&gt;build_web_app&lt;/code&gt; from &lt;code&gt;web_app&lt;/code&gt; and calls it, passing the &lt;code&gt;ask&lt;/code&gt; function as a parameter. This function ensures that the web app is equipped to handle user queries through a streamlined interface.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Main Execution&lt;/strong&gt;: The script concludes with a standard Python convention: checking if the script is being run directly. If it is, it loads the environment variables using &lt;code&gt;load_dotenv()&lt;/code&gt; and starts the web application by calling &lt;code&gt;start_web_app()&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Key Components
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web Application&lt;/strong&gt;: The web application is built using the Streamlit framework, which allows for the creation of interactive web interfaces with minimal effort. Streamlit is ideal for data apps, providing a smooth and intuitive user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataframe reader&lt;/strong&gt;: This module contains the logic related to the reading and lightweight processing of the pandas dataframe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Manager&lt;/strong&gt;: The &lt;code&gt;agent_manager&lt;/code&gt; module contains the logic related to LangChain and OpenAI. It is responsible for creating and managing the intelligent agent that processes natural language queries and interacts with the data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reading the CSV: &lt;code&gt;df_manager.py&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;df_manager.py&lt;/code&gt; file contains a function to read and preprocess our CSV data from Jira.&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_df&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;file_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;csv_dir/Jira_Issues_Simulation_Final_With_Dates.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sep&lt;/span&gt;&lt;span class="o"&gt;=&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="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Category&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="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Labels&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&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="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Team&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="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Labels&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&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="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&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;df&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It mainly uses three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the CSV&lt;/strong&gt;: The &lt;code&gt;read_df&lt;/code&gt; function reads the CSV file located in the &lt;code&gt;csv_dir&lt;/code&gt; directory using pandas, with a pipe (&lt;code&gt;|&lt;/code&gt;) as the separator.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Process Labels&lt;/strong&gt;: It extracts &lt;code&gt;Category&lt;/code&gt; and &lt;code&gt;Team&lt;/code&gt; from the &lt;code&gt;Labels&lt;/code&gt; column, assuming labels are comma-separated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Return DataFrame&lt;/strong&gt;: Finally, it returns the processed DataFrame ready for analysis.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This simple script ensures that our data is correctly loaded and preprocessed, making it ready for the natural language queries handled by our LangChain agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Agent: &lt;code&gt;agent_manager.py&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;agent_manager.py&lt;/code&gt; file contains the logic for creating the LangChain agent using OpenAI's GPT-3.5-turbo model.&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_experimental.agents.agent_toolkits&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_pandas_dataframe_agent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatOpenAI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;getAgentExecutorChatOpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
           Use the column Team to retrieve the team;
           technical or functional refer to the column category;
           Consider that the single row can be called ECOM;
           Consider that state refers to column Status;
           The URL of an ECOM is https://robby.com/{Issue Key}, where {Issue Key} is the value of the column &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Issue Key&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="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_pandas_dataframe_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;ChatOpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&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;gpt-3.5-turbo-0613&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;return_intermediate_steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;agent_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openai-tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;max_iterations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;agent_executor_kwargs&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;handle_parsing_errors&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&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;agent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even here we can describe mainly three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Imports&lt;/strong&gt;: The script imports necessary modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;create_pandas_dataframe_agent&lt;/code&gt; from &lt;code&gt;langchain_experimental.agents.agent_toolkits&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ChatOpenAI&lt;/code&gt; and &lt;code&gt;OpenAI&lt;/code&gt; from &lt;code&gt;langchain_openai&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;getAgentExecutorChatOpenAI Function&lt;/strong&gt;: This function creates and configures the LangChain agent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prefix Instructions&lt;/strong&gt;: A prefix is provided to guide the agent on how to interpret certain columns in the DataFrame. I've added these prefix statements after many attempts. To be honest, I was very impressed when I was able to explain how to build the URL even id I'm not an expert on &lt;code&gt;prompt engineering&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Creation&lt;/strong&gt;: The agent is created using the &lt;code&gt;create_pandas_dataframe_agent&lt;/code&gt; function with several parameters:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ChatOpenAI&lt;/code&gt;: The language model is set to &lt;code&gt;gpt-3.5-turbo-0613&lt;/code&gt; with a temperature of 0 for deterministic responses.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;df&lt;/code&gt;: The DataFrame that the agent will interact with.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prefix&lt;/code&gt;: Instructions to guide the agent.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;verbose&lt;/code&gt;: Enables detailed logging.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;return_intermediate_steps&lt;/code&gt;: Returns intermediate steps for debugging.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agent_type&lt;/code&gt;: Specifies the type of agent as &lt;code&gt;openai-tools&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max_iterations&lt;/code&gt;: Limits the number of iterations to 10.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agent_executor_kwargs&lt;/code&gt;: Additional arguments to handle parsing errors gracefully.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Return Agent&lt;/strong&gt;: Finally, the configured agent is returned for use in querying the DataFrame.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This setup equips our LangChain agent with the ability to process natural language queries on the Jira CSV data, leveraging the power of OpenAI's model. It's worth describing that in this case we've used GPT-3.5-turbo model, but with few changes it is possible to switch to a local llm or to a different llm (ie: Google Gemini)&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the Web Application: &lt;code&gt;web_app.py&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;web_app.py&lt;/code&gt; file sets up a web interface using Streamlit, allowing users to interact with the LangChain agent through natural language queries.&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;streamlit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;streamlit_chat&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_web_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;answer_request&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spinner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Generating response...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;generated_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat_history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;generated_response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
                &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_prompt_history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat_answers_history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;generated_response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;

    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LangChain🦜🔗 Jira facilitator example&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_answers_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;
            &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_prompt_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;
            &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;
            &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text_input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_answers_history&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="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&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_prompt_history&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="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_history&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="p"&gt;[]&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;

    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text_area&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text_input&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;on_change&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;answer_request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_answers_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;generated_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_query&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_answers_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_state&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_prompt_history&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="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;user_query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;is_user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;generated_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;is_user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two main points here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Imports&lt;/strong&gt;: The script imports necessary modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;streamlit&lt;/code&gt; as &lt;code&gt;st&lt;/code&gt; for creating the web interface.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;message&lt;/code&gt; from &lt;code&gt;streamlit_chat&lt;/code&gt; for chat message formatting.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;uuid&lt;/code&gt; for generating unique keys for chat messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;build_web_app Function&lt;/strong&gt;: This function sets up the Streamlit web application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;answer_request Function&lt;/strong&gt;: Handles user queries. When the user inputs a query, it invokes the &lt;code&gt;ask&lt;/code&gt; function to generate a response and updates the chat history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Header&lt;/strong&gt;: Sets the header of the web app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session State Initialization&lt;/strong&gt;: Initializes session state variables for storing chat history, user prompts, and generated responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Input&lt;/strong&gt;: Creates a text area for user input. When the input changes, &lt;code&gt;answer_request&lt;/code&gt; is called.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Display Chat History&lt;/strong&gt;: Iterates over the chat history and displays user queries and generated responses using the &lt;code&gt;message&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This file creates a user-friendly web interface for interacting with the LangChain agent, enabling real-time natural language queries on the Jira CSV data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I'm not a guru in Large Language Models (LLM) or Generative AI (GenAI), I am just beginning to explore the vast potential these technologies offer. The project we've discussed here is a small step into the transformative world of GenAI. The possibilities are truly endless, from simplifying data analysis to creating intelligent agents that can understand and process natural language queries.&lt;/p&gt;

&lt;p&gt;This project is just an example of what can be achieved, and I encourage you to experiment and build upon it. As we continue to learn and adapt, we can look forward to a future where AI plays an integral role in our development processes.&lt;/p&gt;

&lt;p&gt;Let's embrace this transformation and explore the endless opportunities that GenAI has to offer.&lt;/p&gt;

</description>
      <category>langchain</category>
      <category>openai</category>
      <category>python</category>
    </item>
    <item>
      <title>Just F*cking do it! Book takeaways</title>
      <dc:creator>rosidotidev</dc:creator>
      <pubDate>Sun, 04 Feb 2024 12:05:37 +0000</pubDate>
      <link>https://dev.to/rosidotidev/just-fcking-do-it-book-takeaways-25bb</link>
      <guid>https://dev.to/rosidotidev/just-fcking-do-it-book-takeaways-25bb</guid>
      <description>&lt;p&gt;Book written by &lt;strong&gt;Noor Hibbert&lt;/strong&gt; and published in 2019. It has 242 pages distributed in 13 chapters. Each chapter ends with a &lt;strong&gt;Top Takeaways&lt;/strong&gt; section and a &lt;strong&gt;JFDI!&lt;/strong&gt; section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Noor Hibbert&lt;/strong&gt; is a powerhouse, and her book delivers a no-bullsh*t guide to transforming your life. Useful for &lt;strong&gt;professional coaches&lt;/strong&gt; and &lt;strong&gt;IT experts&lt;/strong&gt;, I found her approach refreshing and practical. Here’s why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Psychological Rigor Meets Practical Wisdom&lt;/strong&gt;: Just F*cking Do It combines psychological insights with actionable steps. Noor emphasizes that true personal development starts with changing our mindset and interactions. As coaches, we know that mindset matters, and this book reinforces that beautifully.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Law of Attraction for Success&lt;/strong&gt;: Beyond the usual self-help fluff Noor dives into the Law of Attraction. She shows how aligning our thoughts with positive energy can multiply our success. As IT professionals, we understand the power of alignment – whether it’s code or life goals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content Accessible to a Diverse Audience&lt;/strong&gt;: What sets this book apart is its versatility. It’s not just for seasoned self-help enthusiasts; it’s for us – the coaches, the tech wizards, the problem solvers, Software Architects designing new solutions. Noor’s candid style resonates across diverse audiences, making this a must-read for anyone seeking growth and transformation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Beyond the Buzzwords&lt;/strong&gt;: Noor doesn’t sugarcoat. She challenges us to stop thinking small, cut through the noise, and take action. As IT experts, we appreciate practical advice that cuts to the chase.
In summary, Just F*cking Do It is a wake-up call for those who want to break free from mediocrity. Whether you’re coaching clients or debugging code, this book will throw away your excuses and push you towards your best life.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Book
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;In the first 3 chapters&lt;/strong&gt; the author talks about how her life was changed once she adopted what she reports in the book. Talk about the &lt;strong&gt;Law of Attraction&lt;/strong&gt;: to achieve things you have to think positively and think that things will happen. She talks about the positive vibes you have with the &lt;strong&gt;Universe&lt;/strong&gt; entity. The Law of Attraction allows you to decide what you get out of life. The right way to synchronize with the Universe is by using &lt;strong&gt;Radio Universe&lt;/strong&gt; if it connects us using a negative, short-tempered approach you are using &lt;strong&gt;Radio Shit&lt;/strong&gt;. The author underlines that people's freedom is determined by having objectives in the 8 areas that govern human happiness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spiritual&lt;/li&gt;
&lt;li&gt;Emotional&lt;/li&gt;
&lt;li&gt;Mental&lt;/li&gt;
&lt;li&gt;Physicist&lt;/li&gt;
&lt;li&gt;Relational&lt;/li&gt;
&lt;li&gt;Professional&lt;/li&gt;
&lt;li&gt;Financial&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;She suggests defining a maximum of 3 objectives for each area. To define them she suggests these precautions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write down your goals&lt;/strong&gt;, don't just think about them&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define 5 very specific stages&lt;/strong&gt; that are required to achieve the objective&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Set a deadline&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the objectives in the present tense&lt;/strong&gt;, as if they had already been achieved&lt;/li&gt;
&lt;li&gt;Think of &lt;strong&gt;5 things&lt;/strong&gt; you would &lt;strong&gt;think&lt;/strong&gt;, &lt;strong&gt;believe&lt;/strong&gt; and &lt;strong&gt;feel&lt;/strong&gt; once you reach your goal and re-read it often&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the objectives have been defined, we should not be surprised if we are unable to achieve them by the expected date or through the planned stages. Changes are often decided by the &lt;strong&gt;Universe&lt;/strong&gt; in an irrational way&lt;/p&gt;

&lt;p&gt;The writer defines 2 voices that are within us, the &lt;strong&gt;Ego&lt;/strong&gt; and the &lt;strong&gt;Soul&lt;/strong&gt;. The &lt;strong&gt;Ego&lt;/strong&gt; is that part that always justifies us, that blames others when we don't succeed, that makes us angry when a car cuts us off. The &lt;strong&gt;Soul&lt;/strong&gt;, on the other hand, is that positive voice that pushes us to smile when someone cuts us off, that makes us smile and get along with others.&lt;/p&gt;

&lt;p&gt;In chapters &lt;strong&gt;4,5,6&lt;/strong&gt; the author describes three fundamental aspects to prepare to become the best version of ourselves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Knowing how to look inside ourselves&lt;/strong&gt;: we must look inside ourselves to understand where we want to go, who we want to become. Social media often leads us to define models and objectives that are not ours, which only serve to satisfy others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recognize your limiting beliefs&lt;/strong&gt;: when we look inside ourselves we must be able to identify our limiting beliefs. We are often blocked in our evolution because we have incorporated beliefs in the first years of life. We were not born with these beliefs, we absorbed them from the context in which we grew up. Once identified, we need to understand when we have received them and from whom so that we can chase them away using self-awareness and a technique such as &lt;strong&gt;Tapping&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualize who you want to be&lt;/strong&gt;: once you have identified the external and internal noises you need to proceed to the self-forgiveness phase (&lt;strong&gt;spiritual facelift&lt;/strong&gt;). That is, we need to reset the Ego which is the collector of these disorders and we need to visualize who and how we need to be to achieve the objectives and trigger change. Visualization is learned with practice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the following &lt;strong&gt;3 chapters&lt;/strong&gt; Nori Hibbert describes the main steps to define the best version of yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Choose yourself&lt;/strong&gt;: you need to know how to forgive yourself and others at all times, even if unpleasant things happen you need to look at the positive side of things and think about how to transform that event into a positive one. Furthermore, you need to be selfish to the right degree and celebrate yourself every day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your word is your magic wand&lt;/strong&gt;: our internal and external dialogues are crucial in defining who and how we are. It is enough to change some words that we usually use and the perspective changes from pessimistic to optimistic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not all karma is the same&lt;/strong&gt;: every day we deal with karma, even when it manifests itself adversely we must accept it and not be discouraged by negative events. We must be aware that the choices we make are decisive for our future. We need to be “&lt;strong&gt;more crab&lt;/strong&gt;”. The crab periodically recycles its carapace based on the growth of its body; in practice it is a metaphor to push us to often leave our comfort zone, to take risks, in order to grow more than those around us who do not necessarily have to be our growth model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;strong&gt;final chapters&lt;/strong&gt; sher goes beyond the basics defined in the previous chapters and focuses on more advanced aspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google doesn't know all the answers&lt;/strong&gt;: we often search for answers on Google but we have a very powerful weapon that we don't know how to exploit: &lt;strong&gt;intuition&lt;/strong&gt;. Intuition is often magically precise; it is the means by which &lt;strong&gt;The Universe&lt;/strong&gt; speaks to our &lt;strong&gt;Soul&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exercise gratitude&lt;/strong&gt;: gratitude is the frequency of love. The more we distribute, the more we get back. We must not spare ourselves to express gratitude when it is sincere and true.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The power of your circle&lt;/strong&gt;: we are the sum of the 5 people we hang out with the most, so surrounding ourselves physically and virtually (via social media) with the right people is essential. We need to cut the cord with negative people, let's not give too much importance to the advice of those who have not been able to achieve results in a certain context. In addition to being inspired by those around us, we must also inspire others; questions are better than advice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't just say it, do it, get to the bottom of it&lt;/strong&gt;: it's not enough to know and talk about everything the book has covered up to this point, you have to put it into practice. There are two things that often prevent you from taking action: &lt;strong&gt;the pursuit of perfection&lt;/strong&gt; and &lt;strong&gt;procrastination&lt;/strong&gt;. It is better to have achieved a goal even if not perfectly or incompletely than to not have tried at all.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>coaching</category>
      <category>books</category>
      <category>leadership</category>
      <category>personaldevelopment</category>
    </item>
    <item>
      <title>Flutter 2.0 meets Nimbella</title>
      <dc:creator>rosidotidev</dc:creator>
      <pubDate>Sun, 21 Mar 2021 14:46:01 +0000</pubDate>
      <link>https://dev.to/rosidotidev/flutter-2-0-meets-nimbella-1ejo</link>
      <guid>https://dev.to/rosidotidev/flutter-2-0-meets-nimbella-1ejo</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6qfg4x8jqnem0p8fzya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd6qfg4x8jqnem0p8fzya.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
I'm a developer and a Flutter fun and, some weeks ago, I was waiting for March 3rd 2021 Flutter Engage. &lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=IdrCyS7EF8M&amp;amp;t=353s" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjx92h3ey2ti8cjrcopip.png" alt="Engage video"&gt;&lt;/a&gt;&lt;br&gt;
Once known that Fultter 2.0 is "web stable" I began to think: "how can I test Flutter capabilities and its learning curve for the WEB?"&lt;/p&gt;
&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;In that days I was studying a very nice serverless platform as Nimbella, looking at some Youtube videos. "Ok!" I said, "it's time to begin with both ones for a side PoC project"; thus I decided to implement a simple Todo List web application using Flutter for frontend and Nimbella serverless actions for backend. Studying Nimbella I discovered that it is possible to use it even as frontend server, where deploy something as html/js stuff but ... I decided to don't use this feature and use that PoC even to evaluate the GitHub pages. &lt;/p&gt;
&lt;h2&gt;
  
  
  Plan and Result
&lt;/h2&gt;

&lt;p&gt;Ok, the plan is clear:&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="n"&gt;plan&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Plan&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Get a Nimbella free subscription&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Develop and test a set of Python serverless actions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;\
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(simple REST/CRUD services) for backend (Using Redis &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;\
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Nimbella connector as NoSql DB)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; Upgrade my Futter 1.22 platform to 2.0 and switch to web&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;\ 
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; channel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Implement an MVP todo list web app with Flutter,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;\
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;using some widget and know-how got in another side project&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;\
&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; and connect to Nimbella services with Dio dart library&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phase&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deploy flutter build files to GitHub pages &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple right?&lt;br&gt;
After 10 hours, spread over a whole week end, this is the result:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frosidotidev.github.io%2Fdev.to%2Farticle1%2Ftodolist_home.png"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frosidotidev.github.io%2Fdev.to%2Farticle1%2Ftodolist_crud.png"&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you can see nothing exceptional :-) there could be a lot of improvements (adding a loading wheel, improve backend data api, improve error handling etc etc) but it works and It was useful to learn and experiment new frameworks and services. This web app has an entry page where you choose the username of the owner of the todo list; once entered there is a UI where with simple CRUD operations you can manage all todo items. It's worth noting that this webapp can be easily transformed to a PWA just adding it to Home screen from Chrome menu (on Android).&lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 0 (Get a Nimbella free subscription)
&lt;/h3&gt;

&lt;p&gt;It was very easy, at this &lt;a href="https://nimbella.com/pricing/platform" rel="noopener noreferrer"&gt;link&lt;/a&gt; you can choose to start with a Nimbella free "Starter tier" service subscription that lets you create up to 25 functions; it's enough for basic projects and for leraning purpose. &lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 1 (Python actions on Nimbella)
&lt;/h3&gt;

&lt;p&gt;Here I've "monetized" previous studies on Nimbella looking at Youtube courses (&lt;a href="https://www.youtube.com/watch?v=ocIzYGsNMCA" rel="noopener noreferrer"&gt;1&lt;/a&gt;,&lt;a href="https://www.youtube.com/watch?v=MVJyjL4RqAE&amp;amp;t=1304s" rel="noopener noreferrer"&gt;2&lt;/a&gt;,&lt;a href="https://www.youtube.com/watch?v=CeYhwBwKg4k&amp;amp;t=13s" rel="noopener noreferrer"&gt;3&lt;/a&gt;,&lt;a href="https://www.youtube.com/watch?v=lrRGbeg5flM" rel="noopener noreferrer"&gt;4&lt;/a&gt;,&lt;a href="https://www.youtube.com/watch?v=Uax16DE4K9w&amp;amp;t=657s" rel="noopener noreferrer"&gt;5&lt;/a&gt;) but even reading &lt;a href="https://docs.nimbella.com/" rel="noopener noreferrer"&gt;https://docs.nimbella.com/&lt;/a&gt; or &lt;a href="https://github.com/nimbella/nimbella-training" rel="noopener noreferrer"&gt;Nimbella training&lt;/a&gt;. There you can find even how to install the nimbella cli that lets you execute all commands required to work with Nimbella platform.&lt;br&gt;
If you want to take a complete look at the backend actions &lt;a href="https://github.com/rosidotidev/nimbella_todolist_api" rel="noopener noreferrer"&gt;here&lt;/a&gt; you can find the github repo. Otherwise, you can see here one of the five Python actions used for the  backend API.&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;nimbella&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;appkey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tdlst&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nimbella&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&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="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;==&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="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&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;response&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;result&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;error&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;description&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;item not valid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;
    &lt;span class="n"&gt;usercode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&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-code&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="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;usercode&lt;/span&gt;&lt;span class="o"&gt;==&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="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&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;response&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;result&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;error&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;description&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 not valid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10000000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;appkey&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:item:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;usercode&lt;/span&gt;&lt;span class="o"&gt;+&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="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;

    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&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-code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;usercode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;rsuccess&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&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;response&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;result&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;ok&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;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are right! It's a simple Python main, where the args parameter wraps the json info passed through a simple HTTP request like this one:&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="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$URL_ITEM_ADD"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"user-code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"code-6355808"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"buy a coffe"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'Content-type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;application/json'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest of the code is too easy to be commented, that's why Nimbella Python module allows to use redis in a very intuitive way. If you aren't a Python developer you can use other languages such as JavaScript, TypeScript, PHP, Java, Go, or Swif.&lt;br&gt;
However there is a powerfull architecture behind the scenes that it's totally transparent for the developer&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkm625kllu5fnvimbmcy7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkm625kllu5fnvimbmcy7.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Very impressive! There are a set of architectural ingredients that enable a scalable serverless ecosystem.&lt;br&gt;
Once you have written previous Python code, you need to execute this command to publish the serverless action on the cloud&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nim action create api/item-save item-save.py &lt;span class="nt"&gt;--web&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;nim&lt;/em&gt; is a powerfull commnd line interface (cli) provided by the platform that you can use in order to create new Nimbella projects, actions and even to directly test the actions. &lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2 (Upgrade to Flutter 2.0 for web development)
&lt;/h3&gt;

&lt;p&gt;This is the phase where I was more afraid due to some issues I had in the past during Flutter upgrade (to be honest it happned during early Flutter realeases).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="nv"&gt;$&amp;gt;&lt;/span&gt; flutter upgrade
 &lt;span class="nv"&gt;$&amp;gt;&lt;/span&gt; flutter config &lt;span class="nt"&gt;--enable-web&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead it was quiet easy, I had just to upgrade to last version and then switch to web configuration (it's the mode that let you develop a web application)&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 3 (implement Flutter web app)
&lt;/h3&gt;

&lt;p&gt;Here there is the &lt;a href="https://github.com/rosidotidev/flutter_web_todolist" rel="noopener noreferrer"&gt;project repository&lt;/a&gt;; it is how documentation states: developing a web application with Flutter 2.0 is very easy if you already know Flutter platform. I think the code is 99.99% the same you should write for an Android/iPhone app. Something different are the command for the build&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$&amp;gt;&lt;/span&gt;flutter build web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the command for local test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$&amp;gt;&lt;/span&gt;flutter run &lt;span class="nt"&gt;-d&lt;/span&gt; chrom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I want just to underline how to invoke the Nimbella Python action we've seen at &lt;strong&gt;Phase 1&lt;/strong&gt; using the Dio dart library within a Flutter class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&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;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;usercode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Dio&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;dio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'content-Type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'application/json'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;dio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;NIM_SECRET_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'/api/item-save'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;data:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"user-code"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;usercode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jsonDecode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"response"&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;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"ok"&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"RES_OK"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"RES_NO_OK"&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="p"&gt;.&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;It's easy to both send POST HTTP requests and parse its json response.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 4 (deploy Flutter web app on github pages)
&lt;/h3&gt;

&lt;p&gt;All you need to deploy a web app to Github pages is reported here&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.todeploy%20on%20github%20page%20service"&gt;https://pages.github.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In few words you need a Github account and you have to create a repositrory following a name convention like this: &lt;br&gt;
"&amp;lt;your_account&amp;gt;.github.io"&lt;br&gt;
and all html/js stuff you will push on it will reacheable at this link https://&amp;lt;your_account&amp;gt;.github.io/&lt;br&gt;
really easy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;That's all! I hope that this post can help everyone wants to follow the same path I did to learn (very very basic level) both Flutter and Nimbella. To be honest, I already had a basic knowledge of Flutter before starting this journey; however now I'm sure that: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Flutter is a fantastic framework that let you write Mobile App, Web Apps and Desktop as well (even if not yet with a stable release) with only one language (Dart) end with a unique platform.&lt;/li&gt;
&lt;li&gt;Nimbella is really a great FaaS alternative to question the hegemony of the great cloud serverless players as AWS, Azure and Google Cloud because is very effective and its learning curve is very smooth; I've not yet understood how much it is easy to integrate it with other Cloud solutions (It's something I need to study :-) :-) :-) ). I hope there will be available, as soon as possbile, a lot of connectors in order to be able to interact with other cloud PaaS.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>flutter</category>
      <category>serverless</category>
      <category>nimbella</category>
      <category>python</category>
    </item>
  </channel>
</rss>
