<?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: Lluis Estape</title>
    <description>The latest articles on DEV Community by Lluis Estape (@lluisestape).</description>
    <link>https://dev.to/lluisestape</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%2F4035316%2F4545328b-9213-4cd3-be02-676b5ba2f240.png</url>
      <title>DEV Community: Lluis Estape</title>
      <link>https://dev.to/lluisestape</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lluisestape"/>
    <language>en</language>
    <item>
      <title>Building BoardRoom on Qwen Cloud for the Global AI Hackathon Series. (Track 3: Agent Society)</title>
      <dc:creator>Lluis Estape</dc:creator>
      <pubDate>Sat, 18 Jul 2026 13:01:28 +0000</pubDate>
      <link>https://dev.to/lluisestape/building-boardroom-on-qwen-cloud-for-the-global-ai-hackathon-series-track-3-agent-society-5ekb</link>
      <guid>https://dev.to/lluisestape/building-boardroom-on-qwen-cloud-for-the-global-ai-hackathon-series-track-3-agent-society-5ekb</guid>
      <description>&lt;h2&gt;
  
  
  I built a society of AI agents to review circuit boards. Then I tried to prove it was better, and nearly fooled myself three times.
&lt;/h2&gt;




&lt;p&gt;Every hardware engineer knows the specific dread of clicking "order boards." Three weeks&lt;br&gt;
and a few hundred euros later, a package arrives, and you discover you forgot a&lt;br&gt;
decoupling capacitor, or your I²C bus has no pull-ups. Nothing to do but respin.&lt;/p&gt;

&lt;p&gt;So for the Qwen Cloud hackathon I built &lt;strong&gt;BoardRoom&lt;/strong&gt;: not one AI reviewer, but a&lt;br&gt;
&lt;em&gt;society&lt;/em&gt; of five — power integrity, signal integrity, connectivity/ERC, DFM &amp;amp; layout,&lt;br&gt;
and firmware bring-up — that inspect a real KiCad project through the KiCad MCP server,&lt;br&gt;
file findings that must cite tool evidence, and argue with each other under a Moderator&lt;br&gt;
before signing off.&lt;/p&gt;

&lt;p&gt;The build went fine. It's what happened when I tried to &lt;strong&gt;prove&lt;/strong&gt; the society was better&lt;br&gt;
than a single big agent that turned out to be the interesting part. Three separate times,&lt;br&gt;
my benchmark was quietly lying in my favor. Here's each one, because I think the bugs are&lt;br&gt;
more instructive than the architecture.&lt;/p&gt;
&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;The measurable claim Track 3 asks for is "a demonstrable efficiency gain over&lt;br&gt;
single-agent baselines." So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Corpus:&lt;/strong&gt; stock KiCad demo boards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seeding:&lt;/strong&gt; a script injects reproducible defects with a ground-truth manifest —
removed decoupling cap, swapped SDA/SCL, missing I²C pull-ups, floated enable pin,
renamed power rail. One board (a pure-analog valve preamp) gets &lt;em&gt;no&lt;/em&gt; defects, as an
honesty check that nobody invents findings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two configs, same inputs, same token gateway:&lt;/strong&gt; the society (five cheap specialists
on &lt;code&gt;qwen-flash&lt;/code&gt;/&lt;code&gt;qwen3-vl&lt;/code&gt;/&lt;code&gt;qwen3-coder&lt;/code&gt;, one &lt;code&gt;qwen3-max&lt;/code&gt; Moderator) versus a baseline
of one &lt;code&gt;qwen3-max&lt;/code&gt; agent with &lt;em&gt;all&lt;/em&gt; the tools and a generalist prompt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then I ran it. &lt;strong&gt;Recall: 0.00.&lt;/strong&gt; The society caught zero of the seeded defects.&lt;/p&gt;
&lt;h2&gt;
  
  
  Lie #1: my agents were right, my scoring was wrong
&lt;/h2&gt;

&lt;p&gt;Rather than tune anything, I dumped the actual findings. And there it was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[critical] connectivity_erc: Hierarchical label VCC_PIC has no matching sheet pin
                             in the parent sheet, creating an unconnected rail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's &lt;em&gt;exactly&lt;/em&gt; the defect I'd seeded. The society found it. The scorer called it a miss.&lt;/p&gt;

&lt;p&gt;Why? The matcher compares structured fields — &lt;code&gt;affected_nets&lt;/code&gt;, &lt;code&gt;affected_components&lt;/code&gt; —&lt;br&gt;
and the agents had left them &lt;strong&gt;empty&lt;/strong&gt;, naming the net only in the prose of the claim.&lt;/p&gt;

&lt;p&gt;That's not a benchmark artifact. That's a product bug I'd have shipped: &lt;strong&gt;the report's&lt;br&gt;
headline visualization — a blast-radius graph linking findings to the nets and parts they&lt;br&gt;
touch — is built entirely from those fields.&lt;/strong&gt; My centerpiece visual was silently empty&lt;br&gt;
and I hadn't noticed, because I'd been reading the claims, which looked great.&lt;/p&gt;

&lt;p&gt;The prompts already asked for those fields politely. &lt;code&gt;qwen-flash&lt;/code&gt; ignored it. Making the&lt;br&gt;
final instruction blunt ("a claim that names a net while leaving these arrays empty is&lt;br&gt;
INVALID — the impact graph is built from these fields, not from your prose") took&lt;br&gt;
structured coverage from &lt;strong&gt;0/9 findings to 9/15&lt;/strong&gt;, and recall from 0.00 to 0.50.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; when a model "ignores" a field, check whether anything downstream actually&lt;br&gt;
depends on it. Mine did, and the benchmark found the bug my eyes didn't.&lt;/p&gt;
&lt;h2&gt;
  
  
  Lie #2: I'd accidentally built a strawman
&lt;/h2&gt;

&lt;p&gt;Now the baseline. It scored 0.00, produced zero findings, and burned 6.8K tokens in 29&lt;br&gt;
seconds. I could have shipped that. "Single agent finds nothing, society wins" — a&lt;br&gt;
beautiful chart.&lt;/p&gt;

&lt;p&gt;Except: 6.8K tokens is &lt;em&gt;nothing&lt;/em&gt;. A generalist reviewing a whole board can't be done in&lt;br&gt;
29 seconds. So I looked.&lt;/p&gt;

&lt;p&gt;I'd named the baseline agent &lt;code&gt;moderator&lt;/code&gt; so it would inherit the wildcard "all tools"&lt;br&gt;
entry from my default allowlist. But &lt;code&gt;registry.yaml&lt;/code&gt; &lt;strong&gt;overrides&lt;/strong&gt; the moderator down to&lt;br&gt;
three overview tools — because in the society, the chair doesn't do analysis. My&lt;br&gt;
"single agent with all 24 tools" had been reviewing boards nearly blind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A tool-starved baseline isn't a baseline. It's a strawman&lt;/strong&gt;, and it's exactly the thing&lt;br&gt;
a judge should nuke a submission for. Fixed: the baseline now builds its allowlist from&lt;br&gt;
defaults, genuinely getting every tool. Its token use went 6.8K → 63K.&lt;/p&gt;
&lt;h2&gt;
  
  
  Lie #3: I was grading the baseline on handwriting
&lt;/h2&gt;

&lt;p&gt;Still 0.00, but now doing real work. Fine — maybe one agent really does drown in 24&lt;br&gt;
tools? That's a great narrative. I nearly wrote it.&lt;/p&gt;

&lt;p&gt;Instead I printed its raw output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"B-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hierarchical label mismatch for VCC_PIC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"...breaking connectivity."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"evidence_ids"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"EV-0005"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The baseline found the defect too.&lt;/strong&gt; Every finding was thrown away at the schema&lt;br&gt;
boundary because it wrote &lt;code&gt;title&lt;/code&gt;/&lt;code&gt;description&lt;/code&gt;/&lt;code&gt;evidence_ids&lt;/code&gt; instead of&lt;br&gt;
&lt;code&gt;claim&lt;/code&gt;/&lt;code&gt;evidence&lt;/code&gt;/&lt;code&gt;recommendation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And whose fault was that? Mine. Each specialist prompt carries a full worked JSON example&lt;br&gt;
of the finding shape. The baseline prompt I'd dashed off didn't. &lt;strong&gt;I was measuring prompt&lt;br&gt;
quality and calling it architecture.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I gave the baseline the same worked example the specialists get. I also normalized net&lt;br&gt;
names in the matcher — KiCad legitimately calls the same net &lt;code&gt;VCC_PIC&lt;/code&gt; or&lt;br&gt;
&lt;code&gt;/pic_sockets/VCC_PIC&lt;/code&gt;, and a correct answer shouldn't lose on a naming convention.&lt;/p&gt;

&lt;p&gt;Notice the pattern: &lt;strong&gt;all three bugs pointed the same direction.&lt;/strong&gt; None of them made the&lt;br&gt;
society look worse. That's not coincidence — it's what motivated reasoning looks like&lt;br&gt;
from the inside. You stop debugging when the number agrees with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the honest numbers say
&lt;/h2&gt;

&lt;p&gt;Six boards, twelve seeded defects, &lt;strong&gt;two independent runs per config&lt;/strong&gt;, because LLMs are&lt;br&gt;
nondeterministic and one run isn't a measurement.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;society&lt;/th&gt;
&lt;th&gt;baseline (1× qwen3-max, all tools)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Seeded-defect recall (mean)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.29&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per corpus&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.147&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.429&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt tokens&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;792K&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;312K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Findings surfaced&lt;/td&gt;
&lt;td&gt;49–56&lt;/td&gt;
&lt;td&gt;6–10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hallucination rate&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read the token row and the cost row together, because that's the whole story:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The society burns 2.5× MORE tokens and costs 2.9× LESS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Five cheap specialists doing &lt;em&gt;more&lt;/em&gt; total work are dramatically cheaper than one&lt;br&gt;
expensive generalist doing less. The win isn't "multi-agent is smarter." It's that&lt;br&gt;
decomposition lets you &lt;strong&gt;route by role instead of by model size&lt;/strong&gt; — you only pay&lt;br&gt;
flagship prices for the one job that actually needs a flagship: adjudicating conflicts.&lt;br&gt;
That number reproduced to within 2% across runs.&lt;/p&gt;

&lt;p&gt;And the thing I'm &lt;em&gt;not&lt;/em&gt; claiming: the society led on recall in both runs, but by exactly&lt;br&gt;
&lt;strong&gt;one defect out of twelve&lt;/strong&gt;. With n=2, that's noise — I watched the same config score&lt;br&gt;
0.50 and 0.00 on the same board across runs. So the honest claim is "comparable, possibly&lt;br&gt;
slightly better," and that's what the README says.&lt;/p&gt;

&lt;h2&gt;
  
  
  The most useful result is the one that makes my project look bad
&lt;/h2&gt;

&lt;p&gt;Absolute recall is low for &lt;em&gt;both&lt;/em&gt; configs — 0.21 to 0.29. I could have quietly picked&lt;br&gt;
easier defects. Here's why it's low instead:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Most of the defects I seeded are invisible to every tool that exists.&lt;/strong&gt; Removing a&lt;br&gt;
decoupling cap creates an &lt;em&gt;absence&lt;/em&gt; — no KiCad tool reports "a part that should be here&lt;br&gt;
isn't." A swapped SDA/SCL is electrically valid, so ERC has nothing to say. The only&lt;br&gt;
class anything reliably caught is rail-rename/floating-pin, because ERC and net listings&lt;br&gt;
actually surface it.&lt;/p&gt;

&lt;p&gt;That's not an indictment of the agents. It's a finding about EDA tooling: &lt;strong&gt;the reasoning&lt;br&gt;
layer is now ahead of the observability layer.&lt;/strong&gt; These models can absolutely reason about&lt;br&gt;
a missing bypass cap — they just have no instrument that reports its absence. The&lt;br&gt;
bottleneck isn't intelligence. It's that we never built the tool, because no human needed&lt;br&gt;
one to eyeball a schematic.&lt;/p&gt;

&lt;p&gt;I think that's the most interesting thing I learned, and it only showed up because I&lt;br&gt;
reported a bad number instead of engineering around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell someone starting one of these
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Evidence gating works.&lt;/strong&gt; Every finding must cite a real cached tool-call ID, and
uncited claims are rejected at the boundary — not discouraged in a prompt.
Hallucination rate: &lt;strong&gt;0.00 across every run, both configs.&lt;/strong&gt; Make it structural and
you stop arguing with the model about honesty.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enforce scope in code, not prose.&lt;/strong&gt; Each specialist's tool allowlist is enforced
before the call. Prompts are suggestions; allowlists are physics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Route by role, not by size.&lt;/strong&gt; This is where the 2.9× lives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debug the results that flatter you.&lt;/strong&gt; All three of my bugs produced &lt;em&gt;better&lt;/em&gt; numbers.
If I'd stopped at the first good chart, I'd have submitted a rigged benchmark with a
straight face.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One last confession: BoardRoom's negotiation engine — bounded two-round debates,&lt;br&gt;
evidence-cited rulings, fully unit-tested — &lt;strong&gt;never fired on real data.&lt;/strong&gt; Across the whole&lt;br&gt;
corpus, no two specialists ever produced conflicting findings. Their scopes are narrow&lt;br&gt;
enough that they rarely collide. The repo ships a clearly-labeled synthetic fixture to&lt;br&gt;
demonstrate the viewer, and says so in the README, because the alternative is faking a&lt;br&gt;
fight and calling it a demo.&lt;/p&gt;

&lt;p&gt;That's a real limitation of the design, discovered by measuring instead of assuming. Which&lt;br&gt;
is, I think, the actual point.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;BoardRoom is open source (MIT): &lt;a href="https://github.com/lluisestape-upc/boardroom" rel="noopener noreferrer"&gt;https://github.com/lluisestape-upc/boardroom&lt;/a&gt; — built on&lt;br&gt;
Qwen models via Alibaba Cloud Model Studio, with the KiCad MCP server. Benchmark method,&lt;br&gt;
raw numbers and limitations: &lt;a href="https://github.com/lluisestape-upc/boardroom/blob/main/docs/BENCHMARK.md" rel="noopener noreferrer"&gt;docs/BENCHMARK.md&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>devchallenge</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
