{"id":2527,"date":"2026-09-11T04:17:06","date_gmt":"2026-09-11T04:17:06","guid":{"rendered":"https:\/\/hackmybox.com\/?p=2527"},"modified":"2026-09-11T13:27:36","modified_gmt":"2026-09-11T13:27:36","slug":"visual-composer-2527","status":"publish","type":"post","link":"https:\/\/hackmybox.com\/index.php\/2026\/09\/11\/visual-composer-2527\/","title":{"rendered":"Project RAG System"},"content":{"rendered":"<div class=\"vce-row-container\" data-vce-boxed-width=\"true\"><div class=\"vce-row vce-row--col-gap-30 vce-row-equal-height vce-row-content--top\" id=\"el-21bb39a1\" data-vce-do-apply=\"all el-21bb39a1\"><div class=\"vce-row-content\" data-vce-element-content=\"true\"><div class=\"vce-col vce-col--md-auto vce-col--xs-1 vce-col--xs-last vce-col--xs-first vce-col--sm-last vce-col--sm-first vce-col--md-last vce-col--lg-last vce-col--xl-last vce-col--md-first vce-col--lg-first vce-col--xl-first\" id=\"el-c9c5aede\"><div class=\"vce-col-inner\" data-vce-do-apply=\"border margin background  el-c9c5aede\"><div class=\"vce-col-content\" data-vce-element-content=\"true\" data-vce-do-apply=\"padding el-c9c5aede\"><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-f42d56ba\" data-vce-do-apply=\"all el-f42d56ba\"><h2>Introduction<\/h2><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-481cd1b8\" data-vce-do-apply=\"all el-481cd1b8\"><p>This project demonstrates the practical application of LangChain, Retrieval-Augmented Generation (RAG), vector search, embeddings, and locally hosted Large Language Models (LLMs) to build an AI-powered helpdesk assistant for iManage.<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-5348a7aa\" data-vce-do-apply=\"all el-5348a7aa\"><h2>Objective<\/h2><p>The goal is to create a local conversational assistant that can answer iManage-related questions using information retrieved directly from an iManage knowledge base. This approach helps produce responses that are more relevant, traceable and&nbsp; in official documentation.<\/p><\/div><\/div><div class=\"vce-single-image-container vce-single-image--align-left\"><div class=\"vce vce-single-image-wrapper\" id=\"el-6398934b\" data-vce-do-apply=\"all el-6398934b\"><figure><div class=\"vce-single-image-figure-inner\" style=\"width: 1024px;\"><div class=\"vce-single-image-inner vce-single-image--absolute\" style=\"width: 100%; padding-bottom: 75.3906%;\"><img loading=\"lazy\" decoding=\"async\" class=\"vce-single-image\"  width=\"1024\" height=\"772\" srcset=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/imanage-1024x773.png 1024w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/imanage-320x242.png 320w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/imanage-480x362.png 480w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/imanage-800x604.png 800w\" src=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/imanage-1024x773.png\" data-img-src=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/imanage.png\" data-attachment-id=\"2567\"  alt=\"\" title=\"imanage\" \/><\/div><\/div><figcaption hidden=\"\"><\/figcaption><\/figure><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-ff6dc3ea\" data-vce-do-apply=\"all el-ff6dc3ea\"><p>Source : https:\/\/docs.imanage.com\/work-web-help\/10.5.3\/en-US\/iManage_Work_Help.html<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-d26b29a3\" data-vce-do-apply=\"all el-d26b29a3\"><h2>RAG Workflow<\/h2><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-f3a93d37\" data-vce-do-apply=\"all el-f3a93d37\"><p>1. Knowledge-base extraction -&nbsp; iManage help and knowledge-base content is collected and stored as plain-text documents.<\/p><p>2. Document loading and processing - The extracted text files are loaded into LangChain Document objects along with source metadata.<\/p><p>3. Text chunking - Large documents are divided into smaller overlapping chunks to improve retrieval accuracy.<\/p><p>4. Embedding generation -&nbsp; Each chunk is converted into a numerical vector using the local nomic-embed-text embedding model through Ollama.<\/p><p>5. Vector storage and retrieval -&nbsp; The embeddings are stored in an in-memory vector store, which allows the system to find content semantically related to a user's question.<\/p><p>6. Context-aware generation -&nbsp; The most relevant chunks are provided to the Gemma 4 LLM as context.<\/p><p>7. Grounded responses&nbsp; &nbsp;- The LLM generates an answer based only on the retrieved knowledge-base content and includes the source filename when applicable.<\/p><p>8. Interactive assistant -&nbsp; The complete pipeline is exposed through an interactive command-line chatbot where users can ask questions continuously.<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-42ffdafb\" data-vce-do-apply=\"all el-42ffdafb\"><h2>Technology Stack<\/h2><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-2e7c2ccf\" data-vce-do-apply=\"all el-2e7c2ccf\"><p>The project uses the following technologies:<\/p><p>LangChain - Orchestrates document processing, retrieval, tools, and the AI agent.<\/p><p>Ollama - Runs the LLM and embedding models locally.<\/p><p>Gemma 4 - Provides the language-model capabilities for generating responses.<\/p><p>nomic-embed-text&nbsp; -Converts knowledge-base text into embeddings for semantic search.<\/p><p>InMemoryVectorStore - Stores document embeddings and enables similarity-based retrieval.<\/p><p>Python -&nbsp; Provides the overall application and processing logic.<\/p><p>python-dotenv -&nbsp; Manages environment configuration.<\/p><p>Colorama - Provides readable colored output in the notebook\/terminal.<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-7b2ac6a9\" data-vce-do-apply=\"all el-7b2ac6a9\"><p><span style=\"color: #ffff00;\">1. Install required packages<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-21135301\" data-vce-do-apply=\"all el-21135301\"><p># ============================================================<br># Install packages<br># ============================================================<br>!pip install -U langchain-ollama langchain-chroma langchain-community colorama python-dotenv langchain-text-splitters<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-3f8ff84a\" data-vce-do-apply=\"all el-3f8ff84a\"><table><thead><tr><th>Package<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td>langchain-ollama<\/td><td>Connects LangChain to your local Ollama models<\/td><\/tr><tr><td>langchain-chroma<\/td><td>Lets LangChain use Chroma vector database<\/td><\/tr><tr><td>langchain-community<\/td><td>Provides additional LangChain integrations\/loaders<\/td><\/tr><tr><td>colorama<\/td><td>Adds colored terminal\/Jupyter output<\/td><\/tr><tr><td>python-dotenv<\/td><td>Loads settings\/API keys from a .env file<\/td><\/tr><tr><td>langchain-text-splitters<\/td><td>Splits your iManage documents into chunks<\/td><\/tr><\/tbody><\/table><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-5e0a0cac\" data-vce-do-apply=\"all el-5e0a0cac\"><p><span style=\"color: #ffff00;\">2. This cell is your environment and Ollama connection setup. It imports the required libraries, enables colored output, hides common warnings, loads .env settings, then connects to your local Ollama server and prints the models currently available.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-bda22604\" data-vce-do-apply=\"all el-bda22604\"><p># ============================================================<br># Environment setup<br># ============================================================<br>import os<br>import warnings<br>from getpass import getpass<br>from dotenv import load_dotenv<br>from colorama import Fore, Style, init<\/p><p># Initialize colorama<br>init(autoreset=True)<\/p><p># Suppress warnings<br>warnings.filterwarnings(\"ignore\", category=DeprecationWarning)<br>warnings.filterwarnings(\"ignore\", category=UserWarning)<\/p><p># Load environment variables from .env file<br>load_dotenv(override=True)<\/p><p># Check connection to local Ollama<br>import ollama<br>models = ollama.list()<br>print(f\"{Fore.GREEN}Ollama connected.{Style.RESET_ALL}\")<br>print(f\"{Fore.CYAN}Available models:{Style.RESET_ALL}\")<br>for model in models[\"models\"]:<br>print(f\" - {model['model']}\")<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-6a38b169\" data-vce-do-apply=\"all el-6a38b169\"><p><span style=\"color: #ffff00;\">3. This cell initializes&nbsp; LLM (Large Language Model) Gemma 4 running locally through Ollama.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-96704e0a\" data-vce-do-apply=\"all el-96704e0a\"><p># ============================================================<br># Initialize LLM<br># ============================================================<br>from langchain.chat_models import init_chat_model<br>model = init_chat_model(<br>\"gemma4:latest\",<br>model_provider=\"ollama\",<br>temperature=0,<br>timeout=30,<br>max_retries=3,<br>)<br><br><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-f8aa40fc\" data-vce-do-apply=\"all el-f8aa40fc\"><p><span style=\"color: #3366ff;\">#note : temperature=0 \u2192 makes responses more consistent and less creative.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-adde766a\" data-vce-do-apply=\"all el-adde766a\"><p><span style=\"color: #ffff00;\">4. This cell creates the folder where your iManage knowledge-base documents are stored.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-a801444e\" data-vce-do-apply=\"all el-a801444e\"><p># ============================================================<br># Setup data directory<br># ============================================================<br>from pathlib import Path<br>DATA_DIR = Path(\".\/data\/imanage\/\")<br>DATA_DIR.mkdir(parents=True, exist_ok=True)<br>print(f\"{Fore.GREEN}Data directory: {DATA_DIR.resolve()}{Style.RESET_ALL}\")<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-4ec86e57\" data-vce-do-apply=\"all el-4ec86e57\"><p><span style=\"color: #ffff00;\">5. This code loads all .txt iManage knowledge-base files into LangChain Document objects, storing the file content in page_content and the filename\/path in metadata. It also checks that the data directory exists and that at least one .txt file was found before continuing.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-6a50a046\" data-vce-do-apply=\"all el-6a50a046\"><p># ============================================================<br># Load extracted imanage kb as LangChain Documents<br># ============================================================<br>from langchain_core.documents import Document<\/p><p>def load_text_documents(directory: Path) -&gt; list[Document]:<br>&nbsp; &nbsp; &nbsp;\"\"\"Load every .txt file as a LangChain Document.\"\"\"<\/p><p>if not directory.exists():<br>&nbsp; &nbsp; &nbsp;raise FileNotFoundError(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f\"Data directory not found: {directory.resolve()}\"<br>)<\/p><p>documents: list[Document] = []<\/p><p>for file_path in directory.glob(\"*.txt\"):<br>&nbsp; &nbsp; &nbsp;text = file_path.read_text(encoding=\"utf-8\")<br>&nbsp; &nbsp; &nbsp;documents.append(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Document(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;page_content=text,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;metadata={<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\"source\": file_path.name,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\"file_path\": str(file_path),<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;},<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )<br>&nbsp; &nbsp; )<\/p><p>if not documents:<br>&nbsp; &nbsp; &nbsp;raise ValueError(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f\"No .txt files were found in {directory.resolve()}\"<br>&nbsp; &nbsp; &nbsp;)<\/p><p>return documents<\/p><p>documents = load_text_documents(DATA_DIR)<\/p><p>print(f\"{Fore.GREEN}Documents loaded: {len(documents)}{Style.RESET_ALL}\")<br>for doc in documents:<br>&nbsp; &nbsp; &nbsp;print(f\" - {doc.metadata['source']} ({len(doc.page_content):,} chars)\")<\/p><\/div><\/div><div class=\"vce-single-image-container vce-single-image--align-left\"><div class=\"vce vce-single-image-wrapper\" id=\"el-8f74d705\" data-vce-do-apply=\"all el-8f74d705\"><figure><div class=\"vce-single-image-figure-inner\" style=\"width: 1024px;\"><div class=\"vce-single-image-inner vce-single-image--absolute\" style=\"width: 100%; padding-bottom: 11.2305%;\"><img loading=\"lazy\" decoding=\"async\" class=\"vce-single-image\"  width=\"1024\" height=\"115\" srcset=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/step5-1024x115.png 1024w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/step5-320x36.png 320w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/step5-480x54.png 480w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/step5-800x90.png 800w\" src=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/step5-1024x115.png\" data-img-src=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/step5.png\" data-attachment-id=\"2556\"  alt=\"\" title=\"step5\" \/><\/div><\/div><figcaption hidden=\"\"><\/figcaption><\/figure><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-d84f7202\" data-vce-do-apply=\"all el-d84f7202\"><p><span style=\"color: #ffff00;\">6. This code splits the loaded iManage documents into 350-character chunks with 60-character overlap, then uses Ollama\u2019s nomic-embed-text model to convert each chunk into embeddings and stores them in an in-memory vector store for similarity search. It then creates a retriever that returns the top 4 most relevant chunks for each user question, and prints basic information about the documents and chunks.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-7a9ad987\" data-vce-do-apply=\"all el-7a9ad987\"><p># ============================================================<br># Split documents and create vector store<br># ============================================================<br>from langchain_core.vectorstores import InMemoryVectorStore<br>from langchain_ollama import OllamaEmbeddings<br>from langchain_text_splitters import RecursiveCharacterTextSplitter<br># Split documents into chunks<br>splitter = RecursiveCharacterTextSplitter(<br>chunk_size=350,<br>chunk_overlap=60,<br>)<br>chunks = splitter.split_documents(documents)<\/p><p># Initialize embeddings using Ollama<br>embeddings = OllamaEmbeddings(<br>model=\"nomic-embed-text\",<br>base_url=\"http:\/\/localhost:11434\",<br>)<\/p><p># Create vector store<br>vector_store = InMemoryVectorStore(embedding=embeddings)<br>vector_store.add_documents(chunks)<\/p><p># Create retriever<br>retriever = vector_store.as_retriever(<br>search_kwargs={\"k\": 4}<br>)<\/p><p>print(f\"{Fore.GREEN}Documents: {len(documents)}{Style.RESET_ALL}\")<br>print(f\"{Fore.GREEN}Chunks: {len(chunks)}{Style.RESET_ALL}\")<br>print(f\"{Fore.CYAN}Sample metadata: {chunks[0].metadata}{Style.RESET_ALL}\")<br>print(f\"{Fore.CYAN}Preview: {chunks[0].page_content[:200]}...{Style.RESET_ALL}\")<\/p><\/div><\/div><div class=\"vce-single-image-container vce-single-image--align-left\"><div class=\"vce vce-single-image-wrapper\" id=\"el-7c608755\" data-vce-do-apply=\"all el-7c608755\"><figure><div class=\"vce-single-image-figure-inner\" style=\"width: 1024px;\"><div class=\"vce-single-image-inner vce-single-image--absolute\" style=\"width: 100%; padding-bottom: 18.457%;\"><img loading=\"lazy\" decoding=\"async\" class=\"vce-single-image\"  width=\"1024\" height=\"189\" srcset=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/Doc6-1024x190.png 1024w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/Doc6-320x59.png 320w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/Doc6-480x89.png 480w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/Doc6-800x148.png 800w\" src=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/Doc6-1024x190.png\" data-img-src=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/Doc6.png\" data-attachment-id=\"2560\"  alt=\"\" title=\"Doc6\" \/><\/div><\/div><figcaption hidden=\"\"><\/figcaption><\/figure><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-6cc70267\" data-vce-do-apply=\"all el-6cc70267\"><p><span style=\"color: #ffff00;\">7. This system prompt controls how Gemma 4 behaves as your iManage Helpdesk Assistant. It tells the model to answer only from retrieved RAG context, cite the source filename, avoid making up information, and provide clear support-style answers.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-7a9c056a\" data-vce-do-apply=\"all el-7a9c056a\"><p class=\"PDq2pG_selectionAnchorContainer\" data-start=\"422\" data-end=\"457\">The two important placeholders are:<\/p><p>{context} - the chunks retrieved from your vector store.<\/p><p>{question}&nbsp; -the user's actual question.<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-3f68d7cc\" data-vce-do-apply=\"all el-3f68d7cc\"><p># ============================================================<br># System prompt - iManage Helpdesk Assistant<br># ============================================================<br>prompt = \"\"\"You are a friendly and knowledgeable Helpdesk Support Specialist for the iManage document management system.<\/p><p>Your role is to help users resolve issues, answer questions, and guide them through iManage features using ONLY the information provided in the retrieved context.<\/p><p>Guidelines:<br>- Always be patient, professional, and supportive in tone.<br>- Base every answer strictly on the retrieved context from the iManage knowledge base.<br>- Cite the source filename in square brackets when you use information from it.<br>- If the answer is not found in the retrieved context, say so honestly and suggest the user contact iManage support or check official documentation ,<br>visithttps:\/\/docs.imanage.com\/work-web-help\/10.5.3\/en-US\/iManage_Work_Help.html<br>- Do not invent steps, features, or facts that are not in the context.<br>- Keep answers clear, practical, and focused on the user's question.<br>- Use numbered steps when explaining a procedure.<\/p><p>Retrieved context:<br>{context}<\/p><p>User question:<br>{question}<\/p><p>Your helpful response:\"\"\"<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-f7d5b303\" data-vce-do-apply=\"all el-f7d5b303\"><p><span style=\"color: #ffff00;\">8. This function takes the chunks retrieved by your RAG and formats them into text that can be given to the LLM. It adds the source filename so Gemma 4 can understand where the information came from and cite it in the final answer.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-0b0916d3\" data-vce-do-apply=\"all el-0b0916d3\"><p># ============================================================<br># Format retrieved documents with filename labels<br># ============================================================<br>def format_documents(docs: list[Document]) -&gt; str:<br>&nbsp; &nbsp; &nbsp;\"\"\"Format retrieved documents with filename labels.\"\"\"<\/p><p>&nbsp; &nbsp; &nbsp;if not docs:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return \"No relevant context was retrieved.\"<\/p><p>&nbsp; &nbsp; &nbsp;formatted = []<\/p><p>&nbsp; &nbsp; &nbsp;for position, doc in enumerate(docs, start=1):<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; source = doc.metadata.get(\"source\", \"unknown\")<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; formatted.append(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f\"[Document {position}: {source}]\\n\"<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f\"{doc.page_content}\"<br>)<\/p><p>return \"\\n\\n\".join(formatted)<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-881a71b0\" data-vce-do-apply=\"all el-881a71b0\"><p><span style=\"color: #ffff00;\">9. This code creates a search tool that connects your RAG retriever to the LangChain agent. When the agent receives a question, it can call this tool to search the vector store, retrieve the most relevant chunks, and return their content and source information to the LLM.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-b4aeca3a\" data-vce-do-apply=\"all el-b4aeca3a\"><p># ============================================================<br># Create search tool<br># ============================================================<br>from langchain.tools import tool<br>@tool<\/p><p><br>def search_knowledge_base(query: str) -&gt; str:<br>&nbsp; &nbsp; &nbsp;\"\"\"Search the knowledge base for relevant documents and return their content.\"\"\"<\/p><p><br>&nbsp; &nbsp; retrieved_documents = retriever.invoke(query)<\/p><p>&nbsp; &nbsp; &nbsp;if not retrieved_documents:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return \"No relevant documents were found.\"<\/p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return format_documents(retrieved_documents)<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-1733da01\" data-vce-do-apply=\"all el-1733da01\"><p><span style=\"color: #ffff00;\">10.&nbsp; This code creates the LangChain agent that brings your RAG components together. It gives the agent the Gemma 4 model, your search_knowledge_base tool, and the system prompt, allowing it to decide when to search the iManage knowledge base and then generate a grounded answer.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-4c0b0afb\" data-vce-do-apply=\"all el-4c0b0afb\"><p># ============================================================<br># Create agent<br># ============================================================<br>from langchain.agents import create_agent<\/p><p>agent = create_agent(<br>model=model,<br>tools=[search_knowledge_base],<br>system_prompt=prompt,<\/p><p>)<br>print(f\"{Fore.GREEN}Agent created successfully{Style.RESET_ALL}\")<br>Agent created successfully<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-fc8cd20b\" data-vce-do-apply=\"all el-fc8cd20b\"><p><span style=\"color: #ffff00;\">11. This cell defines five test questions that you will send to your iManage RAG agent. Each question is stored as a separate item in the questions list, which your loop will process one by one to test how well the RAG retrieves information and generates answers.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-cb5364a2\" data-vce-do-apply=\"all el-cb5364a2\"><p># ============================================================<br># Test questions - iManage knowledge base<br># ============================================================<br>questions = [<br>\"Why is my document checked out or locked?\",<br>\"How do I find or share an email in iManage?\",<br>\"How do I send a secure link to an external user?\",<br>\"How do I search for a document in iManage?\",<br>\"Can't access a document in iManage?\",<br>]<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-6d54335a\" data-vce-do-apply=\"all el-6d54335a\"><p><span style=\"color: #ffff00;\">12. This code runs all five test questions automatically instead of testing only one question at a time.&nbsp;For each question, it sends the question to your agent, gets the final answer, and prints the question and answer clearly in the notebook.&nbsp;<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-14e028fb\" data-vce-do-apply=\"all el-14e028fb\"><p># ============================================================<br># Run all test questions<br># ============================================================<br>for question in questions:<br>result = agent.invoke(<br>{\"messages\": [{\"role\": \"user\", \"content\": question}]},<br>)<br>answer = result[\"messages\"][-1].content<br>print(f\"{Fore.CYAN}Question: {question}{Style.RESET_ALL}\")<br>print(f\"{Fore.GREEN}Answer:{Style.RESET_ALL}\")<br>print(\"-\" * 70)<br>print(answer)<br>print(\"-\" * 70)<br>print()<\/p><\/div><\/div><div class=\"vce-single-image-container vce-single-image--align-left\"><div class=\"vce vce-single-image-wrapper\" id=\"el-3acf9d32\" data-vce-do-apply=\"all el-3acf9d32\"><figure><div class=\"vce-single-image-figure-inner\" style=\"width: 1024px;\"><div class=\"vce-single-image-inner vce-single-image--absolute\" style=\"width: 100%; padding-bottom: 81.4453%;\"><img loading=\"lazy\" decoding=\"async\" class=\"vce-single-image\"  width=\"1024\" height=\"834\" srcset=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/QA-test-1024x834.png 1024w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/QA-test-320x261.png 320w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/QA-test-480x391.png 480w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/QA-test-800x652.png 800w\" src=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/QA-test-1024x834.png\" data-img-src=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/QA-test.png\" data-attachment-id=\"2559\"  alt=\"\" title=\"QA test\" \/><\/div><\/div><figcaption hidden=\"\"><\/figcaption><\/figure><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-0a09d2f7\" data-vce-do-apply=\"all el-0a09d2f7\"><p><span style=\"color: #ffff00;\">13. This function turns your RAG into an interactive iManage Helpdesk chatbot. Instead of using a fixed list of questions, the user can type questions continuously, the agent searches the knowledge base and returns an answer, and typing quit, exit, or q ends the session.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-099fcac2\" data-vce-do-apply=\"all el-099fcac2\"><p># ============================================================<br># Interactive Q&amp;A function<br># ============================================================<br>def ask_questions(agent) -&gt; None:<br>\"\"\"Interactive Q&amp;A session with the iManage helpdesk agent.\"\"\"<\/p><p>&nbsp; &nbsp; &nbsp;print(\"\\n\" + \"=\" * 70)<br>&nbsp; &nbsp; &nbsp;print(f\"{Fore.CYAN}iManage Helpdesk Assistant - Ready{Style.RESET_ALL}\")<br>&nbsp; &nbsp; &nbsp;print(f\"{Fore.YELLOW}Ask questions about iManage features and workflows{Style.RESET_ALL}\")<br>&nbsp; &nbsp; &nbsp;print(\"Type 'quit' or 'exit' to stop\")<br>&nbsp; &nbsp; &nbsp;print(\"=\" * 70 + \"\\n\")<\/p><p>&nbsp; &nbsp; question_count = 0<\/p><p>&nbsp; &nbsp; while True:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;question = input(f\"{Fore.CYAN}Question {question_count + 1}: {Style.RESET_ALL}\")<\/p><p>&nbsp; &nbsp; &nbsp;# Exit commands<br>&nbsp; &nbsp; &nbsp;if question.lower() in ['quit', 'exit', 'q']:<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(f\"\\n{Fore.YELLOW}Goodbye!&nbsp; {Style.RESET_ALL}\")<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break<\/p><p># Skip empty input<br>if not question.strip():<br>&nbsp; &nbsp; &nbsp;print(f\"{Fore.YELLOW}Please enter a question.{Style.RESET_ALL}\")<br>&nbsp; &nbsp; &nbsp;continue<\/p><p>try:<br>&nbsp; &nbsp; &nbsp;print(f\"{Fore.YELLOW}Searching knowledge base...{Style.RESET_ALL}\")<br>&nbsp; &nbsp; &nbsp;result = agent.invoke(<br>{\"messages\": [{\"role\": \"user\", \"content\": question}]},<br>)<br>&nbsp; &nbsp; &nbsp;answer = result[\"messages\"][-1].content<\/p><p>&nbsp; &nbsp; question_count += 1<\/p><p>&nbsp; &nbsp; print(f\"\\n{Fore.GREEN}Answer:{Style.RESET_ALL}\")<br>&nbsp; &nbsp;print(\"-\" * 70)<br>&nbsp; &nbsp;print(answer)<br>&nbsp; &nbsp;print(\"-\" * 70)<br>&nbsp; &nbsp;print(\"\\n\" + \"-\" * 70 + \"\\n\")<\/p><p>except Exception as e:<br>&nbsp; &nbsp; print(f\"{Fore.RED}Error: {e}{Style.RESET_ALL}\")<\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-74463d53\" data-vce-do-apply=\"all el-74463d53\"><p><span style=\"color: #ffff00;\">14. Lastly launch RAG Helpdesk Assistant.<\/span><\/p><\/div><\/div><div class=\"vce-text-block\"><div class=\"vce-text-block-wrapper vce\" id=\"el-e4b7dde0\" data-vce-do-apply=\"all el-e4b7dde0\"><p># ============================================================<br># Run interactive Q&amp;A session<br># ============================================================<br>ask_questions(agent)<\/p><\/div><\/div><div class=\"vce-single-image-container vce-single-image--align-left\"><div class=\"vce vce-single-image-wrapper\" id=\"el-a4842ea3\" data-vce-do-apply=\"all el-a4842ea3\"><figure><div class=\"vce-single-image-figure-inner\" style=\"width: 1024px;\"><div class=\"vce-single-image-inner vce-single-image--absolute\" style=\"width: 100%; padding-bottom: 72.2656%;\"><img loading=\"lazy\" decoding=\"async\" class=\"vce-single-image\"  width=\"1024\" height=\"740\" srcset=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/live-1024x740.png 1024w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/live-320x231.png 320w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/live-480x347.png 480w, https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/live-800x578.png 800w\" src=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/live-1024x740.png\" data-img-src=\"https:\/\/hackmybox.com\/wp-content\/uploads\/2026\/09\/live.png\" data-attachment-id=\"2562\"  alt=\"\" title=\"live\" \/><\/div><\/div><figcaption hidden=\"\"><\/figcaption><\/figure><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>IntroductionThis project demonstrates the practical application of LangChain, Retrieval-Augmented Generation (RAG), vector search, embeddings, and locally hosted Large Language Models (LLMs) to build an AI-powered helpdesk assistant for iManage.ObjectiveThe goal is to create a local conversational assistant that can answer iManage-related questions using information retrieved directly from an iManage knowledge base. This approach helps produce [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2577,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"site-container-style":"default","site-container-layout":"default","site-sidebar-layout":"default","site-transparent-header":"default","prose-style":"enable","disable-article-header":"default","disable-site-header":"default","disable-site-footer":"default","disable-content-area-spacing":"default","footnotes":""},"categories":[12],"tags":[],"class_list":["post-2527","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-labs"],"_links":{"self":[{"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/posts\/2527","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/comments?post=2527"}],"version-history":[{"count":45,"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/posts\/2527\/revisions"}],"predecessor-version":[{"id":2581,"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/posts\/2527\/revisions\/2581"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/media\/2577"}],"wp:attachment":[{"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/media?parent=2527"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/categories?post=2527"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hackmybox.com\/index.php\/wp-json\/wp\/v2\/tags?post=2527"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}