<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>AI on Clint Rori</title><link>https://rorimwema.github.io/categories/ai/</link><description>Recent content in AI on Clint Rori</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 02 Mar 2026 15:38:26 +0300</lastBuildDate><atom:link href="https://rorimwema.github.io/categories/ai/index.xml" rel="self" type="application/rss+xml"/><item><title>Building Fenra: From 'Find the Corruption' to Swarm Intelligence</title><link>https://rorimwema.github.io/posts/building-fenra/</link><pubDate>Mon, 02 Mar 2026 15:38:26 +0300</pubDate><guid>https://rorimwema.github.io/posts/building-fenra/</guid><description>&lt;p&gt;How I stopped trying to build one perfect AI and started building a team of specialized ones.&lt;/p&gt;
&lt;h2 id="the-problem-i-actually-wanted-to-solve"&gt;The Problem I Actually Wanted to Solve&lt;/h2&gt;
&lt;p&gt;I started Fenra because I kept reading about corruption cases in Kenya where the patterns were obvious in hindsight—strange procurement patterns, shell companies, duplicate payments—but nobody caught them in real-time. The data was there, scattered across different systems. The connections were there too, but buried under too much noise for humans to spot quickly.&lt;/p&gt;</description><content:encoded><![CDATA[<p>How I stopped trying to build one perfect AI and started building a team of specialized ones.</p>
<h2 id="the-problem-i-actually-wanted-to-solve">The Problem I Actually Wanted to Solve</h2>
<p>I started Fenra because I kept reading about corruption cases in Kenya where the patterns were obvious in hindsight—strange procurement patterns, shell companies, duplicate payments—but nobody caught them in real-time. The data was there, scattered across different systems. The connections were there too, but buried under too much noise for humans to spot quickly.</p>
<p>My first thought: build one smart AI that can read everything and tell you when something looks corrupt.</p>
<p>That didn&rsquo;t work.</p>
<h2 id="why-single-ai-models-fail-at-this">Why Single AI Models Fail at This</h2>
<p>I tried the obvious approach first. Feed documents into a large language model, ask &ldquo;is this corrupt?&rdquo; The results were either:</p>
<ul>
<li><strong>Too vague</strong> (&ldquo;this seems suspicious&rdquo; — thanks, but why?)</li>
<li><strong>Too confident</strong> (flagging legitimate transactions because of unusual but legal patterns)</li>
<li><strong>Or missing things entirely</strong> (not understanding that two shell companies sharing a director matters)</li>
</ul>
<p>The problem isn&rsquo;t that LLMs are dumb. It&rsquo;s that corruption detection requires multiple types of reasoning at once:</p>
<ul>
<li><strong>Pattern matching</strong> (unusual transaction amounts, timing)</li>
<li><strong>Relationship tracing</strong> (who knows who, company networks)</li>
<li><strong>Legal knowledge</strong> (what actually violates procurement laws)</li>
<li><strong>Context awareness</strong> (this is normal for this industry, weird for that one)</li>
</ul>
<p>No single model is good at all of these. And even if one was, I didn&rsquo;t want a black box making accusations.</p>
<h2 id="the-swarm-idea">The Swarm Idea</h2>
<p>I started thinking about how actual investigations work. You don&rsquo;t have one super-detective who does everything. You have:</p>
<ul>
<li>A forensic accountant who traces money</li>
<li>A network analyst who maps relationships</li>
<li>A legal researcher who knows the regulations</li>
<li>A senior investigator who reviews findings before anything goes to court</li>
</ul>
<p>So I built Fenra as a swarm. Multiple specialized agents, each with a specific job, coordinated by a &ldquo;Judge&rdquo; that verifies conclusions before they&rsquo;re reported.</p>
<h2 id="why-graph-rag-was-the-right-choice">Why Graph RAG Was the Right Choice</h2>
<p>Early on, I tried standard RAG (Retrieval-Augmented Generation) — chunk documents, embed them, retrieve relevant chunks when querying. It worked for simple questions but failed on relationships.</p>
<p><strong>Example:</strong> Company A paid Company B. Company B&rsquo;s director is the cousin of a procurement officer. That&rsquo;s three hops. Standard vector search doesn&rsquo;t handle hops well.</p>
<p><strong>Graph RAG</strong> stores entities (companies, people, transactions) as nodes and relationships as edges. Now the &ldquo;network analyst&rdquo; agent can actually traverse connections—follow the money, find shared directors, spot circular payments.</p>
<p>The graph also gives us explainability. When Fenra flags something, we can show the path:</p>
<blockquote>
<p>&ldquo;Flagged because Company A → paid → Company B → director is → Person C → related to → Procurement Officer D.&rdquo;</p>
</blockquote>
<h2 id="the-architecture-that-actually-works">The Architecture That Actually Works</h2>
<p>Here&rsquo;s what I ended up with:</p>
<h3 id="specialist-agents-the-workers">Specialist Agents (The Workers)</h3>
<ul>
<li><strong>Transaction Analyzer</strong>: Looks at financial patterns, outliers, timing anomalies</li>
<li><strong>Network Mapper</strong>: Traverses the knowledge graph to find hidden relationships</li>
<li><strong>Legal Checker</strong>: Knows procurement regulations, flags procedural violations</li>
<li><strong>Document Reader</strong>: Extracts entities and relationships from unstructured text (contracts, emails)</li>
</ul>
<h3 id="the-judge-the-verifier">The Judge (The Verifier)</h3>
<ul>
<li>Takes findings from specialists and verifies them against evidence</li>
<li>Checks for contradictions between agents</li>
<li>Assigns confidence scores</li>
<li>Only escalates high-confidence, well-supported findings</li>
</ul>
<h3 id="the-graph-store">The Graph Store</h3>
<ul>
<li><strong>Neo4j</strong> for relationship data (who knows who, ownership structures)</li>
<li><strong>Vector store</strong> for semantic search (finding similar contract language, for example)</li>
<li>Both feed into each other — vector search finds relevant documents, graph traversal finds connections within them</li>
</ul>
<h2 id="why-ocaml-and-erlang">Why OCaml and Erlang</h2>
<p>I get asked why I didn&rsquo;t just use Python like everyone else. A few reasons:</p>
<p><strong>OCaml for the core logic:</strong> Corruption detection involves a lot of data transformation and rule evaluation. OCaml&rsquo;s type system catches bugs at compile time that would be runtime errors in Python. When you&rsquo;re dealing with legal and financial data, &ldquo;oops, NoneType has no attribute&rdquo; isn&rsquo;t acceptable.</p>
<p>Also, hot code reloading means I can update an agent&rsquo;s logic without stopping the system. Important when you&rsquo;re iterating on detection rules.</p>
<h2 id="what-i-learned-the-hard-way">What I Learned the Hard Way</h2>
<ol>
<li>
<p><strong>Start with synthetic data:</strong> I spent weeks trying to get real procurement data. Don&rsquo;t. Generate fake but realistic corruption patterns first. If your system can&rsquo;t find fake corruption you planted yourself, it won&rsquo;t find real corruption either.</p>
</li>
<li>
<p><strong>The graph schema matters more than the model:</strong> I wasted time fine-tuning LLMs when the real problem was my graph schema didn&rsquo;t capture &ldquo;subsidiary of&rdquo; relationships properly. Fix your data model first.</p>
</li>
<li>
<p><strong>Explainability is not optional:</strong> In a real deployment, every flag Fenra raises will be challenged. &ldquo;The AI said so&rdquo; is not a defense. The graph structure gives us audit trails by default.</p>
</li>
<li>
<p><strong>Human-in-the-loop is a feature, not a bug:</strong> The Judge agent doesn&rsquo;t just verify AI outputs—it creates a checkpoint where human investigators can review, correct, and improve the system. The goal isn&rsquo;t to replace investigators, it&rsquo;s to make them 10x more effective.</p>
</li>
</ol>
]]></content:encoded></item></channel></rss>