TnsAI
Coordination

Council and Voting

TnsAI.Coordination provides two complementary systems for group decision-making: `CouncilExecutor` for multi-model deliberation with peer review, and `ConsensusBuilder` / `GroupDecisionFramework` for agent voting.

CouncilExecutor

The CouncilExecutor lets you get the best answer from multiple LLMs by having them independently respond, anonymously peer-review each other, and then synthesize a top-rated answer. It is a 3-stage deliberation pipeline inspired by Karpathy's llm-council. Multiple LLM models independently answer a question, peer-review each other's responses (anonymized), and a chairman synthesizes the best answer.

Three Stages

The deliberation process follows three stages. Each stage builds on the previous one to produce a high-quality final answer.

  1. Individual Responses -- All members answer the question independently in parallel.
  2. Peer Review -- Each member evaluates all anonymized responses, providing analysis and a ranking.
  3. Chairman Synthesis -- The chairman receives all responses, reviews, and aggregate rankings, then produces a final synthesized answer.

Usage

Create a council with at least two LLM members and a chairman, then call deliberate() with your question. The result includes the final synthesized answer, individual responses, peer reviews, and an aggregate ranking of models.

CouncilExecutor council = CouncilExecutor.builder()
    .members(List.of(gpt4Client, claudeClient, geminiClient, grokClient))
    .chairman(geminiClient)
    .anonymize(true)             // default: true
    .timeout(Duration.ofMinutes(5))
    .build();

CouncilResult result = council.deliberate("How should we architect the auth system?");

// Final synthesized answer
System.out.println(result.finalAnswer());

// Aggregate ranking of models
result.topRanked().ifPresent(r ->
    System.out.println("Top: " + r.llmName() + " (avg rank: " + r.averageRank() + ")"));

// Access each stage
List<CouncilResponse> responses = result.individualResponses();  // Stage 1
List<CouncilReview> reviews = result.peerReviews();              // Stage 2
CouncilSynthesis synthesis = result.synthesis();                  // Stage 3
List<RankedMember> ranking = result.aggregateRanking();

Builder Configuration

These are the parameters you can set when building a council.

ParameterDefaultDescription
members(required)At least 2 LLMClient instances
chairman(required)LLMClient that produces final synthesis
anonymizetrueWhether to hide model identities during peer review
timeout5 minutesPer-stage timeout

Anonymization

Anonymization prevents bias during peer review by hiding which LLM produced each response. When anonymize is true, model identities are replaced with labels (Model A, Model B, ...) during peer review. The chairman receives both labels and real names.

CouncilResult

The CouncilResult contains all outputs from the three deliberation stages, plus an aggregate ranking of which model performed best.

FieldTypeDescription
individualResponses()List<CouncilResponse>Stage 1 responses (llmName, response, durationMs)
peerReviews()List<CouncilReview>Stage 2 reviews (reviewerName, evaluation, parsedRanking)
synthesis()CouncilSynthesisStage 3 chairman output (chairmanModel, synthesis)
aggregateRanking()List<RankedMember>Models ranked by average position across reviews
finalAnswer()StringShortcut to synthesis().synthesis()
topRanked()Optional<RankedMember>The highest-ranked model

RankedMember

A RankedMember records how well a specific LLM performed across all peer reviews. Lower averageRank is better (1.0 means consistently ranked first).

public record RankedMember(String llmName, double averageRank, int rankingsCount)

Lower averageRank is better (1.0 = consistently ranked first).

VotingMethod

TnsAI provides five voting methods for group consensus, ranging from simple majority to weighted voting. Choose the method that matches how much agreement you need.

MethodDescriptionThreshold
MAJORITYSimple majority (\> 50%)50%
SUPERMAJORITYConfigurable threshold (default 2/3)66.7%
UNANIMOUSAll voters must agree100%
RANKED_CHOICEInstant-runoff with ranked preferencesMajority after elimination
WEIGHTEDVotes weighted by voter weight50% of total weight

ConsensusBuilder

The ConsensusBuilder is the simplest way to run a vote among agents. You specify the question, the options, the voters, and the voting method, then call .vote() to get the result. It is a fluent builder that orchestrates a voting session among agents. Collects votes in parallel, applies the chosen voting method, and returns results.

VotingResult result = ConsensusBuilder.create()
    .topic("Which database to use?")
    .options("PostgreSQL", "MySQL", "MongoDB")
    .among(List.of(dbExpert, backendDev, infraAgent))
    .method(VotingMethod.MAJORITY)
    .timeout(Duration.ofSeconds(30))
    .quorum(2)
    .vote();

System.out.println("Winner: " + result.winner());
System.out.println("Total votes: " + result.totalVotes());
System.out.println("Quorum met: " + result.quorumMet());

Configuration

These builder methods let you configure every aspect of the voting session.

MethodDefaultDescription
.topic(String)(required)The question to vote on
.options(String...)(required)Available choices
.among(List<Agent>)(required)Voting agents
.method(VotingMethod)MAJORITYVoting algorithm
.timeout(Duration)30 secondsMaximum wait for votes
.quorum(int)1Minimum votes required
.supermajorityThreshold(double)0.667Threshold for SUPERMAJORITY
.listener(VotingListener)noneEvent callbacks

How Voting Works

Here is what happens internally when you call .vote():

  1. A prompt is built with the topic and options, sent to all agents in parallel.
  2. Each agent's response is parsed using case-insensitive matching against the option list.
  3. Votes are tallied using the selected method (MajorityVoting or RankedChoiceVoting).
  4. The VotingResult includes the winner, vote counts, and quorum status.

VotingListener

Attach a VotingListener to get real-time callbacks as votes come in, when quorum is reached, and when the final result is ready.

ConsensusBuilder.create()
    .topic("Deploy now?")
    .options("Yes", "No", "Defer")
    .among(agents)
    .listener(new VotingListener() {
        @Override
        public void onVoteReceived(Vote vote) {
            System.out.println(vote.voterId() + " voted: " + vote.choice());
        }

        @Override
        public void onQuorumReached(int voteCount, int quorum) {
            System.out.println("Quorum reached: " + voteCount + "/" + quorum);
        }

        @Override
        public void onComplete(VotingResult result) {
            System.out.println("Winner: " + result.winner());
        }
    })
    .vote();

GroupDecisionFramework

The GroupDecisionFramework is a more structured alternative to ConsensusBuilder, designed for use within an AgentGroup. It follows a formal propose-vote-converge lifecycle and records a decision trace for auditability. It provides a structured 3-phase protocol for group-level decision-making within an AgentGroup. Provides propose-vote-converge semantics with decision tracing.

GroupDecisionFramework framework = new DefaultGroupDecisionFramework(traceStore);

// Full pipeline in one call
DecisionProposal proposal = DecisionProposal.of(
    "Which database?",
    List.of("PostgreSQL", "MySQL", "MongoDB")
);
DecisionResult result = framework.makeDecision(group, proposal);

Three Phases

The framework splits every group decision into three distinct phases:

  1. Propose -- Create a DecisionProposal with a topic, options, and voting method.
  2. Vote -- Collect votes from all group members.
  3. Converge -- Tally votes, determine outcome, save trace, broadcast result. Falls back to leader decision if no consensus and a leader exists.
// Step-by-step usage for more control
DecisionProposal proposal = framework.propose(
    "Which database?",
    List.of("PostgreSQL", "MySQL", "MongoDB"),
    VotingMethod.RANKED_CHOICE
);

List<Vote> votes = framework.vote(group, proposal);
DecisionResult result = framework.converge(group, votes, proposal);

DecisionTraceStore

Every decision is recorded in a trace store so you can review what was proposed, who voted for what, and what the outcome was. All decisions are persisted to a DecisionTraceStore for auditability. The default implementation InMemoryDecisionTraceStore keeps traces in memory.

On this page