<?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: Yusen Meng</title>
    <description>The latest articles on DEV Community by Yusen Meng (@yukooshima).</description>
    <link>https://dev.to/yukooshima</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%2F933638%2Fd0bcab9a-6233-48fa-98af-8867aab82754.jpeg</url>
      <title>DEV Community: Yusen Meng</title>
      <link>https://dev.to/yukooshima</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yukooshima"/>
    <language>en</language>
    <item>
      <title>Building a Multi-Agent Framework from Scratch with LlamaIndex</title>
      <dc:creator>Yusen Meng</dc:creator>
      <pubDate>Tue, 29 Oct 2024 07:57:32 +0000</pubDate>
      <link>https://dev.to/yukooshima/building-a-multi-agent-framework-from-scratch-with-llamaindex-5ecn</link>
      <guid>https://dev.to/yukooshima/building-a-multi-agent-framework-from-scratch-with-llamaindex-5ecn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: For a better reading experience, please visit the &lt;a href="https://github.com/YukoOshima/Blog/blob/main/articles/multi_agents.md" rel="noopener noreferrer"&gt;full article on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;: The complete source code for this tutorial is available in the &lt;a href="https://github.com/YukoOshima/Blog/tree/main/code/multi_agents" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Multi-agent systems are like teams of specialized workers, each with their own expertise, working together to accomplish complex tasks. In this tutorial, we'll build a multi-agent system using LlamaIndex that generates high-quality Anki flashcards from any given text.&lt;/p&gt;

&lt;p&gt;We'll start simple and gradually add more capabilities, similar to how you might build a team - starting with one person and gradually adding more specialists as needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version 1: Basic Single-Agent System
&lt;/h2&gt;

&lt;p&gt;In our first version, we'll create a simple system with just one agent that can generate Anki flashcards from text. Think of it as hiring your first employee who knows how to create educational content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph LR
    Input[Input Text] --&amp;gt;|Process| QA[Q&amp;amp;A Generator]
    QA --&amp;gt;|Generate| Cards[Flashcards]

    style Input fill:#e1f5fe,stroke:#01579b
    style QA fill:#e8f5e9,stroke:#2e7d32
    style Cards fill:#fff3e0,stroke:#ef6c00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Core Components
&lt;/h3&gt;

&lt;p&gt;Let's break down our code into manageable pieces:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data Models&lt;/strong&gt;: First, we define what our flashcards should look like using Pydantic:
&lt;/li&gt;
&lt;/ol&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;QACard&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;question&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;answer&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;extra&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Flashcard_model&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;cards&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;QACard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;LLM Setup&lt;/strong&gt;: We configure LlamaIndex to use our preferred language model:
&lt;/li&gt;
&lt;/ol&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;get_shared_llm&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Returns a shared LLM instance for all agents.&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;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;api_base&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:4000/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;api_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;sk-test&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Agent Creation&lt;/strong&gt;: Our Q&amp;amp;A Generator agent is specialized in creating flashcards:
&lt;/li&gt;
&lt;/ol&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;qa_generator_factory&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;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&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 educational content creator specializing in Anki flashcard generation.
    Your task is to create clear, concise flashcards following these guidelines:

    1. Each card should focus on ONE specific concept
    2. Questions should be clear and unambiguous
    3. Answers should be concise but complete
    4. Include relevant extra information in the extra field
    5. Follow the minimum information principle

    Format each card as:
    &amp;lt;card&amp;gt;
        &amp;lt;question&amp;gt;Your question here&amp;lt;/question&amp;gt;
        &amp;lt;answer&amp;gt;Your answer here&amp;lt;/answer&amp;gt;
        &amp;lt;extra&amp;gt;Additional context, examples, or explanations&amp;lt;/extra&amp;gt;
    &amp;lt;/card&amp;gt;
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_tools&lt;/span&gt;&lt;span class="p"&gt;(&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="nf"&gt;get_shared_llm&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Response Handling&lt;/strong&gt;: We use a transformer function to convert the agent's output into structured data:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;stop_after_attempt&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="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;wait_exponential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;multiplier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;chat_prompt_tmpl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChatPromptTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;message_templates&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_shared_llm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;structured_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;structured_predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Flashcard_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chat_prompt_tmpl&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;structured_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Main Function
&lt;/h3&gt;

&lt;p&gt;Here's how we put it all together:&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;generate_anki_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_text&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;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Create the agent
&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;qa_generator_factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Generate flashcards
&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&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&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;Generate Anki flashcards from the following text:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;input_text&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="c1"&gt;# Transform the response into structured data
&lt;/span&gt;    &lt;span class="n"&gt;structured_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;transformer&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;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;structured_response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Usage
&lt;/h3&gt;

&lt;p&gt;Let's try it with a sample text about RSI (Relative Strength Index):&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;sample_text&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 Relative Strength Index (RSI) is a momentum indicator used in technical analysis.
It measures the speed and magnitude of recent price changes to evaluate overbought
or oversold conditions. RSI is displayed as an oscillator on a scale from 0 to 100.
Readings above 70 generally indicate overbought conditions, while readings below 30
indicate oversold conditions.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;flashcards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_anki_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample_text&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;flashcards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Single Responsibility&lt;/strong&gt;: Our agent focuses solely on creating flashcards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Validation&lt;/strong&gt;: Pydantic ensures our data is properly structured&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt;: Retry mechanism helps handle temporary failures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured Output&lt;/strong&gt;: Consistent XML format for easy parsing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety&lt;/strong&gt;: Python type hints help catch errors early&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Current Limitations
&lt;/h3&gt;

&lt;p&gt;This basic version has some limitations we'll address in future versions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No quality control (no one reviewing the cards)&lt;/li&gt;
&lt;li&gt;Limited understanding of complex topics&lt;/li&gt;
&lt;li&gt;No way to handle specialized content (like code examples)&lt;/li&gt;
&lt;li&gt;No memory of previous messages&lt;/li&gt;
&lt;li&gt;No way to improve cards based on feedback&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the next version, we'll add a second agent to review and improve the generated flashcards, making our system more robust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version 2: Two-Agent System
&lt;/h2&gt;

&lt;p&gt;In this version, we'll add a second agent - the Reviewer - to improve the quality of our flashcards. Think of it like having a teacher who creates the flashcards (Q&amp;amp;A Generator) and an editor who reviews and improves them (Reviewer).&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph LR
    Input[Input Text] --&amp;gt;|Generate| QA[Q&amp;amp;A Generator]
    QA --&amp;gt;|Review| Rev[Reviewer]
    Rev --&amp;gt;|Output| Cards[Final Flashcards]

    style Input fill:#e1f5fe,stroke:#01579b
    style QA fill:#e8f5e9,stroke:#2e7d32
    style Rev fill:#f3e5f5,stroke:#7b1fa2
    style Cards fill:#fff3e0,stroke:#ef6c00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New Components
&lt;/h3&gt;

&lt;p&gt;Let's look at what we're adding to our system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Agent Types&lt;/strong&gt;: First, we define our agent types using an Enum:
&lt;/li&gt;
&lt;/ol&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;Speaker&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="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;QA_GENERATOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Q&amp;amp;A Generator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;REVIEWER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reviewer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reviewer Agent&lt;/strong&gt;: This agent specializes in improving flashcard quality:
&lt;/li&gt;
&lt;/ol&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;reviewer_factory&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;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&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 the Reviewer agent. Your task is to review and refine Anki flashcards,
    ensuring they follow these rules:

    1. Each card should test ONE piece of information
    2. Questions must be:
       - Simple and direct
       - Testing a single fact
       - Using cloze format when appropriate
    3. Answers must be:
       - Brief and precise
       - Limited to essential information
    4. Extra field must include:
       - Detailed explanations
       - Examples
       - Context
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_tools&lt;/span&gt;&lt;span class="p"&gt;(&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="nf"&gt;get_shared_llm&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;State Management&lt;/strong&gt;: We track the progress of our flashcard creation:
&lt;/li&gt;
&lt;/ol&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;get_initial_state&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="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;dict&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;input_text&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qa_cards&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;review_status&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;pending&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;h3&gt;
  
  
  Main Function
&lt;/h3&gt;

&lt;p&gt;Here's how we combine both agents:&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;generate_anki_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_text&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;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Initialize state
&lt;/span&gt;    &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_initial_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 1: Generate initial cards
&lt;/span&gt;    &lt;span class="n"&gt;generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;qa_generator_factory&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;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&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;Generate Anki flashcards from the following text:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&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;input_text&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="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;qa_cards&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="nf"&gt;str&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;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 2: Review and improve cards
&lt;/span&gt;    &lt;span class="n"&gt;reviewer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;reviewer_factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;review_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reviewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&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;Review and improve these flashcards:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&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;qa_cards&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="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;qa_cards&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="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;review_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Transform final cards into structured data
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;transformer&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qa_cards&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;h3&gt;
  
  
  Example Usage
&lt;/h3&gt;

&lt;p&gt;Let's see how it works with our RSI example:&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;sample_text&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 Relative Strength Index (RSI) is a momentum indicator used in technical analysis.
It measures the speed and magnitude of recent price changes to evaluate overbought
or oversold conditions. RSI is displayed as an oscillator on a scale from 0 to 100.
Readings above 70 generally indicate overbought conditions, while readings below 30
indicate oversold conditions.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;flashcards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_anki_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Output
&lt;/h3&gt;

&lt;p&gt;Here's what the process looks like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initial Generation&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;cards&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;card&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;question&amp;gt;&lt;/span&gt;What is RSI in technical analysis?&lt;span class="nt"&gt;&amp;lt;/question&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;answer&amp;gt;&lt;/span&gt;A momentum indicator that measures speed and magnitude of recent price changes&lt;span class="nt"&gt;&amp;lt;/answer&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;extra&amp;gt;&lt;/span&gt;Used to evaluate overbought/oversold conditions&lt;span class="nt"&gt;&amp;lt;/extra&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/card&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/cards&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;After Review&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;cards&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;card&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;question&amp;gt;&lt;/span&gt;RSI (Relative Strength Index) is a _____ indicator in technical analysis.&lt;span class="nt"&gt;&amp;lt;/question&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;answer&amp;gt;&lt;/span&gt;momentum&lt;span class="nt"&gt;&amp;lt;/answer&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;extra&amp;gt;&lt;/span&gt;
        Key points about RSI:
        - Measures speed/magnitude of price changes
        - Scale: 0 to 100
        - Overbought: Above 70
        - Oversold: Below 30
        &lt;span class="nt"&gt;&amp;lt;/extra&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/card&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/cards&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Improvements
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Quality Control&lt;/strong&gt;: The Reviewer agent ensures better card quality&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Format&lt;/strong&gt;: Cloze deletions for more effective learning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Richer Context&lt;/strong&gt;: More detailed extra field content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Progress Tracking&lt;/strong&gt;: State management shows card status&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Structure&lt;/strong&gt;: XML format maintained throughout&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Current Limitations
&lt;/h3&gt;

&lt;p&gt;While better than Version 1, this system still has some limitations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No way to analyze complex topics&lt;/li&gt;
&lt;li&gt;Basic two-step process (could be more sophisticated)&lt;/li&gt;
&lt;li&gt;No memory of previous messages&lt;/li&gt;
&lt;li&gt;Limited error handling&lt;/li&gt;
&lt;li&gt;No way to handle specialized content (like code)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Version 3, we'll add more agents to handle these limitations and create a more robust system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version 3: Multi-Agent Orchestra
&lt;/h2&gt;

&lt;p&gt;In this version, we enhance our system by enabling multiple agents to collaborate effectively. Each agent has a specific role, and they work together to create high-quality flashcards. The Orchestrator agent plays a crucial role in managing this collaboration, ensuring that each agent contributes at the right time. Additionally, the Topic Analyzer helps break down complex topics into simpler parts, providing a structured overview of the content.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Multi-Agent Collaboration Works
&lt;/h3&gt;

&lt;p&gt;In a multi-agent system, each agent is like a team member with a specific expertise. Here's how they collaborate:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Specialized Roles&lt;/strong&gt;: Each agent is designed to perform a specific task. For example, the Q&amp;amp;A Generator creates flashcards, while the Reviewer ensures their quality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sequential Processing&lt;/strong&gt;: Agents work in a sequence, with each one building on the output of the previous agent. This ensures that the final product is refined and comprehensive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dynamic Decision-Making&lt;/strong&gt;: The Orchestrator agent decides which agent should work next based on the current state of the process. This allows the system to adapt to the needs of the content dynamically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Shared Context&lt;/strong&gt;: A memory system maintains context across interactions, allowing agents to make informed decisions based on previous outputs.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Introducing the Orchestrator Agent
&lt;/h3&gt;

&lt;p&gt;The Orchestrator is the manager of our multi-agent system. It coordinates the workflow, ensuring that each agent contributes effectively. Here's how it works:&lt;/p&gt;

&lt;h4&gt;
  
  
  Orchestrator's Role
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decision-Making&lt;/strong&gt;: The Orchestrator evaluates the current state and decides which agent should run next. It ensures that the workflow is efficient and that all necessary tasks are completed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: The Orchestrator can choose any agent at any time, allowing for a flexible and adaptive process. It can run agents multiple times if needed or skip steps if the content is already complete.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;End Condition&lt;/strong&gt;: The Orchestrator decides when the process is complete, ensuring that the final flashcards are comprehensive and high-quality.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Orchestrator Implementation
&lt;/h4&gt;

&lt;p&gt;Here's how we implement the Orchestrator:&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;orchestrator_factory&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="nb"&gt;dict&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;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt; &lt;span class="o"&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;
    You are the Orchestrator agent. Your task is to coordinate the interaction between all agents to create high-quality flashcards.

    Current State:
    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;pformat&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;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    Available agents:
    * Topic Analyzer - Breaks down complex topics
    * Q&amp;amp;A Generator - Creates flashcards
    * Reviewer - Improves card quality

    Decision Guidelines:
    - Use Topic Analyzer first for topic breakdown
    - Use Q&amp;amp;A Generator to create cards
    - Use Reviewer to refine cards
    - Choose END when the cards are ready

    Output only the next agent to run (&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Topic Analyzer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Q&amp;amp;A Generator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reviewer&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;END&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_tools&lt;/span&gt;&lt;span class="p"&gt;(&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="nf"&gt;get_shared_llm&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&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;h3&gt;
  
  
  Introducing the Topic Analyzer Agent
&lt;/h3&gt;

&lt;p&gt;The Topic Analyzer is responsible for breaking down complex topics into manageable parts. It provides a structured overview of the content, which helps in creating more focused and comprehensive flashcards.&lt;/p&gt;

&lt;h4&gt;
  
  
  Topic Analyzer's Role
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Content Breakdown&lt;/strong&gt;: The Topic Analyzer identifies key topics and subtopics from the input text, helping to structure the content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hierarchical Structuring&lt;/strong&gt;: It creates a hierarchical structure of topics, making it easier to understand the relationships between different concepts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Application Suggestions&lt;/strong&gt;: The agent suggests real-world applications or case studies related to the topics, enriching the flashcards with practical insights.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Topic Analyzer Implementation
&lt;/h4&gt;

&lt;p&gt;Here's how we implement the Topic Analyzer:&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;topic_analyzer_factory&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="nb"&gt;dict&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;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt; &lt;span class="o"&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;
    You are the Topic Analyzer agent. Your task is to analyze the given text and identify key topics for flashcard creation.

    Current State:
    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;pformat&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;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    Instructions:
    1. Identify main concepts and sub-concepts
    2. Create a structured list of topics
    3. Suggest real-world applications

    Output format:
    &amp;lt;topics&amp;gt;
        &amp;lt;topic&amp;gt;
            &amp;lt;name&amp;gt;Main topic name&amp;lt;/name&amp;gt;
            &amp;lt;subtopics&amp;gt;
                &amp;lt;subtopic&amp;gt;Subtopic 1&amp;lt;/subtopic&amp;gt;
                &amp;lt;subtopic&amp;gt;Subtopic 2&amp;lt;/subtopic&amp;gt;
            &amp;lt;/subtopics&amp;gt;
        &amp;lt;/topic&amp;gt;
    &amp;lt;/topics&amp;gt;
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_tools&lt;/span&gt;&lt;span class="p"&gt;(&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="nf"&gt;get_shared_llm&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Main Function
&lt;/h3&gt;

&lt;p&gt;The main function now includes the Orchestrator, which dynamically decides the workflow:&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;generate_anki_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_text&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;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Initialize state and memory
&lt;/span&gt;    &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_initial_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setup_memory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Get current chat history
&lt;/span&gt;        &lt;span class="n"&gt;current_history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memory&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="c1"&gt;# Let Orchestrator decide next step
&lt;/span&gt;        &lt;span class="n"&gt;orchestrator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;orchestrator_factory&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;next_agent&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;orchestrator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Decide which agent to run next based on the current state.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;chat_history&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_history&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;strip&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="nf"&gt;strip&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="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;Orchestrator selected: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;next_agent&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;next_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;END&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;Orchestrator decided to end the process&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;

        &lt;span class="c1"&gt;# Execute selected agent
&lt;/span&gt;        &lt;span class="k"&gt;try&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;next_agent&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Speaker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TOPIC_ANALYZER&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="n"&gt;analyzer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;topic_analyzer_factory&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&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;Analyze this text for flashcard topics:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&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;input_text&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="n"&gt;chat_history&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_history&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;topics&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="nf"&gt;str&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;)&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;Topic Analysis Results:&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;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;topics&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;next_agent&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Speaker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QA_GENERATOR&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="n"&gt;generator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;qa_generator_factory&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;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&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;Generate flashcards for this topic:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&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;topics&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="n"&gt;chat_history&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_history&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qa_cards&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="nf"&gt;str&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;)&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;review_status&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="s"&gt;needs_review&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="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Generated Cards:&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;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;qa_cards&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;next_agent&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Speaker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REVIEWER&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="n"&gt;reviewer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;reviewer_factory&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;reviewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&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;Review these flashcards:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&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;qa_cards&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="n"&gt;chat_history&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_history&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qa_cards&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="nf"&gt;str&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;)&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;review_status&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="s"&gt;reviewed&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="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Reviewed Cards:&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;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;qa_cards&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

                &lt;span class="c1"&gt;# Update memory with new interaction
&lt;/span&gt;                &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatMessage&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;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&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;response&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;Updated memory with &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;next_agent&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;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="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Error in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;next_agent&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="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;continue&lt;/span&gt;

    &lt;span class="c1"&gt;# Transform final cards into structured data
&lt;/span&gt;    &lt;span class="n"&gt;final_cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;transformer&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qa_cards&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;final_cards&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Usage
&lt;/h3&gt;

&lt;p&gt;Here's how the orchestrated system works with our RSI example:&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;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;sample_text&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 Relative Strength Index (RSI) is a momentum indicator used in technical analysis.
    It measures the speed and magnitude of recent price changes to evaluate overbought
    or oversold conditions. RSI is displayed as an oscillator on a scale from 0 to 100.
    Readings above 70 generally indicate overbought conditions, while readings below 30
    indicate oversold conditions. The RSI can also help identify divergences, trend lines,
    and failure swings that may not be apparent on the underlying price chart.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;flashcards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_anki_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample_text&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;Generated, Analyzed, and Reviewed Flashcards:&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;flashcards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Improvements
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Coordinated Workflow&lt;/strong&gt;: The Orchestrator manages agent interactions, ensuring a smooth and efficient process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Topic Analysis&lt;/strong&gt;: The Topic Analyzer provides a deeper understanding of content structure, leading to more comprehensive flashcards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent Memory&lt;/strong&gt;: Context is maintained across interactions, allowing for more informed decision-making.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible Execution&lt;/strong&gt;: The Orchestrator dynamically selects agents based on the current state, adapting to the needs of the content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hierarchical Processing&lt;/strong&gt;: Topics are broken down into manageable chunks, making it easier to create detailed and accurate flashcards.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;p&gt;While this version is more sophisticated, it still has some areas for improvement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No specialized handling of code examples&lt;/li&gt;
&lt;li&gt;Limited formatting options&lt;/li&gt;
&lt;li&gt;Basic error handling&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Version 4, we'll introduce the Code and Extra Field Expert agent and a Formatter agent to handle code examples and ensure consistent formatting. We'll also improve error handling and add support for different content types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version 4: Enhanced Capabilities
&lt;/h2&gt;

&lt;p&gt;In this version, we introduce two new agents: the Code and Extra Field Expert and the Formatter. These agents handle code examples and ensure consistent formatting, respectively. We also improve error handling and add support for different content types.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph TB
    Input[Input Text] --&amp;gt;|Start| Orch[Orchestrator]

    Orch --&amp;gt;|Analyze| TA[Topic Analyzer]
    Orch --&amp;gt;|Process Code| Code[Code Expert]
    Orch --&amp;gt;|Generate| QA[Q&amp;amp;A Generator]
    Orch --&amp;gt;|Format| Format[Formatter]
    Orch --&amp;gt;|Review| Rev[Reviewer]

    TA --&amp;gt;|Topics| Decision{Continue?}
    Code --&amp;gt;|Results| Decision
    QA --&amp;gt;|Results| Decision
    Format --&amp;gt;|Results| Decision
    Rev --&amp;gt;|Results| Decision

    Decision --&amp;gt;|Yes| Orch
    Decision --&amp;gt;|No| Final[Final Flashcards]

    style Input fill:#e1f5fe,stroke:#01579b
    style Orch fill:#fff3e0,stroke:#ef6c00
    style TA fill:#e8f5e9,stroke:#2e7d32
    style Code fill:#e8f5e9,stroke:#2e7d32
    style QA fill:#bbdefb,stroke:#1976d2
    style Format fill:#bbdefb,stroke:#1976d2
    style Rev fill:#f3e5f5,stroke:#7b1fa2
    style Final fill:#fff3e0,stroke:#ef6c00
    style Decision fill:#ffecb3,stroke:#ffa000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New Components
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Updated Agent Types
&lt;/h4&gt;

&lt;p&gt;We expand our agent types to include the new roles:&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;Speaker&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="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;QA_GENERATOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Q&amp;amp;A Generator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;REVIEWER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reviewer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;TOPIC_ANALYZER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Topic Analyzer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;ORCHESTRATOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Orchestrator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;CODE_AND_EXTRA_FIELD_EXPERT&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 and Extra Field Expert&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;FORMATTER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Formatter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Code and Extra Field Expert
&lt;/h4&gt;

&lt;p&gt;This agent enhances flashcards with code examples and detailed explanations:&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;code_and_extra_field_expert_factory&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;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&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 the Code and Extra Field Expert agent. Your task is to enhance Anki flashcards
    by adding relevant code snippets and comprehensive extra content.

    Instructions:
    1. Add clear, concise code examples that illustrate key concepts
    2. Ensure code snippets are well-commented and easy to understand
    3. In the extra field, provide:
       - Step-by-step explanations of code snippets 
       - Common use cases and scenarios
       - Potential pitfalls and edge cases
       - Best practices and optimization tips
    4. Use appropriate markdown formatting for code blocks
    5. Include relevant documentation links
    6. Ensure explanations are clear for a 15-year-old
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_tools&lt;/span&gt;&lt;span class="p"&gt;(&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="nf"&gt;get_shared_llm&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&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;h4&gt;
  
  
  3. Formatter Agent
&lt;/h4&gt;

&lt;p&gt;This agent ensures that the flashcards are properly formatted:&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;formatter_agent_factory&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;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&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 the Formatter agent. Your task is to ensure proper XML structure and markdown
    formatting in the flashcards.

    Formatting Rules:
    1. Maintain valid XML structure
    2. Properly escape special characters
    3. Format code blocks with appropriate language tags
    4. Use consistent indentation
    5. Ensure markdown compatibility
    6. Preserve code snippets exactly as provided
    7. Handle nested structures properly
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OpenAIAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_tools&lt;/span&gt;&lt;span class="p"&gt;(&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="nf"&gt;get_shared_llm&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;system_prompt&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;h3&gt;
  
  
  Enhanced Error Handling and Validation
&lt;/h3&gt;

&lt;p&gt;We improve error handling with retries and validation:&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;@retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;stop_after_attempt&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="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;wait_exponential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;multiplier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_and_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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;dict&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="c1"&gt;# Transform to structured data
&lt;/span&gt;        &lt;span class="n"&gt;chat_prompt_tmpl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ChatPromptTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;message_templates&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="n"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;structured_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_shared_llm&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;structured_predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;Flashcard_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;chat_prompt_tmpl&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;structured_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ET&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseError&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;XML validation error: &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;raise&lt;/span&gt; &lt;span class="n"&gt;TryAgain&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;Transformation error: &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;raise&lt;/span&gt; &lt;span class="n"&gt;TryAgain&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Usage
&lt;/h3&gt;

&lt;p&gt;Here's how the enhanced system works with a sample text that includes 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;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;sample_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    To calculate the RSI (Relative Strength Index) in Python, you typically use 
    technical analysis libraries like pandas-ta or the ta library. The RSI is 
    calculated using the average gains and losses over a specified period 
    (usually 14 periods). Here&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s how you can implement it:

    1. Using the ta library:
    ```

python
    import pandas as pd
    import ta

    # Assuming you have price data in a DataFrame
    df[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RSI&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;] = ta.momentum.RSIIndicator(
        close=df[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;close&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;],
        window=14
    ).rsi()


    ```

    2. Manual implementation:
    ```

python
    def calculate_rsi(data, periods=14):
        delta = data.diff()
        gain = (delta.where(delta &amp;gt; 0, 0)).rolling(
            window=periods).mean()
        loss = (-delta.where(delta &amp;lt; 0, 0)).rolling(
            window=periods).mean()
        rs = gain / loss
        return 100 - (100 / (1 + rs))


    ```
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;flashcards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_anki_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample_text&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;Generated Flashcards with Code Examples:&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;flashcards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Improvements
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Code Handling&lt;/strong&gt;: Specialized agent for code examples and explanations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Formatting&lt;/strong&gt;: Dedicated formatter agent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robust Error Handling&lt;/strong&gt;: Improved validation and retries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich Extra Content&lt;/strong&gt;: Comprehensive explanations and best practices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markdown Support&lt;/strong&gt;: Proper formatting of code blocks and text&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Throughout this tutorial, we've built a sophisticated multi-agent system for generating Anki flashcards, progressing from a simple single-agent implementation to a complex orchestrated system. Let's recap the key developments across each version:&lt;/p&gt;

&lt;h3&gt;
  
  
  Evolution of the System
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Version 1: Basic Single-Agent&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Established core data structures&lt;/li&gt;
&lt;li&gt;Implemented basic flashcard generation&lt;/li&gt;
&lt;li&gt;Set up error handling foundation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Version 2: Two-Agent Interaction&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added quality control through review process&lt;/li&gt;
&lt;li&gt;Introduced state management&lt;/li&gt;
&lt;li&gt;Implemented iterative refinement&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Version 3: Multi-Agent Orchestra&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added orchestration layer&lt;/li&gt;
&lt;li&gt;Implemented topic analysis&lt;/li&gt;
&lt;li&gt;Enhanced context management through memory system&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Version 4: Enhanced Capabilities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added specialized code handling&lt;/li&gt;
&lt;li&gt;Implemented consistent formatting&lt;/li&gt;
&lt;li&gt;Enhanced error handling and validation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Key Takeaways
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Modular Design&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each agent has a specific responsibility&lt;/li&gt;
&lt;li&gt;Easy to add new agents or modify existing ones&lt;/li&gt;
&lt;li&gt;Clear separation of concerns&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Robust Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State management across agents&lt;/li&gt;
&lt;li&gt;Error handling and retry mechanisms&lt;/li&gt;
&lt;li&gt;Memory system for context preservation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quality Control&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple layers of review and refinement&lt;/li&gt;
&lt;li&gt;Consistent formatting and structure&lt;/li&gt;
&lt;li&gt;Rich content with code examples and explanations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Future Enhancements
&lt;/h3&gt;

&lt;p&gt;While our system is already quite capable, there are several potential areas for future improvement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Parallel Processing&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement concurrent card generation&lt;/li&gt;
&lt;li&gt;Add batch processing capabilities&lt;/li&gt;
&lt;li&gt;Optimize for large-scale operations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Advanced Features&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image handling and processing&lt;/li&gt;
&lt;li&gt;Multi-language support&lt;/li&gt;
&lt;li&gt;Audio content integration&lt;/li&gt;
&lt;li&gt;Interactive examples&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Learning Capabilities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Feedback incorporation&lt;/li&gt;
&lt;li&gt;Quality metrics tracking&lt;/li&gt;
&lt;li&gt;Adaptive prompt refinement&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Integration Options&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API endpoints&lt;/li&gt;
&lt;li&gt;Web interface&lt;/li&gt;
&lt;li&gt;Direct Anki integration&lt;/li&gt;
&lt;li&gt;Version control for cards&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Building a multi-agent system requires careful consideration of agent interactions, state management, and error handling. This tutorial has demonstrated how to incrementally build such a system, starting from basic components and progressively adding sophistication.&lt;/p&gt;

&lt;p&gt;The final system showcases the power of combining multiple specialized agents, each with its own expertise, to create a robust and flexible solution. While the focus has been on Anki flashcard generation, the patterns and principles demonstrated here can be applied to many other multi-agent applications.&lt;/p&gt;

&lt;p&gt;Remember that the key to successful multi-agent systems lies in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear agent responsibilities&lt;/li&gt;
&lt;li&gt;Robust communication patterns&lt;/li&gt;
&lt;li&gt;Comprehensive error handling&lt;/li&gt;
&lt;li&gt;Flexible state management&lt;/li&gt;
&lt;li&gt;Consistent output formatting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these principles and the patterns demonstrated in this tutorial, you can build your own multi-agent systems for various applications beyond flashcard generation.&lt;/p&gt;

</description>
      <category>multiagents</category>
      <category>llamaindex</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>Understanding and Mitigating Message Loss in Apache Kafka</title>
      <dc:creator>Yusen Meng</dc:creator>
      <pubDate>Thu, 25 Apr 2024 07:14:36 +0000</pubDate>
      <link>https://dev.to/yukooshima/understanding-and-mitigating-message-loss-in-apache-kafka-28jp</link>
      <guid>https://dev.to/yukooshima/understanding-and-mitigating-message-loss-in-apache-kafka-28jp</guid>
      <description>&lt;p&gt;Apache Kafka, a popular distributed streaming platform, enables the building of scalable and fault-tolerant real-time data pipelines and applications. However, like any distributed system, Kafka is not immune to message loss, which can lead to data inconsistencies and impact system reliability.&lt;br&gt;
In this article, we will explore the potential causes of message loss in Apache Kafka, focusing on producers, brokers, and consumers. We'll discuss scenarios such as improper acknowledgment settings, asynchronous disk flushing, replica synchronization issues, and the pitfalls of auto-commit in consumers.&lt;br&gt;
By understanding these message loss scenarios, we can develop strategies to mitigate risks and ensure the reliability of our Kafka-based applications. We'll cover techniques like proper configuration, manual offset committing, idempotent message processing, and transactional commits.&lt;br&gt;
So, let's dive in and learn how to build robust and fault-tolerant Kafka-based systems that minimize message loss and guarantee data integrity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Producer
&lt;/h2&gt;

&lt;p&gt;When we call producer.send() to send a message, it doesn't get sent to the broker directly. There are two threads and a queue involved in the message-sending process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Application thread&lt;/li&gt;
&lt;li&gt;Record accumulator&lt;/li&gt;
&lt;li&gt;Sender thread (I/O thread)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The flow of a message from the producer to the broker can be visualized as follows:&lt;/p&gt;

&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%2Fppjg99427bt12ohs9fvr.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%2Fppjg99427bt12ohs9fvr.png" alt="flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Application Thread:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;The application thread is responsible for creating the producer record and calling the producer.send() method.&lt;/li&gt;
&lt;li&gt;It serializes the key and value of the record using the configured serializers.&lt;/li&gt;
&lt;li&gt;The record is then added to the record accumulator.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Record Accumulator:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;The record accumulator is a buffer that holds the records waiting to be sent to the Kafka broker.&lt;/li&gt;
&lt;li&gt;It is essentially a queue that stores the records in memory.&lt;/li&gt;
&lt;li&gt;The records are grouped into batches based on the topic and partition they belong to.&lt;/li&gt;
&lt;li&gt;The batch size and the time to wait before sending the batch can be configured using the 'batch.size' and 'linger.ms' properties, respectively.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Sender Thread:

&lt;ul&gt;
&lt;li&gt;The sender thread, also known as the I/O thread, is responsible for sending the batches of records from the record accumulator to the Kafka broker.&lt;/li&gt;
&lt;li&gt;It periodically checks the record accumulator for any ready batches and sends them to the corresponding broker.&lt;/li&gt;
&lt;li&gt;The sender thread handles the network communication with the Kafka broker.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To ensure that messages are reliably sent to the broker and to prevent message loss, we need to configure the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;'acks': This property determines the level of acknowledgment required from the broker.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;'acks=0': The producer does not wait for any acknowledgment from the broker. Messages may be lost if the broker fails.&lt;/li&gt;
&lt;li&gt;'acks=1' (default): The producer waits for the leader to acknowledge the write. Messages may be lost if the leader fails before replicating to followers.&lt;/li&gt;
&lt;li&gt;'acks=all' or 'acks=-1': The producer waits for the full set of in-sync replicas to acknowledge the write. This provides the highest level of durability but increases latency.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;'retries': This property specifies the number of times the producer will attempt to resend a failed record.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, 'retries' is set to 0, meaning no retries will be attempted.&lt;/li&gt;
&lt;li&gt;Setting 'retries' to a higher value, such as 3 or 5, allows the producer to handle transient failures and improve the chances of successful message delivery.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/Shopify/sarama"&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;sarama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewConfig&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;Producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequiredAcks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sarama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitForAll&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;Producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Retry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;

&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sarama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSyncProducer&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"localhost:9092"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;config&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Handle error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sarama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProducerMessage&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Topic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"my-topic"&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;sarama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&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="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sarama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Handle error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Broker
&lt;/h2&gt;

&lt;p&gt;A broker cluster should not lose messages when it is functioning normally. However, we need to understand which extreme situations might lead to message loss:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Asynchronous Disk Flush:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Kafka brokers use an asynchronous disk flush mechanism to improve I/O throughput and performance.&lt;/li&gt;
&lt;li&gt;When a producer sends a message to a broker, the message is initially stored in memory and not immediately written to disk.&lt;/li&gt;
&lt;li&gt;The broker periodically flushes the messages from memory to disk in the background.&lt;/li&gt;
&lt;li&gt;If the broker instance crashes or experiences a sudden shutdown before the flush occurs, the messages that were in memory but not yet flushed to disk will be lost.&lt;/li&gt;
&lt;li&gt;To mitigate this risk, Kafka provides configurable flush settings, such as 'log.flush.interval.messages' and 'log.flush.interval.ms', which determine when the broker should flush messages to disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Replica Synchronization:

&lt;ul&gt;
&lt;li&gt;Kafka ensures data durability and fault tolerance by maintaining replicas of partitions across multiple broker instances.&lt;/li&gt;
&lt;li&gt;Each partition has a leader replica and zero or more follower replicas.&lt;/li&gt;
&lt;li&gt;The leader replica handles all read and write operations for the partition, while the follower replicas passively replicate the data from the leader.&lt;/li&gt;
&lt;li&gt;If the leader replica fails, one of the follower replicas is elected as the new leader to ensure data availability.&lt;/li&gt;
&lt;li&gt;However, if the replicas are not properly synchronized or if there is a significant lag between the leader and followers, message loss can occur in certain scenarios:

&lt;ul&gt;
&lt;li&gt;If the leader replica fails and a follower replica with outdated data is elected as the new leader, any messages that were not yet replicated to the follower will be lost.&lt;/li&gt;
&lt;li&gt;If a producer sends a message with 'acks=1' (only wait for the leader acknowledgment) and the leader fails before replicating the message to followers, the message will be lost.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;To minimize the risk of message loss due to replica synchronization issues, it is important to configure the replication factor and the 'min.insync.replicas' setting appropriately.&lt;/li&gt;
&lt;li&gt;The replication factor determines the number of replicas for each partition, providing redundancy.&lt;/li&gt;
&lt;li&gt;The 'min.insync.replicas' setting specifies the minimum number of in-sync replicas required for a write to be considered successful, ensuring data consistency.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a diagram illustrating the replication process in Kafka:&lt;/p&gt;

&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%2F5c8vsyrv181ymdomnbhr.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%2F5c8vsyrv181ymdomnbhr.png" alt="flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this diagram, the producer sends a message to the leader replica, which then replicates the message to the follower replica. Once the follower replica acknowledges the replication, the leader replica sends an acknowledgment back to the producer.&lt;/p&gt;

&lt;p&gt;To ensure data durability and minimize message loss, it is recommended to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure a sufficient replication factor (e.g., 3) to maintain multiple copies of the data.&lt;/li&gt;
&lt;li&gt;Set 'min.insync.replicas' to a value greater than 1 to ensure that writes are considered successful only when the message is replicated to multiple replicas.&lt;/li&gt;
&lt;li&gt;Use 'acks=all' or 'acks=-1' to wait for acknowledgment from all in-sync replicas before considering a write successful.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By following these best practices and configuring Kafka appropriately, the risk of message loss in a broker cluster can be significantly reduced, even in extreme situations.&lt;/p&gt;
&lt;h2&gt;
  
  
  Consumer
&lt;/h2&gt;

&lt;p&gt;Kafka offers different ways to commit offsets, which represent the position of the last consumed message in a partition. Offset committing is crucial for tracking the progress of a consumer and ensuring that messages are not processed multiple times or skipped. However, the auto-commit feature in Kafka can sometimes lead to message loss if not used carefully.&lt;/p&gt;

&lt;p&gt;Auto-Commit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, Kafka consumers have auto-commit enabled, which means the consumer will automatically commit the offsets of the messages it has received at a regular interval.&lt;/li&gt;
&lt;li&gt;The auto-commit interval is controlled by the 'auto.commit.interval.ms' configuration property, which defaults to 5 seconds.&lt;/li&gt;
&lt;li&gt;When auto-commit is enabled, the consumer sends an asynchronous commit request to the Kafka broker at the specified interval, acknowledging the messages it has received and processed.&lt;/li&gt;
&lt;li&gt;However, auto-commit can be problematic in certain scenarios, particularly when the consumer is down or fails in the middle of processing a batch of messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Potential Message Loss with Auto-Commit:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Consumer Failure during Message Processing:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Consider a scenario where the consumer has received a batch of messages and auto-commit is enabled.&lt;/li&gt;
&lt;li&gt;The consumer starts processing the messages but encounters an error or crashes before completing the processing of all messages in the batch.&lt;/li&gt;
&lt;li&gt;Since the offsets were automatically committed at the beginning of the batch, the consumer will resume from the next offset when it restarts, even though some messages in the previous batch were not fully processed.&lt;/li&gt;
&lt;li&gt;This can lead to message loss because the unprocessed messages will be skipped, and the consumer will move on to the next batch.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Delayed Message Processing:

&lt;ul&gt;
&lt;li&gt;In some cases, message processing might take longer than the auto-commit interval.&lt;/li&gt;
&lt;li&gt;If the consumer is still processing a message when the auto-commit interval elapses, the offset will be committed before the message processing is complete.&lt;/li&gt;
&lt;li&gt;If the consumer fails or is shut down after the auto-commit but before completing the message processing, the message will be considered processed even though it was not fully handled.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&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%2F6h7ca1wciwinpw4tdfxs.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%2F6h7ca1wciwinpw4tdfxs.png" alt="flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To mitigate the risk of message loss with auto-commit, consider the following approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manual Offset Committing:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Instead of relying on auto-commit, you can manually control when offsets are committed.&lt;/li&gt;
&lt;li&gt;After successfully processing a message or a batch of messages, the consumer can call the &lt;code&gt;commitSync()&lt;/code&gt; or &lt;code&gt;commitAsync()&lt;/code&gt; method to commit the offsets explicitly.&lt;/li&gt;
&lt;li&gt;This ensures that offsets are only committed when the messages are fully processed, reducing the chances of message loss.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Idempotent Message Processing:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Design your consumer to handle message processing in an idempotent manner.&lt;/li&gt;
&lt;li&gt;Idempotence means that the processing of the same message multiple times should have the same effect as processing it once.&lt;/li&gt;
&lt;li&gt;By making the message processing idempotent, even if a message is processed more than once due to offset commit issues, it will not have unintended consequences.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Batch Processing with Transactional Commits:

&lt;ul&gt;
&lt;li&gt;If your consumer processes messages in batches, you can use transactional commits to ensure atomic offset commits.&lt;/li&gt;
&lt;li&gt;With transactional commits, the offset commit is tied to the successful processing of the entire batch.&lt;/li&gt;
&lt;li&gt;If the batch processing fails, the transaction is aborted, and the offsets are not committed, allowing the consumer to reprocess the batch from the beginning.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's an example of manual offset committing in using the Kafka consumer API:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/Shopify/sarama"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sarama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewConfig&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;Consumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

    &lt;span class="c"&gt;// Create a new consumer&lt;/span&gt;
    &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sarama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewConsumer&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"localhost:9092"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;config&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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="c"&gt;// Subscribe to the topic&lt;/span&gt;
    &lt;span class="n"&gt;topic&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"my-topic"&lt;/span&gt;
    &lt;span class="n"&gt;partitionConsumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConsumePartition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sarama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OffsetNewest&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;partitionConsumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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="c"&gt;// Consume messages&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;partitionConsumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Messages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="c"&gt;// Process the message&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received message: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

            &lt;span class="c"&gt;// Manually commit the offset after processing the message&lt;/span&gt;
            &lt;span class="n"&gt;partitionConsumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarkOffset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;partitionConsumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;Another condition is that the consumer may consume the message multiple times.&lt;/p&gt;

&lt;p&gt;In the given scenario, the Kafka consumer is configured with auto-commit enabled, which means that the consumer automatically commits the offsets of the messages it has consumed at regular intervals specified by the auto-commit interval.&lt;/p&gt;

&lt;p&gt;The consumer starts by polling a batch of messages (batch 1) from the Kafka broker. It then processes messages 1, 2, and 3 from batch 1. During the processing of batch 1, the auto-commit interval elapses, but the consumer does not explicitly commit the offsets for batch 1 to the Kafka broker.&lt;/p&gt;

&lt;p&gt;Next, the consumer polls the next batch of messages (batch 2) from the Kafka broker and starts processing messages 4 and 5 from batch 2. However, while processing batch 2, the consumer fails or crashes.&lt;/p&gt;

&lt;p&gt;When the consumer restarts, it resumes from the last committed offset, which is the offset before batch 1 (since no explicit offset commit was made). The consumer polls messages from the last committed offset, which includes messages from batch 1 and batch 2. As a result, the consumer reprocesses messages 4 and 5 from batch 2, along with messages 6 and 7.&lt;/p&gt;

&lt;p&gt;The issue with this scenario is that messages 4 and 5 are reprocessed because the offsets were not explicitly committed to the Kafka broker before the consumer failure. Reprocessing messages can lead to challenges such as duplicate processing or inconsistent state.&lt;/p&gt;

&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%2F2vmj0737mn6z2a8q9zdt.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%2F2vmj0737mn6z2a8q9zdt.png" alt="flow"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this article, we explored the potential causes of message loss in Kafka and discussed strategies to mitigate them. We covered message loss scenarios in Kafka producers, brokers, and consumers, highlighting the importance of proper configuration and handling.&lt;/p&gt;

&lt;p&gt;For producers, configuring the appropriate &lt;code&gt;acks&lt;/code&gt; and &lt;code&gt;retries&lt;/code&gt; settings ensures reliable message delivery. In the case of brokers, asynchronous disk flushing and replica synchronization issues can lead to message loss, which can be mitigated by configuring flush settings, replication factors, and &lt;code&gt;min.insync.replicas&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Consumers, on the other hand, need to be cautious when using auto-commit, as it can result in message loss if the consumer fails during message processing. To prevent this, manual offset committing, idempotent message processing, and transactional commits can be employed.&lt;/p&gt;

&lt;p&gt;Additionally, we discussed the scenario where a consumer may consume the same message multiple times due to the lack of explicit offset commits before a consumer failure. This can lead to duplicate processing and inconsistent states. To address this, manual offset committing or transactional processing can be used to ensure that offsets are only committed when messages are fully processed.&lt;/p&gt;

&lt;p&gt;By understanding the potential pitfalls and applying the appropriate strategies, developers can build reliable and fault-tolerant Kafka-based systems. It is crucial to carefully consider the configuration settings, offset commit strategies, and error handling mechanisms to ensure data integrity and prevent message loss.&lt;/p&gt;

&lt;p&gt;As with any distributed system, testing and monitoring play a vital role in identifying and resolving issues related to message loss. Regular monitoring of Kafka metrics, logs, and consumer lag can help detect anomalies and take corrective actions promptly.&lt;/p&gt;

&lt;p&gt;In conclusion, while Kafka provides a robust and scalable platform for real-time data streaming, it is important to be aware of the potential message loss scenarios and employ the necessary measures to mitigate them. By following best practices and implementing the appropriate strategies discussed in this article, developers can build reliable and resilient Kafka-based applications that ensure data integrity and minimize the risk of message loss.&lt;/p&gt;

</description>
      <category>bigdata</category>
      <category>datareliability</category>
      <category>streamprocessing</category>
      <category>distributed</category>
    </item>
    <item>
      <title>From the function of API Gateway, see the evolution of Web architecture</title>
      <dc:creator>Yusen Meng</dc:creator>
      <pubDate>Wed, 01 Nov 2023 14:59:36 +0000</pubDate>
      <link>https://dev.to/yukooshima/from-the-function-of-api-gateway-see-the-evolution-of-web-architecture-134f</link>
      <guid>https://dev.to/yukooshima/from-the-function-of-api-gateway-see-the-evolution-of-web-architecture-134f</guid>
      <description>&lt;p&gt;This article summarizes the evolution of Web service architecture from start-ups to large enterprises based on my own past work experience. These experiences come from practices in different companies and different levels of project complexity. These architectures come from practical experience in work, may not be complete, and there may be omissions or inaccuracies. Welcome to discuss and exchange, so that we can learn and progress together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monolithic architecture, a handy Swiss army knife
&lt;/h2&gt;

&lt;p&gt;A new project or a start-up company, the most common Web architecture is monolithic architecture. It can still be seen in many small teams in the company. As the name suggests, in this architecture, all functions and components are packaged into a single, tightly integrated program and run in a process space. Strictly speaking, there is no API Gateway service here, all requests will be forwarded to the same Server through NGINX or Apache's reverse proxy.&lt;/p&gt;

&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%2Fh52m6x3c0r8xuadzp856.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%2Fh52m6x3c0r8xuadzp856.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Monolithic architecture has the following characteristics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Tightly integrated components: In a monolithic application, all functions and components are tightly integrated. They may interact through function calls, library references, and other mechanisms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simple deployment: Since it is a monolithic application or service, deployment is usually relatively simple. Just need to start an application or service, in the early days when virtualization technology has not yet appeared, simple deployment and startup reduce the complexity of the project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scalability issues: As the application scale and complexity grow, it is easy to produce monolithic applications, and the application becomes difficult to maintain and expand. Especially when horizontal expansion is needed, we can only deploy the entire application to multiple servers, rather than deploying the bottleneck part.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fault isolation: Since all functions are in one application, a component failure may cause the entire application to crash, affecting the integrity of the entire application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Technology stack restrictions: In a monolithic application, usually use a technology stack or framework. If you need to introduce a new technology stack or framework, you often need to do a complete reconstruction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Continuous integration/continuous deployment: As the complexity and volume of the application increase, building, testing, and deployment may become slower.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Monolithic architecture has been very popular in early Internet companies and has long dominated the mainstream. Therefore, we often hear about deploying a service to a 48C, 48G server. However, with the rise of containerization technology, this kind of monolithic application gradually disappeared in the long river of history. We now hear more about deploying a service to a 2C, 2G server, and then supporting more traffic and services through horizontal expansion.&lt;/p&gt;

&lt;h2&gt;
  
  
  The embryonic form of microservices, splitting monolithic applications into multiple small services
&lt;/h2&gt;

&lt;p&gt;In response to the various problems encountered by monolithic applications, we have split the monolithic applications according to functions, which is usually judged by the independence of business logic or data. For example, user management, order processing, inventory management, etc. can be regarded as independent services. Next, we need to set up a service gateway, such as NGINX, to handle all requests and responses. The main responsibility of the service gateway is to forward the request to the corresponding service according to the path of the request. For example, all requests starting with /user are forwarded to the user management service, and all requests starting with /order are forwarded to the order processing service.&lt;/p&gt;

&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%2Fv63nwl3vhwl9tmx7icxs.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%2Fv63nwl3vhwl9tmx7icxs.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This method splits the original monolithic application, isolates according to different functions, reduces the complexity and maintenance cost of the application, increases the scalability and robustness of the application, and to a certain extent solves the problems brought by the previous monolithic application.&lt;/p&gt;

&lt;p&gt;But this Web architecture also has some problems of its own.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Direct communication between the client and the microservice, strong coupling between the Server and the client. The subsequent iteration and upgrade of the Server are difficult, and the compatibility of old applications needs to be considered.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Part of an application often involves multiple services, requires multiple requests, and then aggregates data at the client level. The workload of the client increases, and the delay may increase due to the increase in the number of requests. Generally speaking, if our application wants to iterate quickly, it needs to be light in the front and heavy in the back. The front end mainly handles UI display logic, and the iteration speed is fast. If there is a lot of front-end logic, it will affect the delivery speed of the business.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is not conducive to the unification of protocols. Because of the direct communication between the client and the server, the server needs to adapt to multiple ends. A function needs to provide different APIs for the client and the web end, and the complexity of API docking increases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The compatibility of the client is coupled to the internal service, making the server need to handle complex compatibility logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unified logic cannot converge, such as authentication, flow control, circuit breaking, etc., it is very difficult to handle scattered in various Servers.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  BFF, the appearance of the savior
&lt;/h2&gt;

&lt;p&gt;In order to solve the above problems, we follow the first principle of Internet engineering, that is, if the problem cannot be solved, add a layer on it. Therefore, we added an isolation layer in the middle:&lt;/p&gt;

&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%2Fxdoujuyw2m55hnezkk3d.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%2Fxdoujuyw2m55hnezkk3d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By adding a layer of service directly facing the customer, the Server and the client are isolated. We do data aggregation and processing in this layer of service, provide APIs and data for front-end business scenarios. The underlying microservices use the same protocol for data export, only need to provide coarse-grained APIs. Facing the front end and the client, Node.js has a natural advantage, so the Node.js ecosystem has also become popular with this business architecture. This layer of service is the BFF (Backend for frontend) layer we are familiar with today.&lt;/p&gt;

&lt;p&gt;There are many advantages after joining BFF:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Lightweight interaction: Each service only needs to consider the intranet interface and provide coarse-grained APIs. The protocol has been simplified.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decoupling and rapid iteration: The work of data trimming and aggregation is placed in the BFF layer, and the API is customized for end users. The underlying microservices do not need to consider the end-user scenario, can iterate quickly and upgrade dynamically, only need to ensure the compatibility of the original interface and system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The improvement of communication efficiency, the cooperation mode evolves into Web Server + Core Server.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  BFF split, increase the robustness of the application
&lt;/h2&gt;

&lt;p&gt;Using a single BFF layer as the only exit has an unavoidable problem, which is easy to cause single point failure. To solve this problem, we split BFF according to business scenarios, split into different BFFs, and are responsible by different teams, such as Order BFF, User BFF, Item BFF.&lt;/p&gt;

&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%2F5dv0a3wo2r6cjfxv0uai.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%2F5dv0a3wo2r6cjfxv0uai.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Many horizontal functional logics, such as security authentication, log monitoring, flow control, circuit breaking, etc., can be aggregated into a new gateway layer. Here we introduce a new API Gateway gateway layer, which sinks all common horizontal functions such as routing, authentication, flow control, and security.&lt;/p&gt;

&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%2F9yk16exg8slvgz1cofag.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%2F9yk16exg8slvgz1cofag.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;API Gateway plays a crucial role, it realizes the decoupling and separation of a single BFF, so that each business line team can independently develop and deliver their own microservices. The common horizontal logic has been transferred from BFF to the gateway, so that BFF developers can focus more on the delivery of business logic, achieving separation of concerns (Separation of Concerns).&lt;/p&gt;

&lt;p&gt;The actual business flow has also evolved into:&lt;/p&gt;

&lt;p&gt;Client/Browser -&amp;gt; NLB -&amp;gt; API Gateway -&amp;gt; BFF -&amp;gt; Microservice&lt;/p&gt;

&lt;p&gt;According to Conway's law, organizational structure will affect software architecture, and software architecture reflects organizational structure. At this stage, the engineering team is usually split into: Gateway Team, BFF Web Server Team, and Core Server Team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;There is no silver bullet in this world, the appearance and existence of each architecture has its specific advantages and disadvantages. Blindly choosing the most complex architecture is not always the best choice. According to the complexity and scenario of the business, as well as the human resources and engineering capabilities of the team, choosing the most suitable architecture is the optimal solution. As the business grows, we should gradually evolve the technical architecture and choose the architecture that is most suitable for the current situation.&lt;/p&gt;

</description>
      <category>apigateway</category>
      <category>webarchitecture</category>
      <category>microservices</category>
      <category>bff</category>
    </item>
    <item>
      <title>Understanding Two-Phase and Three-Phase Commit Protocols in Distributed Systems</title>
      <dc:creator>Yusen Meng</dc:creator>
      <pubDate>Mon, 30 Oct 2023 13:52:45 +0000</pubDate>
      <link>https://dev.to/yukooshima/understanding-two-phase-and-three-phase-commit-protocols-in-distributed-systems-396</link>
      <guid>https://dev.to/yukooshima/understanding-two-phase-and-three-phase-commit-protocols-in-distributed-systems-396</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: What problems might we encounter in a distributed system?
&lt;/h2&gt;

&lt;p&gt;In a distributed system, multiple nodes need to work together to complete various tasks. Take an e-commerce website as an example, the services of the website are distributed across multiple data centers. Users place orders on the website, the order service is in one data center, and the inventory service is in another data center. Without a coordination mechanism (such as two-phase commit), the following problems may occur: the order service has already created the order, but when reducing the inventory, due to network problems, the inventory service did not receive the request, resulting in incorrect inventory quantity, and users may purchase goods that are actually sold out. Or, the inventory service has already reduced the inventory, but there was a problem when the order service created the order, causing the inventory to be reduced erroneously and there is no corresponding order.&lt;/p&gt;

&lt;p&gt;This is just one example of many possibilities. Without a suitable distributed transaction processing mechanism, it may lead to data inconsistency, system unreliability, and damage to the user's shopping experience. To solve these problems, we need to introduce protocols like two-phase commit to ensure that transactions in distributed systems can be executed safely and completely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two-Phase Commit: A Deep Understanding of the Core of Distributed Transactions
&lt;/h2&gt;

&lt;p&gt;With the popularity of distributed systems, how to ensure data consistency across multiple nodes has become an important challenge. Two-phase commit (2PC) is one of the classic algorithms to solve the distributed transaction problem. This article will provide an in-depth analysis of the working principle of two-phase commit and its advantages and disadvantages.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Two-Phase Commit?
&lt;/h3&gt;

&lt;p&gt;Two-phase commit (2PC) is a protocol that implements transaction atomicity in a distributed system. Atomicity means that a transaction (transaction) is either fully executed or not executed at all, and there will be no partial execution. In a distributed system, a transaction may involve multiple nodes, so a mechanism is needed to ensure that all nodes either commit (commit) the transaction or roll back (rollback) the transaction. This is the role of the two-phase commit protocol.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Process of Two-Phase Commit
&lt;/h3&gt;

&lt;p&gt;2PC mainly involves two roles: Coordinator and Participant.&lt;/p&gt;

&lt;h3&gt;
  
  
  First Phase (Preparation Phase)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Voting request: The coordinator sends a transaction request to all participants, asking them whether they can commit the transaction.&lt;/li&gt;
&lt;li&gt;Voting: Each participant pre-executes the transaction and decides to vote based on its local situation. If it can be executed, it records the transaction log and responds with "YES"; otherwise, it responds with "NO".&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Second Phase (Commit/Rollback Phase)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;All votes are YES: If all participants respond with "YES", the coordinator sends a "commit" command to all participants.&lt;/li&gt;
&lt;li&gt;Some votes are NO: If any participant responds with "NO", or does not respond within a specified time, the coordinator sends a "rollback" command to all participants.
Each participant, after receiving the "commit" or "rollback" command, performs the corresponding operation and sends a confirmation to the coordinator.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N0uFzCWj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qdm9lhk26sz56rkp67z5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N0uFzCWj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qdm9lhk26sz56rkp67z5.png" alt="2PC" width="800" height="822"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros and Cons
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Pros:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ensures transaction atomicity in a distributed environment&lt;/strong&gt;: The two-phase commit protocol ensures transaction atomicity in a distributed environment through two stages of operation. In the first stage, all participants pre-execute the transaction and decide whether they can commit the transaction based on their local situation. In the second stage, if all participants agree to commit the transaction, the transaction will be committed, otherwise it will be rolled back. In this way, whether the transaction is committed or not, all participants' states can be consistent, thus achieving transaction atomicity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The structure is relatively simple and easy to understand&lt;/strong&gt;: The process and structure of the two-phase commit protocol are relatively simple. It only includes two stages: the preparation stage and the commit/rollback stage. In the preparation stage, the coordinator sends a transaction request to all participants, and the participants vote based on their local situation. In the commit/rollback stage, the coordinator decides whether to commit or rollback the transaction based on the voting results. This process is intuitive, easy to understand, and easy to implement.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Cons:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance overhead&lt;/strong&gt;: The two-phase commit protocol involves multiple network communications, including the coordinator sending transaction requests to participants, participants returning voting results to the coordinator, and the coordinator sending commit or rollback commands to participants. These communication processes will increase the system latency, especially in poor network environments, the performance overhead may be greater.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Single point of failure&lt;/strong&gt;: In the two-phase commit protocol, the coordinator plays a key role. If the coordinator fails or crashes, it will cause the participants to be in an uncertain state, not knowing whether to commit or rollback the transaction. In this case, the participants must wait for the coordinator to recover before they can continue to execute, which may cause the overall performance of the system to decline. Multiple coordinators can be used to avoid single point of failure. For example, you can use the master-slave mode. When the master coordinator fails, the backup coordinator can take over. In addition, heartbeat detection and timeout mechanisms can be used to detect and handle coordinator failures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Blocking problem&lt;/strong&gt;: In the second stage of the two-phase commit protocol, if a participant does not return a voting result, or the returned result is "NO", then the coordinator will send a rollback command to all participants. However, if a participant fails or is delayed at this stage, other participants must wait for this participant to recover before they can continue to execute, which may cause a blocking problem. In some scenarios, this blockage may last a long time, seriously affecting the performance and availability of the system. Introducing a timeout mechanism can solve the blocking problem. If the participant does not respond within a specified time, the coordinator can decide to rollback the transaction to avoid other participants waiting for a long time.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Three-Phase Commit
&lt;/h2&gt;

&lt;p&gt;However, these strategies cannot completely solve the problems of the two-phase commit protocol. In order to better solve the distributed transaction problem, we propose the three-phase commit protocol (3PC). 3PC adds a timeout mechanism and a pre-commit stage to 2PC, which can better solve the single point of failure and blocking problems.&lt;/p&gt;

&lt;p&gt;The three-phase commit introduces a new stage, making the entire protocol have the following three stages:&lt;/p&gt;

&lt;h3&gt;
  
  
  First Phase (CanCommit Phase)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Commit Inquiry: The coordinator sends a commit inquiry to all participants, asking them whether they can enter the next stage, that is, commit the transaction.&lt;/li&gt;
&lt;li&gt;Participant Decision: Each participant decides whether it can commit based on its own status, and then responds with "can" or "cannot".&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Second Phase (PreCommit Phase)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;All participants agree: If all participants reply "can", then the coordinator decides to continue to commit and enter this stage, sending a "pre-commit" message to all participants.&lt;/li&gt;
&lt;li&gt;Participant Pre-execution: After receiving the "pre-commit" message, the participant executes the transaction operation but does not commit, and then sends a "ready to commit" message to the coordinator.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Third Phase (DoCommit Phase)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;All participants are ready: After the coordinator receives the "ready to commit" message from all participants, it sends them a "commit" message.&lt;/li&gt;
&lt;li&gt;Participant Commit: After receiving the "commit" message, the participant officially commits its transaction.&lt;/li&gt;
&lt;li&gt;Transaction Abort: If during this process, any participant or coordinator sends an "abort" message or does not respond, then the transaction will be aborted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SBgHIwIU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2aac8cp0citfut1oyxjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SBgHIwIU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2aac8cp0citfut1oyxjl.png" alt="3PC" width="800" height="1233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Better solves single point of failure and blocking problems&lt;/strong&gt;: The three-phase commit protocol adds a pre-commit stage and a timeout mechanism to the two-phase commit, which makes it better at solving single point of failure and blocking problems. In the pre-commit stage, participants execute transaction operations but do not commit, which provides more flexibility for the coordinator to handle possible failures and blockages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enhances system availability and robustness&lt;/strong&gt;: By introducing a timeout mechanism, the three-phase commit protocol can avoid other participants waiting for a long time in the case of no response from a participant or a response of "NO", thereby enhancing the availability and robustness of the system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improves transaction execution efficiency&lt;/strong&gt;: In the three-phase commit protocol, participants begin to execute transaction operations in the pre-commit stage, which can improve the execution efficiency of the transaction, especially when the transaction operation takes a long time.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Cons and Solutions:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Higher message overhead&lt;/strong&gt;: The three-phase commit protocol adds a stage to the two-phase commit protocol, which means more message exchanges, leading to higher message overhead. This may affect the performance of the system, especially in poor network environments. The solution is to optimize the network environment and message transmission mechanism to reduce message overhead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased complexity&lt;/strong&gt;: The introduction of a new pre-commit stage and timeout mechanism increases the complexity of the protocol. This may increase the difficulty of implementation and maintenance. The solution is to use more advanced protocols, such as Paxos or Raft, which can better handle failures and blocking problems when processing distributed transactions, and also provide higher performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Blocking problem still exists&lt;/strong&gt;: Although the three-phase commit protocol solves the blocking problem by introducing a timeout mechanism, in some cases, such as network partitioning or simultaneous failure of the coordinator and participants, blocking may still occur. The solution is to introduce a fault recovery mechanism, such as log recording. When the coordinator or participant fails, the state can be recovered through the log to avoid blocking.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;In a distributed system, transaction processing is an important issue. Two-phase commit (2PC) and three-phase commit (3PC) protocols are two common solutions. 2PC ensures transaction atomicity in a distributed environment through two stages of operation, but it has performance overhead, single point of failure, and blocking problems. 3PC adds a pre-commit stage and a timeout mechanism to 2PC, better solves the single point of failure and blocking problems, improves the execution efficiency of the transaction, but brings higher message overhead and complexity. In practical applications, the appropriate protocol needs to be selected based on the specific requirements and environment of the system.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
