Build a Company Policy AI Assistant

Build a RAG chatbot that answers questions about company policy documents.

Introduction

30 Second Summary

Every company has policy documents buried in shared drives that nobody reads until they need an urgent answer. Finding the right paragraph in the right document takes longer than it should.

In this project, you will build a terminal-based AI assistant that reads your company's PDF and Word policy documents, indexes them for smart retrieval, and answers natural-language questions while citing the exact source text and filename.

What You'll Build

You run the app, type a question like "Can I install AnyDesk on my laptop?", and the assistant searches through your documents, finds the relevant section, and responds with the exact policy language and source file name.

By the end of this project, you'll have:

  • A working RAG pipeline that answers any question in plain language, grounded in your actual policy documents.
  • Automatic source citations on every answer, quoting the exact passage and naming the file it came from so you can verify it.
  • An interactive chat loop that lets you keep asking follow-up questions without restarting the app.
  • Secret Mission: Add document filtering so you can target your queries at specific policies.

Are there any prerequisites?

You should have basic Python knowledge (variables, functions, and running scripts from the terminal). You also need a free Gemini API key from Google AI Studio, which you can grab at aistudio.google.com.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters to you.

Set Up Your Project

Your policy assistant needs to connect to Google's Gemini API and read PDF and Word documents. Before any of that can happen, you need the right packages installed and your API key configured.

In this step, you'll create an isolated Python project, install the LlamaIndex packages that handle document loading and AI queries, and set up your Gemini API key.

In this step, get ready to:
  • Create a project folder with a virtual environment.
  • Install LlamaIndex packages and document readers.
  • Configure your Gemini API key and add policy documents.
Create a project folder and virtual environment

A virtual environment keeps this project's packages separate from your system Python. This prevents version conflicts with other projects on your machine.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder by running:
mkdir policy-assistant
  • Confirm the folder was created by running:
ls

You should see policy-assistant listed in the output.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code and press Enter to open it.
  • Click File in the top menu bar.
  • Click Open Folder.
  • Select the policy-assistant folder on your Desktop, then click Open.

VS Code opens with policy-assistant shown in the Explorer sidebar on the left.

  • Open the integrated terminal by pressing Ctrl+` (backtick key, usually above Tab).

A terminal panel appears at the bottom of VS Code, already inside your policy-assistant folder.

  • Create and activate a virtual environment by running the commands for your operating system:

macOS

python3 -m venv venv
source venv/bin/activate

Windows

python -m venv venv
venv\Scripts\activate

You should see (venv) appear at the beginning of your terminal prompt. This confirms you are working inside the virtual environment.

Don't see (venv) in your prompt?

On Windows, if you see an error about execution policies, run Set-ExecutionPolicy -Scope CurrentUser RemoteSigned and then try the activate command again.

On macOS, make sure you typed source before the path. Without it, the activation script does not run in your current shell.

help me activate my Python virtual environment

  • Install the required packages by running:
pip install llama-index-core llama-index-llms-google-genai llama-index-embeddings-google-genai docx2txt pypdf

What are these packages?

  • llama-index-core is the foundation that handles document chunking, indexing, and querying.
  • llama-index-llms-google-genai connects LlamaIndex to Google's Gemini models for text generation.
  • llama-index-embeddings-google-genai converts your document chunks into vector embeddings for semantic search.
  • docx2txt and pypdf let LlamaIndex read Word and PDF files.

The install takes a minute or two. When it finishes, you see Successfully installed followed by a list of package names.

Install failed or timed out?

Make sure (venv) is visible in your prompt. If you accidentally installed outside the virtual environment, activate it and run the install again.

If you see a network timeout, check your internet connection and retry the same command.

help me fix my pip install errors

Configure the Gemini API key

Your app needs to authenticate with Google's Gemini API to generate responses. The standard approach is storing your API key in a .env file that stays on your machine.

  • In VS Code's Explorer sidebar, click the New File icon (the page icon with a plus sign).
  • Name the file .env and press Enter.
  • Paste the following content into the file, replacing your-api-key-here with your actual Gemini API key from Google AI Studio:
GOOGLE_API_KEY=your-api-key-here

What does this env var do?

The GOOGLE_API_KEY environment variable is the standard name that the Google GenAI SDK and LlamaIndex's Google integration look for when authenticating requests.

Keeping it in a .env file means it never gets committed to version control.

  • Save .env by pressing Cmd+S (macOS) or Ctrl+S (Windows).
  • Install the package that loads .env files into your app by running:
pip install python-dotenv

You see Successfully installed python-dotenv in the output.

✔️ Awesome, I've got everything!

Great. Double check you have saved your .env file with your actual API key pasted in.

ⓧ I'd like to double check the full code

Your .env file should contain exactly one line:

GOOGLE_API_KEY=your-api-key-here

Replace your-api-key-here with the API key you copied from Google AI Studio.

Add your policy documents

The assistant needs documents to search through. You'll create a folder and fill it with your company's PDF and Word policy files.

  • Create the documents folder by running this command in your terminal:
mkdir data
  • Open the data folder in Finder (macOS) or File Explorer (Windows) and copy your PDF and Word policy documents into it.

Pick 5-10 documents to start

Any combination of .pdf and .docx files works. If you do not have company policies handy, search online for sample HR, IT, or workplace policy templates and download a handful.

  • Confirm your documents are in place by running:
ls data

You should see your PDF and Word file names listed in the output.

Seeing an empty output?

Make sure you copied the files into the data folder inside policy-assistant on your Desktop. If ls data shows nothing, the folder is empty and the files ended up elsewhere.

help me get my documents into the right folder

Before you run the next command, what do you think will happen if the packages installed correctly?

  • Verify everything is connected by running:
python -c "from llama_index.llms.google_genai import GoogleGenAI; print('Setup OK')"

You should see Setup OK printed in your terminal. This confirms that LlamaIndex and the Google GenAI integration are installed and importable.

Seeing ModuleNotFoundError?

Check that (venv) appears in your terminal prompt. If it does not, activate your virtual environment again and retry.

If you see an error mentioning a missing module, run the full pip install command from the first substep again. One of the packages may not have installed completely.

help me fix my LlamaIndex import error

Your environment is ready. Next up, you'll write the code that loads your documents and builds a searchable index from them.

Load Documents and Build the Index

Your environment is locked in and your policy documents are sitting in the data folder. Now it's time to give the AI something to work with.

Before the assistant can answer policy questions, it needs to read your documents, break them into chunks, and store them as searchable vector embeddings. This is the indexing phase of RAG. In this step you'll see the first visible proof that the system works.

In this step, get ready to:
  • Create app.py and connect it to the Gemini API.
  • Load your policy documents and build a searchable vector index.
  • Run the script and confirm your documents are indexed.
Create app.py and configure the AI models

LlamaIndex needs two models configured globally: an LLM for generating answers and an embedding model for converting text into vectors. You'll point both at Google's Gemini API using the key you stored in .env.

  • In VS Code, create a new file called app.py in the root of your policy-assistant folder.
  • Add the following code to set up your imports and model configuration:
import os
from dotenv import load_dotenv
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.llms.google_genai import GoogleGenAI
from llama_index.embeddings.google_genai import GoogleGenAIEmbedding

# Load environment variables
load_dotenv()

# Configure LLM and embedding model
Settings.llm = GoogleGenAI(model="gemini-2.5-flash")
Settings.embed_model = GoogleGenAIEmbedding(model_name="gemini-embedding-exp-03-07")

What does this code do?

load_dotenv() reads your .env file and makes GOOGLE_API_KEY available to the LlamaIndex packages automatically.

Settings.llm tells LlamaIndex which model to use for generating text answers. Settings.embed_model tells it which model to use for converting document chunks into vector embeddings that can be searched.

Load documents and build the vector index

SimpleDirectoryReader reads all supported files from a folder automatically. It handles PDFs (via pypdf) and Word docs (via docx2txt) without extra configuration. VectorStoreIndex then chunks the text, generates embeddings for each chunk, and stores everything in memory for fast retrieval.

  • Add the following code below your model configuration in app.py:
# Load documents from the data folder
print("Loading documents...")
documents = SimpleDirectoryReader("./data", filename_as_id=True).load_data()
print(f"Loaded {len(documents)} documents")

# Build the vector index
print("Building index...")
index = VectorStoreIndex.from_documents(documents)
print("Index built successfully!")

What does this code do?

SimpleDirectoryReader("./data", filename_as_id=True) reads every PDF and Word file in your data folder. The filename_as_id=True parameter sets each document's unique ID to its file path, which makes source tracking easier later.

VectorStoreIndex.from_documents(documents) splits each document into chunks, sends them to the embedding model to generate vectors, and stores everything in an in-memory index. The print statements give you progress feedback so you know each stage completed.

  • Save app.py.
Run the script and verify your index

Your script is ready to load documents and build the index. Before you run it, think about what you expect to see in the terminal.

  • How many documents did you put in your data folder? Predict the number you expect to see printed.
  • Run your script with this command:
python app.py

You should see output like this:

Loading documents...
Loaded 10 documents
Building index...
Index built successfully!

The number after "Loaded" matches however many files you placed in your data folder. If you see "Index built successfully!" your documents are now chunked, embedded, and searchable.

Seeing an error?

  • If you see No files found or zero documents loaded, make sure your data folder contains at least one .pdf or .docx file.
  • If you see an authentication error mentioning your API key, double check that .env contains GOOGLE_API_KEY= followed by your actual key from Google AI Studio.
  • If you see a rate limit error, wait 60 seconds and try again. The free tier allows 10 requests per minute.

Help me debug my LlamaIndex document loading error

✔️ Awesome, I've got everything!

Great. Double check you've saved app.py and that your output shows the correct document count.

ⓧ I'd like to double check the full code

Here is the complete app.py at this point:

import os
from dotenv import load_dotenv
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.llms.google_genai import GoogleGenAI
from llama_index.embeddings.google_genai import GoogleGenAIEmbedding

# Load environment variables
load_dotenv()

# Configure LLM and embedding model
Settings.llm = GoogleGenAI(model="gemini-2.5-flash")
Settings.embed_model = GoogleGenAIEmbedding(model_name="gemini-embedding-exp-03-07")

# Load documents from the data folder
print("Loading documents...")
documents = SimpleDirectoryReader("./data", filename_as_id=True).load_data()
print(f"Loaded {len(documents)} documents")

# Build the vector index
print("Building index...")
index = VectorStoreIndex.from_documents(documents)
print("Index built successfully!")

Your documents are now chunked, embedded, and sitting in a searchable index. Next up, you'll query that index and see the AI answer a real policy question for the first time.

Ask Your First Policy Question

In the previous step you loaded your policy documents and built a searchable vector index. The index is ready to go, but right now it just sits there.

The whole point of a RAG pipeline is to ask questions in plain language and get answers grounded in your actual documents. In this step, you will query the index for the first time and discover what the default response looks like.

In this step, get ready to:
  • Create a query engine from the index and ask a test question about your policies.
  • Examine the response and notice what is missing from it.
  • Print the raw source nodes to confirm the retrieval is working behind the scenes.
Create a query engine and ask a test question

A query engine wraps your index with a retrieval and synthesis pipeline. When you ask a question, it finds the most relevant document chunks, sends them to Gemini as context, and returns a natural-language answer.

  • In app.py, find the line that says print("Index built successfully!").
  • Add the following code below it to create a query engine and ask your first policy question:
# Create a basic query engine and ask a test question
query_engine = index.as_query_engine(similarity_top_k=3)
test_question = "What is the policy on remote work?"
response = query_engine.query(test_question)
print(f"\nResponse: {response}")

What does this code do?

index.as_query_engine(similarity_top_k=3) creates a query engine that retrieves the 3 most relevant document chunks for each question. The higher the similarity_top_k value, the more context the LLM receives.

query_engine.query() sends your question through the full RAG pipeline: embed the question, retrieve matching chunks, pass them to Gemini, and synthesise a response.

Before you run this, think about what you expect the response to look like. Do you think it will clearly name which document the answer came from and quote the exact policy text?

  • Save app.py.
  • Run the script by running this command:
python app.py

You will see the document loading and index building output from before, followed by a response about remote work. The answer draws on your policy content, but look carefully at the formatting.

The response gives a reasonable answer, but it does not clearly state which file it came from. It does not quote the exact policy text verbatim either. That gap is intentional. The default query engine synthesises an answer but does not format citations for you.

Seeing an error instead of a response?

  • If you see an authentication error, double-check your .env file contains a valid GOOGLE_API_KEY value.
  • If you see a rate limit error, wait 60 seconds and try again. The free tier allows 10 requests per minute.
  • If you see a file-not-found error for the ./data folder, make sure the folder exists and contains at least one PDF or Word document.

Help me debug my query engine error

Print the source nodes to see what was retrieved

The response object contains the text chunks that were retrieved from your index. Printing them reveals what the retrieval layer found, confirming it is pulling from the right documents.

  • In app.py, add the following code below the print(f"\nResponse: {response}") line:
print("\nSource nodes:")
for node in response.source_nodes:
    print(f"  - {node.metadata.get('file_name', 'unknown')}: {node.text[:100]}...")

What does this code do?

response.source_nodes gives you the list of document chunks the engine retrieved. Each node has a metadata dictionary (containing the file name) and a text field (the actual chunk content).

This confirms the retrieval is working. The engine found the right chunks, but the final synthesised response above does not surface these details in a structured way. That is the limitation you will fix in the next step.

  • Save app.py and run the script again:
python app.py

Below the response, you now see a list of source nodes. Each line shows the file name and the first 100 characters of the retrieved chunk. The retrieval is pulling from the correct documents.

Source nodes showing 'unknown' for file names?

This means the metadata does not contain a file_name key. Check that your SimpleDirectoryReader call includes filename_as_id=True. This parameter attaches the filename as metadata to each document.

Help me fix my source node metadata

Double check the full code

✔️ Awesome, I've got everything!

Great. Make sure you have saved app.py before moving on.

ⓧ I'd like to double check the full code

Your app.py should contain these sections in order. Scroll up and confirm each one is present:

  • Imports and load_dotenv() call.
  • Settings configuration for the LLM and embedding model.
  • Document loading with SimpleDirectoryReader and the print statement showing document count.
  • Index building with VectorStoreIndex.from_documents(documents) and the success print.
  • Query engine creation with index.as_query_engine(similarity_top_k=3), the test question, and response print.
  • Source node loop printing file names and text previews.

You have confirmed that the retrieval works. The engine finds the right policy chunks and generates a reasonable answer. But a policy assistant needs to be verifiable. In the next step, you will add a custom prompt that forces the AI to cite the exact source document and quote the relevant passage.

Add Exact Policy Citations

In the last step, you queried your policy index and got a response grounded in your documents. But look at the output closely. The answer is reasonable, yet it does not clearly name which file the information came from or quote the exact policy language.

For a policy assistant, that is a deal-breaker. Users need to verify answers against the original document. A custom prompt template solves this by instructing Gemini to always cite the source filename and quote the relevant passage word for word.

In this step, get ready to:
  • Create a custom PromptTemplate with citation rules.
  • Configure the query engine to use the new prompt.
  • Test the same question and see structured citations in the response.
Create the citation prompt

The default query engine sends your question and the retrieved text chunks to Gemini, but it does not tell Gemini how to format the answer. You will replace the old query code with a PromptTemplate that gives Gemini explicit formatting rules.

  • In app.py, find the import line at the top of the file:
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
  • Add PromptTemplate to the end of that import so the line looks like this:
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings, PromptTemplate
  • Now scroll to the bottom of the file and find this entire section:
# Create a basic query engine and ask a test question
query_engine = index.as_query_engine(similarity_top_k=3)
test_question = "What is the policy on remote work?"
response = query_engine.query(test_question)
print(f"\nResponse: {response}")
print("\nSource nodes:")
for node in response.source_nodes:
    print(f"  - {node.metadata.get('file_name', 'unknown')}: {node.text[:100]}...")
  • Select that entire block (from # Create a basic query engine to the last line) and delete it.
  • In its place, paste this citation prompt:
# Custom citation prompt
citation_prompt = PromptTemplate(
    "You are a company policy assistant. Your job is to answer questions "
    "based ONLY on the provided context from internal policy documents.\n\n"
    "Rules:\n"
    "1. Always cite the source document filename.\n"
    "2. Always quote the exact relevant passage from the policy.\n"
    "3. If the context does not contain enough information to answer, say "
    "'I could not find a relevant policy for this question.'\n"
    "4. Format your answer as:\n"
    "   Answer: [yes/no/explanation]\n"
    "   Source: [filename]\n"
    "   Policy text: \"[exact quote from the document]\"\n\n"
    "Context information:\n"
    "---------------------\n"
    "{context_str}\n"
    "---------------------\n\n"
    "Question: {query_str}\n"
    "Answer: "
)

What does this prompt do?

This template wraps every query with explicit instructions for Gemini. The {context_str} placeholder is where LlamaIndex injects the retrieved document chunks. The {query_str} placeholder is where your question goes.

The rules force Gemini to always name the source file, quote the exact passage, and give a clear answer. Without these rules, the LLM often paraphrases and drops the source reference entirely.

Configure the query engine and test citations
  • Directly below your citation_prompt, add the new query engine and test question:
# Create query engine with citation prompt
query_engine = index.as_query_engine(
    similarity_top_k=3,
    text_qa_template=citation_prompt,
)

test_question = "What is the policy on remote work?"
response = query_engine.query(test_question)
print(f"\nResponse: {response}")

What changed from the old query engine?

The key addition is text_qa_template=citation_prompt. This tells LlamaIndex to use your custom prompt instead of its generic default whenever it sends context and a question to Gemini.

You also removed the source-nodes loop because the citation prompt now forces Gemini to include source info directly in the answer text.

  • Save app.py.

Before you run this, think about what you expect to see. Will the response look the same as last time, or will it be structured differently?

  • Run your script by entering this command in the terminal:
python app.py

This time the response follows your citation format. You should see output structured like:

Loading documents...
Loaded X documents
Building index...
Index built successfully!

Response: Answer: [explanation of the policy]
   Source: [one of your document filenames]
   Policy text: "[an exact quote from that document]"

Compare this to the unstructured answer you saw in the previous step. The response now names the exact file and quotes the policy language verbatim.

Response still looks unstructured?

  • Confirm you deleted the entire old query section. If any of the old query_engine = index.as_query_engine(similarity_top_k=3) line remains, Python may use it instead of your new code.
  • Check that text_qa_template=citation_prompt is inside the as_query_engine() call. A misplaced comma or missing argument means the default prompt runs.
  • Make sure PromptTemplate appears in your import line at the top of the file.

Still stuck? Help me debug why my citation prompt is not working

✔️ Awesome, I've got everything!

Great. Double check you have saved app.py and the citation format is appearing in your output.

ⓧ I'd like to double check the full code

Your app.py should now contain these sections in order. Scroll up and confirm each is present:

  • Imports (including PromptTemplate at the end of the core import line).
  • Environment loading and model configuration (Settings.llm and Settings.embed_model).
  • Document loading with SimpleDirectoryReader and the index build.
  • The citation_prompt variable containing your full PromptTemplate.
  • The query_engine with text_qa_template=citation_prompt, followed by the test question and print statement.

The old source_nodes loop should be gone entirely.

Your policy assistant now backs up every answer with a verifiable citation. Next up, you will turn this into an interactive chat loop so you can keep asking questions without restarting the script.

Build the Interactive Chat Loop

Your policy assistant now answers questions with proper citations, naming the source document and quoting the exact policy text.

But running the script for every single question is not practical for daily use. In this step, you'll replace the single test query with an interactive loop that lets you keep asking questions without restarting.

In this step, get ready to:
  • Replace the single test query with an interactive input loop.
  • Add a welcome message and clean exit commands.
  • Test the assistant with multiple policy questions in sequence.
Remove the test query

The hardcoded test question served its purpose in the last step. Now you need to clear it out so you can replace it with something dynamic.

  • In app.py, scroll to the bottom of the file and find these three lines:
test_question = "What is the policy on remote work?"
response = query_engine.query(test_question)
print(f"\nResponse: {response}")
  • Delete all three lines. Leave your cursor at the blank line after the query_engine definition.
Add the interactive chat loop

A while True loop keeps the program running until the user explicitly types a quit command. Each iteration prompts for a new question, sends it through the query engine, and prints the cited answer.

  • Add the following code at the bottom of app.py, right after the query_engine definition:
# Interactive chat loop
print("\n" + "=" * 50)
print("Company Policy Assistant")
print("=" * 50)
print("Ask any question about company policies.")
print("Type 'quit' or 'exit' to stop.\n")

while True:
    question = input("You: ").strip()
    if question.lower() in ("quit", "exit"):
        print("Goodbye!")
        break
    if not question:
        continue

    response = query_engine.query(question)
    print(f"\nAssistant: {response}\n")

What does this code do?

  • The print statements at the top create a clear welcome banner so the user knows the assistant is ready.
  • input("You: ").strip() waits for the user to type a question, then removes any leading or trailing whitespace.
  • The if question.lower() in ("quit", "exit") check gives users two ways to exit cleanly instead of forcing a keyboard interrupt.
  • if not question: continue skips empty input so hitting Enter without typing anything does not trigger an API call.
  • Save app.py.

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on to the test.

ⓧ I'd like to double check the full code

Your app.py is longer than 30 lines, so scroll through and confirm these sections are present in order:

  • Imports and load_dotenv() at the top.
  • Settings.llm and Settings.embed_model configuration.
  • SimpleDirectoryReader loading documents and VectorStoreIndex.from_documents() building the index.
  • The citation_prompt PromptTemplate definition.
  • The query_engine created with text_qa_template=citation_prompt.
  • The interactive chat loop with welcome banner, while True, quit/exit handling, and query_engine.query(question).
  • No leftover test_question lines at the bottom.

Seeing a SyntaxError or IndentationError?

  • Make sure you deleted all three lines of the old test query. A leftover test_question variable above the loop can cause unexpected behavior.
  • Check that the while True: block and everything inside it is indented consistently with 4 spaces per level.

Help me fix a SyntaxError in my interactive loop code.

Test the assistant with multiple questions

Time to see if the loop actually works. You should be able to ask several questions in a row without the script stopping between them.

Before you run this, think about what you expect to see first. Will the script print something before waiting for your input, or will it just show a blank cursor?

  • Run the assistant by entering this command in your terminal:
python app.py

After the documents load and the index builds, you'll see the welcome banner followed by a You: prompt waiting for your input.

  • Type a question about one of your policy documents and press Enter. For example, ask about remote work, software installation, or any topic your documents cover.
  • After seeing the cited answer, type a second question about a different policy topic.
  • Ask a third question to confirm the assistant retrieves from different source documents depending on the topic.
  • Type quit and press Enter.

The program prints Goodbye! and exits cleanly back to your terminal prompt.

What should I see?

Each answer should include the source document filename and a quoted passage from the policy text. Different questions about different topics should cite different source files, confirming the retrieval is actually searching across your documents.

Getting a rate limit error?

The Gemini free tier has a limit of 10 requests per minute. If you ask questions too quickly in sequence, wait a few seconds between each question.

Help me troubleshoot a Gemini API rate limit error in my LlamaIndex app.

Your policy assistant is now a real tool you can use every day. Open it up, ask as many questions as you need, and close it when you're done. Next up, the Secret Mission challenges you to add document filtering so you can target queries at specific policies.

Secret mission

Add Document Filtering

When you have 10+ documents covering different topics (IT, HR, Finance), sometimes you want to search only within a specific policy area. In this secret mission, you'll add metadata tagging and a filter prefix so you can target your queries at specific documents for more precise results.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally and uses the Gemini API free tier, so there are no ongoing costs.

Resources you used:

  • The policy-assistant project folder on your Desktop (containing app.py, .env, data/, and your virtual environment).
  • A Google AI Studio API key (free tier, no charges).

Keep everything running

No action needed. Choose this if you're still actively building or want to keep asking policy questions.

  • Your project folder stays on your Desktop, ready to run anytime.
  • The vector index is rebuilt in memory each time you run app.py. There is nothing stored persistently between runs.
  • Your Gemini API key remains active on the free tier at zero cost.

Pause - I'll come back to this later

Shut down any running processes to free up your terminal. Your files stay intact for when you return.

  • If the assistant is still running in your terminal, type quit to exit.
  • Deactivate your virtual environment by running:
deactivate
  • Everything else stays as-is. When you come back, reactivate the virtual environment and run python app.py to pick up where you left off.

Delete - I don't want to use this again

Remove all project files from your machine and optionally revoke your API key.

  • If the assistant is still running, type quit to exit.
  • Deactivate your virtual environment by running:
deactivate
  • Delete the entire project folder by running:

macOS

cd ~/Desktop
rm -rf policy-assistant

Windows

cd ~\Desktop
rmdir /s /q policy-assistant
  • To delete your API key, go to Google AI Studio, open the API keys page, find the key you created for this project, and click the trash icon to revoke it.

That's a Wrap!

That's a Wrap!

Nice work! You just built a fully functional RAG-powered policy assistant that reads your real company documents, retrieves the relevant sections, and answers questions with verifiable citations.

You've learned how to:

  • Build a RAG pipeline that loads PDF and Word documents, chunks them, and creates a searchable vector index.
  • Connect LlamaIndex to the Gemini API for both embeddings and text generation at zero cost.
  • Engineer a citation prompt that forces the AI to quote exact policy text and name the source document.
  • Create an interactive terminal assistant for daily policy lookups.
  • Secret Mission: Added metadata filtering to target queries at specific documents.

Ready to quiz yourself?