Show HN:可回放的 A2A 陪审团,用于追踪 Agent 如何影响决策
英文标题:🔶 Show HN: A replayable A2A jury for tracing how agents influence decisions
ProtoLink 展示了一个可离线、可确定性回放的虚构责任审判,用多 Agent 陪审团模拟不同通信拓扑如何影响最终裁决。该示例比较 solo、independent、foreperson-star 与 direct-mesh 四种条件,并记录每条公开消息后的立场、投票及罪责评分变化。在默认 seed-7 结果中,mesh 通信使陪审团从 2–3 的无罪转为 3–2 的有罪,而 star 虽提高平均罪责评分却未改变裁决。项目为开发者提供 JSON 结果、ProtoLink traces、公开逐字记录与交互式 HTML 回放,同时强调这些固定夹具结果不代表网状通信普遍提升准确性。
75.4 KB
中文
AI Agent 能通过彼此对话得出更好的答案,还是更糟的答案?
这个 ProtoLink 展示将自主 Agent 置于一个虚构的责任审判庭中,并使其通信过程可被观察。案件本身令人印象深刻,但案件并非产品;产品是交互本身:
- 具有不同角色、激励、职业和沟通习惯的 Agent;
- 直接的 ProtoLink Agent-to-Agent 任务;
- 可自行决定联系谁、提出什么问题的陪审员;
- 每条公开消息之后均可回放的观点变化;
- 单人、独立、首席陪审员星型及直接网状结构的对比;
- 使用相同应用协议的 provider/model 实验。
默认运行是确定性的,并且离线执行。它会生成 JSON 结果、ProtoLink traces、公开逐字记录以及独立的交互式 HTML 报告。
本示例中的所有内容与所有人物均为虚构。这是一项软件实验,并非法律分析、法律建议或经过验证的安全评估。
案件:C-91 事故
在一个雨夜的 21:47,一辆自主驾驶的 Aster Vale Robotaxi 在临时过街区域内撞死了 31 岁的骑行者 Lina Ortega。车辆在撞击前仅 0.35 秒开始紧急制动。36 小时前,该车接收了 Orchid 4.8 软件版本。
虚构审判庭提出的问题是:
Aster Vale Mobility 是否因疏忽部署导致 Lina Ortega 死亡的自动驾驶车辆系统,而构成刑事过失罪?
证据构成了一个相互作用的失效问题:
| ID | 已采纳证据 |
|---|---|
E1 |
摄像头分类将骑行者和车道箭头标志牌合并识别;雷达检测到了运动,但制动被抑制。 |
E2 |
一名工程师曾在 20 次晚制动模拟中的 3 次出现问题后阻止发布,但后续校准在 20 次重跑中全部通过。 |
E3 |
撞车运行的是 C-91 校准版本,而安全报告验证的是 C-90;一个 CI bot 共用了签名凭证。 |
E4 |
一名承包商移动了箭头标志牌,却未更新城市地图,导致约 1.1 秒的有效观察时间损失。 |
E5 |
一项获监管机构批准的设计允许摄像头分类在车速高于 25 km/h 时否决仅由雷达触发的制动。 |
E6 |
尽管事故地点附近此前发生过两次断网,蜂窝网络中断仍使远程操作员保障措施失效。 |
E7 |
重建结果显示,校准和道路布局都会实质性改变安全停车率。 |
二元指控的范围被刻意限定得比因果故事更窄。无罪裁决不意味着没有任何环节出错,有罪裁决也不意味着 Aster Vale 是唯一责任方。
参与者声明被有意明确地写入 run.py,没有任何工厂模式隐藏 ProtoLink 的组成。
| Agent | 年龄 | 性别 | 角色与激励 |
|---|---|---|---|
| Judge Imani Quill | 58 | 女 | 中立的审判庭主持人;将因果贡献与法律罪责区分开来 |
| Amara Bell | 41 | 女 | Lina 家属的律师;反对借复杂性消解问责 |
| Rowan Hale | 47 | 男 | Aster Vale 安全主管;主张外部失效造成了不可预见的组合 |
| Dr. Nia Sol | 36 | 女 | 感知工程师;对校准和发布流水线有严谨的认识 |
| Elias Trent | 56 | 男 | 安全监管机构官员;坦率但在制度上具有防御性 |
| Dana Pierce | 50 | 女 | 保险理赔主管,具有明确的经济利益 |
| Dr. Amina Kade | 44 | 女 | 独立事故调查员,负责重建相互作用的原因 |
| 陪审员 | 年龄 | 性别 | 人类视角 |
| --- | --- | --- | --- |
| Evelyn Brooks | 62 | 女 | 前碰撞事故侦探 |
| Malik Thompson | 43 | 男 | 民权律师 |
| Dr. Anika Rao | 38 | 女 | 人因心理学家 |
| Ruben Park | 35 | 男 | 站点可靠性工程师 |
| Sofia Bell | 46 | 女 | 调查记者兼首席陪审员 |
| Casey Morgan (仅 solo) | 40 | 女 | 公民事务通才 |
这些 prompts 描述的是人物,而不是预先设定的数值。它们不会说“你的初始值为 61/100”,也不会暴露诸如 reinforce_ally 之类的路由枚举。仅供参考的固定夹具系数始终位于所有面向人类的 prompt 之外。年龄和性别是虚构的 prompt 元数据,而不是数值先验。在 provider 对比中应保持其不变,或有意轮换分配,以避免将人口统计变化误认为模型效应。
Agent 编写的通信
世界引擎负责安排有界回合并执行拓扑约束。它不会决定陪审员该说什么,也不会决定网状结构中的陪审员应联系谁。
在审议回合中,陪审员会返回一个可观察的公开动作:
{
"move": "ask_question",
"target_id": "juror_ruben",
"message": "Does the shared CI token make the company more accountable, or only make attribution harder?",
"evidence_ids": ["E3"],
"public_intent": "Clarify whether release automation changes organizational control."
}
应用程序会根据当前拓扑验证目标,随后发言者通过 ProtoLink 将消息直接发送给所选 Agent。接收者会返回更新后的公开登记值、分类投票、简洁理由和公开回复。
同侪消息绝不会自动暴露其他陪审员的私人概率、置信度或投票。Agent 只会公开其自主选择写入公开消息的内容。
一名公民事务通才接收公开记录,并在没有同侪的情况下作出决定。这是一个直观的产品基线,而不是纯粹的通信处理对照:它同时改变了陪审团规模、角色构成和推理预算。
相同的五名陪审员接收相同的公开审判记录,并在没有同侪消息的情况下投票。这一条件在没有审议的前提下,捕捉专业化和多样性。
陪审员通过首席陪审员 Sofia Bell 发送公开消息。首席陪审员既是信息枢纽,也可能成为瓶颈。
每位陪审员都获得一个回合,其他所有陪审员均是允许的目标。Agent 自行编写接收者、动作、消息及公开意图。
主要通信对比是在其保存的控制指纹和公开记录哈希一致时,对比 independent 与 star 或 mesh。
默认回放显示的内容
离线 seed-7 固定夹具旨在让一次快速运行中通信处理的影响清晰可见:
| 条件 | 同侪消息数 | 裁决 | 票数 | 平均罪责登记值 |
|---|---|---|---|---|
solo |
0 | 有罪 | 1–0 | 78.59 |
independent |
0 | 无罪 | 2–3 | 77.56 |
star |
5 | 无罪 | 2–3 | 80.21 |
mesh |
5 | 有罪 | 3–2 | 80.54 |
独立陪审团和网状陪审团接收相同的公开记录。在 mesh 中,首席陪审员 Sofia Bell 选择就未经验证的 C-91 校准与事故现场地图之间的相互作用,向人因心理学家 Dr. Anika Rao 提出质疑。Anika 的公开罪责登记值从 77.90 升至 81.41,其分类投票也从无罪变为有罪。后续消息进一步强化了这一立场,但第一次直接交流才是可观察台账中改变多数结果的事件。
星型拓扑同样提高了平均罪责登记值,但它将消息集中到首席陪审员处,并未改变 2–3 的裁决。因此,该演示的重点并非“消息越多越好”。谁能向谁发言,会改变哪些假设被暴露出来。
这些是用于说明的确定性固定夹具结果,并不代表网状通信通常会提高准确性。对实时模型的比较需要重复的配对运行和消息消融实验。
从仓库根目录运行:
python examples/ai_courtroom/run.py
默认命令使用确定性的 reference provider,并在无需网络访问或凭证的情况下运行全部四种条件。
运行一种条件:
python examples/ai_courtroom/run.py \
--provider reference \
--condition mesh \
--seed 17
精确输出位置会在结束时打印。如需自行选择位置:
python examples/ai_courtroom/run.py \
--condition all \
--seed 17 \
--output-dir examples/ai_courtroom/output/c-91-incident-seed-17
当复用输出目录时,只有该示例已知的生成文件会被替换。traces.jsonl 不允许在新结果旁累积过期运行记录。
运行器会在任务执行时报告进度,以免实时模型看上去像是卡住:
- 离线
referenceprovider 使用紧凑的阶段和步骤更新; - 实时 provider 默认显示每次 A2A 交换及其耗时;
-v或--verbose强制显示详细的消息、接受和修复更新;-q或--quiet会在默认 Agent 日志级别下抑制应用程序进度,仅保留运行头信息和最终条件摘要;--agent-verbosity {0,1,2}独立控制 ProtoLink 自身的每 Agent 日志,默认值为0。
例如:
python examples/ai_courtroom/run.py \
--condition mesh \
--verbose \
--agent-verbosity 1
应用程序进度和 Agent 日志被有意分开。应从默认显示或 --verbose 开始;只有在诊断底层 Agent 运行时,才提高 --agent-verbosity。修复诊断属于常规进度,因此除非选择 --quiet,否则它们会保持可见。
报告从通信开始,而不是先展示一面基准指标墙:
- 审议前后的裁决;
- 可播放的 A2A 事件回放;
- 当前发送者和接收者;
- 自然语言的问题、质疑、澄清或让步;
- 接收者的公开回复;
- 同步展示的消息前后罪责登记值和分类投票;
- 证据引用和 ProtoLink 任务元数据;
- 使用明确非因果措辞描述的、消息后观察到的变化。
完整事件台账仍以静态、无障碍访问的后备形式提供。
报告不会暴露 chain-of-thought。公开理由是应用程序产物,可能并不完整,也可能是事后解释。
每种条件都会写入:
| 文件 | 用途 |
|---|---|
result.json |
完整配置、公开记录、Agent 模型、决策历史、动作、事件、指标和裁决 |
summary.json |
紧凑的结果和对比数据 |
transcript.md |
经转义的公开逐字记录 |
report.html |
独立的交互式回放与分析报告 |
traces.jsonl |
ProtoLink 任务、推理和 A2A 遥测数据 |
运行全部条件还会写入 index.html,其中呈现 solo → independent → star → mesh 的阶梯式对比。
保存的元数据包括:
- 每个 Agent 的 provider 和精确解析后的模型;
- seed、temperature、证据顺序、轮数以及两种重试上限;
- 公开记录哈希;
- 基线和审议前快照哈希;
- 对比控制指纹;
- 消息、重试、延迟、估算 token、依据关联和路由信息。
安装可选客户端:
python -m pip install -e '.[llms]'
示例:
export OPENAI_API_KEY="..."
python examples/ai_courtroom/run.py \
--provider openai \
--model "your-model-id" \
--temperature 0 \
--condition mesh \
--seed 17
支持的后端:
openaianthropicgeminiollamaopenai-compatible
可使用 --base-url 指定本地或兼容服务器。
通过实时 provider 运行 --condition all 时,必须显式使用 --allow-multi-condition-live 确认,因为这会成倍增加 API 使用量。
先从一种条件开始,并明确指定本地安装的模型:
python examples/ai_courtroom/run.py \
--provider ollama \
--model "your-ollama-model" \
--base-url "http://localhost:11434" \
--condition mesh \
--action-parse-attempts 5 \
--max-attempts 5 \
--verbose
如果所有参与者都使用同一个 Ollama 后端,则无需使用陪审员专属的 provider 参数。仅当陪审员有意使用不同模型或端点时,才使用 --juror-provider ollama、--juror-model 和 --juror-base-url。
实时响应会跨越两个有意分离的验证边界:
--action-parse-attempts控制 ProtoLink 推理循环可要求模型修正其外层动作信封的次数。--max-attempts控制审判庭在收到最终内容后,针对每条 A2A 消息允许进行多少次有界的应用契约尝试。
二者默认值均为 3,接受范围为 1..5,并会在再次尝试前提供针对性的验证反馈。二者相互独立,因为有效的 ProtoLink FinalAction 仍可能包含格式错误的法庭 JSON。增加任一上限都可能帮助较小的本地模型恢复,但也会延长运行时间。被接受的应用修复和失败尝试会持续显示在进度输出及保存的事件元数据中;更底层的动作解析器诊断可通过 --agent-verbosity 查看。
Provider/网络退避是第三个、更底层的层级,不受任一 flag 控制。重试预算可能相互叠加,因此应有意识地提高它们,而非将所有上限都设为最大值。
严格解析和模型自我修正仍是主要路径。外层解析器仅针对这里暴露的响应形态增加两项有限规范化:它可以序列化放在 FinalAction.content 内的对象/列表;并且仅当不存在 ProtoLink 动作信封字段时,才可将直接的应用对象视作最终内容。它不会猜测缺失的投票、证据、目标或论点。
对于此前“有效散文、但没有应用 JSON”的失败情形,应用程序还提供了一项同样有限的最终兜底:在最后一次结构化尝试之后,非空的律师、证人或法官公开陈述可以保留为其 statement,但只会提取精确匹配的已采纳 E1–E7 引用。该事件会被标记为恢复警告。陪审员评估、选票、分类裁决字段和审议目标绝不会使用此散文兜底,因为恢复它们将需要编造决策数据。
一次全条件的实时运行会为每种条件重复完整听证,并且
English / 原文
Can AI agents talk themselves into a better answer, or a worse one?
This ProtoLink showcase puts autonomous agents inside a fictional liability tribunal and makes their communication observable. The case is memorable, but the case is not the product. The product is the interaction:
- agents with different roles, incentives, professions, and communication habits;
- direct ProtoLink agent-to-agent tasks;
- jurors who choose whom to address and what to ask;
- replayable opinion changes after every public message;
- solo, independent, foreperson-star, and direct-mesh comparisons;
- provider/model experiments using the same application protocol.
The default run is deterministic and offline. It produces JSON results, ProtoLink traces, a public transcript, and standalone interactive HTML reports.
Everything and everyone in this example is fictional. It is a software experiment, not legal analysis, legal advice, or a validated safety assessment.
The case: The C-91 Incident
At 21:47 on a rain-soaked evening, an autonomous Aster Vale robotaxi struck and killed 31-year-old cyclist Lina Ortega inside a temporary crossing. The car began emergency braking only 0.35 seconds before impact. Thirty-six hours earlier it received the Orchid 4.8 software release.
The fictional tribunal asks:
Is Aster Vale Mobility guilty of criminally negligent deployment of an autonomous vehicle system that caused Lina Ortega's death?
The evidence creates an interacting-failures problem:
| ID | Admitted evidence |
|---|---|
E1 |
Camera classification merged the cyclist and lane-arrow board; radar detected motion but braking was suppressed. |
E2 |
An engineer had blocked release after 3 of 20 late-braking simulations, but a later calibration passed 20 of 20 reruns. |
E3 |
The crashed car ran calibration C-91 while the safety report validated C-90; a CI bot shared the signing credential. |
E4 |
A contractor moved the arrow board and failed to update the city map, removing roughly 1.1 seconds of useful observation. |
E5 |
A regulator-approved design allowed camera classification to veto radar-only braking above 25 km/h. |
E6 |
A cellular outage defeated the remote-operator safeguard despite two earlier outages near the site. |
E7 |
Reconstruction shows both calibration and road layout materially changed the safe-stop rate. |
The binary charge is deliberately narrower than the causal story. A not-guilty verdict does not mean nothing went wrong, and a guilty verdict does not mean Aster Vale was the only contributor.
The actor declarations are intentionally explicit in run.py-there is no factory hiding the ProtoLink composition.
| Agent | Age | Gender | Character and incentive |
|---|---|---|---|
| Judge Imani Quill | 58 | Woman | Neutral tribunal chair; separates causal contribution from legal guilt |
| Amara Bell | 41 | Woman | Lawyer for Lina's family; resists complexity being used to dissolve accountability |
| Rowan Hale | 47 | Man | Aster Vale safety executive; argues that external failures created an unforeseeable combination |
| Dr. Nia Sol | 36 | Woman | Perception engineer; precise about calibration and the release pipeline |
| Elias Trent | 56 | Man | Safety regulator; candid but institutionally defensive |
| Dana Pierce | 50 | woman | Insurance claims director with an explicit financial interest |
| Dr. Amina Kade | 44 | Woman | Independent accident investigator who reconstructs interacting causes |
| Juror | Age | Gender | Human perspective |
| --- | --- | --- | --- |
| Evelyn Brooks | 62 | Woman | Former collision detective |
| Malik Thompson | 43 | Man | Civil-rights lawyer |
| Dr. Anika Rao | 38 | Woman | Human-factors psychologist |
| Ruben Park | 35 | Man | Site-reliability engineer |
| Sofia Bell | 46 | Woman | Investigative journalist and foreperson |
| Casey Morgan (solo only) | 40 | woman | Civic generalist |
These prompts describe people, not seeded numbers. They do not say “you begin at 61/100” and they do not expose routing enums such as reinforce_ally. Reference-only fixture coefficients remain outside every human-facing prompt. Age and gender are fictional prompt metadata, not numerical priors. Hold them fixed across provider comparisons, or deliberately rotate the assignments, so demographic changes are not mistaken for model effects.
Agent-authored communication
The world engine schedules bounded turns and enforces topology. It does not choose what a juror should say or whom a mesh juror should approach.
On a deliberation turn, a juror returns an observable public action:
{
"move": "ask_question",
"target_id": "juror_ruben",
"message": "Does the shared CI token make the company more accountable, or only make attribution harder?",
"evidence_ids": ["E3"],
"public_intent": "Clarify whether release automation changes organizational control."
}
The application validates the target against the current topology, then the speaker sends the message directly to the selected agent through ProtoLink. The receiver returns an updated public register, categorical vote, concise reason, and public reply.
Peer messages never automatically expose another juror's private probability, confidence, or vote. An agent reveals only what it chooses to put in its public message.
One civic generalist receives the public record and decides without peers. This is an intuitive product baseline, not a clean communication treatment: it also changes panel size, persona composition, and inference budget.
The same five jurors hear the same public tribunal record and vote without peer messages. This captures specialization and diversity without deliberation.
Jurors send public messages through foreperson Sofia Bell. The foreperson is an information hub and possible bottleneck.
Every juror receives a turn with all other jurors as permitted targets. The agent authors the recipient, move, message, and public intent.
The primary communication comparison is independent versus star or mesh when their saved control fingerprints and public-record hashes match.
What the default replay shows
The offline seed-7 fixture is designed to make the communication treatment visible in one quick run:
| Condition | Peer messages | Verdict | Tally | Mean guilt register |
|---|---|---|---|---|
solo |
0 | Guilty | 1–0 | 78.59 |
independent |
0 | Not guilty | 2–3 | 77.56 |
star |
5 | Not guilty | 2–3 | 80.21 |
mesh |
5 | Guilty | 3–2 | 80.54 |
The independent and mesh panels receive the same public record. In mesh, foreperson Sofia Bell chooses to challenge human-factors psychologist Dr. Anika Rao with the interaction between the unvalidated C-91 calibration and the crash-scene map. Anika's public guilt register moves from 77.90 to 81.41 and her categorical vote changes from not guilty to guilty. Later messages strengthen that position, but the first direct exchange is the majority-changing event in the observable ledger.
The star topology also raises the mean guilt register, but it concentrates messages at the foreperson and does not change the 2–3 verdict. The demo's point is therefore not “more messages are better.” Who can address whom changes which assumptions are exposed.
These are illustrative deterministic-fixture results, not evidence that mesh communication generally improves accuracy. Live-model comparisons need repeated paired runs and message ablations.
Run from the repository root:
python examples/ai_courtroom/run.py
The default command uses the deterministic reference provider and runs all four conditions without network access or credentials.
Run one condition:
python examples/ai_courtroom/run.py \
--provider reference \
--condition mesh \
--seed 17
The exact output location is printed at the end. To choose it:
python examples/ai_courtroom/run.py \
--condition all \
--seed 17 \
--output-dir examples/ai_courtroom/output/c-91-incident-seed-17
When an output directory is reused, only the example's known generated files are replaced. traces.jsonl is not allowed to accumulate stale runs beside a new result.
The runner reports work as it happens so a live model does not look stalled:
- the offline
referenceprovider uses compact phase and step updates; - live providers show each A2A exchange and its elapsed time by default;
-vor--verboseforces detailed message, acceptance, and repair updates;-qor--quietsuppresses application progress at the default agent log level, only run headers and final condition summaries remain;--agent-verbosity {0,1,2}independently controls ProtoLink's own per-agent logs and defaults to0.
For example:
python examples/ai_courtroom/run.py \
--condition mesh \
--verbose \
--agent-verbosity 1
Application progress and agent logs are separate on purpose. Start with the default display or --verbose; raise --agent-verbosity only when diagnosing the underlying agent runtime. Repair diagnostics are ordinary progress, so they remain visible unless --quiet is selected.
The report opens with communication, not a wall of benchmark metrics:
- the pre- versus post-deliberation verdict;
- a playable A2A event replay;
- the active sender and receiver;
- the natural question, challenge, clarification, or concession;
- the receiver's public reply;
- synchronized before/after guilt registers and categorical votes;
- evidence citations and ProtoLink task metadata;
- observed after-message shifts using explicitly non-causal language.
The full event ledger remains available as a static, accessible fallback.
The report does not expose chain-of-thought. A public reason is an application artifact that may be incomplete or post-hoc.
Each condition writes:
| File | Purpose |
|---|---|
result.json |
Full configuration, public record, agent models, decision histories, actions, events, metrics, and verdict |
summary.json |
Compact outcome and comparison data |
transcript.md |
Escaped public transcript |
report.html |
Standalone interactive replay and analysis |
traces.jsonl |
ProtoLink task, inference, and A2A telemetry |
An all-condition run also writes index.html, which presents the solo → independent → star → mesh ladder.
Saved metadata includes:
- provider and exact resolved model for every agent;
- seed, temperature, evidence order, rounds, and both retry limits;
- public-record hash;
- baseline and pre-deliberation snapshot hashes;
- a comparison control fingerprint;
- message, retry, latency, estimated-token, grounding, and routing information.
Install optional clients:
python -m pip install -e '.[llms]'
Example:
export OPENAI_API_KEY="..."
python examples/ai_courtroom/run.py \
--provider openai \
--model "your-model-id" \
--temperature 0 \
--condition mesh \
--seed 17
Supported backends:
openaianthropicgeminiollamaopenai-compatible
Use --base-url for a local or compatible server.
Running --condition all with a live provider requires the explicit --allow-multi-condition-live acknowledgement because it multiplies API use.
Start with one condition and name the locally installed model explicitly:
python examples/ai_courtroom/run.py \
--provider ollama \
--model "your-ollama-model" \
--base-url "http://localhost:11434" \
--condition mesh \
--action-parse-attempts 5 \
--max-attempts 5 \
--verbose
If every actor uses the same Ollama backend, the juror-specific provider flags are unnecessary. Use --juror-provider ollama, --juror-model, and --juror-base-url only when the jurors intentionally use a different model or endpoint.
Live responses cross two intentionally separate validation boundaries:
--action-parse-attemptscontrols how many times the ProtoLink inference loop may ask the model to correct its outer action envelope.--max-attemptscontrols how many bounded application-contract attempts the tribunal permits for each A2A message after it receives final content.
Both default to 3, accept 1..5, and provide targeted validation feedback before another attempt. They are separate because a valid ProtoLink FinalAction can still contain malformed courtroom JSON. Increasing either limit can help a smaller local model recover, but it also increases run time. Accepted application repairs and failed attempts remain visible in progress output and saved event metadata; lower-level action-parser diagnostics are visible through --agent-verbosity.
Provider/network backoff is a third, lower layer and is not controlled by either flag. Retry budgets can multiply, so increase them deliberately rather than setting every limit to its maximum.
Strict parsing and model self-correction remain the primary path. The outer parser adds two narrow normalizations for the response shapes exposed here: it can serialize an object/list placed inside FinalAction.content, and it can treat a direct application object as final content only when no ProtoLink action-envelope fields are present. It does not guess missing votes, evidence, targets, or arguments.
The application has one equally narrow last-resort fallback for the earlier “valid prose, no application JSON” failure: after the final structured attempt, a nonempty lawyer, witness, or judge public statement may be kept as its statement, with only exact admitted E1–E7 references extracted. The event is marked with a recovery warning. Juror assessments, ballots, categorical verdict fields, and deliberation targets never use this prose fallback because recovering them would require inventing decision data.
An all-condition live run repeats the full hearing for each condition and may take substantially longer:
python examples/ai_courtroom/run.py \
--provider ollama \
--model "your-ollama-model" \
--base-url "http://localhost:11434" \
--condition all \
--allow-multi-condition-live \
--verbose
Controlled juror-only model comparison
An end-to-end provider switch changes the lawyers, witnesses, public record, and jury. That is visually interesting but scientifically confounded.
For a cleaner comparison, keep tribunal actors deterministic and change only the jurors:
python examples/ai_courtroom/run.py \
--provider reference \
--juror-provider anthropic \
--juror-model "your-model-id" \
--condition mesh \
--temperature 0 \
--seed 17
For publishable comparisons:
- Freeze prompts, persona demographics, case, evidence order, topology, round count, and temperature, or preregister a balanced rotation of demographic assignments.
- Pair runs by seed.
- Verify record hashes and control fingerprints.
- Repeat every cell.
- Include schema failures, warnings, and routing failures.
- Report outcome, calibration, grounding, volatility, latency, and cost separately.
- Describe the result as a case study, not a general intelligence leaderboard.
Provider temperature zero is not a determinism guarantee.
python examples/ai_courtroom/compare.py \
path/to/solo/summary.json \
path/to/independent/summary.json \
path/to/star/summary.json \
path/to/mesh/summary.json \
--output comparison.md
The comparison treats solo polarization and consensus as N/A.
Interpreting opinion and influence
guilt_probability is an application-owned public register. It is not a probe of hidden model belief.
The categorical guilty or not_guilty vote is authored by the juror under the fictional tribunal burden. The application does not silently derive criminal guilt from a 50% threshold.
The default mesh replay contains this immediate change:
Sofia Bell → Dr. Anika Rao
77.90 not guilty → 81.41 guilty
Observed after-message shift: +3.51
It is not automatically proof that Sofia caused the full change. Causal language requires a matched message ablation across repeated paired runs.
The repository's default test discovery targets the root tests/ directory, so run this example's offline tests explicitly:
pytest -q examples/ai_courtroom/tests
examples/ai_courtroom/
├── run.py
├── compare.py
├── README.md
├── ARTICLE.md
├── courtroom/
│ ├── case_data.py
│ ├── providers.py
│ ├── reference_llm.py
│ ├── schemas.py
│ ├── simulation.py
│ └── reporting.py
├── tests/
│ ├── conftest.py
│ └── test_courtroom.py
└── output/
└── .gitignore
ProtoLink is the communication substrate. The showcase question is deliberately open: communication can correct an error, amplify one, expose a hidden assumption, or merely make a group more confident. The replay lets you see which happened.