Generative AI’s “agent” craze promised software that could reason and act autonomously, but early reality didn’t live up to the hype. Many teams found that beyond impressive demos, these AI agents often hit a wall around 70–80% reliability – prone to looping, making malformed tool calls, or losing track of state . Dex Horthy, an AI engineer and founder of HumanLayer, saw this first-hand after experimenting with just about every agent framework available – from plug-and-play libraries like LangChain to minimalist “smol” agents to more “production-grade” systems such as LangGraph and Griptape . The takeaway? Most “AI agents” that actually succeed in production aren’t magical autonomous beings at all – they’re mostly well-engineered traditional software, with LLM capabilities carefully sprinkled in at key points .
In early 2025, Horthy distilled these hard-earned lessons into a set of best practices he calls “12-Factor Agents,”unveiled during a talk at the AI Engineer World’s Fair and a now-popular GitHub repository . Modeled in the spirit of Heroku’s classic 12-Factor App methodology , this framework lays out twelve principles for designing LLM-powered software that’s robust, maintainable, and truly ready for production use. The approach struck a nerve in the developer community – the open-source guide quickly climbed to the front page of Hacker News, garnered thousands of GitHub stars, and sparked lively discussions among AI engineers about how to build “AI-native” applications the right way . In this article, we’ll explore what these 12 factors entail, how they translate into practical implementation patterns, and how this philosophy compares to other agent frameworks on the market.
Why LLM Agents Need New Ground Rules
Horthy’s 12-Factor Agents is fundamentally a response to the shortcomings of first-generation LLM agent implementations. Over the past two years, developers eagerly embraced libraries like LangChain or experimental projects like Auto-GPT to let large language models orchestrate tools and multi-step tasks. But in interviews with more than 100 startup founders and AI engineers, Horthy found a common story arc : teams would grab an agent framework to move fast, achieve maybe 70–80% of the desired functionality, then hit a performance ceiling. Beyond a certain point, the agent would start hallucinating steps, looping infinitely, or otherwise failing to meet the reliability bar needed for real users . Pushing past that 80% mark often meant digging into the framework’s guts – reverse-engineering prompts, tweaking hidden state handling, overriding default logic – essentially rebuilding the solution from scratch . As Horthy noted, many of the successful AI products he’s seen didn’t rely on off-the-shelf agent frameworks at all; instead, they cherry-picked a few modular techniques from the “agentic” approach and folded them into their own stack .
In spirit and name, 12-Factor Agents pays homage to the well-known 12-Factor App guidelines for cloud applications . Just as the original 12 factors (published by Heroku in 2011) provided a blueprint for building scalable, maintainable web services, Horthy’s version aims to bring proven software engineering discipline into the free-wheeling world of LLM-powered agents . Crucially, it’s not an out-of-the-box framework or SDK – it’s a language-agnostic manifesto of principles, meant to guide architects in any tech stack . “AI-native” systems, Horthy argues, shouldn’t throw out decades of wisdom about modularity, observability, and robustness. Instead, we should treat AI agents as another kind of software component and apply sound engineering practices to them. As one engineer put it, “Even if LLMs become 100× smarter, we’ll still need context compression, deterministic control, and schema validation to go to production.” In other words, no matter how powerful the model, reliable applications demand structure around it.
The 12 Factors for Building Reliable AI Agents
Much like the original 12-Factor App, Horthy’s 12-Factor Agent framework is organized as a dozen key principles. These cover everything from prompt design and tool use to state management and scaling. The ethos is to break the “big, monolithic AI” into well-defined pieces and give developers full control over each part of the agent’s operation . Below we outline each factor and what it means in practice for teams building LLM-driven applications. Following these guidelines can help turn an unreliable AI demo into a production-grade system that engineers (and CTOs) can actually trust.
Structure Prompts, Tools, and Context
-
Factor 1: Natural Language to Tool Calls. Don’t let the model’s outputs be a free-form wildcard. The agent should convert user requests in natural language into structured, schema-valid commands for tools or functions . In practice, this means defining a clear interface (often a JSON schema or function signature) that the LLM must use when it wants to take an action. By forcing the model to produce a well-formed “tool call” (rather than arbitrary text), you prevent cascading errors and ensure the next step can be executed deterministically . For example, instead of returning “I’ll search for that” as plain text, an agent could output a JSON object like {"action": "WebSearch", "query": "latest sales figures"} which your code will parse and run. This pattern — akin to OpenAI’s function-calling API or JSON-based outputs — makes agent behavior far more predictable and debuggable.
-
Factor 2: Own Your Prompts. Treat prompts as first-class code, not one-off strings buried in a framework. Horthy advocates keeping full ownership over every prompt that goes into your model . In practice, teams should version-control their prompts and prompt templates, expose them for easy editing, and avoid opaque “prompt engineering” libraries that hide prompt details. By “owning” the prompt, you can fine-tune instructions, add guardrails, and adjust formatting as your understanding evolves . This factor is a reaction against heavy abstraction: rather than trusting an external library’s magic prompt, you write and maintain the exact instructions the LLM sees. The benefit is granular debugging and optimization – if the agent gives a bad answer, you can dive into the prompt and adjust it like you would a piece of code.
-
Factor 3: Own Your Context Window. In LLM applications, context is the new “memory”, and managing it well is critical. This principle (what some are calling “context engineering”) means explicitly controlling what information goes into the model’s context window at each step . Instead of dumping entire transcripts or databases into the prompt and hoping the model copes, developers should design strategic context: summarize or compress long histories, use structured formats for interim data, and include only what’s relevant for the task. By treating context as a limited cache, teams have squeezed out 30–60% token savings and improved model accuracy . In practice, this could involve maintaining a rolling summary of a conversation, encoding state in a compact form (like key-value pairs or domain-specific notation), or retrieving just-in-time facts from a knowledge base. The key is to deliberately curate the model’s “world view” each turn, rather than letting it accumulate noise or stale info.
-
Factor 4: Tools Are Just Structured Outputs. When an LLM “calls” a tool, under the hood it’s really generating a snippet of text instructing some action. Horthy’s guidance is to formalize this: define tools as structured output schemas and validate them strictly . For instance, if your agent can hit an API or run a SQL query, describe the exact JSON format or code syntax it should produce for that action. By treating tool use as structured output generation, you can catch malformed requests (e.g. an invalid JSON or a nonsense SQL) before they cause havoc . This factor overlaps with Factor 1, reinforcing the idea that every LLM output which drives execution should adhere to a spec. Many teams use JSON schemas or function definitions and have the model fill in the parameters – an approach that not only yields more reliable agent behavior but also makes it easier to evolve those tool APIs over time without the model getting confused.
Manage State and Control Flow
-
Factor 5: Unify Execution State and Business State. In traditional software, application state (user data, DB records) and workflow state (where in a process you are) often live separately. For AI agents, Horthy suggests unifying them: store all agent interactions as part of your core application state, typically as an event log . Every input, output, and intermediate step the agent takes can be recorded in an append-only event stream tied to a relevant business entity (like a support ticket, an order ID, etc.). This way, the agent’s “memory” isn’t just in the LLM’s head or in a temp variable – it’s in your database. The benefit is twofold : you can replay and inspect past agent sessions for debugging or compliance (since every decision is logged), and you can recover from crashes by reloading the last known state from the log. This event-sourcing pattern also enables horizontal scaling – another server can pick up where one left off by reading the state log – making the agent effectively stateless between steps (see Factor 12).
-
Factor 6: Launch, Pause, and Resume with Simple APIs. Real-world processes often aren’t a single continuous loop – they may need to wait for external events or human input. A production-grade agent should therefore provide controls to start, pause, and resume its workflow programmatically . Horthy advises designing your agent logic such that it can be stopped and safely resumed at well-defined checkpoints. For example, if an agent has to handle a long-running task or wait for a human approval (Factor 7), it should be able to save its state (per Factor 5) and exit, and later continue from that state. Implementing this might involve exposing an API or function calls for pausing and resuming, and storing a resume token or state snapshot. The practical payoff is significant : you can integrate human-in-the-loop review, orchestrate the agent asynchronously (e.g. via a job queue or scheduler), and prevent losing work if something crashes mid-stream. Essentially, treat the agent like a process you can control – because in production, you will need that control.
-
Factor 7: Contact Humans via Tool Calls. Even the best AI agents will encounter situations where they should defer to a person – whether it’s an ambiguous decision or a safety-sensitive action. Rather than handling that outside the agent, 12-Factor Agents suggests making “ask a human” a first-class action for the AI . In practice, you can implement a special tool or output schema that represents escalating to a human. For example, the agent could emit {"action": "HumanApproval", "details": "..."}, which your system recognizes as a cue to involve a human (sending a notification or creating a review task). By structuring human hand-offs this way, they become part of the agent’s event stream and can be tracked and audited just like any other tool use . This factor ensures that when an agent reaches its knowledge or confidence limit, it doesn’t silently fail or do something reckless – it explicitly flags for human help. It’s an important pattern for human-AI collaboration, allowing the overall workflow to continue reliably with human guidance where needed.
-
Factor 8: Own Your Control Flow. Many agent frameworks run a closed-loop where the LLM decides when to stop or repeat. Horthy’s advice: don’t treat the agent’s internal loop as a black box – instrument it and guard it . Concretely, developers should implement the agent’s control flow in code, with clear conditions for looping, retrying, or halting, rather than relying on the model to self-regulate. For example, you might set a max number of iterations, or use a heuristic to detect when the agent is “not converging” on a solution (perhaps tracking if it repeats itself or scoring diminishing returns) . Owning the loop means you can prevent runaway behavior (infinite loops) and insert logging or metrics at each cycle . It also allows custom retry logic – e.g. if the model produces an invalid tool call, you can catch it (Factor 4) and decide whether to give the model another chance or fallback to a default. Essentially, Factor 8 is about not surrendering all flow control to the AI. You design the outer OODA loop(observe–orient–decide–act) and keep a kill-switch in hand, much like any robust distributed system would .
Keep Agents Small and Stateless
-
Factor 9: Compact Errors into Context. When an agent step fails – say a tool returns an error or the model’s answer is wrong – the naive approach is to either let it keep going blindly or to abort. This principle recommends a smarter middle ground: summarize errors and feed them back into the model’s context for the next step . In other words, allow the agent to “learn” from its mistakes on the fly. For example, if an API call returns a 400 error, the agent’s next prompt might include a concise note like “Previous step failed because the query was malformed.” This gives the model a chance to adjust its plan or ask for clarification, rather than either repeating the same invalid call or quitting without insight. By compactly encoding failures into the context window, you encourage the model to avoid redundant attempts and possibly self-correct . It’s akin to how a human programmer would read an error message and do something different next run. This factor ties back to robust error handling: instead of infinite retries or fatal stops, turn errors into informative context and let the AI try again with that knowledge (all while logging these events per Factor 5 for later analysis).
-
Factor 10: Small, Focused Agents. Perhaps the most fundamental shift in mindset is to compose your solution from multiple narrow agents rather than one generalist agent . Horthy and others observed that a “single big agent” trying to handle a complex workflow end-to-end tends to be brittle . Instead, you get better results by breaking the problem into smaller subtasks and giving each its own mini-agent or LLM call specialized for that task. For example, instead of one AI agent that reads an email, queries a database, and drafts a reply, you might have one component that purely extracts key facts from the email, another that formulates the database query, and a third that generates the reply using those results. Each piece is simpler and easier to optimize. In practice, implementing Factor 10 could mean orchestrating multiple LLM calls or agent instances via a higher-level script or workflow engine (not unlike microservices in traditional architecture). The benefits reported are higher reliability (specific agents can hit 90%+ success on their focused task, versus a monolithic agent failing 20%+ of the time) , easier debugging when something goes wrong, and even performance gains under load (smaller context per agent = faster inference). Community anecdotes back this up: one CTO noted that when they broke a complex process into clear, deterministic workflows with LLM “assistants” at certain nodes, they achieved human-level results that “big fat agents” couldn’t match .
Splitting a complex job into multiple specialized micro-agents can yield more reliable results than a single sprawling agent. Each small agent handles a focused task (e.g. summarization, classification, calculation) as part of a larger pipeline, which makes the overall system easier to debug and scale . In this example diagram, an initial event triggers a sequence of purpose-specific LLM agents rather than one monolithic agent trying to do everything.
-
Factor 11: Trigger from Anywhere, Meet Users Anywhere. Traditional agents are often built as chatbots or single-interface apps. Factor 11 encourages developers to decouple agent logic from any single interface and allow it to be invoked from any context . In practice, this means your agent’s core functionality should be accessible via an API, so it can be triggered by a web UI, a mobile app, a scheduled job, an incoming webhook, or any other source of events. Likewise, it should be able to respond or take action across multiple channels – not just sending a chat reply, but maybe updating a database, sending an email, or posting to Slack as needed. The idea is to “meet users where they are.” If your customers interact via text, voice, email, etc., your agent should plug into those modalities without requiring a completely separate AI for each. Implementing this might involve an event-driven architecture or a middleware layer that funnels different input sources into the agent and then routes its outputs appropriately. By designing agents to be trigger-agnostic, you create omnichannel AI services and a unified user experience across platforms . This factor is also about flexibility: the agent becomes a reusable component that can be inserted wherever automation or intelligence is needed, rather than a one-off bot living only on your website.
-
Factor 12: Make Your Agent a Stateless Reducer. The final principle echoes a concept from functional programming: treat the agent like a pure function (reducer) that takes in an input state + event and emits an output state, without carrying hidden state in between . In practical terms, design your agent so that each turn it only acts on the explicit context it’s given (Factor 3) and produces an explicit result, which then can be stored or passed along. Any memory the agent needs from prior steps should come through the provided context (e.g. from the event log per Factor 5). By avoiding reliance on internal, implicit state, you achieve statelessness – meaning you could spin up multiple instances of the agent behind a load balancer, or recover from a crash by reloading context, without inconsistency. This makes scaling out much easier and testing more straightforward (you can feed a given context into the agent and expect a deterministic result, all else equal). Essentially, Factor 12 ties together several earlier ones (context, logging, small units) into a philosophy that an LLM agent should behave like a pure function from input to output. That may not be 100% achievable (LLMs do have hidden weights and randomness), but treating the system this way is a guiding ideal to minimize bugs and surprises . It’s no coincidence that this mirrors the stateless, horizontally scalable nature of 12-Factor App services.
Reactions and Alternatives in the Agent Ecosystem
Horthy’s 12-Factor Agents hit a sweet spot of timing and insight. The repository’s launch rapidly drew attention, accumulating over 10,000 GitHub stars and counting . On Hacker News, the concept spurred extensive discussion from AI developers – many nodding along with their own war stories. “I had my own list of takeaways after doing this for a couple years,” one commenter wrote, agreeing that owning the low-level planning loop and using heuristics to detect when an agent is stuck are crucial . Another reader quipped that “reliable LLM applications” sounds like an oxymoron on its face, akin to “jumbo shrimp”, reflecting healthy skepticism in the community . But others responded that reliability is possible “once you pin [the LLM] down the right way and lower your expectations” – likening an LLM to a “misbehaving database” that needs the proper constraints (schemas, validations, etc.) instead of being allowed to “go YOLO with regex-like intelligence” . In essence, the crowd acknowledged that you can build robust AI agents, but not by treating the model as an infallible oracle. It requires guardrails and good old-fashioned engineering.
Notably, even authors of popular frameworks have taken these lessons to heart. The LangChain team, for instance, highlighted 12-Factor Agents as recommended reading, noting that many of Horthy’s points boil down to better “context engineering” and developer control . In a blog post, they introduced LangGraph, a new module aiming to make LangChain’s agents more transparent and controllable – explicitly allowing developers to decide each step, each piece of context, and each tool invocation rather than leaving it to hidden abstraction . This shift aligns with Factors like #2 (own your prompts) and #8 (own your loop), suggesting a convergence toward more flexible, framework-agnostic approaches.
Meanwhile, alternative agent frameworks continue to emerge. Projects like smol-ai (inspired by the “minimal AGI” ethos) tried to strip agents down to bare essentials, while others like Griptape or Dust marketed themselves as “production-ready” agent orchestration tools. Yet Horthy’s experience was that few of these were actually in use at scale . Many companies quietly built custom tooling, guided by similar principles, rather than trust a one-size-fits-all library. The hype around fully autonomous agents (exemplified by last year’s Auto-GPT craze) has given way to a more pragmatic outlook: letting an LLM run wild with a bag of tools rarely ends well in production . Instead, the industry momentum is toward “AI copilots” and modular AI services that do specific tasks under tight supervision. 12-Factor Agents crystallized that mindset and gave it a name.
It’s worth noting that 12-Factor Agents itself isn’t static doctrine. The open-source guide on GitHub continues to evolve (a version 1.1 is in the works with community contributions ), and developers are adding their own refinements. Some have suggested extra “factors” like defining an agent’s identity and roles more explicitly, or distinguishing deterministic vs. probabilistic capabilities in an agent’s design . Others debate how far to go in chasing reliability – will future AI models be so much better that some of these precautions become unnecessary? Or will new abstraction layers emerge that encapsulate these patterns in easier-to-use ways (much as high-level programming languages encapsulate machine code) ? For now, Horthy and like-minded engineers argue that we’re still in the early innings of figuring out “AI-native” software architecture. Building a great LLM application in 2025 often means pushing the model to its limits and wrapping it in as much protective scaffolding as needed to get consistent results . In Horthy’s words, “the only way to build really impressive experiences in AI is to find something right at the edge of the model’s capability, and to get it right consistently” – which inevitably demands careful engineering.
Conclusion
For software engineers and CTOs eyeing the promises of AI, the emergence of 12-Factor Agents is a timely reality check. It suggests that developing reliable LLM-driven applications is less about secret prompt sauce or all-in-one frameworks, and more about applying solid architecture principles to these alien new components. The excitement of an AI agent that “figures it out on the fly” must be balanced with the sobering truth that, underneath, it’s still software – and software needs structure. Horthy’s framework essentially bridges modern AI and classical software engineering, urging teams to treat their AI agents like any other critical service: isolate its responsibilities, give it clear interfaces, manage its state transitions, monitor its behavior, and plan for the unexpected.
Whether or not the “12-Factors” become as iconic as their Heroku inspiration, they have already begun influencing how practitioners talk about AI systems. We’re seeing a movement from the ad-hoc agent scripts of last year toward robust AI architectures that borrow concepts from microservices, functional programming, and DevOps. In time, higher-level libraries will likely incorporate these ideas – or new development patterns (even programming languages) will emerge specifically for AI orchestration. Until then, the 12-Factor Agents guide offers a blueprint that engineers can apply today, with whatever tools they choose. The message is clear: LLMs bring the brains, but it’s up to us to provide the scaffolding. As the community mantra goes, “LLMs provide intelligence. The 12 Factors provide reliability.”
Unlock the Future of Business with AI
Dive into our immersive workshops and equip your team with the tools and knowledge to lead in the AI era.