Can Different LLMs Be Used for the Generator and Critic in ADHD? A Complete Configuration Guide

Yes. The ADHD framework explicitly supports using different LLMs for the generator and critic through separate model and criticModel configuration options, with full mechanical isolation between the divergence and convergence phases.

ADHD (Automatic Divergence-Harmonized Deepening) is a structured reasoning framework that separates idea generation from evaluation. This architectural split naturally extends to model selection—allowing you to optimize each phase with purpose-built models, whether that means a creative generator paired with a rigorous critic or cost-efficient tiering across phases.

How ADHD Separates Generator and Critic at the Architecture Level

The framework implements a hard wall between two distinct operational phases:

  • Generator (divergence): Produces branching idea trees via divergeBranch()
  • Critic (convergence): Scores, clusters, and refines via scoreIdeas() and clusterIdeas()

This separation is enforced mechanically in src/engine.ts. The two phases never share KV-cache, conversation history, or model weights—guaranteeing true independence even when accidentally configured with the same model identifier.

RunOptions Configuration Interface

The type definitions in src/types.ts (lines 61–64) declare explicit fields for dual-model configuration:

type RunOptions = {
  model?: string;        // LLM for all generator calls (divergence)
  criticModel?: string;  // LLM for critic calls (score + cluster)
  // ... additional options
};

When criticModel is omitted, the critic falls back to the generator model for backward compatibility.

Engine Implementation: Model Routing Mechanics

Inside src/engine.ts, the run() function resolves model selection with explicit fallback logic at lines 27–30:

const critic = criticModel ?? model;  // src/engine.ts L27-30

This critic constant is then passed exclusively to convergence-phase operations. The divergence phase receives only the base model argument. Examining lines 58–70 reveals the complete routing:

  • divergeBranch(problem, model, ...) — generator phase
  • scoreIdeas(ideas, critic, ...) — critic phase
  • clusterIdeas(scored, critic, ...) — critic phase

Each call routes through callLLM() independently, ensuring zero cross-contamination between generator and critic contexts.

Programmatic Usage: Configure Different LLMs in Code

Pass distinct model identifiers to run() for精细化 phase-specific optimization:

import { run } from "./engine.js";

await run({
  problem: "Design a low-latency cache for a high-throughput service",
  // Generator: Anthropic Claude for creative architectural exploration
  model: "anthropic/claude-2",
  // Critic: Google Gemini for structured evaluation and clustering
  criticModel: "google/gemini-1.5-flash",
  framesPerRun: 5,
  ideasPerFrame: 6,
  topK: 3,
});

This configuration routes all divergence calls to Claude-2 while scoring and clustering execute on Gemini-1.5-flash—enabling you to pair models with complementary strengths.

CLI Support: Command-Line Model Overrides

The command-line interface in src/cli.ts (lines 64–66 and 41–44) exposes the same dual-model configuration:

Flag Scope
--model NAME Overrides default SDK model for both phases
--critic-model NAME Overrides model only for critic passes (score + cluster)

Example invocation with generator-critic model split:


# Generator on Claude, critic on Groq-hosted Llama 3

adhd "Refactor the authentication layer for zero-trust" \
  --model claude-2 \
  --critic-model llama3-8b \
  --frames 6 \
  --ideas 8 \
  --top 4 \
  --json > result.json

The divergence phase invokes claude-2 while scoring and clustering phases route to llama3-8b.

Design Rationale: Why Separate Generator and Critic Models

The architectural documentation in documentation/how-it-works.md and documentation/vs-cot-and-tot.md explains the motivations for mechanical separation:

  1. Error pattern decorrelation — Different models exhibit distinct failure modes; separating them prevents correlated hallucinations from compounding
  2. Critic-strangulation prevention — A dominant single model can prematurely converge; physical model separation enforces genuine multi-perspective evaluation
  3. Cost and latency optimization — Use expensive, capable models for generation and lighter, faster models for structured scoring

This design intentionally contrasts with Chain-of-Thought and Tree-of-Thought approaches where a single model context handles both generation and evaluation.

Supported Model Provider Patterns

The callLLM() abstraction (invoked identically for both phases) accepts any identifier your configured SDK recognizes. Common patterns include:

  • Same provider, different tiers: gpt-4 (generator) + gpt-3.5-turbo (critic)
  • Cross-provider specialization: anthropic/claude-3-opus (generator) + openai/gpt-4-turbo (critic)
  • Local + cloud hybrid: ollama/llama2-70b (generator) + groq/llama3-70b (critic)

The framework imposes no restrictions on provider mixing—only that both models are accessible through your runtime environment's LLM SDK configuration.

Summary

  • Yes, different LLMs work: ADHD's architecture mechanically separates generator and critic phases through independent model and criticModel parameters
  • Configure in code: Pass model and criticModel to run() in src/engine.ts
  • Configure via CLI: Use --model and --critic-model flags parsed in src/cli.ts
  • Mechanical guarantee: Phases invoke callLLM() separately with no shared state
  • Design benefit: Separating models decorrelates errors and prevents premature convergence

Frequently Asked Questions

What happens if I only specify model and omit criticModel?

The critic falls back to the generator model using nullish coalescing (criticModel ?? model at src/engine.ts:27). This ensures backward compatibility while preserving the option for separation.

Can I use the same model provider with different temperature settings for each phase?

Not directly through RunOptions. The current interface accepts model identifiers only. Temperature and other inference parameters are controlled at the SDK level. For phase-specific sampling, you would need to wrap callLLM() or use provider-specific model aliases with preset configurations.

Does using different models increase API costs?

Potentially, depending on your pricing structure. However, the framework enables cost reduction strategies: use an expensive, capable model for generation (where quality matters most) and a cheaper, faster model for scoring and clustering (which are more structured tasks). The documentation/vs-cot-and-tot.md analysis discusses this tradeoff explicitly.

Are there any constraints on which models work together?

No hard constraints exist in the codebase. The abstraction layer in callLLM() treats all model identifiers uniformly. Practical constraints depend on your SDK configuration: both models must be routable through your provider setup, and output formats must be parseable by the downstream scoreIdeas() and clusterIdeas() functions (which expect specific JSON schemas).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →