<?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: Pavel Koryagin</title>
    <description>The latest articles on DEV Community by Pavel Koryagin (@pavelkoryagin).</description>
    <link>https://dev.to/pavelkoryagin</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%2F1027152%2F633fcc4e-dee2-4add-839c-315eaca82bcd.jpg</url>
      <title>DEV Community: Pavel Koryagin</title>
      <link>https://dev.to/pavelkoryagin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pavelkoryagin"/>
    <language>en</language>
    <item>
      <title>Maximize efficiency: CrewAI Task isolation problem</title>
      <dc:creator>Pavel Koryagin</dc:creator>
      <pubDate>Wed, 29 Jan 2025 10:48:35 +0000</pubDate>
      <link>https://dev.to/pavelkoryagin/maximize-efficiency-crewai-task-isolation-problem-16in</link>
      <guid>https://dev.to/pavelkoryagin/maximize-efficiency-crewai-task-isolation-problem-16in</guid>
      <description>&lt;p&gt;I’m a TDD fan!&lt;/p&gt;

&lt;p&gt;Don’t get me wrong: I don’t perform literally every change in the code by editing a test first. But I’ve mastered running parts individually without the whole product. This saves me time and even money.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ This post is part of the &lt;strong&gt;“Crew AI Caveats”&lt;/strong&gt; series, which I create to fill in the gaps left by official courses and to help you master CrewAI faster and easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Stuff must be tested in isolation
&lt;/h2&gt;

&lt;p&gt;Of course, in the practical approach to CrewAI, the first obvious thing to me was to run tasks individually.&lt;/p&gt;

&lt;p&gt;Really, when I start, I don’t know what tasks I need. Will a task as I imagine it work in one shot, or should I split it into many? No one knows until we try. And the same is true for improvement ideas regarding tasks we already have.&lt;/p&gt;

&lt;p&gt;Additionally, we tune our internal formats and data transformations, and we debug tools. All these things should be runnable in isolation. And all the cloud vendor connections should be mockable. If they are not, then we’re losing on waiting for irrelevant tasks and LLM calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  But how?
&lt;/h2&gt;

&lt;p&gt;I am only on the way to assembling a TDD-friendly CrewAI environment. You can check &lt;a href="https://community.crewai.com/t/how-to-run-a-task-out-of-its-crew-with-manual-context/2678" rel="noopener noreferrer"&gt;my topic&lt;/a&gt; in the CrewAI community and share your tricks, architecture, and code snippets.&lt;/p&gt;

&lt;p&gt;Here’re my examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tool-testing script
&lt;/h2&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;src.publishing.tools.get_articles_backlog&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GetArticlesBacklog&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="c1"&gt;# Load environment variables  
&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;# Initialize the tool  
&lt;/span&gt;    &lt;span class="n"&gt;backlog_tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GetArticlesBacklog&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;=== Testing Articles Backlog Tool ===&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
        &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;backlog_tool&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;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&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="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; articles in backlog:&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;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;article&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&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;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="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Article &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&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="k"&gt;for&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="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&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 occurred: &lt;/span&gt;&lt;span class="si"&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;e&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;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;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Invoking partial crews
&lt;/h2&gt;

&lt;p&gt;I don’t have an extensive guide on how to run tasks and their combinations individually. I am trying &lt;a href="https://community.crewai.com/t/how-to-run-a-task-out-of-its-crew-with-manual-context/2678/4" rel="noopener noreferrer"&gt;various hacks&lt;/a&gt;. They work, but none of them could be recommended as a good practice.&lt;/p&gt;

&lt;p&gt;Here’s the extract from &lt;code&gt;crew.py&lt;/code&gt;, though:&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="nd"&gt;@CrewBase&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Publishing&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mock_tasks&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;context&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;task_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prev_result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;prev_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getattr&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;task_name&lt;/span&gt;&lt;span class="p"&gt;)()&lt;/span&gt;
            &lt;span class="n"&gt;pydantic_output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prev_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_export_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev_result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;prev_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TaskOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prev_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prev_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;expected_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prev_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected_output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prev_result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;pydantic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pydantic_output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;json_dict&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json_output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Mock&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;output_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prev_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_get_output_format&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@crew&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;crew&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;mode&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="bp"&gt;None&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;Crew&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;mode&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;Crew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;agents&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&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;tasks&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;tasks&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="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ideate&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;Crew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;agents&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;idea_hunter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;tasks&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;ideate_free&lt;/span&gt;&lt;span class="p"&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="p"&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;mode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;research_idea&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;Crew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;agents&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;scientific_researcher&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;tasks&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;prepare_idea_research&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;research_idea&lt;/span&gt;&lt;span class="p"&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="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# An example of a completely detached agent for testing-only purposes
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test_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;tool_tester&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;Tool Tester&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;Test and validate the provided tool&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s functionality&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;I am an expert at testing tools and validating their outputs. I ensure tools work as expected. Use word &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dog&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; as a part of the product name and &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;language learning&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; as domain to search for knowledge.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search_in_knowledge_base&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;allow_delegation&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="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;tool_test_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test the {tool} tool by using it and validating its 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;expected_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A detailed report of the tool&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s functionality and performance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tool_tester&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="nc"&gt;Crew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tool_tester&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tool_test_task&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequential&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="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&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;Unknown mode: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mode&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;This way I can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define named sub-sets of tasks.&lt;/li&gt;
&lt;li&gt;Mock results of the preceding tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here’s how it call that Crew in &lt;code&gt;main.py&lt;/code&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;assemble_regular_inputs&lt;/span&gt;&lt;span class="p"&gt;():&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;current_run/input.md&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;r&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="nb"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&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;read&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="c1"&gt;# Stuff for very different tasks is mixed together,
&lt;/span&gt;        &lt;span class="c1"&gt;# because CrewAI interpolates all the task strings, not only the used ones.
&lt;/span&gt;        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;session_date&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;2025-01-12&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;task&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;Inspect content plan, suggest ideas to fill the gaps&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;calendar_principles&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;get_publication_calendar_principles&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;input&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;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Run the crew.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;agentops&lt;/span&gt;&lt;span class="p"&gt;.&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;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RUN_MODE&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="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;cmd&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="nf"&gt;assemble_regular_inputs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nc"&gt;Publishing&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;crew&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="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ideate&lt;/span&gt;&lt;span class="sh"&gt;'&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="nf"&gt;assemble_regular_inputs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nc"&gt;Publishing&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;crew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ideate&lt;/span&gt;&lt;span class="sh"&gt;'&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="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test_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;tool_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmd&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="mi"&gt;1&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;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;tool_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;Publishing&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;crew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test_tool&lt;/span&gt;&lt;span class="sh"&gt;'&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="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&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;Unknown command: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cmd&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;This post is rather a heads-up that CrewAI won’t make your crew test-friendly in traditional sense. It comes with its own “test” concept that is fantastic, but is not a replacement for traditional test engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  The end of the series
&lt;/h2&gt;

&lt;p&gt;As you could see, I dive deep into CrewAI, but also found some problems I’d prefer not to have.&lt;/p&gt;

&lt;p&gt;I plan to continue my AI-agents the following flows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep using CrewAI for at least one of my projects.&lt;/li&gt;
&lt;li&gt;Try to adapt a schema, where &lt;a href="https://github.com/crewAIInc/crewAI-examples/tree/main/CrewAI-LangGraph" rel="noopener noreferrer"&gt;CrewAI is a node in LangGraph&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Study new frameworks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy building!&lt;/p&gt;

</description>
      <category>crewai</category>
      <category>ai</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Flow vs. Crew: The clash of CrewAI templates</title>
      <dc:creator>Pavel Koryagin</dc:creator>
      <pubDate>Tue, 28 Jan 2025 10:38:46 +0000</pubDate>
      <link>https://dev.to/pavelkoryagin/flow-vs-crew-the-clash-of-crewai-templates-1n0g</link>
      <guid>https://dev.to/pavelkoryagin/flow-vs-crew-the-clash-of-crewai-templates-1n0g</guid>
      <description>&lt;p&gt;Welcome to the least informative post of the whole series! 😁 Just a small heads-up. The really complex topic is for tomorrow.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ This post is part of the &lt;strong&gt;“Crew AI Caveats”&lt;/strong&gt; series, which I create to fill in the gaps left by official courses and to help you master CrewAI faster and easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These two commands create entry points that are structured very differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;crewai create crew &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crewai create flow &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;create crew&lt;/code&gt; version &lt;code&gt;main.py&lt;/code&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

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

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

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

&lt;span class="c1"&gt;# No `if __name__ == "__main__"` statement at all
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;create flow&lt;/code&gt; version &lt;code&gt;main.py&lt;/code&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="k"&gt;def&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;poem_flow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PoemFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;poem_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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;poem_flow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PoemFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;poem_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="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;kickoff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is that the flow version is structured as a script entry point and the crew version is nonfunctional without the &lt;code&gt;crewai run&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Additionally, the &lt;code&gt;crew&lt;/code&gt; version exports some interesting entrypoints, while the &lt;code&gt;flow&lt;/code&gt; version does not. Not sure why—maybe because they design that the crews should be trained independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay tuned
&lt;/h2&gt;

&lt;p&gt;In the next post: CrewAI hurts TDD fans! Let’s invent a cure.&lt;/p&gt;

</description>
      <category>crewai</category>
      <category>ai</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>CrewAI’s output_pydantic is almost perfect. Here’s the missing part</title>
      <dc:creator>Pavel Koryagin</dc:creator>
      <pubDate>Mon, 27 Jan 2025 11:13:43 +0000</pubDate>
      <link>https://dev.to/pavelkoryagin/crewais-outputpydantic-is-almost-perfect-heres-the-missing-part-4i2j</link>
      <guid>https://dev.to/pavelkoryagin/crewais-outputpydantic-is-almost-perfect-heres-the-missing-part-4i2j</guid>
      <description>&lt;p&gt;&lt;code&gt;output_pydantic&lt;/code&gt; is awesome and guarantees the output format to you. But its implementation is missing an important obvious thing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ This post is part of the &lt;strong&gt;“Crew AI Caveats”&lt;/strong&gt; series, which I create to fill in the gaps left by official courses and to help you master CrewAI faster and easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If &lt;a href="https://dev.to/pavelkoryagin/add-monitoring-asap-smooth-out-your-dev-experience-with-crewai-1p8c"&gt;you use monitoring&lt;/a&gt;, you could make interesting discoveries, and one of mine is this.&lt;/p&gt;

&lt;p&gt;When you use &lt;code&gt;output_pydantic&lt;/code&gt;, the LLM does not see your field descriptions.&lt;/p&gt;

&lt;p&gt;Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FillContentPlanGapsOutput&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;date&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;time&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;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Channel ID. Lowercase name, e.g. twitter, youtube, etc.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;typeOfContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;LLM prompt from monitoring:&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%2Fr49eh6yulcbt0pzoga95.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%2Fr49eh6yulcbt0pzoga95.png" alt="Screen showing that the description part is lost" width="519" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s &lt;a href="https://community.crewai.com/t/can-pydantic-describe-output-fields-for-llm/2581" rel="noopener noreferrer"&gt;my topic&lt;/a&gt; where I approach the solutions. &lt;/p&gt;

&lt;p&gt;And here’s a very early draft of a solution:&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="nd"&gt;@task&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fill_content_plan_gaps&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;Task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;field_info&lt;/span&gt; &lt;span class="o"&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;Output fields:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;field_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field_instance&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;FillContentPlanGapsOutput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model_fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;field_info&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;field_name&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;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;field_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&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;field_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&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="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Task&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;tasks_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;fill_content_plan_gaps&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;expected_output&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;tasks_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;fill_content_plan_gaps&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;expected_output&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;field_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;output_pydantic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FillContentPlanGapsOutput&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;Logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This is the expect criteria for your final answer: List of content requests with channel, content type, and time slot.

Output fields:
- date
- time
- channel: Channel ID. Lowercase name, e.g. twitter, youtube, etc.
- typeOfContent

you MUST return the actual complete content as the final answer, not a summary.
Ensure your final answer contains only the content in the following format: {
  "date": str,
  "time": str,
  "channel": str,
  "typeOfContent": str
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you read it, the problem might be already fixed in the framework. Otherwise, make a generic implementation of the prompt customizer that I haven’t made yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay tuned
&lt;/h2&gt;

&lt;p&gt;In the next post: No revolutionary observations, just a heads-up about a discrepancy in official boilerplate versions.&lt;/p&gt;

</description>
      <category>crewai</category>
      <category>ai</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The dual nature of a CrewAI Task. Have you overlooked it too?</title>
      <dc:creator>Pavel Koryagin</dc:creator>
      <pubDate>Fri, 24 Jan 2025 15:49:29 +0000</pubDate>
      <link>https://dev.to/pavelkoryagin/the-dual-nature-of-a-crewai-task-have-you-overlooked-it-too-3o69</link>
      <guid>https://dev.to/pavelkoryagin/the-dual-nature-of-a-crewai-task-have-you-overlooked-it-too-3o69</guid>
      <description>&lt;p&gt;Tasks in Crew AI are not what they seem. There’s more to them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ This post is part of the &lt;strong&gt;“Crew AI Caveats”&lt;/strong&gt; series, which I create to fill in the gaps left by official courses and to help you master CrewAI faster and easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s take a look at a task definition.&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%2Frgrlo33wkgalrd4vb90t.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%2Frgrlo33wkgalrd4vb90t.png" alt="What is a CrewAI task? A YAML with definition and a stereotypical code snippet" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have a separate YAML file with string templates where the values are yet to be interpolated. This YAML file goes into a Python object of class &lt;code&gt;Task&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What do I (and, as it turns out, others too) expect when we see this? The contents of the &lt;code&gt;Task&lt;/code&gt; object seem to be a definition of the task, right? With experience in things like n8n or Redux, we expect that the actual data will flow somewhere in memory, according to this definition, and will be returned by &lt;code&gt;kickoff()&lt;/code&gt; in the end.&lt;/p&gt;

&lt;p&gt;The reality is different.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key takeaway.&lt;/strong&gt; A Task object is a task definition &lt;strong&gt;and&lt;/strong&gt; a runtime container at the same time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes, it holds the template strings yet to be interpolated. But it also has the &lt;code&gt;output&lt;/code&gt; property of type &lt;code&gt;TaskOutput&lt;/code&gt; that gets populated at runtime when the task has reached its final answer.&lt;/p&gt;

&lt;p&gt;You can access the output value by reading it on the respective task object.&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;researcher&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;config&lt;/span&gt;&lt;span class="o"&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;researcher&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;research_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&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;tasks_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;research_task&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;researcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;crew&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Crew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;researcher&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;research_task&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="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;crew&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="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Ignoring the return value  
&lt;/span&gt;
&lt;span class="c1"&gt;# Reading the output on the task object
&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;research_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# print(research_task.output.json)
# print(research_task.output.to_dict())
# print(research_task.output.pydantic)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look, in this example, I don’t take the result from the kickoff function. Instead, it is accessed on the task object.&lt;/p&gt;

&lt;p&gt;With decorators, it also works, although it looks even more cryptic because you extract the runtime data from a function call that instantiates a Task object... but alright, I complained about the decorators two days ago.&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;crew_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SampleCrew&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;crew_base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;crew&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="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Ignoring the return value  
&lt;/span&gt;
&lt;span class="c1"&gt;# Reading the output on the task object
&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;crew_base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;research_task&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# print(crew_base.research_task().output.json)
# print(crew_base.research_task().output.to_dict())
# print(crew_base.research_task().output.pydantic)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Knowing this, we can better predict how our crew works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Every task is always a single instance per execution.&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Maybe in the future, they will make the tasks optional.&lt;/li&gt;
&lt;li&gt;It is impossible to make them plural without breaking the contract.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;When you are &lt;strong&gt;puzzled about which result&lt;/strong&gt; you are actually getting from your crew, use &lt;code&gt;your_task.output.raw/json/pydantic&lt;/code&gt; for granular control, rather than the result of &lt;code&gt;kickoff()&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;With decorators, you have to create different instances of "CrewBase" for separate runs. There are other bugs with multiple instances, but it mostly works.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;And I cannot say this is not reflected in the docs. It is:&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%2Fcpu18rqngbuoeobgcl4w.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%2Fcpu18rqngbuoeobgcl4w.png" alt="Screen from CrewAI docs on task outputs" width="680" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But to me, this doc makes sense only when I already know how it works. Before that, these parts felt out of context. The courses did not help either. And those &lt;code&gt;Task&lt;/code&gt; methods/properties do not exist today, maybe they are from &lt;code&gt;TaskOutput&lt;/code&gt; or reserved for the future?&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay tuned
&lt;/h2&gt;

&lt;p&gt;In the next post: &lt;code&gt;output_pydantic&lt;/code&gt; is awesome! But you have to patch the framework.&lt;/p&gt;

</description>
      <category>crewai</category>
      <category>ai</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>CrewAI Agent is not a team player. It craves a conveyor, not a crew</title>
      <dc:creator>Pavel Koryagin</dc:creator>
      <pubDate>Thu, 23 Jan 2025 16:11:10 +0000</pubDate>
      <link>https://dev.to/pavelkoryagin/crewai-agent-is-not-a-team-player-it-craves-a-conveyor-not-a-crew-1ph9</link>
      <guid>https://dev.to/pavelkoryagin/crewai-agent-is-not-a-team-player-it-craves-a-conveyor-not-a-crew-1ph9</guid>
      <description>&lt;p&gt;I like CrewAI, but I must admit its name has fooled me.&lt;/p&gt;

&lt;p&gt;Problems with AI frameworks start before you’ve even chosen one. There are a ton of frameworks already, so we guess their properties based on very fragmented knowledge.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ This post is part of the &lt;strong&gt;“Crew AI Caveats”&lt;/strong&gt; series, which I create to fill in the gaps left by official courses and to help you master CrewAI faster and easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;How did the name of CrewAI fool me? I imagined agents interacting like a crew, but in practice, it turned out to be built for sequential processes, and the behavior that you expect for a virtual crew—resembling a human crew—is either not working or is absent completely.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is already available
&lt;/h2&gt;

&lt;p&gt;Objecting to this thesis, CrewAI offers asynchronous tasks and hierarchical processes, but these features are underwhelming.&lt;/p&gt;

&lt;p&gt;Asynchronous tasks only optimize execution time without affecting the outcomes.&lt;/p&gt;

&lt;p&gt;The hierarchical process is buggy and poorly documented. For instance, tasks calling other tasks &lt;a href="https://community.crewai.com/t/agents-fail-to-call-each-other-and-where-to-edit-the-system-prompt/2687" rel="noopener noreferrer"&gt;often produce errors&lt;/a&gt;, and the manager meant to dispatch tasks sometimes mishandles them. Telemetry reveals bizarre interactions, like a Frankenstein-style combination of a task definition with a wrong agent. Join &lt;a href="https://community.crewai.com/t/does-hierarchical-process-even-work-your-experience-is-highly-appreciated/2690/4" rel="noopener noreferrer"&gt;my topic&lt;/a&gt; to see the research I conducted.&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%2F7b1fs6dag0zuw52whi3b.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%2F7b1fs6dag0zuw52whi3b.png" alt="Artifacts in task calling by LLM, caused by insufficiency of the internal prompt" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a “crew,” according to my intuition
&lt;/h2&gt;

&lt;p&gt;The agents should decide what they do and what they don’t. The tasks and task dependencies should be a set of best practices rather than a strict to-do list. Agents or their dispatcher should decide which sub-tasks (or predefined processes) are relevant to the current request and which are not.&lt;/p&gt;

&lt;p&gt;This isn’t available right now in CrewAI. All the tasks in a crew are mandatory. The sequential process is the only type that works reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can I implement it manually?
&lt;/h2&gt;

&lt;p&gt;Look, the process in CrewAI is a sort of &lt;a href="https://en.wikipedia.org/wiki/Finite-state_machine" rel="noopener noreferrer"&gt;state machine&lt;/a&gt;. And CrewAI also comes with an explicit state machine—the &lt;code&gt;Flow&lt;/code&gt; class. It might be the base for DIY solutions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I’m going to experiment with a &lt;a href="https://github.com/crewAIInc/crewAI-examples/tree/main/CrewAI-LangGraph" rel="noopener noreferrer"&gt;LangGraph example&lt;/a&gt; where CrewAI is only a node in a LangGraph state machine. Also, I found how to run a single CrewAI task (with its agent) out of the Crew and Process—will see if it helps or not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Wrapping up, if you want something more complex than a sequential process with CrewAI, implement it yourself. Do you know a framework that allows agents to decide which task definitions are relevant to the current user request? Please share.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay tuned
&lt;/h2&gt;

&lt;p&gt;In the next post: You are probably getting CrewAI’s &lt;code&gt;Task&lt;/code&gt; object wrong, as I did. Let’s clarify how it physically works.&lt;/p&gt;

</description>
      <category>crewai</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The evil decorators of CrewAI. Fight or flight?</title>
      <dc:creator>Pavel Koryagin</dc:creator>
      <pubDate>Wed, 22 Jan 2025 12:11:33 +0000</pubDate>
      <link>https://dev.to/pavelkoryagin/the-evil-decorators-of-crewai-fight-or-flight-3k2f</link>
      <guid>https://dev.to/pavelkoryagin/the-evil-decorators-of-crewai-fight-or-flight-3k2f</guid>
      <description>&lt;p&gt;After completing the course “Multi AI Agent Systems with crewAI,” &lt;a href="https://dev.to/pavelkoryagin/ive-learned-crewai-now-i-want-to-make-your-learning-smoother-1m1g"&gt;mentioned earlier&lt;/a&gt;, you’re confident that CrewAI is a piece of cake, and you’re ready to start solving your own tasks! That’s the moment where the first obstacle arises.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ This post is part of the &lt;strong&gt;“Crew AI Caveats”&lt;/strong&gt; series, which I create to fill in the gaps left by official courses and to help you master CrewAI faster and easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To start, you need to create a project locally, right? But the course didn’t teach you how to do that.&lt;/p&gt;

&lt;p&gt;You decide to follow the official Quickstart guide to set up your local project, but you see a discrepancy with the course: YAML, a class, and decorators.&lt;/p&gt;

&lt;p&gt;This is a limbo state: “Multi AI Agent Systems with crewAI” does not show decorators at all, then “Practical Multi AI Agents and Advanced Use Cases with crewAI” shows YAML with manual processing, and demos like “How To Create AI Agents From Scratch” show them without much explanation.&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%2F6t4aephp7xzzcb7elewv.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%2F6t4aephp7xzzcb7elewv.png" alt="Decorators and YAML are unexpected" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So what to do?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option 1. My Quickstart
&lt;/h3&gt;

&lt;p&gt;Recommended for your first project right after completing the course “Multi AI Agent Systems with crewAI.” This option uses a plain and straightforward crew boilerplate.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Honestly, I’ve checked a few boilerplates and dozens of examples. All of them either use directives (that’s our Option 2) or are broken in some way. The example I recommend here is the closest to perfect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Make a copy of this directory: &lt;a href="https://github.com/crewAIInc/crewAI-examples/tree/main/instagram_post" rel="noopener noreferrer"&gt;instagram_post example&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Initialize a git repo and make the initial commit.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create an empty &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In &lt;code&gt;pyproject.toml&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update &lt;code&gt;crewai&lt;/code&gt; to the latest version,&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;crewai_tools&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;poetry lock&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;Resolve version conflicts and execute &lt;code&gt;poetry lock&lt;/code&gt; again.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Run &lt;code&gt;poetry install --no-root&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Find &lt;code&gt;self.llm = Ollama(model=os.environ['MODEL'])&lt;/code&gt; and replace it with a provider-agnostic version &lt;code&gt;self.llm = LLM(model=os.environ['MODEL'])&lt;/code&gt;, where &lt;code&gt;LLM&lt;/code&gt; is imported from &lt;code&gt;crewai&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Do not try&lt;/strong&gt; to run it as it is.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you do, you’ll have to resolve several dependencies (run Ollama locally, obtain two API keys, install a package missing in &lt;code&gt;pyproject.toml&lt;/code&gt;). These complications are not what you need when you start a project.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Instead,&lt;/strong&gt; start editing the tasks and agents to your needs right at this point.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start small (one task and one agent; not all the tasks you imagine at once).&lt;/li&gt;
&lt;li&gt;Fill the &lt;code&gt;.env&lt;/code&gt; file, using your knowledge from the course and the providers you’re already familiar with.&lt;/li&gt;
&lt;li&gt;Either delete &lt;code&gt;.env.example&lt;/code&gt; or synchronize it with &lt;em&gt;your&lt;/em&gt; version of &lt;code&gt;.env&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The same is for &lt;code&gt;README.md&lt;/code&gt;–delete or adjust.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Run &lt;code&gt;python main.py&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Fix errors.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Enjoy yourself.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&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%2Fu9nhym1jppqma85s6r4b.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%2Fu9nhym1jppqma85s6r4b.png" alt="Proof of concept: it works" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, I’d recommend adding monitoring as the previous post suggests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ I had no capacity to test adding monitoring and to publish an updated version of this boilerplate. Sorry, maybe later. Write in the comments if anything doesn’t work for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Option 2. Official Quickstart
&lt;/h2&gt;

&lt;p&gt;Do this only when you have solved a couple of your own problems via Option 1 and gained confidence in using CrewAI elements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take the official &lt;a href="https://docs.crewai.com/quickstart" rel="noopener noreferrer"&gt;Quickstart&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ensure that the process with all the tasks at once works.&lt;/li&gt;
&lt;li&gt;Fight with problems as you add something a bit less trivial.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I did many experiments of code organization with decorators to avoid the problems I’m sharing below, but so far, I have no robust solution to share. I will show you some hacks in snippets in the post “Running tools and tasks individually or in subsets” of this series.&lt;/p&gt;

&lt;p&gt;This is it! But you probably want to know why I don’t like decorators? There’s more than just discrepancy with the course.&lt;/p&gt;

&lt;h2&gt;
  
  
  The good, the bad, and the fragile
&lt;/h2&gt;

&lt;p&gt;YAML idea is okay, generally intuitive, and maybe even neat. But in order to make it work, you need to do some implicit transformations.&lt;/p&gt;

&lt;p&gt;In plain code, you cannot reference an agent by name:&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;the_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;the_agent&lt;/span&gt; &lt;span class="c1"&gt;# A variable, this works
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;the_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;the_agent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;# A string id, does not work
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same is true for tools. But with YAML, this is exactly what you do. To make it work, CrewAI introduces some decorators...&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%2F5kk96f3bzkx44g1fr1vb.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%2F5kk96f3bzkx44g1fr1vb.png" alt="Decorators as they appear in the official boilerplate" width="707" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first glance, those five decorators look alright (&lt;code&gt;@tool&lt;/code&gt;, the 5th, is not in the screenshot). The caveat is that they introduce unexpected behaviors. The basic sequential task flow with a complete crew as in the boilerplate works, but any deviation results in cryptic error messages.&lt;/p&gt;

&lt;p&gt;As a software architect, I insist on testing app components separately (and there is a post on it in this series down the road). However, creating subsets of tasks for focused testing is problematic with CrewAI decorators.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you create a separate crew function for testing, it fails because the agents list hasn’t been initialized by the decorator.&lt;/li&gt;
&lt;li&gt;Adding a parameter to the API might work, but only for scalar values.&lt;/li&gt;
&lt;li&gt;Passing more complex data structures results in cryptic errors:&lt;/li&gt;
&lt;/ul&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%2Fqtleywroazj5l7rhrfan.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%2Fqtleywroazj5l7rhrfan.png" alt="One of my hacks that failed" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that things might fail in a different way if you’re reading this post months later than it was written.&lt;/p&gt;

&lt;p&gt;And one more thing: the problem is not in the “decorator” pattern per se! The problematic ones are these five (CrewBase, agent, task, tool, crew). As opposed to this, you could find a good example of decorators in &lt;a href="https://docs.crewai.com/concepts/flows" rel="noopener noreferrer"&gt;Flow&lt;/a&gt; of the same framework. They are elegant, flexible, and I haven’t faced any problem with them so far.&lt;/p&gt;

&lt;p&gt;So, if you want full control or simply fewer surprises, consider building your own architecture instead of relying on CrewAI’s default setup. In this series, down the road, you will find more solutions to incorporate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay tuned
&lt;/h2&gt;

&lt;p&gt;In the next post: CrewAI’s name has fooled me. Let’s see what its Process variants can and what they cannot.&lt;/p&gt;

</description>
      <category>crewai</category>
      <category>ai</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Add monitoring ASAP! Smooth out your dev experience with CrewAI</title>
      <dc:creator>Pavel Koryagin</dc:creator>
      <pubDate>Tue, 21 Jan 2025 13:36:10 +0000</pubDate>
      <link>https://dev.to/pavelkoryagin/add-monitoring-asap-smooth-out-your-dev-experience-with-crewai-1p8c</link>
      <guid>https://dev.to/pavelkoryagin/add-monitoring-asap-smooth-out-your-dev-experience-with-crewai-1p8c</guid>
      <description>&lt;p&gt;With AI, our app’s quality is becoming less predictable than ever. In this post, we’re going to reduce the frameworks’ contribution to the chaos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ This post is part of the &lt;strong&gt;“Crew AI Caveats”&lt;/strong&gt; series, which I create to fill in the gaps left by official courses and to help you master CrewAI faster and easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We choose CrewAI for its unique prompt crafting and some hard-coded logic. These features make it stand out, but their opacity is also a profound source of frustration and misconceptions.&lt;/p&gt;

&lt;p&gt;When the agent produces incorrect or even nonsensical conclusions, it’s not always clear whether it’s an LLM hallucination, missing context, or a bug in the prompt-building code (all three are real.) These cases assume very different mitigation actions, so we need to know for sure what’s actually happening inside the agent.&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%2Fz7koskbeqn8mwz947isz.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%2Fz7koskbeqn8mwz947isz.png" alt="Three branches of problems" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another challenge is designing your agent crew. Questions like how data from one task will transfer to another, whether tasks will share the same chat history, and similar issues are all confusing. Documentation is also vague on these topics, so we need an X-ray vision to see the reality.&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;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verbose mode is insufficient in CrewAI, but there’s a superior method—monitoring (aka telemetry, aka observability.) For experienced developers, the need for observability is obvious. For newcomers, CrewAI might become your first experience with this kind of tool.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NB:&lt;/strong&gt; In CrewAI, the word “telemetry” is reserved for the data &lt;em&gt;they&lt;/em&gt; collect from &lt;em&gt;your&lt;/em&gt; app. Although I normally prefer that word, today I’m going to call it “monitoring” as I’m talking about the data &lt;em&gt;you&lt;/em&gt; collect from &lt;em&gt;your&lt;/em&gt; app.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s start. I won’t dig here into how to connect telemetry—just check the &lt;a href="https://docs.crewai.com/how-to/agentops-observability" rel="noopener noreferrer"&gt;relevant sections&lt;/a&gt; on the CrewAI website. All these one-page guides are simple and straightforward.&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%2Fld0p4pk0kgrcyd96212q.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%2Fld0p4pk0kgrcyd96212q.png" alt="Integration options from CrewAI docs" width="349" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead, I’ll show you how to use it. I started with AgentOps, simply because it was the first on the list. Although I'm disappointed and will try the alternatives, it is still a fine option to start with.&lt;/p&gt;

&lt;p&gt;Here’s a screenshot of my session. When I run &lt;code&gt;crewai run&lt;/code&gt;, I get a link at the beginning and end of the session.&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%2F2ep92vea2ke4o78sy5mu.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%2F2ep92vea2ke4o78sy5mu.png" alt="A link to UI for a monitoring session" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking the link opens a screen where chats are rendered per agent and separately per LLM call.&lt;/p&gt;

&lt;p&gt;Here's my take on its UI. Don’t rely on the rendered chats—they are misleading. Instead, hover over a block in the LLM and tools diagram of the "Session Replay" tab, click to freeze the selection, and navigate to the “Raw JSON” tab.&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%2Femeabxeqes2pe15wasmq.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%2Femeabxeqes2pe15wasmq.png" alt="The bad and the good parts of AgentOps UI" width="800" height="1440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the true representation of the request sent to the LLM, revealing how CrewAI actually works under the hood in your particular case. Isn't that awesome to access this secret?&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%2Fj07h890u7nq79keorx96.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%2Fj07h890u7nq79keorx96.png" alt="Puzzled how, say, Task.context works? Open the monitoring and see" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, by pressing &lt;code&gt;[Cmd+F]&lt;/code&gt;, I can search for expected strings from previous tasks. This allows me to verify how tools and task data are being fed into the LLM. See how they are wrapped into the prompts and does their formatting conflict with other parts of the prompt. &lt;/p&gt;

&lt;p&gt;You've got the point: with AI agents, monitoring is not for production only. It’s eye-opening to see the actual source of unexpected LLM responses.&lt;/p&gt;

&lt;p&gt;You should enable monitoring asap even locally, to make debugging straightforward. Fortunately, it is simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay tuned
&lt;/h2&gt;

&lt;p&gt;In the next post: Decorators in CrewAI frustrate the beginners. I am going to smooth things over on your learning journey.&lt;/p&gt;

</description>
      <category>crewai</category>
      <category>ai</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I’ve learned CrewAI. Now I want to make your learning smoother</title>
      <dc:creator>Pavel Koryagin</dc:creator>
      <pubDate>Mon, 20 Jan 2025 21:30:44 +0000</pubDate>
      <link>https://dev.to/pavelkoryagin/ive-learned-crewai-now-i-want-to-make-your-learning-smoother-1m1g</link>
      <guid>https://dev.to/pavelkoryagin/ive-learned-crewai-now-i-want-to-make-your-learning-smoother-1m1g</guid>
      <description>&lt;p&gt;Is CrewAI friendly to fast-learners and software architects?&lt;/p&gt;

&lt;p&gt;Let me tell you my story. After some struggles in adapting LangChain with fast-learner techniques, I decided to take a traditional course for the next thing I’m going to learn.&lt;/p&gt;

&lt;p&gt;The next thing to try was CrewAI, and Google brought me the course “Multi AI Agent Systems with crewAI.” It was a great learning experience, and CrewAI’s neat, straightforward approach really won me over. It felt like that moment when you realize you’ve finally found a tool that you can just take and use.&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%2F0zawa1wotujt9df64isr.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%2F0zawa1wotujt9df64isr.png" alt="My course completion screen" width="671" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But of course, nothing’s ever that simple. Once I started building my own project, I hit roadblock after roadblock—turns out there’s a big difference between reading about how something works and actually getting it to work. Through plenty of trial, error, and dig-the-sources, I picked up a bunch of insights I wish I’d had from the start.&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%2F6ohlsz1x1dhj0rev292c.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%2F6ohlsz1x1dhj0rev292c.png" alt="Logs with a cryptic problem" width="647" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s why I’m kicking off this series of posts. I want to share with you what I’ve learned in practice that either didn’t catch enough attention when I was learning or is not properly documented at all.&lt;/p&gt;

&lt;p&gt;This series is especially for those of you who’ve started tinkering with CrewAI and found yourself wondering, “Now what?”&lt;/p&gt;

&lt;p&gt;But if you’re just starting out, then this first post is for you. As a fast-learner by spirit and a dev mentor, I continuously look for ways to turn my experience into an optimal learning plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  My version of the shortest way to master CrewAI
&lt;/h2&gt;

&lt;p&gt;Here are the three mandatory and two optional steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1.&lt;/strong&gt; 🎓 Take the free course &lt;a href="https://www.deeplearning.ai/short-courses/multi-ai-agent-systems-with-crewai/" rel="noopener noreferrer"&gt;Multi AI Agent Systems with crewAI&lt;/a&gt;. I started with it, and I see nothing better. It is from the CrewAI creator.&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%2F54c6r5dvbhsqn9djwdgg.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%2F54c6r5dvbhsqn9djwdgg.png" alt="The course contents–video and code" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2.&lt;/strong&gt; 📃 Read through this my series of posts. Apparently 😊&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3.&lt;/strong&gt; 🔨 Start your own real project with CrewAI. Better yet, kick it off while you’re still doing the course from step 1.&lt;/p&gt;

&lt;p&gt;However, there’s a critical discrepancy between their course and their boilerplate, discussed in my post “Decorators.” Recipe what to do is also there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optional step 4.&lt;/strong&gt; Complete (or skim over) another free course of the same author &lt;a href="https://www.deeplearning.ai/short-courses/practical-multi-ai-agents-and-advanced-use-cases-with-crewai/" rel="noopener noreferrer"&gt;Practical Multi AI Agents and Advanced Use Cases with crewAI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optional step out of the order.&lt;/strong&gt; If you’re like me and enjoy podcast-style demonstrations, consider watching this at any stage of your learning: &lt;a href="https://www.youtube.com/watch?v=PM9zr7wgJX4&amp;amp;t=4239s" rel="noopener noreferrer"&gt;How To Create AI Agents From Scratch (CrewAI, Zapier, Cursor)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay tuned
&lt;/h2&gt;

&lt;p&gt;In the next post: How to transform CrewAI debugging from guesswork into engineering and peek under the hood of your AI agents.&lt;/p&gt;

</description>
      <category>crewai</category>
      <category>ai</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
