# How DeepSeek-Reasonix Two-Model Collaboration Works: Planner and Executor Architecture

> Discover how DeepSeek-Reasonix two-model collaboration optimizes costs and cache with its Planner and Executor architecture. Learn how agents coordinate for efficient AI.

- Repository: [YHH/DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix)
- Tags: architecture
- Published: 2026-06-23

---

**DeepSeek-Reasonix runs two isolated language-model agents—a read-only Planner and a full-capability Executor—coordinated by the `Coordinator` type to optimize costs while preserving cache efficiency.**

DeepSeek-Reasonix supports an advanced **two-model collaboration feature** that enables running separate planner and executor models within a single conversation. This architecture, implemented in the [`internal/agent/coordinator.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/agent/coordinator.go) file, allows developers to use a lightweight model for planning and a powerful model for execution, reducing API costs while maintaining stable model-prefix caches.

## Architecture Overview

The collaboration centers on two distinct agents orchestrated by the **`Coordinator`** type. When the configuration key `agent.planner_model` names a different provider than the executor, the CLI creates a `Coordinator` that wires a dedicated planner provider to an executor `Agent`.

The **Planner model** operates as a low-frequency, read-only agent that produces concise, ordered plans without mutating the workspace. It can browse documentation and inspect files but cannot execute tools that write or run shell commands.

The **Executor model** is a full-capability agent that performs actual work using all registered tools. It runs in an isolated session separate from the planner, ensuring that heavy-weight operations do not contaminate the planning context.

## Session Isolation and Cache Optimization

Session isolation is fundamental to the design. The planner runs in its own **`plannerSess`** while the executor maintains a separate `Session`. Both sessions are **prepend-only**, meaning the model-prefix cache remains stable throughout the conversation.

This isolation prevents the "cache-reset" that would occur if a single session switched models mid-conversation. By keeping each model’s system prompt and history in dedicated sessions, DeepSeek-Reasonix reconciles its cache-first philosophy with the need for distinct model capabilities, as specified in [§3.5 of SPEC.md](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/docs/SPEC.md#35-two-model-collaboration-coordinator).

## The Collaboration Workflow

The `Coordinator.Run` method manages the hand-off between models through a structured sequence of checks and transformations.

### Planning Phase

When `Coordinator.Run` receives input, it first evaluates `shouldPlan`. If planning is required, the coordinator emits a planning phase event and invokes `plan(ctx, input)`. This streams the planner’s response, appends the raw plan text to `plannerSess`, and returns the plan string for the next stage.

The planner sees only read-only tools during this phase, guaranteeing safety while it analyzes the workspace and formulates the execution strategy.

### No-Op Detection

After receiving the plan, `isNoOpPlan` examines the text for phrases like "no changes needed". If the planner determines the task is already satisfied, `persistExecutorNoOp` records the plan in the executor’s session and skips the execution phase entirely.

This saves a provider call and associated costs when no actual work is required.

### Hand-Off to Executor

If the plan is not a no-op, `Coordinator.Run` calls `formatHandoff` to create a self-contained instruction set embedding the original task, the planner’s output, and any executor-tool context. This formatted string is fed to `executor.Run`, which treats the planner’s output as context rather than as its own role description.

The executor then runs exactly like a normal `Agent`, invoking tools, editing files, and executing commands while its session grows independently, preserving its own cache prefix.

## Configuration and Code Implementation

The following Go example demonstrates how to instantiate the two-model collaboration programmatically:

```go
// Create a planner provider (e.g. a cheap model) and an executor provider (full model)
plannerProv := provider.NewOpenAI("deepseek-planner", cfg.PlannerAPIKey)
executorProv := provider.NewOpenAI("deepseek-executor", cfg.ExecutorAPIKey)

// Planner session is isolated from the executor’s session
plannerSess := internal.Agent.NewSession("planner")
executor := internal.Agent.New(executorProv, tool.NewRegistry(), nil, internal.Agent.Options{}, nil)

// Wire them together via Coordinator
coord := internal.Agent.NewCoordinator(
    plannerProv,               // planner provider
    plannerSess,               // planner session
    nil,                      // pricing (optional)
    nil,                      // planner tools (read-only only)
    internal.Agent.Options{}, // planner options
    executor,                  // executor agent
    0.0,                       // temperature
    event.Discard,             // event sink
    nil,                       // shouldPlan (nil = always plan)
)

// Run a task – the coordinator will first ask the planner, then hand off to the executor
ctx := context.Background()
if err := coord.Run(ctx, "Refactor the `utils` package to use Go 2 generics"); err != nil {
    log.Fatalf("run failed: %v", err)
}

```

When the user toggles plan-only mode via the UI, `Coordinator.SetPlanMode` propagates the flag to both the planner agent and the executor, ensuring consistent permission handling across both models.

## Key Source Files

- **[`internal/agent/coordinator.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/agent/coordinator.go)** – Core implementation of the two-model `Coordinator` (session handling, planning, hand-off, and no-op detection).
- **[`docs/SPEC.md`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/docs/SPEC.md)** – Architectural specification describing the two-model collaboration intent and cache-first design principles.
- **[`docs/GUIDE.md`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/docs/GUIDE.md)** – User-facing documentation explaining how to enable the feature from the CLI or UI.
- **[`internal/agent/agent.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/agent/agent.go)** – The standard single-model `Agent` implementation used as the executor side of the collaboration.
- **[`internal/control/controller_test.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/control/controller_test.go)** – Unit tests exercising `Coordinator` logic including planner-executor hand-off and no-op handling.

## Summary

- **Two-model collaboration** in DeepSeek-Reasonix uses a `Coordinator` to manage a read-only Planner and a full-capability Executor.
- **Session isolation** via prepend-only sessions keeps each model’s cache prefix stable, avoiding expensive cache resets.
- **No-op detection** through `isNoOpPlan` and `persistExecutorNoOp` eliminates unnecessary executor calls when the planner determines no changes are needed.
- **Safe hand-off** via `formatHandoff` ensures the executor receives clean, self-contained instructions without role confusion.
- **Plan mode propagation** via `SetPlanMode` keeps permission states synchronized across both models.

## Frequently Asked Questions

### What is the purpose of separating planner and executor models?

Separating the models allows you to use a cheaper, lightweight model for planning while reserving expensive, powerful models for actual execution. This reduces API costs and latency while ensuring that complex reasoning about strategy (planning) remains distinct from the heavy lifting of implementation (execution).

### How does the Coordinator handle cache efficiency?

The `Coordinator` maintains separate `Session` instances for the planner and executor, both configured as prepend-only. This prevents the cache invalidation that would occur if a single session alternated between models, ensuring that each model’s system prompt and conversation history remain stable in the provider’s kv-cache.

### What happens when the planner determines no action is needed?

When the planner output contains phrases like "no changes needed", the `isNoOpPlan` function returns true, triggering `persistExecutorNoOp`. This records the plan in the executor’s session for context but skips the execution phase entirely, saving a provider call and associated costs.

### Can I use the same model for both planner and executor?

While technically possible by configuring identical providers, doing so defeats the architectural purpose of the feature. The design assumes distinct capabilities and costs; using the same model would not provide the cost optimization or safety isolation benefits, though the `Coordinator` would still function as a pass-through layer.