Insights
Building Autonomous Agents: Advanced Tools and Architectures
Published by Oxydata Software | AI & Agentic Systems
In the realm of artificial intelligence, few concepts capture the imagination like the notion of an autonomous agent. The idea of a software system that can perceive, reason, act, and learn on its own has long been a staple of science fiction. But today, thanks to advances in natural language processing, knowledge representation, and machine learning, the dream of building truly agentic AI is becoming a reality.
However, the path from scripted chatbots to autonomous problem-solvers is not a simple one. It requires a fundamentally different approach to architecture and a suite of advanced tools and technologies. At Oxydata, we have been at the forefront of this transition, building real-world agentic AI systems like IRIS and Oxa for Malaysian enterprises. In this blog post, we share some of the key lessons we have learned along the way, and provide a practical guide to the tools and architectures needed to build autonomous agents.
The Agentic AI Technology Stack
1. Vectorized Knowledge Bases
The foundation of any agentic AI system is its knowledge base — the corpus of information it draws upon to understand the world and make decisions. In Oxa and OPAL, that foundation lives in PostgreSQL with the pgvector extension — the same database estate that holds operational data: open roles, scored candidates, CV intake records, and hiring workflow state. Early prototypes used lighter-weight stores for speed, but as requirements grew in size and complexity, we consolidated on Postgres for scalability, transactional integrity, and a single source of truth.
pgvector lets us perform semantic search and retrieval on high-dimensional vector embeddings of text data. By representing each chunk of knowledge as a dense vector, we can efficiently find relevant information even as the knowledge base scales.
Here is a simplified example of how we create an embedding and insert it into our Postgres knowledge base:
import psycopg2
from sentence_transformers import SentenceTransformer
# Load a pre-trained embedding model
embedder = SentenceTransformer('all-MiniLM-L6-v2')
# Connect to the database
conn = psycopg2.connect(
host='localhost',
port=5432,
dbname='oxa_kb'
)
# Create a table to store the embeddings
cur = conn.cursor()
cur.execute('''
CREATE TABLE IF NOT EXISTS knowledge (
id SERIAL PRIMARY KEY,
text TEXT,
embedding VECTOR(384)
)
''')
# Insert a new chunk of knowledge
text = "Oxydata is a leading provider of agentic AI solutions."
embedding = embedder.encode(text).tolist()
cur.execute('''
INSERT INTO knowledge (text, embedding)
VALUES (%s, %s)
''', (text, embedding))
conn.commit()
With this setup, we can perform efficient semantic searches over our entire knowledge base, even as it scales to millions of entries:
query = "What does Oxydata specialize in?"
query_embedding = embedder.encode(query).tolist()
cur.execute('''
SELECT text
FROM knowledge
ORDER BY embedding <=> %s::vector
LIMIT 1
''', (query_embedding,))
result = cur.fetchone()[0]
print(result)
# Outputs: "Oxydata is a leading provider of agentic AI solutions."
This vectorized knowledge base forms the foundation of Oxa's ability to understand and reason about its domain.
2. Orchestration with LangChain and LangGraph
A common question when building agentic AI is: should we use LangChain or LangGraph? The answer is both — but for different purposes.
LangChain provides the foundational integration layer: connecting LLMs, defining tools, managing prompts, and handling retrieval. Think of it as the plumbing that wires your components together.
LangGraph sits on top of LangChain and provides stateful, graph-based orchestration for complex agentic workflows. Unlike simple chains that execute linearly, LangGraph models your agent as a directed graph — where nodes are agents or tools, and edges represent conditional transitions. This enables:
- Loops — retry, reflect, and self-correct
- Conditional branching — route to different tools based on context
- Parallel execution — run multiple agents simultaneously
- Human-in-the-loop — pause and await human input at any node
- Persistent state — maintain context across multi-turn interactions
For true agentic AI, LangGraph is the right choice. Here is how it maps to our systems:
| Feature | IRIS (WhatsApp Agent) | Oxa (OPAL Chat Agent) |
|---|---|---|
| Stateful conversation | LangGraph state | LangGraph state |
| Conditional routing | Score threshold branching | Intent-based routing |
| Tool calling | Candidate lookup, scoring | Postgres lookups, semantic search |
| Human-in-the-loop | Recruiter escalation | Recruiter override |
Here is a simplified example of a LangGraph agent for Oxa:
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from typing import TypedDict, List
# Define agent state
class OxaState(TypedDict):
messages: List
intent: str
context: str
response: str
# Initialize LLM
llm = ChatOpenAI(model="gpt-4.1", temperature=0)
# Define nodes
def understand_intent(state: OxaState) -> OxaState:
"""Use LLM to classify user intent."""
prompt = f"Classify the intent of: {state['messages'][-1]}"
result = llm.invoke([HumanMessage(content=prompt)])
state['intent'] = result.content
return state
def retrieve_context(state: OxaState) -> OxaState:
"""Retrieve relevant context from pgvector knowledge base."""
query_embedding = embedder.encode(state['messages'][-1]).tolist()
cur.execute('''
SELECT text FROM knowledge
ORDER BY embedding <=> %s::vector
LIMIT 3
''', (query_embedding,))
rows = cur.fetchall()
state['context'] = "\n".join([r[0] for r in rows])
return state
def generate_response(state: OxaState) -> OxaState:
"""Generate final response using LLM + retrieved context."""
prompt = f"""
Context: {state['context']}
User question: {state['messages'][-1]}
Answer helpfully and concisely.
"""
result = llm.invoke([HumanMessage(content=prompt)])
state['response'] = result.content
return state
def route_by_intent(state: OxaState) -> str:
"""Conditional routing based on intent."""
if "candidate" in state['intent'].lower():
return "retrieve_context"
elif "schedule" in state['intent'].lower():
return "schedule_tool"
else:
return "generate_response"
# Build the graph
workflow = StateGraph(OxaState)
workflow.add_node("understand_intent", understand_intent)
workflow.add_node("retrieve_context", retrieve_context)
workflow.add_node("generate_response", generate_response)
workflow.set_entry_point("understand_intent")
workflow.add_conditional_edges(
"understand_intent",
route_by_intent,
{
"retrieve_context": "retrieve_context",
"generate_response": "generate_response"
}
)
workflow.add_edge("retrieve_context", "generate_response")
workflow.add_edge("generate_response", END)
# Compile and run
app = workflow.compile()
result = app.invoke({
"messages": ["What are the top skills for data science candidates?"],
"intent": "",
"context": "",
"response": ""
})
print(result['response'])
This graph-based approach is what separates a true agent from a scripted pipeline. At each node, the agent reasons about what to do next — it is not following a pre-determined script.
3. Composable Tool Chains
Beyond orchestration, agentic AI requires a modular set of tools that the agent can dynamically select and invoke. In LangGraph terms, these are tool nodes — discrete capabilities the agent can call when needed.
Here is how we define tools in Oxa's tool chain using LangChain's tool interface:
from langchain_core.tools import tool
from typing import Dict
@tool
def score_candidate(candidate_profile: Dict) -> Dict:
"""Score a candidate based on their profile against the job rubric."""
# Call OPAL's scoring pipeline
scores = scoring_pipeline.run(candidate_profile)
return scores
@tool
def search_knowledge_base(query: str) -> str:
"""Search the Oxa knowledge base using semantic similarity."""
query_embedding = embedder.encode(query).tolist()
cur.execute('''
SELECT text FROM knowledge
ORDER BY embedding <=> %s::vector
LIMIT 3
''', (query_embedding,))
rows = cur.fetchall()
return "\n".join([r[0] for r in rows])
@tool
def get_candidate_status(candidate_id: int) -> Dict:
"""Retrieve the current hiring status of a candidate from Postgres."""
cur.execute('''
SELECT name, score, hiring_status
FROM scored_candidates
WHERE candidate_id = %s
''', (candidate_id,))
row = cur.fetchone()
return {"name": row[0], "score": row[1], "status": row[2]}
# Register tools with the LangGraph agent
tools = [score_candidate, search_knowledge_base, get_candidate_status]
# Bind tools to the LLM
llm_with_tools = llm.bind_tools(tools)
When a user asks Oxa "What is the status of candidate 1042?", the LangGraph agent automatically selects get_candidate_status, calls it with the right parameters, and returns a natural language response — no hard-coded routing required.
A Reference Architecture for Enterprise Agentic AI
Putting it all together, our reference architecture for enterprise agentic AI consists of four layers:
- Data Layer — PostgreSQL with pgvector for vectorized knowledge storage, semantic retrieval, and operational data (jobs, candidates, CV intake)
- Tool Layer — Individual AI tools and microservices, each handling a specific capability
- Orchestration Layer — LangGraph for stateful graph-based agent orchestration, LangChain for tool and LLM integration
- Interaction Layer — Conversational UI, task-specific UI, or API (WhatsApp for IRIS, chat panel for Oxa)
graph TD
A[End User] --> B[Interaction Layer]
B --> C[Conversational UI]
B --> D[WhatsApp - IRIS]
B --> E[API]
C --> F[Orchestration Layer]
D --> F
E --> F
F --> G[LangGraph Stateful Agent Graph]
G --> H[LangChain Tool and LLM Integration]
H --> I[Tool Layer]
I --> J[Language Models GPT-4.1 / Gemini Flash]
I --> K[Candidate Scoring OPAL Pipeline]
I --> L[Semantic Search Knowledge Base Tool]
I --> M[Scheduling and Notifications]
J --> N[Data Layer]
K --> N
L --> N
M --> N
N --> O[PostgreSQL pgvector Vectorized KB]
N --> P[Postgres Candidates and Scoring]
N --> Q[Postgres Jobs and CV Intake]
Implementing Agentic AI: Team, Talent, and Trajectory
Building agentic AI systems requires a unique combination of skills and expertise. At Oxydata, our agentic AI teams bring together:
- AI Engineers — Experts in LLMs, embeddings, LangGraph orchestration, and evaluation
- Backend Engineers — Skilled in FastAPI, PostgreSQL, pgvector, and scalable infrastructure
- Domain Experts — Deep knowledge of the specific industry and use case (e.g., recruitment for IRIS and Oxa)
- Product Managers — Ensure the AI system is aligned with business goals and user needs
Some of the key principles we have found effective:
- Cross-functional collaboration — Engineers, domain experts, and PMs work closely together from ideation through deployment
- Agile experimentation — Rapid prototyping, frequent iteration, and continuous evaluation
- Phased rollout — Start with a narrow MVP, then gradually expand capabilities based on real usage
For many enterprises, building this capability in-house is challenging given the scarcity of AI talent and the rapidly evolving technology landscape. That is where partnerships with experienced agentic AI providers like Oxydata can be invaluable. Typical engagement models include:
- Pilot projects — Rapidly prototype an agentic AI solution for a specific use case to demonstrate value and feasibility
- Co-development — Work side-by-side with Oxydata to build and deploy a production-grade agentic AI system, while building in-house capabilities
- Platform licensing — Leverage Oxydata's pre-built agentic AI platform and tools, customised and extended for your specific needs
Conclusion
The advent of agentic AI represents a major shift in how we conceive of and interact with artificial intelligence. Rather than narrow, scripted systems, we are moving towards AI that can autonomously perceive, reason, act, and learn — AI that can engage in open-ended dialogue, tackle complex problems, and continuously improve itself.
At Oxydata, we are excited to be at the forefront of this transition, pioneering agentic AI solutions for Malaysian enterprises. Through our work on IRIS and Oxa within OPAL, we have developed a deep understanding of the tools, architectures, and approaches needed to build truly agentic AI — from PostgreSQL with pgvector for scalable knowledge management, to LangGraph for stateful multi-agent orchestration.
The future of AI is agentic — autonomous, adaptive, and deeply integrated into the fabric of our work and lives. If you are interested in exploring how agentic AI could transform your business, contact our team or explore our AI Solutions & Development.
Ready to build your first AI agent? We can help you design, build, and deploy agentic AI solutions tailored for your enterprise.
Oxydata Software Sdn Bhd is a Malaysia Digital-certified Microsoft Technology Partner specialising in GenAI services, AI automation, and AI-powered recruitment screening. Our solutions are built and hosted in Malaysia, ensuring full data residency compliance under PDPA.