<?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: JWL AI</title>
    <description>The latest articles on DEV Community by JWL AI (@junwei_lai_71641e0a742b33).</description>
    <link>https://dev.to/junwei_lai_71641e0a742b33</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%2F4012513%2Fb55ed78e-d4ed-4b08-9124-3ee49babddd3.jpg</url>
      <title>DEV Community: JWL AI</title>
      <link>https://dev.to/junwei_lai_71641e0a742b33</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/junwei_lai_71641e0a742b33"/>
    <language>en</language>
    <item>
      <title>How a Negotiating Agent Society Out-Plans a Single Scheduler</title>
      <dc:creator>JWL AI</dc:creator>
      <pubDate>Fri, 03 Jul 2026 08:44:01 +0000</pubDate>
      <link>https://dev.to/junwei_lai_71641e0a742b33/how-a-negotiating-agent-society-out-plans-a-single-scheduler-55ai</link>
      <guid>https://dev.to/junwei_lai_71641e0a742b33/how-a-negotiating-agent-society-out-plans-a-single-scheduler-55ai</guid>
      <description>&lt;p&gt;&lt;em&gt;Turn a five-way scheduling trade-off into a debate you can audit: five advocate agents argue, a charge-nurse referee rules, and the plan beats a single agent on the same scorer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The scariest scheduling failures are the confident ones.&lt;/p&gt;

&lt;p&gt;You hand one LLM a clinic's week — 56 patients, 43 slots, three nurses — and ask it to book the follow-ups. No errors. No complaints. It returns a clean, plausible schedule in a single pass. But is it a &lt;em&gt;good&lt;/em&gt; plan, or did it quietly sacrifice something that mattered?&lt;/p&gt;

&lt;p&gt;Score it and you find out. High-acuity patients: all seen. Continuity of care: collapsed — patients bounced to whichever nurse had a gap. Overdue follow-ups: slipping. The agent anchored on the one objective that's easy to name and let the messy ones rot — and it never told you it made that trade.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A quiet objective is not a satisfied objective. Usually it's the opposite.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a case study in fixing that with a &lt;strong&gt;multi-agent society&lt;/strong&gt; — and it won't stay abstract. Every number comes from one real system: &lt;strong&gt;RehabPanel&lt;/strong&gt;, a rehab-scheduling agent built for the Qwen Cloud hackathon (Track 3), running on real Qwen models and deployed live on Alibaba Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: one agent collapses the trade-off
&lt;/h2&gt;

&lt;p&gt;Five objectives fight for the same slots — clinical acuity, overdue windows, continuity with the primary nurse, hard capacity, patient preference. They genuinely conflict: seat the sickest patient and you may break someone's continuity; honor a preference and you may bump an overdue visit.&lt;/p&gt;

&lt;p&gt;A single agent resolves that tension &lt;em&gt;inside one prompt&lt;/em&gt;, invisibly. You get an answer, not an argument. And you can't audit an answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: make the conflict explicit and negotiated
&lt;/h2&gt;

&lt;p&gt;RehabPanel replaces the one planner with &lt;strong&gt;five advocate agents&lt;/strong&gt;, each obsessed with exactly one objective, plus a &lt;strong&gt;charge-nurse referee&lt;/strong&gt; who brokers between them. It's a LangGraph state machine — &lt;code&gt;draft → critique → negotiate → arbitrate&lt;/code&gt;, looping until nobody's still objecting.&lt;/p&gt;

&lt;p&gt;Each round:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;All five advocates object&lt;/strong&gt; to the current plan, in their own words — in parallel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The loudest objection's advocate proposes&lt;/strong&gt; a concrete swap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The rest split into FOR / AGAINST coalitions&lt;/strong&gt; by whose objective the swap helps or hurts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The referee rules&lt;/strong&gt; on a fixed priority ranking (capacity ≻ acuity ≻ overdue ≻ continuity ≻ preference) — and explains the ruling in plain language, appending it to a &lt;strong&gt;conflict ledger&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nobody scripts that explanation. Mid-run, the referee writes things like: &lt;em&gt;"approved because it improves preference without violating any higher-ranked objective, and no competing acuity, overdue, or continuity claim contests this slot."&lt;/em&gt; That ledger is the whole point — a single agent never shows this work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq20cihq7a745y4dvi5zo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq20cihq7a745y4dvi5zo.png" alt="A round in the coordinator app: five advocates object with their own reasons, a FOR/AGAINST coalition forms, and the charge-nurse referee explains the ruling in prose" width="799" height="319"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;One round: five objections, the coalition split, and the referee's prose ruling appended to the conflict ledger.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The whole thing is a LangGraph state machine with one explicit exit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TB
    DR["node_draft&amp;lt;br/&amp;gt;acuity-first skeleton — no LLM (or a warm seed)"]
    CR["node_critique&amp;lt;br/&amp;gt;all 5 advocates object — in parallel"]
    CD{"hot objection&amp;lt;br/&amp;gt;&amp;amp;amp; round &amp;amp;lt; cap?"}
    NG["node_negotiate&amp;lt;br/&amp;gt;top objector proposes · FOR/AGAINST coalitions"]
    AR["node_arbitrate&amp;lt;br/&amp;gt;referee brokers on priority rank (deterministic)&amp;lt;br/&amp;gt;+ writes the ruling in prose · logs the ledger"]
    EN(["END"])
    DR --&amp;gt; CR --&amp;gt; CD
    CD -- yes --&amp;gt; NG --&amp;gt; AR --&amp;gt; CR
    CD -- "no · stalled" --&amp;gt; EN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Draft once, then critique → negotiate → arbitrate until no hot objection remains.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rule 1: Parallelize the debate. Serialize the decision.
&lt;/h2&gt;

&lt;p&gt;The expensive, creative part is the critique — five agents reading the whole caseload and reasoning about their objective. So &lt;strong&gt;run the five critiques concurrently&lt;/strong&gt;: one round-trip, not five sequential ones. That single change is the difference between a demo and a coffee break.&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="c1"&gt;# orchestrator.py — the five advocates critique the SAME draft concurrently
&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;advocates&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;objections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;advocates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The part that has to be &lt;em&gt;trustworthy&lt;/em&gt; — who wins — is the opposite. The referee's &lt;strong&gt;decision is deterministic Python&lt;/strong&gt;; only its &lt;strong&gt;rationale is the LLM&lt;/strong&gt;. Autonomy lives where it earns its keep (what to flag, how hard, why) and stays out of where it doesn't (the ruling itself). You get a negotiation that's alive but reproducible.&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="c1"&gt;# orchestrator.py — the verdict is a fixed priority ranking, never an LLM
&lt;/span&gt;&lt;span class="n"&gt;_RANK&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;capacity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;priority&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;window&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;continuity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preference&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;_decide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;against&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&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;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent&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;capacity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;against&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;                    &lt;span class="c1"&gt;# capacity veto — never break feasibility
&lt;/span&gt;    &lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;_RANK&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="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;forc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;default&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;ar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;_RANK&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="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;against&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;default&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;ar&lt;/span&gt;           &lt;span class="c1"&gt;# approve iff FOR outranks AGAINST
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Design heuristic:&lt;/strong&gt; put the LLM on the reasoning, keep a deterministic rule on the verdict. It's testable, it's cheap, and it can't drift.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Rule 2: Keep the judge outside the system
&lt;/h2&gt;

&lt;p&gt;Both planners — the single agent and the society — are scored by the &lt;strong&gt;same pure-Python function&lt;/strong&gt;. No LLM anywhere near it. It's locked in CI.&lt;/p&gt;

&lt;p&gt;That's not decoration. If the thing declaring the winner is an LLM, "the society is better" is a vibe. If it's forty deterministic lines that neither planner controls, it's a claim. On the same scorer, same week, the society reaches a plan the single agent can't.&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="c1"&gt;# scorer.py — one pure-Python function, no LLM anywhere, CI-locked
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assignments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patients&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clinicians&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;   &lt;span class="c1"&gt;# multi-objective: acuity coverage, overdue days, continuity, capacity, preference
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rule 3: Show the number you can defend
&lt;/h2&gt;

&lt;p&gt;Here's the honest part. The first time I ran the full protocol on real Qwen, the live society scored &lt;em&gt;lower&lt;/em&gt; than my deterministic reference implementation of the same protocol.&lt;/p&gt;

&lt;p&gt;For a day that looked like a bug. It wasn't. The rule-based reference runs its critique to exhaustion — it finds &lt;em&gt;every&lt;/em&gt; fixable conflict. The live LLM critique is sharper about what it flags but flags &lt;em&gt;fewer&lt;/em&gt; things per round, so it converges earlier. Same scorer, honest gap.&lt;/p&gt;

&lt;p&gt;So I had a choice: quote the big reproducible ceiling, or show the real run for what it is. I showed the real run. On live Qwen the society climbs &lt;strong&gt;160 → 181 (+21)&lt;/strong&gt; over twelve rounds — continuity breaks 30 → 25, preference misses 26 → 17, high-acuity coverage held throughout.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F54tr8y5lc1hre3bs1vqm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F54tr8y5lc1hre3bs1vqm.png" alt="Same week, same scorer: the society scores 181 versus the single agent's 160 — a +21 multi-objective gain" width="800" height="250"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Same week, same deterministic scorer — the society (+21) recovers the continuity and preference a single agent abandons.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Show the number you can defend on a machine a stranger controls, not the number you wish you had. A smaller live win beats a bigger offline one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Rule 4: If it costs money per click, gate it
&lt;/h2&gt;

&lt;p&gt;I wanted judges to run it live. Which means an open public URL that fires real Qwen — a way to donate your token voucher to the first crawler that finds it.&lt;/p&gt;

&lt;p&gt;So the demo has two doors. &lt;strong&gt;▶ Replay&lt;/strong&gt; plays a recorded real negotiation for anyone, free, no key. &lt;strong&gt;◉ Run live&lt;/strong&gt; and &lt;strong&gt;⟳ Re-plan&lt;/strong&gt; stream a fresh real negotiation over SSE, &lt;strong&gt;token-gated&lt;/strong&gt; — only the judge link fires the models. Same protocol; the cost is contained.&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="c1"&gt;# api.py — the live SSE endpoint bills the voucher, so gate it (constant-time compare)
&lt;/span&gt;&lt;span class="n"&gt;gate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REHABPANEL_DEMO_TOKEN&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;gate&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare_digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;JSONResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&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;live negotiation is token-gated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One more trick that keeps live runs watchable instead of expensive: an &lt;strong&gt;explicit context cache&lt;/strong&gt; on the invariant caseload. The big patient-and-slot table is identical on every advocate call, every round, so it's cached once (~99% prefix hit) instead of re-billed forty times.&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="c1"&gt;# advocates.py — mark the invariant caseload block so Qwen caches the prefix
&lt;/span&gt;&lt;span class="n"&gt;sysblocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&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;type&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;text&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;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_caseload_ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
     &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_control&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;ephemeral&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;   &lt;span class="c1"&gt;# DashScope context-cache marker
&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;text&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;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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;        &lt;span class="c1"&gt;# + this advocate's role (changes)
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What you take away
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Make the conflict a first-class object.&lt;/strong&gt; A society that argues produces an auditable ledger; a single agent produces an opaque answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallelize critique, serialize the verdict&lt;/strong&gt; — LLM on the reasoning, deterministic rule on the decision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the scorer pure and external&lt;/strong&gt;, or your "win" isn't measurable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy it, and gate what costs money.&lt;/strong&gt; A live, clickable demo is worth ten screenshots — as long as a crawler can't run up the bill.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A single agent collapses the trade-off. A society forced to negotiate under a referee reaches what one agent can't — and shows you exactly why each patient sits where they do.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Code (MIT): &lt;a href="https://github.com/jwlai-cloud/rehabpanel" rel="noopener noreferrer"&gt;github.com/jwlai-cloud/rehabpanel&lt;/a&gt;. Live on Alibaba Cloud — ▶ Replay is free; ◉ Run live is token-gated. Built entirely on Qwen Cloud (dashscope-intl), LangGraph, FastAPI. Decision support, fully synthetic data — no real patient records, anywhere.&lt;/em&gt;&lt;/p&gt;

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