DEV Community

Cover image for Architecting Resilient LLM Agents with System 1 and System 2 Thinking
Ameer Hamza
Ameer Hamza

Posted on

Architecting Resilient LLM Agents with System 1 and System 2 Thinking

Introduction: The "Vibe Coding" Trap

We've all been there: you build a "smart" agent that handles 80% of tasks beautifully, only to watch it hallucinate wildly when faced with a slightly ambiguous edge case. The industry is currently obsessed with "vibe coding"—relying on the raw, intuitive output of LLMs without structural guardrails. This approach fails because it treats a probabilistic engine as a deterministic logic processor.

To build production-ready agents, we must move beyond simple prompt-response loops and adopt a dual-process architecture inspired by Daniel Kahneman’s System 1 and System 2 thinking.

Architecture and Context: Dual-Process Engineering

In human cognition, System 1 is fast, instinctive, and emotional. System 2 is slower, more deliberative, and logical.

In software engineering, we can replicate this:

  • System 1 (The LLM): Handles natural language understanding, creative generation, and pattern matching.
  • System 2 (The Orchestrator): Handles validation, state management, tool execution, and "sanity checks" using deterministic code.

The Hybrid Loop

Instead of a single prompt, the architecture follows a Plan-Execute-Verify cycle:

  1. System 1 proposes a plan.
  2. System 2 parses the plan against a schema.
  3. System 2 executes tools in a sandboxed environment.
  4. System 1 reviews the output for "logical drift."

Deep-Dive Guide: Implementing the "Verification Gate"

The most complex part of this implementation is the Verification Gate. This is a System 2 component that prevents the agent from proceeding if the LLM's output doesn't meet specific technical criteria.

Production-Ready Implementation (TypeScript)

interface AgentAction {
  tool: string;
  params: Record<string, any>;
  reasoning: string;
}

async function system2VerificationGate(
  rawOutput: string,
  allowedTools: string[]
): Promise<AgentAction> {
  try {
    // 1. Strict Schema Validation
    const action: AgentAction = JSON.parse(rawOutput);

    // 2. Security Check: Tool Whitelisting
    if (!allowedTools.includes(action.tool)) {
      throw new Error(`Security Violation: Unauthorized tool '${action.tool}'`);
    }

    // 3. Logic Check: Parameter Integrity
    if (action.tool === 'database_query' && !action.params.query.includes('LIMIT')) {
      console.warn("Performance Risk: Query missing LIMIT. Injecting safe constraint...");
      action.params.query += " LIMIT 100";
    }

    return action;
  } catch (e) {
    // Fallback: System 2 forces a retry or halts execution
    throw new Error(`System 2 Rejected Output: ${e.message}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

Common Pitfalls & Edge Cases

  • Token Exhaustion: System 2 must monitor the "reasoning" length. If the LLM enters a loop, System 2 should terminate the session.
  • State Drift: In long-running agents, the "context window" becomes a liability. Use a Vector Database to store only relevant historical facts, rather than the entire chat history.

Conclusion

Building resilient AI isn't about finding a "better prompt." It's about building a robust System 2 framework that treats the LLM as a powerful but fallible component. By enforcing deterministic gates around probabilistic outputs, we can finally move AI agents from "cool demos" to "mission-critical infrastructure."


About the Author: Ameer Hamza is a Software Engineer. He specializes in modern web frameworks and AI integrations. Check out his portfolio at ameer.pk to see his latest work, follow ameer hamza, or reach out for your next development project.

Top comments (0)