Anatomy of an agent
Create a more complex agent with dynamic prompts, tools, structured data, and dependency injection.
Last updated
Create a more complex agent with dynamic prompts, tools, structured data, and dependency injection.
Last updated
Our goal for this agent is to demonstrate how to automate customer support for a bank (albeit within a limited context). The agent interacts with customers, analyzes their queries, and generates meaningful responses. It showcases how an agent can integrate with a database to retrieve customer-specific information, such as their name and account balance. It also demonstrates how an agent can return a structured response.
The first step is to define the agent. In AXAR, an agent is a subclass of Axar's built-in Agent
class.
When defining an agent, we need to specify:
The LLM the agent should use: This is done using the @model
decorator.
A high-level prompt or instruction for the agent: This is specified using the class-level @systemPrompt
decorator.
Its input and output format: These are defined using the @input
and @output
annotations (along with generics provided in the class declaration).
We also want to provide the agent with access to the customerId
and a database connection. This is achieved using simple dependency injection through the agent's constructor.
With that our SupportAgent
now look like this:
If an agent only works with plain strings as input or output, we don’t need to use the @input
or @output
annotations respectively. For example, in the code above, there is no @input
annotation because the input is a simple string.
Now that the agent has access to the customerId
and the database, we want it to dynamically insert customer-specific context at runtime. To achieve this, we use the @systemPrompt
decorator with an instance method inside the agent class.
The purpose of this method is to retrieve the customer's name from the database and include it as part of the agent's context. This way, whenever the agent processes a customer query, it already has the relevant context available.
Here’s how it looks:
As you may have noticed, we have yet to define the agent's response schemaSupportResponse
. For this support agent, we want the response to include:
A support advice: A string containing human-readable advice for the customer.
Risk level: A number between 0 and 1 representing the risk level of the customer query.
Card blocking: A boolean indicating whether blocking the customer’s card is necessary.
Customer’s emotional state: An optional field using an enum (Happy
, Sad
, or Neutral
) to represent the customer’s emotional state.
Since this schema is for an LLM, we want to provide not just the structure of the response but also additional metadata such as descriptions and validation rules. In AXAR, we use annotations to define schemas with this metadata.
Here’s how we define the SupportResponse
schema:
What if an agent needs to perform an action or gather additional data based on a request? This is where tools become valuable. Tools allow an agent to access specific functionality, which they can invoke only when needed. In AXAR, tools are defined as instance methods and annotated with @tool
.
For this agent, we define a tool that takes a parameter of type ToolParams
(containing the customer's name and whether to include pending transactions) and returns the customer's bank balance.
Here’s how it looks:
This guide covered how to build a functional, context-aware agent using AXAR AI. With dynamic prompts, schema definitions, and tools, you can create agents tailored to specific tasks and workflows. From here, you can explore more advanced use cases or refine the approach as needed for your applications.
The full example code is available in the directory on our GitHub.