Building Agentic Systems

By Alexander Lontke

Building Agentic Systems

In this post, we explore the concept of agentic systems. We cover the foundations first, including the role of Large Language Models (LLMs), the importance of context, and design principles that help us build effective systems. Then we move into practical considerations, such as how to design an agent's environment and tools, and how to keep the system robust and scalable.

Introduction

Agentic systems are the natural evolution of Large Language Model (LLM)-based applications that had strong generative capabilities but limited autonomy and little ability to interact with the world in meaningful ways (beyond summarization or content generation). An agent is a system that can perceive its environment, make decisions, and take actions to achieve specific goals. Agentic systems often consist of multiple agents, and those agents can interact with each other to solve complex tasks. This is particularly beneficial for tasks that are ambiguous. For example, in insurance claims processing, each case is unique and may require different actions to be taken. While traditional and LLM-based workflows often struggle with this kind of variability due to their predefined nature, an agentic system can adapt to the specific needs of each case and handle the process accordingly.

Foundations of Agentic Systems

In this section, we focus on the basic building blocks of agentic systems. In broad terms, agentic systems consist of three main components: the agent itself, its environment, and the actions it can take. These map directly to what we cover here: the LLM that enables reasoning, the context in which the agent operates, and the tools the agent can use to perform actions.

Large Language Models (LLMs)

Large Language Models (LLMs) are a type of artificial intelligence model that has been trained on vast amounts of text data to generate human-like language. They do this by predicting the next token in a sequence, given previous tokens (context). One token represents a part of a word or a whole word, depending on the tokenization method used. By using an LLM, we can mirror a human-like stream of consciousness, where the model reasons about a problem, generates potential solutions, and then takes actions based on that reasoning. All of this is done simply by generating text or special tokens that represent actions.

Models have a limited number of tokens they can use as context when generating the next token. This limitation is tied to hardware constraints, because model weights and attention state must fit in memory. As a result, the context window is finite, and the model can only consider a bounded amount of information at once.

Context

Context is the term used to describe the tokens that are already present in the model's context window. The context therefore influences the probability distribution of the next token the model will generate. In the case of an agentic system, the context includes prior user interactions, actions performed, and reasoning steps taken by the agent. That means all of this information affects what comes next, whether that is another reasoning step or an action.

Due to the limited context window, it is important to design the context in a way that provides the model with the most relevant information. Otherwise, context pollution is easy to introduce, which leads to weaker instruction following and lower overall system performance.

Tools

Tools are the mechanism that allows an agent to move from reasoning to execution. Without tools, an agent can only generate text; with tools, it can query systems, update state, and trigger real-world outcomes.

In practice, tools are often exposed as structured interfaces, such as function calls or API operations with clear inputs and outputs. The clearer this contract is, the easier it is for the agent to choose the right action at the right time. This is why tool design quality is directly tied to agent performance.

At a minimum, good tools should be discoverable, predictable, and safe:

  • Discoverable: names and descriptions should make intent obvious.
  • Predictable: inputs and outputs should follow consistent schemas and naming.
  • Safe: tools should include clear validation and meaningful error messages for recovery.

When these properties are in place, the agent spends less effort interpreting the interface and more effort solving the user problem.

Design Principles

Now that we have covered the basics, I want to share some design principles that I have found to be helpful when building agentic systems.

Trust in Agent Autonomy

When we are designing an agentic system, it is vital to keep the constant improvement of LLMs in mind. Additionally, it is important to trust the agent's ability to perform a task (given the right context and tools). Otherwise the entire exercise of building the system becomes futile.

Due to these two factors, it is important to design the system in a way that allows the agent to perform actions autonomously, without patching over issues through excessive retries or output coercion. In many cases, this does more harm than good, because it hides the real root cause instead of allowing it to surface and be fixed.

Tell the Agent what goal to achieve (not what not to do)

This is somewhat in line with the previous point about trusting in agent autonomy. When designing the system, it is important to tell the agent what to do, rather than what not to do. This is in part due to models improving over time, which means they'll get better at handling edge cases. However, it is primarily about allowing the agent to capitalize on its improved capabilities. If you tell it all the things it should not do, you may accidentally prevent it from performing a correct action that you were not able to foresee.

The same applies to telling the agent too narrowly what steps it should follow. This may then work well for workflows that are very standardized, but that is the exact opposite of the type of workflow that benefits from an agentic system. Instead, give the agent a clear goal and an environment that enables success, while preserving the freedom to determine how to achieve the outcome.

Design Interfaces with Intent (Affordances)

To that exact point, about needing to give the agent an environment that enables it to achieve its goal, it becomes imperative to design all interfaces between the agent and its environment to be as clear and unambiguous as possible.

Take for example the tools list_items and add_item in a to-do list application. The naming of these tools already implies what they should be used for. However, if the agent is now given the task "add an item to the to-do list and add an item to the shopping cart" the naming becomes ambiguous. That is why clear naming (an important software design practice in general) becomes even more important in agentic systems. Additionally, consistency in naming is also crucial. If list_items returns [{id: 1, name: "item1"}, {id: 2, name: "item2"}] and add_item returns {item_id: 3, name: "item3"}, the agent will probably infer that item_id and id are the same thing, but this is avoidable complexity.

Furthermore, docstrings have gained new value as they are now a vital part of how the agent discovers its environment and how it can interact with it. Good examples of clean docstrings can be found in the pandas documentation, which is concise and practical while still covering functions, parameters, and return values.

Lastly, the concept of affordances becomes increasingly important when designing interfaces for agentic systems.

Affordance: a use or purpose that a thing can have, that people notice as part of the way they see or experience it

Give a child a cube and a cube shaped hole, and the child will quickly figure out that the cube can be put into the hole. The same applies to interfaces in agentic systems. If an interface has a clear affordance, the agent is more likely to understand how to interact with it and use it effectively.

Minimal output from tools

While the last point was about designing the input interface from the agent to its environment, the opposite direction is just as important. As we remember, the context window is what informs the model's next token generation, but is also limited in size. Therefore it is crucial to be minimalistic in the output that the tools return to the agent, to avoid context pollution. To prevent this, we can use established principles such as pagination, which allows the agent to work through tasks iteratively.

At the same time, outputs should be informative and discovery-oriented, providing enough signal for the agent to understand the environment state and make informed next decisions. For example, if there is an error in the input provided by the agent, the tool should return an error message that clearly states what the issue is and how it can be resolved, rather than just returning a generic error code.

Ensure Observability of Actions and Reasoning

As you can tell from the previous points, agentic systems can be sensitive to nuances in their design. To be able to capture these nuances and to be able to iterate on the design of the system, it is crucial to ensure that all actions taken by the agent and all reasoning steps are observable.

Observability is therefore an important topic. Tools such as Langfuse or Arize Phoenix can help by capturing interactions between the agent and its environment, including reasoning traces and tool actions. This still requires instrumentation in your own application code, for example to capture tool outputs in a structured, queryable way.

Conclusion

Building effective agentic systems is less about adding complexity and more about designing for clarity. If you provide a capable model with the right context, explicit goals, reliable interfaces, and concise tool feedback, it can adapt far better than rigid workflows in uncertain environments.

The most practical way to improve an agentic system is iterative: observe what the agent did, identify where the environment or interfaces created friction, and then refine those design surfaces. Over time, this creates a compounding effect: better interfaces lead to better actions, better actions create cleaner context, and cleaner context leads to better decisions.

In short, strong agentic systems come from strong system design. Trust autonomy, design affordances deliberately, keep context high-signal, and invest in observability from day one.