How to Use the `criticModel` Option for Separate Scoring and Clustering in ADHD
Set the criticModel option in your RunOptions to use a different LLM for the convergence phase (scoring and clustering) while keeping the divergence phase on the original model.
The ADHD framework separates creative idea generation from critical evaluation through a two-phase architecture. By default, both phases use the same language model, but the criticModel option allows you to offload scoring and clustering to a distinct model. This is particularly useful when you want to use a high-performance model for generation and a cost-effective model for evaluation.
Understanding ADHD’s Two-Phase Architecture
ADHD’s engine operates through two distinct stages:
- Divergence – Parallel generator calls produce raw ideas using the primary model.
- Convergence – A critic pass scores each idea and clusters them into logical groups.
By default, the critic uses the same LLM specified in the model parameter. However, sourcing a separate criticModel lets you optimize for cost or latency during the evaluation phase without sacrificing generation quality.
How criticModel Works in the Source Code
The separation of concerns is implemented in three core files:
Type Definition in src/types.ts
The RunOptions interface declares criticModel as an optional string that overrides the default model only for scoring and clustering:
export type RunOptions = {
// ...
model?: string; // generator + critic default
criticModel?: string; // overrides model **only** for scoring & clustering
// ...
};
Engine Implementation in src/engine.ts
The run function resolves the effective critic model using a nullish coalescing operator. If criticModel is provided, it takes precedence; otherwise, it falls back to the main model:
const critic = criticModel ?? model; // uses criticModel if provided
const [scoreMap, clusters] = await Promise.all([
scoreIdeas(problem, allIdeas, critic), // scoring uses critic
clusterIdeas(problem, allIdeas, critic), // clustering uses critic
]);
Both scoreIdeas and clusterIdeas receive the resolved critic variable and internally call the LLM via callLLM (defined in src/llm.ts). The generator calls in the divergence phase remain unaffected by this setting.
Code Examples
Default Behavior (Same Model for Both Phases)
When you omit criticModel, the engine uses the specified model for generation, scoring, and clustering:
import { run } from "./src/engine.js";
await run({
problem: "Add real-time collaborative editing to our note-taking app",
model: "claude-3-5-sonnet-20240620", // used for both phases
});
Using a Separate Critic Model
To use a cheaper or faster model for evaluation while keeping generation on a premium model:
import { run } from "./src/engine.js";
await run({
problem: "Add real-time collaborative editing to our note-taking app",
model: "claude-3-5-sonnet-20240620", // generator only
criticModel: "gpt-4o-mini", // scoring & clustering only
});
In this configuration, idea generation runs on Claude 3.5 Sonnet, while the convergence phase (scoring and clustering) executes on GPT-4o-mini.
Debugging with Event Logging
Verify that the correct model is being used by attaching an event listener:
import { run } from "./src/engine.js";
await run({
problem: "Add real-time collaborative editing to our note-taking app",
model: "claude-3-5-sonnet-20240620",
criticModel: "gpt-4o-mini",
onEvent: (e) => console.log("[ADHD]", e),
});
The onEvent callback emits progress events such as score:done and cluster:done, confirming that the critic pass used the overridden model.
When to Use a Separate Critic Model
Consider configuring criticModel in the following scenarios:
- Cost optimization – Use an expensive, high-capability model for generation and a cheaper model for evaluation.
- Latency reduction – Deploy a faster model for clustering large idea sets without regenerating content.
- Evaluation consistency – Standardize on a specific judge model across different generation experiments to ensure consistent scoring baselines.
Summary
- The
criticModeloption insrc/types.tsallows you to specify a distinct LLM for the convergence phase. - In
src/engine.ts, the engine resolves the critic model withcriticModel ?? modeland passes it toscoreIdeasandclusterIdeas. - The divergence phase (idea generation) always uses the primary
modelparameter, regardless ofcriticModelsettings. - Event logging via
onEventconfirms which model handles scoring and clustering operations.
Frequently Asked Questions
What happens if I don't specify a criticModel?
If criticModel is undefined, the engine defaults to using the value provided in the model parameter for both generation and evaluation. This ensures backward compatibility and consistent behavior when only one model is intended for the entire pipeline.
Can I use any LLM provider for the criticModel?
Yes, as long as the model string is supported by the underlying callLLM implementation in src/llm.ts. The ADHD framework uses the Claude Agent SDK internally, so any model identifier valid within that SDK (or your configured provider) works for the critic pass.
Does criticModel affect the idea generation phase?
No. The criticModel parameter only influences the convergence phase. The divergence phase—where parallel generator calls produce raw ideas—strictly uses the model parameter specified in RunOptions. This separation ensures that creative generation remains consistent while evaluation strategies can vary.
How can I verify which model is being used for scoring?
Attach an onEvent callback to your run invocation. The framework emits structured events including score:done and cluster:done. While these events don't explicitly name the model in the current implementation, you can inspect network calls or add custom logging inside src/llm.ts to confirm which model identifier is being passed to scoreIdeas and clusterIdeas.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →