Introduction
From Using AI to Engineering AI Systems
In the previous module, you explored Generative AI, Large Language Models, prompt engineering, ensemble learning, model optimization, and modern Deep Learning. You learned how advanced AI models generate responses, how multiple models can work together, and how neural networks form the foundation of many intelligent systems.
You are now ready to move beyond understanding individual models and begin studying how complete AI applications are engineered.
A Large Language Model can generate fluent text, explain ideas, write code, and support many professional tasks. However, an LLM working alone has important limitations. It may not know information created after its training period. It cannot automatically access your organisation's private documents, query a live database, inspect an internal knowledge base, or perform actions through external software unless those capabilities are deliberately added.
Modern AI engineering addresses these limitations by connecting language models with other systems.
Large Language Model
+
Structured Data
+
External Knowledge
+
Tools and APIs
↓
Practical AI Application
In this module, you will study three technologies that play a central role in this architecture: SQL, Retrieval-Augmented Generation, and Agentic AI.
Why SQL Matters in AI Engineering
Many organisations store valuable information in relational databases. Customer records, transactions, product catalogues, examination results, inventory levels, and operational data are commonly arranged into tables that can be queried using SQL.
An AI application may need to retrieve this structured information before it can answer a question or make a decision. For example, an educational assistant may need to find a learner's course progress, while a retail assistant may need to check whether a product is currently in stock. SQL provides the bridge between the AI system and this structured data.
Why Retrieval-Augmented Generation Matters
Organisations also store large amounts of unstructured information in documents, manuals, reports, policies, research papers, web pages, and support articles. This information cannot always be handled effectively through ordinary SQL queries.
Retrieval-Augmented Generation, usually called RAG, allows an AI system to search an external knowledge source, retrieve relevant passages, and provide those passages to a language model before it generates an answer. Instead of relying only on knowledge stored during model training, the system can respond using information selected for the current question.
User Question
↓
Retrieve Relevant Information
↓
Add Retrieved Context to the Prompt
↓
Large Language Model
↓
Grounded Answer
A well-designed RAG system can improve factual accuracy, support private organisational knowledge, and make answers easier to trace back to source material. However, RAG is not simply a matter of uploading documents to an AI model. Engineers must make decisions about document preparation, chunking, embeddings, vector storage, retrieval, prompt construction, and evaluation.
Why Agentic AI Matters
Some AI applications must do more than retrieve information and generate a response. They may need to select a tool, call an API, query a database, compare results, create a plan, or repeat a process until a goal is reached.
Agentic AI refers to systems in which a model can reason about a goal, choose from available tools, perform actions, observe the results, and decide what to do next. An AI agent might search a knowledge base, calculate a result, check a calendar, update a record, or coordinate several specialised components.
This capability creates powerful opportunities, but it also introduces new engineering challenges. Agents need clearly defined tools, controlled permissions, reliable memory, appropriate stopping conditions, and safeguards against incorrect or unnecessary actions.
A Practical, Code-Based Module
Earlier modules introduced many concepts through explanation and small examples. This module moves to an intermediate-to-advanced level and places greater emphasis on implementation. You will write SQL queries, examine Python-based RAG workflows, and study how tool-using agents are constructed.
The aim is not to memorise one framework. Libraries and platforms change quickly. The more durable skill is understanding the architecture beneath them: where information comes from, how it is retrieved, how it reaches the model, what actions the system may take, and how the entire workflow can be evaluated.
Learning Objectives
By the end of this module, you should be able to:
- Explain why production AI applications require access to data, knowledge, and tools beyond the language model itself.
- Describe the role of relational databases and SQL in modern AI systems.
- Write practical SQL queries using SELECT, WHERE, ORDER BY, LIMIT, aggregate functions, GROUP BY, and JOIN.
- Distinguish between structured database retrieval and semantic retrieval from unstructured documents.
- Explain the complete Retrieval-Augmented Generation pipeline from document preparation to final answer generation.
- Describe how chunking, embeddings, vector databases, and similarity search support retrieval.
- Build and interpret a small Python-based RAG workflow using an LLM, document embeddings, and a vector store.
- Evaluate common RAG failure points, including poor chunking, weak retrieval, missing context, and unsupported answers.
- Explain the difference between an AI assistant, an automated workflow, and an AI agent.
- Describe how agents use tools, memory, planning, observations, and stopping conditions.
- Interpret Python code for a basic tool-using AI agent.
- Identify important safety, reliability, and human-oversight requirements for RAG and Agentic AI systems.
What You Will Build
Throughout the module, you will work with practical examples that mirror the architecture of real AI applications. These examples will include:
- SQL queries that retrieve structured information from related tables
- A small document-retrieval pipeline
- A RAG workflow that supplies retrieved context to a language model
- A simple agent that selects and uses an external tool
These implementations are intentionally small enough to understand line by line, but they introduce the same core components used in larger production systems.
How to Approach This Module
Do not treat the code as something to copy without interpretation. For every query or Python block, identify the role it plays in the wider system. Ask what information enters the step, what transformation occurs, what output is produced, and what could go wrong.
By the end of the module, you should be able to look at a modern AI application and recognise its major engineering layers: structured data access, semantic retrieval, prompt construction, model generation, tool execution, and system evaluation.
SQL for AI
Why AI Engineers Need SQL
Artificial Intelligence systems depend on data. Some of that data appears in documents, images, audio files, or websites, but a large amount of business information is stored in relational databases. Customer records, product details, transactions, examination results, inventory levels, and support tickets are often organised into tables that can be queried using SQL.
SQL stands for Structured Query Language. It allows an engineer to retrieve, filter, sort, combine, and summarise structured information. In an AI application, SQL may be used before a model generates an answer, while an agent is completing a task, or during the preparation of data for analysis and training.
Consider an educational assistant that answers questions such as:
- Which students scored above 80?
- Which course has the highest average mark?
- How many learners are enrolled in each course?
- What is the latest score recorded for a particular student?
A language model should not invent these answers. It should retrieve the relevant records from the database, interpret the results, and then present them clearly.
A Simple Relational Database
We will use three related tables throughout this section.
students
--------
student_id
student_name
city
courses
-------
course_id
course_name
marks
-----
student_id
course_id
score
The student_id and course_id fields connect the tables. These identifiers allow us
to combine related information without repeating every detail in one large table.
Retrieving Data with SELECT
The SELECT statement retrieves data from a table.
SELECT student_name, city
FROM students;
This query returns the student_name and city columns for every student.
To retrieve all columns, use an asterisk:
SELECT *
FROM students;
Although SELECT * is convenient during exploration, production systems should usually request only
the columns they need. This reduces unnecessary data transfer and makes the query easier to understand.
Filtering Records with WHERE
The WHERE clause limits the result to records that satisfy a condition.
SELECT student_name, city
FROM students
WHERE city = 'Chennai';
We can also use comparison operators with numerical values.
SELECT student_id, course_id, score
FROM marks
WHERE score >= 80;
Multiple conditions may be combined using AND or OR.
SELECT student_id, score
FROM marks
WHERE score >= 80
AND course_id = 2;
Sorting and Limiting Results
The ORDER BY clause sorts query results. By default, values are sorted in ascending order.
Use DESC for descending order.
SELECT student_id, score
FROM marks
ORDER BY score DESC;
The LIMIT clause restricts the number of rows returned.
SELECT student_id, score
FROM marks
ORDER BY score DESC
LIMIT 5;
This query returns the five highest scores. In an AI application, limiting results can prevent a tool from sending thousands of unnecessary rows to a language model.
Summarising Data with Aggregate Functions
Aggregate functions calculate a single result from several rows. Common functions include
COUNT(), SUM(), AVG(), MIN(), and MAX().
SELECT COUNT(*) AS total_students
FROM students;
SELECT AVG(score) AS average_score
FROM marks;
SELECT MAX(score) AS highest_score
FROM marks;
The AS keyword creates a readable alias for the result column.
Grouping Data with GROUP BY
GROUP BY is used when an aggregate calculation is required for each category.
SELECT course_id, AVG(score) AS average_score
FROM marks
GROUP BY course_id;
This query calculates the average score separately for each course.
We can also count how many marks records exist for each course.
SELECT course_id, COUNT(*) AS total_results
FROM marks
GROUP BY course_id;
Combining Tables with JOIN
A relational database becomes especially useful when information is distributed across several tables.
A JOIN combines related records.
SELECT
students.student_name,
courses.course_name,
marks.score
FROM marks
JOIN students
ON marks.student_id = students.student_id
JOIN courses
ON marks.course_id = courses.course_id;
This query produces a human-readable result containing the learner's name, the course name, and the score.
Without the joins, the marks table would contain only numerical identifiers.
We can combine joins with filtering and sorting.
SELECT
students.student_name,
courses.course_name,
marks.score
FROM marks
JOIN students
ON marks.student_id = students.student_id
JOIN courses
ON marks.course_id = courses.course_id
WHERE marks.score >= 80
ORDER BY marks.score DESC;
Using SQL from Python
AI applications commonly execute SQL through Python. The following example uses Python's built-in
sqlite3 library.
import sqlite3
connection = sqlite3.connect("learnerbox.db")
cursor = connection.cursor()
query = """
SELECT
students.student_name,
courses.course_name,
marks.score
FROM marks
JOIN students
ON marks.student_id = students.student_id
JOIN courses
ON marks.course_id = courses.course_id
WHERE marks.score >= ?
ORDER BY marks.score DESC
"""
cursor.execute(query, (80,))
results = cursor.fetchall()
for row in results:
print(row)
connection.close()
Notice the question mark in the query. This is a parameter placeholder. The value is supplied separately through
cursor.execute(). Parameterised queries are safer than inserting user input directly into an SQL
string because they help protect the application from SQL injection.
SQL as an AI Tool
In a tool-using AI system, SQL may be exposed through a controlled function. The language model does not need unrestricted access to the entire database. Instead, the application can provide a small, validated interface that accepts a limited request and returns only the required information.
User asks:
"Which course has the highest average score?"
AI selects database tool
↓
Application executes validated SQL
↓
Database returns results
↓
AI explains the result
This separation is important. The database performs precise retrieval and calculation, while the language model interprets the result and communicates it naturally.
SQL and Semantic Retrieval Are Different
SQL is excellent when the information is structured and the question can be expressed through exact conditions, joins, or calculations. It is less suitable for questions that depend on meaning across long documents.
| Question | Best Retrieval Method |
|---|---|
| Which five students have the highest scores? | SQL |
| How many products are currently out of stock? | SQL |
| What does the employee handbook say about remote work? | Semantic document retrieval |
| Summarise the main safety recommendations across these reports. | Semantic document retrieval |
Many practical AI systems use both approaches. SQL retrieves precise structured facts, while a RAG pipeline retrieves relevant passages from unstructured knowledge sources. In the next section, you will learn how that RAG pipeline is designed and implemented.
RAG Engineering
Connecting Language Models with External Knowledge
Large Language Models can generate fluent and useful responses, but they do not automatically know everything an organisation needs. Their training data may be outdated, incomplete, or unrelated to private information such as internal policies, product manuals, research notes, support documents, or course materials.
Retrieval-Augmented Generation, or RAG, addresses this limitation by combining information retrieval with language generation. Instead of asking the model to answer only from what it learned during training, a RAG system first searches an external knowledge source and adds the most relevant information to the prompt.
User Question
↓
Retrieve Relevant Passages
↓
Build a Context-Rich Prompt
↓
Large Language Model
↓
Grounded Answer
The word grounded is important. A grounded answer is based on supplied evidence rather than unsupported model recall. RAG does not guarantee perfect accuracy, but it gives the model access to current, private, and domain-specific information at the moment a question is asked.
The Complete RAG Pipeline
A practical RAG system usually contains two major workflows:
- Indexing: preparing documents so they can be searched efficiently
- Retrieval and generation: finding relevant content and using it to answer a question
Indexing Workflow
Documents → Cleaning → Chunking → Embeddings → Vector Index
Question Workflow
Question → Query Embedding → Similarity Search → Retrieved Chunks
→ Prompt Construction → LLM → Answer
Step 1: Loading and Preparing Documents
The first stage is to collect the knowledge sources. These may include plain-text files, PDFs, web pages, database exports, manuals, reports, or transcripts. Before indexing, the text should be cleaned so that repeated headers, navigation menus, broken characters, and irrelevant metadata do not interfere with retrieval.
Every stored passage should retain useful metadata, such as its source file, page number, section heading, or URL. Metadata allows the application to provide citations and filter retrieval results later.
Step 2: Chunking
Long documents are rarely embedded as one enormous block. They are divided into smaller units called chunks. A chunk might contain a paragraph, several paragraphs, or a fixed number of words or tokens.
Chunk size creates an engineering trade-off. Very small chunks may lose important context. Very large chunks may contain too much unrelated information and consume more of the model's context window. Many systems also use overlap so that an idea divided near a boundary appears in both neighbouring chunks.
def chunk_text(text, chunk_size=120, overlap=25):
words = text.split()
chunks = []
start = 0
while start < len(words):
end = start + chunk_size
chunks.append(" ".join(words[start:end]))
start += chunk_size - overlap
return chunks
This function is intentionally simple. Production chunking may respect headings, paragraphs, sentences, tables, or document structure rather than dividing text only by word count.
Step 3: Embeddings
A computer cannot perform semantic search directly over raw sentences. It first converts each chunk into an embedding: a numerical vector representing aspects of the text's meaning.
Texts with similar meanings tend to receive vectors that are close together in the embedding space. This allows a query such as “How can I reset my account password?” to retrieve a passage titled “Recovering access to your profile,” even when the wording is different.
from sentence_transformers import SentenceTransformer
embedding_model = SentenceTransformer("all-MiniLM-L6-v2")
documents = [
"Learners can reset their password from the account settings page.",
"Premium members receive access to advanced AI engineering modules.",
"Course certificates are issued after the required assessments are completed."
]
document_vectors = embedding_model.encode(
documents,
normalize_embeddings=True
)
Normalising the vectors makes it convenient to compare them using cosine-style similarity through an inner product index.
Step 4: Building a Vector Index
A vector index stores embeddings and searches for nearby vectors. For a small learning project, FAISS provides a direct way to create an in-memory similarity index.
import faiss
import numpy as np
document_vectors = np.asarray(document_vectors, dtype="float32")
dimension = document_vectors.shape[1]
index = faiss.IndexFlatIP(dimension)
index.add(document_vectors)
IndexFlatIP performs an exact inner-product search. Because the vectors were normalised, higher
scores indicate stronger semantic similarity.
Step 5: Retrieving Relevant Chunks
The user's question is embedded using the same model. The index then returns the most similar document vectors.
def retrieve(question, top_k=2):
query_vector = embedding_model.encode(
[question],
normalize_embeddings=True
)
query_vector = np.asarray(query_vector, dtype="float32")
scores, indices = index.search(query_vector, top_k)
results = []
for score, position in zip(scores[0], indices[0]):
results.append({
"text": documents[position],
"score": float(score)
})
return results
matches = retrieve("How do I change my password?")
for match in matches:
print(match)
Retrieval is not generation. At this stage, the system has only selected potentially relevant evidence. The next task is to construct a prompt that clearly separates the evidence from the user's question.
Step 6: Constructing the RAG Prompt
def build_prompt(question, retrieved_items):
context = "\n\n".join(
item["text"] for item in retrieved_items
)
return f"""
You are a helpful assistant.
Answer the question using only the context below.
If the context does not contain enough information,
say that the answer is not available in the knowledge base.
Context:
{context}
Question:
{question}
Answer:
""".strip()
This prompt gives the model a clear instruction, the retrieved evidence, and the user's question. The instruction to admit insufficient evidence is important because retrieval may fail or the knowledge base may not contain the answer.
Step 7: Generating the Answer
The completed prompt can be sent to any compatible language-model interface. The exact client code depends on the model or provider being used, so it is useful to keep generation separate from retrieval.
def answer_question(question, generate_text):
retrieved_items = retrieve(question, top_k=3)
prompt = build_prompt(question, retrieved_items)
answer = generate_text(prompt)
return {
"answer": answer,
"sources": retrieved_items
}
Here, generate_text represents a function connected to a local model, hosted model, or external
model API. This design keeps the RAG architecture modular: the embedding model, vector index, retrieval logic,
and generation model can be changed independently.
Improving Retrieval Quality
A working pipeline is not necessarily a good pipeline. RAG quality depends heavily on retrieval. If the correct evidence is not selected, even an excellent language model may produce an incomplete or incorrect response.
Engineers commonly improve retrieval by:
- testing different chunk sizes and overlaps
- preserving headings and document structure
- storing accurate metadata
- retrieving more candidates and reranking them
- combining semantic search with keyword search
- filtering by document type, date, department, or permission
- rewriting ambiguous questions before retrieval
More retrieval is not always better. Adding many weakly related chunks can distract the model and reduce answer quality. The aim is to provide enough relevant evidence without flooding the prompt with noise.
Evaluating a RAG System
RAG evaluation should examine the system in separate stages. A single “good” or “bad” answer does not reveal where the problem occurred.
| Evaluation Layer | Question to Ask |
|---|---|
| Retrieval | Did the system retrieve the passages needed to answer the question? |
| Relevance | Were the retrieved passages closely related to the question? |
| Groundedness | Is the generated answer supported by the retrieved evidence? |
| Completeness | Did the answer include all important information available in the evidence? |
| Citation Quality | Can the user trace claims back to the correct source? |
A useful test set contains realistic questions, expected source passages, and reference answers. Engineers can then compare changes to chunking, embeddings, retrieval depth, and prompt design systematically rather than relying only on intuition.
Common RAG Failure Modes
- Missing evidence: the required information was never indexed
- Poor chunking: the answer was split away from its important context
- Weak retrieval: semantically similar but incorrect passages were selected
- Context overload: too many irrelevant chunks were added to the prompt
- Unsupported generation: the model added claims not present in the evidence
- Stale knowledge: the indexed documents were not updated
- Permission failure: users retrieved information they were not authorised to access
Security is therefore part of RAG engineering. Access controls should be applied before retrieved content is placed into the prompt. A language model should never be treated as the mechanism responsible for deciding whether confidential information may be revealed.
RAG as an Engineering System
RAG is sometimes presented as a simple sequence of loading documents, creating embeddings, and asking questions. That sequence is useful for learning, but production systems require considerably more care. Documents change, users have different permissions, indexes must be updated, retrieval must be monitored, and generated answers must be evaluated.
The central engineering lesson is that every stage matters. A strong language model cannot compensate for absent documents, poorly designed chunks, irrelevant retrieval, or unsafe access controls. Reliable RAG systems emerge from the coordinated design of the entire pipeline.
In the next section, you will move beyond systems that only retrieve and answer. You will explore Agentic AI, where models can select tools, perform actions, observe results, and work through multi-step tasks.
Agentic AI
From Generating Answers to Taking Action
A traditional AI assistant receives a request and generates a response. A Retrieval-Augmented Generation system improves that response by retrieving relevant evidence before generation. However, many real-world tasks require more than answering a question. The system may need to choose a tool, collect information from several sources, perform a calculation, update a record, check whether an action succeeded, and decide what to do next.
Agentic AI refers to AI systems that can work toward a goal by selecting actions and interacting with tools or environments. The language model acts as a reasoning and decision-making component, while the surrounding application controls which tools are available, how they are executed, and when the process should stop.
User Goal
↓
Interpret the Task
↓
Choose a Tool or Action
↓
Execute the Action
↓
Observe the Result
↓
Decide the Next Step
↓
Return the Final Response
This action-observation cycle is what distinguishes an agent from a simple chatbot. The agent does not merely describe what could be done. Within carefully defined limits, it can use software capabilities to perform parts of the task.
Assistant, Workflow, and Agent
The terms assistant, workflow, and agent are sometimes used interchangeably, but they describe different levels of system behaviour.
| System Type | How It Operates | Example |
|---|---|---|
| AI Assistant | Responds to a user prompt | Explains a concept or drafts an email |
| AI Workflow | Follows a predefined sequence of steps | Summarises a document and then formats the result |
| AI Agent | Selects actions dynamically based on the goal and observations | Chooses whether to search documents, query a database, or perform a calculation |
A workflow offers predictability because the steps are designed in advance. An agent offers flexibility because it can decide which step is appropriate. Greater flexibility also creates greater risk, so engineers should not use an agent when a simple workflow is sufficient.
The Core Components of an Agent
Most agentic systems contain several important components:
- Goal: the outcome the agent is expected to achieve
- Model: the language model that interprets the task and selects actions
- Tools: controlled functions the agent may call
- State: information retained during the current task
- Memory: information retained across steps or conversations
- Observations: results returned by tools or the environment
- Policy and safeguards: rules defining permitted behaviour
- Stopping condition: the rule that ends the process
Tools
A tool is a function exposed to the agent for a specific purpose. Examples include searching a knowledge base, querying a database, using a calculator, reading a calendar, sending a message, or calling an external API.
Tools should have clear names, precise descriptions, validated inputs, and restricted permissions. The model may decide which tool to request, but ordinary application code should validate and execute the call.
def calculate_average(values):
if not values:
raise ValueError("At least one value is required.")
return sum(values) / len(values)
def search_course_policy(question):
# In a complete application, this function would call
# the RAG retriever created in the previous section.
return "Retrieved policy passage for: " + question
These functions are deterministic application components. The agent uses them, but the language model does not replace their internal logic.
Representing Tools for the Agent
A small learning implementation can represent tools through a dictionary. Each entry contains a callable function and a description of when it should be used.
TOOLS = {
"calculate_average": {
"description": "Calculate the average of a list of numbers.",
"function": calculate_average
},
"search_course_policy": {
"description": "Search the course policy knowledge base.",
"function": search_course_policy
}
}
Modern model APIs often support structured tool calling. The model returns a tool name and validated arguments rather than writing an unstructured instruction such as “use the calculator now.”
A Simple Agent Loop
The central logic of an agent is a loop. The system gives the model the user goal, available tools, and current observations. The model either requests a tool or returns a final answer.
def run_agent(user_goal, decide_next_action, max_steps=5):
state = {
"goal": user_goal,
"observations": []
}
for step in range(max_steps):
decision = decide_next_action(
goal=state["goal"],
tools=TOOLS,
observations=state["observations"]
)
if decision["type"] == "final":
return decision["answer"]
if decision["type"] != "tool_call":
raise ValueError("Unsupported agent decision.")
tool_name = decision["tool_name"]
arguments = decision["arguments"]
if tool_name not in TOOLS:
raise ValueError("The requested tool is not available.")
tool_function = TOOLS[tool_name]["function"]
result = tool_function(**arguments)
state["observations"].append({
"tool": tool_name,
"arguments": arguments,
"result": result
})
return "The agent stopped after reaching the maximum number of steps."
The function decide_next_action represents the language-model interaction. It must return structured
data describing either a tool call or a final answer. The application then checks the request before executing
it.
The max_steps limit is essential. Without a stopping condition, an agent could repeat actions,
consume excessive resources, or continue indefinitely.
How the Agent Uses Observations
Tool results become observations. The model receives those observations during the next decision step and uses them to determine whether it has enough information.
Goal:
"Find the attendance policy and calculate the average
of the learner's last three scores."
Step 1:
Tool → search_course_policy
Observation → Relevant attendance policy passage
Step 2:
Tool → calculate_average
Arguments → [78, 84, 91]
Observation → 84.33
Step 3:
Final response → Policy explanation and calculated average
This illustrates how an agent can combine retrieval with deterministic computation. The RAG system provides unstructured knowledge, while the calculator produces an exact numerical result.
State and Memory
State usually refers to information required during the current run, such as the goal, tool calls, retrieved evidence, and intermediate results. Memory may persist information beyond one run, such as a user's preferences or the outcome of an earlier task.
Memory should be added deliberately. Saving every conversation indefinitely may create privacy risks, increase retrieval noise, and cause outdated information to influence future decisions. Useful memory is selective, permission-aware, editable, and removable.
Planning and Task Decomposition
Complex goals may need to be divided into smaller tasks. An agent could first create a plan and then execute each step, or it could decide one step at a time based on new observations.
Goal: Prepare a course progress report
Possible plan:
1. Retrieve learner details
2. Query assessment scores
3. Calculate average performance
4. Retrieve attendance requirements
5. Compare progress with requirements
6. Draft the report
A plan improves transparency, but it should not be assumed to be correct merely because it was generated by a model. The application may need to validate the plan, especially before sensitive or irreversible actions.
Human Approval and Action Boundaries
Agent tools can be divided into read actions and write actions. Read actions retrieve information. Write actions change the external world by sending a message, modifying a database, placing an order, or deleting a record.
Write actions require stronger controls. A useful design pattern is to allow the agent to prepare an action but require human confirmation before execution.
Agent proposes:
"Send the progress report to the learner."
Application response:
"Approval required before sending."
Human reviews and confirms
↓
Application executes the action
Guardrails for Agentic Systems
A production agent should be designed according to the principle of least privilege: it receives only the tools and permissions necessary for the current task.
- Use allowlists for permitted tools and operations.
- Validate tool arguments before execution.
- Separate read permissions from write permissions.
- Require approval for high-impact actions.
- Apply time, cost, and step limits.
- Log decisions, tool calls, results, and errors.
- Protect secrets and personal information.
- Test how the agent behaves when tools fail.
- Provide a clear way for users to stop or override the process.
Single-Agent and Multi-Agent Systems
A single agent can often handle tasks by using several tools. Some architectures instead assign specialised roles to multiple agents, such as a researcher, analyst, reviewer, and writer.
Research Agent
↓
Analysis Agent
↓
Review Agent
↓
Final Output
Multi-agent systems may improve separation of responsibilities, but they also increase cost, latency, and coordination complexity. Agents can pass errors to one another or create the appearance of independent verification even when all of them rely on similar models and evidence.
For many applications, one well-controlled agent with reliable tools is preferable to a large collection of loosely coordinated agents.
Evaluating Agentic AI
Agent evaluation should measure more than whether the final response sounds good. Engineers should examine:
- whether the agent selected the correct tool
- whether tool arguments were accurate and valid
- whether the task was completed successfully
- whether unnecessary steps were avoided
- whether permissions and policies were respected
- whether the agent recovered safely from errors
- whether the final response matched the observations
Test cases should include normal tasks, ambiguous requests, missing information, tool failures, conflicting instructions, and attempts to obtain unauthorised access. The goal is not only successful operation, but predictable and safe failure when the task cannot be completed.
The Role of the AI Engineer
Agentic AI does not remove the need for software engineering. It increases it. The AI engineer must define the system's capabilities, build tool interfaces, validate actions, manage state, enforce permissions, evaluate outcomes, and decide where human oversight is required.
The most reliable agent is not the one given unlimited autonomy. It is the one whose autonomy is matched carefully to the task, the available evidence, and the consequences of error.
With SQL, RAG, and Agentic AI, you have now explored three major layers of modern AI application development. SQL retrieves precise structured data. RAG supplies relevant knowledge from documents. Agents coordinate tools and actions to complete multi-step goals. Together, these technologies form a practical foundation for advanced AI engineering.
Module Summary
Congratulations! You have completed the final module of the free AI Engineer Program.
Throughout this module, you moved beyond learning how AI models work and began exploring how modern AI applications are engineered. Rather than viewing a Large Language Model as a standalone component, you examined how AI systems interact with databases, knowledge repositories, retrieval pipelines, and external tools to solve practical problems.
Review
- SQL for querying structured data
- Using SELECT, WHERE, ORDER BY, GROUP BY and JOIN
- Retrieval-Augmented Generation (RAG)
- Document chunking and embeddings
- Vector databases and semantic retrieval
- Prompt construction using retrieved context
- Evaluating and improving RAG systems
- Agentic AI concepts
- Tool calling, planning, memory and observations
- Guardrails and safe AI engineering practices
Key Concepts
- SQL
- Structured Data
- Embeddings
- Vector Database
- Semantic Search
- Retrieval-Augmented Generation (RAG)
- Tool Calling
- AI Agent
- Planning
- Guardrails
The premium AI Engineer Program builds directly on these foundations with production-scale RAG systems, advanced agent architectures, model deployment, evaluation, orchestration, MLOps, and scalable AI application development.
Reflection
Take a few minutes to reflect on your learning before moving on.
- Why is connecting an LLM to external data often better than relying only on the model's internal knowledge?
- How would you decide whether a problem should use SQL, a RAG system, or an AI agent?
- What are the most important engineering decisions when designing a reliable RAG pipeline?
- Why should AI agents have limited permissions and clearly defined tools?
- Which topic from the six free modules would you most like to explore further in the premium AI Engineer Program?
You have now completed the complete free AI Engineer learning path—from Python programming and data analysis to Machine Learning, Deep Learning, Generative AI, RAG Engineering, and Agentic AI. You now possess the conceptual foundation required to begin building modern AI applications.
Knowledge Check
- What problem does Retrieval-Augmented Generation solve that a standalone Large Language Model cannot always solve effectively?
- Why are embeddings required for semantic search?
- What is the purpose of chunking documents before creating embeddings?
- Explain the difference between SQL retrieval and semantic document retrieval.
- What role does a vector database play in a RAG system?
- Why should an AI agent use validated tools instead of directly performing unrestricted actions?
- List four core components commonly found in an AI agent.
- Why are guardrails and human approval important for high-impact AI actions?