<?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: Emmanuel Utibe Ernest</title>
    <description>The latest articles on DEV Community by Emmanuel Utibe Ernest (@emmanuel_ernest_7).</description>
    <link>https://dev.to/emmanuel_ernest_7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4017960%2F484f4449-5e3e-4567-bf5e-ef8d7df16a16.jpg</url>
      <title>DEV Community: Emmanuel Utibe Ernest</title>
      <link>https://dev.to/emmanuel_ernest_7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/emmanuel_ernest_7"/>
    <language>en</language>
    <item>
      <title>Building an LLM Gateway Proxy with Security Guardrails and Observability</title>
      <dc:creator>Emmanuel Utibe Ernest</dc:creator>
      <pubDate>Tue, 07 Jul 2026 08:29:16 +0000</pubDate>
      <link>https://dev.to/emmanuel_ernest_7/building-an-llm-gateway-proxy-with-security-guardrails-and-observability-4e1h</link>
      <guid>https://dev.to/emmanuel_ernest_7/building-an-llm-gateway-proxy-with-security-guardrails-and-observability-4e1h</guid>
      <description>&lt;h2&gt;
  
  
  The Problem: Calling an LLM API Is Easy. Operating One Responsibly Is Harder.
&lt;/h2&gt;

&lt;p&gt;Building an application that sends prompts directly to an LLM API is surprisingly simple.&lt;/p&gt;

&lt;p&gt;A user submits a request, the application forwards it to the model, and the response is returned.&lt;/p&gt;

&lt;p&gt;For prototypes and personal projects, that architecture is often sufficient.&lt;/p&gt;

&lt;p&gt;As applications grow, however, additional concerns begin to emerge.&lt;/p&gt;

&lt;p&gt;Some common challenges include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Preventing accidental exposure of personally identifiable information (PII)&lt;/li&gt;
&lt;li&gt;Detecting prompt injection attempts before they reach the model&lt;/li&gt;
&lt;li&gt;Understanding API costs over time&lt;/li&gt;
&lt;li&gt;Measuring latency and request volume&lt;/li&gt;
&lt;li&gt;Creating audit trails for troubleshooting and operational visibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These responsibilities are largely independent of the language model itself.&lt;/p&gt;

&lt;p&gt;Instead of embedding them throughout an application, I wanted to explore a different architectural approach:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What if every LLM request passed through a dedicated gateway responsible for security, validation, and observability before communicating with the model?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To answer that question, I built an &lt;strong&gt;LLM Gateway Proxy&lt;/strong&gt; that sits between client applications and the OpenAI API.&lt;/p&gt;

&lt;p&gt;The gateway performs three primary responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Compliance&lt;/li&gt;
&lt;li&gt;Operational monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Introduce a Gateway?
&lt;/h2&gt;

&lt;p&gt;One design option would have been to place validation logic directly inside the application.&lt;/p&gt;

&lt;p&gt;Instead, I chose to isolate these responsibilities into a dedicated middleware layer.&lt;/p&gt;

&lt;p&gt;This provides several advantages.&lt;/p&gt;

&lt;p&gt;Security logic exists in one location.&lt;/p&gt;

&lt;p&gt;Monitoring becomes consistent across every request.&lt;/p&gt;

&lt;p&gt;Future applications can reuse the same gateway without duplicating code.&lt;/p&gt;

&lt;p&gt;This mirrors a common architectural pattern where cross-cutting concerns—such as authentication, logging, and rate limiting—are centralized rather than scattered across multiple services.&lt;/p&gt;

&lt;h2&gt;
  
  
  High-Level Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 User Request
                      │
                      ▼
             PII Sanitization
                      │
                      ▼
         Prompt Injection Detection
                      │
        Safe? ────────┼──────── Block
          │                        │
          ▼                        ▼
      OpenAI API             Local Refusal
          │
          ▼
     Response Validation
          │
          ▼
     Metrics Collection
          │
          ▼
    Streamlit Dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rather than acting as a simple proxy, the gateway becomes a control point responsible for validating and monitoring every interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 1: PII Sanitization
&lt;/h2&gt;

&lt;p&gt;The first responsibility of the gateway is identifying sensitive information before it leaves the local application.&lt;/p&gt;

&lt;p&gt;Using regular expressions, the gateway searches for common forms of personally identifiable information, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email addresses&lt;/li&gt;
&lt;li&gt;Telephone numbers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When detected, the values are replaced with placeholder tokens such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight email"&gt;&lt;code&gt;&lt;span class="nt"&gt;[EMAIL]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PHONE_NUMBER]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sanitized request is then forwarded instead of the original text.&lt;/p&gt;

&lt;p&gt;Although this implementation uses pattern matching, it demonstrates an important architectural principle:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sensitive information should be handled as early as possible within the request lifecycle.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Future versions could extend this layer with Named Entity Recognition (NER) models for broader PII detection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 2: Prompt Injection Detection
&lt;/h2&gt;

&lt;p&gt;The next stage evaluates incoming prompts for known prompt injection patterns.&lt;/p&gt;

&lt;p&gt;The initial implementation uses a lightweight heuristic approach.&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;check_input_guardrail&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;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;malicious_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ignore previous instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system prompt&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;reveal your rules&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;override&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;normalized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;normalized&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;malicious_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If suspicious content is detected, the gateway immediately returns a local refusal rather than forwarding the request to the language model.&lt;/p&gt;

&lt;p&gt;This design provides two benefits.&lt;/p&gt;

&lt;p&gt;First, it prevents unnecessary API calls.&lt;/p&gt;

&lt;p&gt;Second, it reduces the risk of processing requests that attempt to manipulate system behavior.&lt;/p&gt;

&lt;p&gt;It is worth noting that this approach intentionally favors simplicity over completeness.&lt;/p&gt;

&lt;p&gt;Heuristic detection is inexpensive and easy to understand, but it cannot detect every adversarial prompt.&lt;/p&gt;

&lt;p&gt;More sophisticated approaches could combine embeddings, classifiers, or dedicated guardrail models.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 3: Observability and Cost Tracking
&lt;/h2&gt;

&lt;p&gt;Once a request successfully passes validation, it is forwarded to the OpenAI API.&lt;/p&gt;

&lt;p&gt;The gateway measures several operational metrics during execution, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request latency&lt;/li&gt;
&lt;li&gt;Prompt tokens&lt;/li&gt;
&lt;li&gt;Completion tokens&lt;/li&gt;
&lt;li&gt;Total token usage&lt;/li&gt;
&lt;li&gt;Estimated API cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each request is then recorded in a CSV ledger.&lt;/p&gt;

&lt;p&gt;Although a CSV file is a lightweight persistence mechanism, it provides enough historical data to analyze usage trends during development.&lt;/p&gt;

&lt;p&gt;The broader lesson is that observability should not be treated as an afterthought.&lt;/p&gt;

&lt;p&gt;Understanding how AI systems behave over time is just as important as generating responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Dashboard
&lt;/h2&gt;

&lt;p&gt;Collecting metrics is useful.&lt;/p&gt;

&lt;p&gt;Visualizing them is even more useful.&lt;/p&gt;

&lt;p&gt;To explore the recorded data, I built a Streamlit dashboard that serves two primary purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interactive Playground
&lt;/h2&gt;

&lt;p&gt;Developers can experiment with different prompts and immediately observe how the gateway responds.&lt;/p&gt;

&lt;p&gt;This makes it easier to verify that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PII is properly redacted.&lt;/li&gt;
&lt;li&gt;Injection attempts are rejected.&lt;/li&gt;
&lt;li&gt;Safe requests continue normally.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Operational Metrics
&lt;/h2&gt;

&lt;p&gt;The dashboard also summarizes execution history by displaying:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total requests&lt;/li&gt;
&lt;li&gt;Estimated API cost&lt;/li&gt;
&lt;li&gt;Average latency&lt;/li&gt;
&lt;li&gt;Historical request logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having immediate visibility into these metrics makes it easier to understand how the system behaves over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engineering Trade-offs
&lt;/h2&gt;

&lt;p&gt;Every architectural decision comes with trade-offs.&lt;/p&gt;

&lt;p&gt;Introducing a gateway increases processing time slightly because every request passes through additional validation layers.&lt;/p&gt;

&lt;p&gt;However, this overhead improves consistency, visibility, and security.&lt;/p&gt;

&lt;p&gt;Similarly, heuristic prompt detection is intentionally lightweight.&lt;/p&gt;

&lt;p&gt;It offers low latency and straightforward implementation, but it cannot detect more subtle attacks.&lt;/p&gt;

&lt;p&gt;Likewise, storing execution logs as CSV files simplifies development and inspection, though a production deployment would likely use a database or centralized logging platform.&lt;/p&gt;

&lt;p&gt;Recognizing these trade-offs helped shape the design decisions throughout the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker and Reproducibility
&lt;/h2&gt;

&lt;p&gt;To ensure consistent execution across environments, the application is containerized using Docker.&lt;/p&gt;

&lt;p&gt;Containerization provides several practical benefits.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent Python environments&lt;/li&gt;
&lt;li&gt;Reproducible dependency management&lt;/li&gt;
&lt;li&gt;Simplified onboarding&lt;/li&gt;
&lt;li&gt;Easier CI integration&lt;/li&gt;
&lt;li&gt;Isolation from host system differences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rather than solving a security problem directly, Docker helps ensure the gateway behaves consistently regardless of where it is executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Integration
&lt;/h2&gt;

&lt;p&gt;The repository also includes a GitHub Actions workflow that performs automated quality checks whenever new code is pushed.&lt;/p&gt;

&lt;p&gt;The pipeline currently validates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependency installation&lt;/li&gt;
&lt;li&gt;Static analysis&lt;/li&gt;
&lt;li&gt;Linting with flake8&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While straightforward, this reinforces an important engineering principle:&lt;/p&gt;

&lt;p&gt;Automation should verify software quality before deployment rather than after release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges I Encountered
&lt;/h2&gt;

&lt;p&gt;Building the gateway involved more than integrating an API.&lt;/p&gt;

&lt;p&gt;Some of the more interesting engineering challenges included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choosing where validation should occur&lt;/li&gt;
&lt;li&gt;Preventing duplicate logging&lt;/li&gt;
&lt;li&gt;Estimating token costs accurately&lt;/li&gt;
&lt;li&gt;Designing guardrails that remain lightweight&lt;/li&gt;
&lt;li&gt;Separating middleware responsibilities from presentation logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These decisions influenced the architecture far more than the individual API calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;This project reinforced several ideas about AI engineering.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Should Be Layered
&lt;/h3&gt;

&lt;p&gt;Language models should not be expected to enforce every security policy on their own.&lt;/p&gt;

&lt;p&gt;Application-level validation provides an additional layer of defense.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability Is Essential
&lt;/h3&gt;

&lt;p&gt;Without visibility into latency, costs, and request history, optimizing an AI system becomes largely guesswork.&lt;/p&gt;

&lt;h3&gt;
  
  
  Middleware Encourages Reuse
&lt;/h3&gt;

&lt;p&gt;By isolating validation and monitoring inside a gateway, multiple client applications can benefit from the same security policies without duplicating implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;p&gt;There are several directions I'd like to explore next.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Semantic guardrails using embeddings&lt;/li&gt;
&lt;li&gt;Named Entity Recognition for richer PII detection&lt;/li&gt;
&lt;li&gt;Redis-based response caching&lt;/li&gt;
&lt;li&gt;PostgreSQL for persistent execution history&lt;/li&gt;
&lt;li&gt;OpenTelemetry tracing&lt;/li&gt;
&lt;li&gt;Prometheus and Grafana metrics&lt;/li&gt;
&lt;li&gt;Authentication and API keys&lt;/li&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;FastAPI deployment&lt;/li&gt;
&lt;li&gt;Kubernetes orchestration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These additions would extend the gateway into a more comprehensive platform for managing LLM interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building this project reinforced an idea that extends beyond AI applications.&lt;/p&gt;

&lt;p&gt;Reliable systems are built by combining capable models with disciplined software engineering.&lt;/p&gt;

&lt;p&gt;Security, observability, validation, and cost awareness are not optional additions—they are architectural concerns that shape how AI systems behave in practice.&lt;/p&gt;

&lt;p&gt;Rather than treating the language model as the center of the application, this project treats it as one component within a larger system designed to improve reliability, transparency, and operational control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Code
&lt;/h2&gt;

&lt;p&gt;The complete source code, Docker configuration, GitHub Actions workflow, and documentation are available on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;em&gt;&lt;a href="https://github.com/ernest-emmanuel-utibe/llm-guardrail-dashboard.git" rel="noopener noreferrer"&gt;https://github.com/ernest-emmanuel-utibe/llm-guardrail-dashboard.git&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're building AI infrastructure, LLM gateways, or observability tools, I'd be interested to hear how you've approached similar challenges or what improvements you would make to this architecture.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>python</category>
      <category>ai</category>
      <category>security</category>
    </item>
    <item>
      <title>How I Built a Multi-Agent AI Research Suite with Human-in-the-Loop Validation</title>
      <dc:creator>Emmanuel Utibe Ernest</dc:creator>
      <pubDate>Mon, 06 Jul 2026 15:21:39 +0000</pubDate>
      <link>https://dev.to/emmanuel_ernest_7/how-i-built-a-multi-agent-ai-research-suite-with-human-in-the-loop-validation-n49</link>
      <guid>https://dev.to/emmanuel_ernest_7/how-i-built-a-multi-agent-ai-research-suite-with-human-in-the-loop-validation-n49</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Everyone is talking about autonomous AI agents.&lt;/p&gt;

&lt;p&gt;Give an agent internet access, connect it to an LLM, and it can research topics, write reports, analyze businesses, and even execute tasks with little human intervention.&lt;/p&gt;

&lt;p&gt;It sounds impressive—until you let an autonomous agent run unattended.&lt;/p&gt;

&lt;p&gt;In practice, AI agents can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hallucinate facts&lt;/li&gt;
&lt;li&gt;collect irrelevant information&lt;/li&gt;
&lt;li&gt;collect irrelevant information&lt;/li&gt;
&lt;li&gt;misunderstand search intent&lt;/li&gt;
&lt;li&gt;waste expensive API tokens&lt;/li&gt;
&lt;li&gt;confidently produce inaccurate reports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For prototypes, that might be acceptable.&lt;/p&gt;

&lt;p&gt;For production systems, it isn't.&lt;/p&gt;

&lt;p&gt;That question led me to build a project around a different philosophy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI should automate the work, but humans should validate the decisions that matter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of building another fully autonomous agent, I designed a multi-agent AI research system that deliberately pauses before analysis, allowing a human to review the collected research before the workflow continues.&lt;/p&gt;

&lt;p&gt;The result combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CrewAI&lt;/li&gt;
&lt;li&gt;OpenAI GPT models&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;Human-in-the-Loop validation
and follows software engineering practices inspired by real production systems rather than simple AI demos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why Not Use One Giant Prompt?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the earliest design decisions was refusing to build everything inside one prompt.&lt;/p&gt;

&lt;p&gt;Could GPT research, analyze, and write in one request?&lt;/p&gt;

&lt;p&gt;Absolutely.&lt;/p&gt;

&lt;p&gt;Should it?&lt;/p&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;Large prompts become difficult to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;debug&lt;/li&gt;
&lt;li&gt;improve&lt;/li&gt;
&lt;li&gt;test&lt;/li&gt;
&lt;li&gt;reuse&lt;/li&gt;
&lt;li&gt;scale
Instead, I separated responsibilities into independent agents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Agent&lt;/strong&gt;               &lt;strong&gt;Responsibility&lt;/strong&gt;&lt;br&gt;
Researcher       Finds information from online sources&lt;br&gt;
Analyst              Evaluates findings using structured reasoning&lt;br&gt;
Writer               Produces a polished Markdown report&lt;/p&gt;

&lt;p&gt;This separation follows the Single Responsibility Principle, making each component easier to optimize independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overall Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;User&lt;br&gt;
   │&lt;br&gt;
   ▼&lt;br&gt;
Research Agent&lt;br&gt;
   │&lt;br&gt;
   ▼&lt;br&gt;
Human Validation (HITL)&lt;br&gt;
   │&lt;br&gt;
Approve / Edit / Reject&lt;br&gt;
   │&lt;br&gt;
   ▼&lt;br&gt;
Analysis Agent&lt;br&gt;
   │&lt;br&gt;
   ▼&lt;br&gt;
Writer Agent&lt;br&gt;
   │&lt;br&gt;
   ▼&lt;br&gt;
Markdown Report&lt;/p&gt;

&lt;p&gt;Unlike many AI workflows, there is an intentional pause between research and analysis.&lt;/p&gt;

&lt;p&gt;That pause became the most important feature of the entire project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Human-in-the-Loop Gateway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most autonomous AI demos assume the first agent always produces trustworthy output.&lt;/p&gt;

&lt;p&gt;I intentionally challenged that assumption.&lt;/p&gt;

&lt;p&gt;Instead of passing research directly into the Analyst, I configured CrewAI with:&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;human_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When execution reaches that task:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the workflow pauses&lt;/li&gt;
&lt;li&gt;research findings appear in the terminal&lt;/li&gt;
&lt;li&gt;the user reviews them&lt;/li&gt;
&lt;li&gt;corrections can be made&lt;/li&gt;
&lt;li&gt;the pipeline resumes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That small change dramatically improves report quality.&lt;/p&gt;

&lt;p&gt;Rather than asking an LLM to fix another LLM's mistakes, the workflow allows a human reviewer to intercept problems before they propagate through downstream agents.&lt;/p&gt;

&lt;p&gt;This mirrors approval workflows commonly found in enterprise software.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Engineering Decisions That Matter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the biggest lessons from this project was that building AI systems involves far more than prompt engineering.&lt;/p&gt;

&lt;p&gt;Several infrastructure decisions significantly improved reliability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Containerizing the application ensured the environment remained consistent across machines.&lt;/p&gt;

&lt;p&gt;One interesting challenge was supporting interactive user input inside a Docker container.&lt;/p&gt;

&lt;p&gt;Because the workflow pauses for human approval, standard container execution wasn't sufficient.&lt;/p&gt;

&lt;p&gt;The solution required enabling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stdin_open&lt;/li&gt;
&lt;li&gt;tty&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;inside Docker Compose so terminal interaction remained available.&lt;/p&gt;

&lt;p&gt;Without those flags, the Human-in-the-Loop stage would fail inside the container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Actions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To keep the repository production-ready, every push automatically runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dependency installation&lt;/li&gt;
&lt;li&gt;linting with flake8&lt;/li&gt;
&lt;li&gt;code validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although simple, continuous integration ensures basic quality checks happen before changes are merged.&lt;/p&gt;

&lt;p&gt;It also demonstrates an important engineering principle:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Automation should validate code long before deployment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Cost Optimization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Running multiple agents means every task consumes API tokens.&lt;/p&gt;

&lt;p&gt;During development I experimented with different OpenAI models.&lt;/p&gt;

&lt;p&gt;For research workflows, switching to GPT-4o Mini reduced costs considerably while maintaining acceptable quality for most tasks.&lt;/p&gt;

&lt;p&gt;The experience reinforced an important lesson:&lt;/p&gt;

&lt;p&gt;Choosing the most expensive model isn't always the best engineering decision.&lt;/p&gt;

&lt;p&gt;Balancing quality, latency, and cost is often more valuable than maximizing raw intelligence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenges I Encountered&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The project wasn't without obstacles.&lt;/p&gt;

&lt;p&gt;Some of the most interesting engineering problems included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;maintaining structured outputs between agents&lt;/li&gt;
&lt;li&gt;preventing context drift&lt;/li&gt;
&lt;li&gt;handling interactive terminal sessions in Docker&lt;/li&gt;
&lt;li&gt;designing prompts that encourage reasoning instead of repetition&lt;/li&gt;
&lt;li&gt;deciding where human intervention should occur&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each challenge pushed the project beyond being a simple AI demo and closer to a realistic production workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'd Improve Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If I continue developing this project, I'd like to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieval-Augmented Generation (RAG) for higher-quality research&lt;/li&gt;
&lt;li&gt;persistent storage using PostgreSQL&lt;/li&gt;
&lt;li&gt;Redis task queues&lt;/li&gt;
&lt;li&gt;asynchronous agent execution&lt;/li&gt;
&lt;li&gt;observability with OpenTelemetry&lt;/li&gt;
&lt;li&gt;evaluation metrics for agent performance&lt;/li&gt;
&lt;li&gt;FastAPI endpoints for external integration&lt;/li&gt;
&lt;li&gt;Kubernetes deployment&lt;/li&gt;
&lt;li&gt;authentication and user roles&lt;/li&gt;
&lt;li&gt;report version history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These additions would move the project toward an enterprise-ready AI platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lessons Learned&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Building this project changed how I think about AI systems.&lt;/p&gt;

&lt;p&gt;The most valuable lesson wasn't how to orchestrate multiple agents.&lt;/p&gt;

&lt;p&gt;It was learning that reliability comes from engineering, not just intelligence.&lt;/p&gt;

&lt;p&gt;Production AI systems require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validation&lt;/li&gt;
&lt;li&gt;observability&lt;/li&gt;
&lt;li&gt;automation&lt;/li&gt;
&lt;li&gt;testing&lt;/li&gt;
&lt;li&gt;cost optimization&lt;/li&gt;
&lt;li&gt;human oversight&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Powerful language models are only one part of the solution.&lt;/p&gt;

&lt;p&gt;Good software architecture is what transforms them into dependable systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The excitement around autonomous AI agents is well deserved.&lt;/p&gt;

&lt;p&gt;But autonomy alone isn't enough.&lt;/p&gt;

&lt;p&gt;The systems that businesses trust will be those that balance automation with accountability.&lt;/p&gt;

&lt;p&gt;This project was my exploration of that idea combining specialized AI agents with Human-in-the-Loop validation to produce more reliable research while following production-inspired engineering practices.&lt;/p&gt;

&lt;p&gt;If you're interested in AI Engineering, MLOps, or multi-agent systems, I'd love to hear your thoughts.&lt;/p&gt;

&lt;p&gt;The complete source code is available on GitHub, and contributions or feedback are always welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>devops</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
