CouncilEx.Councils.WeightedConsensus (CouncilEx v0.1.0)

Copy Markdown View Source

Topology — independent_analysis → weighted_synthesis (chair).

Members analyse the input in parallel; the chair synthesizes with per-member weights surfaced in its prompt input. Weights are pulled from (in order):

  1. Static :weight opt declared on the member tuple
  2. :confidence field on the member's %MemberResult{} (populated by CouncilEx.Confidence when the member sets :confidence)
  3. Equal weight as fallback

Weights are normalized to sum to 1.0 across :ok members. The chair receives the digest of each prior round with :weight and :confidence attached per member, so chair prompts can prioritize high-weight contributions.

Inspired by Wu et al. Council Mode (arXiv:2604.02923) — the paper's "Consensus Engine" that weights agent contributions by reliability metrics rather than equal-weight or majority vote.

Usage

council =
  CouncilEx.Councils.WeightedConsensus.new(
    as: MyApp.WeightedPanel,
    members: [
      {:expert, MyApp.Members.Expert,
       [provider: :openai, model: "gpt-4o", weight: 0.6]},
      {:generalist, MyApp.Members.Gen,
       [provider: :openai, model: "gpt-4o-mini", weight: 0.4]}
    ],
    chair: {MyApp.Members.Synth, [provider: :openai, model: "gpt-4o"]}
  )

CouncilEx.run(council, %{topic: "..."})

With member self-reported confidence

Omit :weight and let confidence drive the weighting:

members: [
  {:a, MyApp.A, [provider: :openai, model: "gpt-4o-mini", confidence: :self_report]},
  {:b, MyApp.B, [provider: :openai, model: "gpt-4o-mini", confidence: :self_report]}
]

Each member self-rates and the synthesis round normalizes those into weights.

Summary

Functions

Build the WeightedConsensus topology as a generated council module.

Build the same WeightedConsensus topology as new/1 but as a data-only %CouncilEx.DynamicCouncil{}.

Functions

new(opts)

@spec new(keyword()) :: module()

Build the WeightedConsensus topology as a generated council module.

Opts

  • :expose_confidence (boolean, default true) — forwarded to Rounds.WeightedSynthesis. See its moduledoc for the Wu 2025 conformity-mitigation rationale.

new_dynamic(opts)

@spec new_dynamic(keyword()) :: CouncilEx.DynamicCouncil.t()

Build the same WeightedConsensus topology as new/1 but as a data-only %CouncilEx.DynamicCouncil{}.