<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: NEBULA DATA</title>
    <description>The latest articles on Forem by NEBULA DATA (@nebuladata).</description>
    <link>https://forem.com/nebuladata</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3683442%2F3ce981e2-3e06-47e0-ac57-c7ec69ac6df2.png</url>
      <title>Forem: NEBULA DATA</title>
      <link>https://forem.com/nebuladata</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nebuladata"/>
    <language>en</language>
    <item>
      <title>Specialized chatbot using RAG</title>
      <dc:creator>NEBULA DATA</dc:creator>
      <pubDate>Mon, 09 Mar 2026 08:25:01 +0000</pubDate>
      <link>https://forem.com/nebuladata/specialized-chatbot-using-rag-4n59</link>
      <guid>https://forem.com/nebuladata/specialized-chatbot-using-rag-4n59</guid>
      <description>&lt;h1&gt;
  
  
  Specialized Chatbot using RAG (Retrieval-Augmented Generation) — Part II
&lt;/h1&gt;

&lt;p&gt;In the previous episode, we already discussed the concept of &lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt; and prepared our &lt;strong&gt;project structure, requirements, and source data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now we are moving to the &lt;strong&gt;most important step of the RAG pipeline&lt;/strong&gt;, which is &lt;strong&gt;ingesting our knowledge source into the vector database&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This process includes several stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reading the PDF&lt;/li&gt;
&lt;li&gt;Splitting the document into chunks&lt;/li&gt;
&lt;li&gt;Creating embeddings&lt;/li&gt;
&lt;li&gt;Storing them inside ChromaDB&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once this process is completed, our chatbot will have a &lt;strong&gt;searchable knowledge base&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Later, when a user asks a question, our system will retrieve the &lt;strong&gt;most relevant parts of the document&lt;/strong&gt; and use them as context for the model.&lt;/p&gt;

&lt;h1&gt;
  
  
  Understanding the Ingestion Pipeline
&lt;/h1&gt;

&lt;p&gt;Before jumping into the code, let's understand the overall workflow.&lt;/p&gt;

&lt;p&gt;Our program will perform the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load the PDF document
&lt;/li&gt;
&lt;li&gt;Extract text from the PDF
&lt;/li&gt;
&lt;li&gt;Split the text into smaller chunks
&lt;/li&gt;
&lt;li&gt;Convert each chunk into embeddings
&lt;/li&gt;
&lt;li&gt;Store the embeddings and text into ChromaDB
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result will be a &lt;strong&gt;vector database&lt;/strong&gt; that represents the entire &lt;strong&gt;BCA Annual Report&lt;/strong&gt; in semantic form.&lt;/p&gt;

&lt;h1&gt;
  
  
  Importing Required Libraries
&lt;/h1&gt;

&lt;p&gt;First, we import all the libraries used in our program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;chromadb&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pypdf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PdfReader&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;

&lt;h3&gt;
  
  
  Explanation of Each Library
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;os&lt;/strong&gt;&lt;br&gt;
Used to interact with our system environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;chromadb&lt;/strong&gt;&lt;br&gt;
Our vector database that will store embeddings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pypdf&lt;/strong&gt;&lt;br&gt;
Used to read and extract text from PDF documents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAI client (Nebula API)&lt;/strong&gt;&lt;br&gt;
Used to generate embeddings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dotenv&lt;/strong&gt;&lt;br&gt;
Used to securely load our API key from the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;h1&gt;
  
  
  Loading Environment Variables
&lt;/h1&gt;

&lt;p&gt;Next, we load the environment variables.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;python&lt;br&gt;
load_dotenv()&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This allows our program to read the &lt;strong&gt;NEBULA_API_KEY&lt;/strong&gt; stored inside the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Example &lt;code&gt;.env&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
NEBULA_API_KEY=your_api_key_here&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This method is important because &lt;strong&gt;API keys should never be hardcoded directly inside the program&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Initializing Nebula API Client
&lt;/h1&gt;

&lt;p&gt;Now we initialize the API client that will communicate with Nebula.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;python&lt;br&gt;
client = OpenAI(&lt;br&gt;
    api_key=os.getenv("NEBULA_API_KEY"),&lt;br&gt;
    base_url="https://llm.ai-nebula.com/v1"&lt;br&gt;
)&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here we use an &lt;strong&gt;OpenAI-compatible client&lt;/strong&gt;, but the request is actually sent to the &lt;strong&gt;Nebula API endpoint&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This allows us to use &lt;strong&gt;Nebula infrastructure while keeping the OpenAI SDK interface&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Initializing ChromaDB
&lt;/h1&gt;

&lt;p&gt;Now we prepare our vector database.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`python&lt;br&gt;
db_path = "./chroma_db"&lt;/p&gt;

&lt;p&gt;chroma_client = chromadb.PersistentClient(path=db_path)&lt;/p&gt;

&lt;p&gt;collection = chroma_client.get_or_create_collection(&lt;br&gt;
    name="bca_annual_report_2025"&lt;br&gt;
)&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Explanation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PersistentClient&lt;/strong&gt;&lt;br&gt;
Creates a persistent database stored locally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;db_path&lt;/strong&gt;&lt;br&gt;
The folder where our vector database will be stored.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collection&lt;/strong&gt;&lt;br&gt;
Similar to a &lt;strong&gt;table in a traditional database&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this case we create a collection called:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
bca_annual_report_2025&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This collection will contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;document chunks&lt;/li&gt;
&lt;li&gt;embeddings&lt;/li&gt;
&lt;li&gt;document IDs&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Step 1 — Reading the PDF
&lt;/h1&gt;

&lt;p&gt;Now we create a function to read the entire PDF document.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`python&lt;br&gt;
def read_pdf(path):&lt;br&gt;
    reader = PdfReader(path)&lt;br&gt;
    text = ""&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for page in reader.pages:
    text += page.extract_text() + "\n"

return text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What This Function Does
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Opens the PDF file&lt;/li&gt;
&lt;li&gt;Iterates through every page&lt;/li&gt;
&lt;li&gt;Extracts the text&lt;/li&gt;
&lt;li&gt;Combines all text into a single string&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since the &lt;strong&gt;BCA Annual Report contains around 600 pages&lt;/strong&gt;, this step may take a few seconds depending on your machine.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2 — Splitting the Document into Chunks
&lt;/h1&gt;

&lt;p&gt;Next we split the document into smaller pieces.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`python&lt;br&gt;
def chunk_text(text, chunk_size=500, overlap=50):&lt;br&gt;
    words = text.split()&lt;br&gt;
    chunks = []&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for i in range(0, len(words), chunk_size - overlap):
    chunk = " ".join(words[i:i+chunk_size])
    chunks.append(chunk)

return chunks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Do We Need Chunking?
&lt;/h3&gt;

&lt;p&gt;Because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Language models have &lt;strong&gt;context limits&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Sending the entire document into the prompt would be &lt;strong&gt;extremely inefficient&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, we break the document into smaller segments.&lt;/p&gt;

&lt;p&gt;In this code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
chunk_size = 500 words&lt;br&gt;
overlap = 50 words&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;overlap helps preserve context continuity between chunks&lt;/strong&gt;, which improves retrieval quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Structure
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
Chunk 1 : word 1 → word 500&lt;br&gt;
Chunk 2 : word 450 → word 950&lt;br&gt;
Chunk 3 : word 900 → word 1400&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This technique helps &lt;strong&gt;prevent information loss between chunks&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3 — Creating Embeddings
&lt;/h1&gt;

&lt;p&gt;Now we convert each chunk into embeddings.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`python&lt;br&gt;
def embed(texts):&lt;br&gt;
    response = client.embeddings.create(&lt;br&gt;
        model="text-embedding-3-large",&lt;br&gt;
        input=texts&lt;br&gt;
    )&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return [e.embedding for e in response.data]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Embeddings are &lt;strong&gt;numerical vector representations of text&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of storing raw text only, we convert each chunk into vectors so the database can perform &lt;strong&gt;semantic similarity search&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Concept
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
"bank revenue growth" → [0.021, -0.771, 0.144, ...]&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Texts with &lt;strong&gt;similar meaning&lt;/strong&gt; will have vectors &lt;strong&gt;close to each other in vector space&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is what allows &lt;strong&gt;RAG systems to find relevant knowledge quickly&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 4 — Running the Ingestion Process
&lt;/h1&gt;

&lt;p&gt;Now we run the entire ingestion pipeline.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`python&lt;br&gt;
pdf_path = "source/20260212-BCA-AR-2025-ID.pdf"&lt;/p&gt;

&lt;p&gt;if os.path.exists(pdf_path):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print("⏳ Reading PDF...")
pdf_text = read_pdf(pdf_path)

print("⏳ Creating chunks...")
chunks = chunk_text(pdf_text)

print(f"⏳ Creating embeddings for {len(chunks)} chunks...")
embeddings = embed(chunks)

collection.add(
    documents=chunks,
    embeddings=embeddings,
    ids=[str(i) for i in range(len(chunks))]
)

print(f"✅ Success! Database saved to: {db_path}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;else:&lt;br&gt;
    print(f"❌ File not found: {pdf_path}")&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step-by-Step Explanation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Check if the PDF exists&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;python&lt;br&gt;
os.path.exists(pdf_path)&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This prevents errors if the file is missing.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Step 2 — Extract the text&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;python&lt;br&gt;
pdf_text = read_pdf(pdf_path)&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The entire PDF is converted into &lt;strong&gt;raw text&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Create chunks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;python&lt;br&gt;
chunks = chunk_text(pdf_text)&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The document is split into smaller pieces.&lt;/p&gt;

&lt;p&gt;For a &lt;strong&gt;600-page report&lt;/strong&gt;, this may generate &lt;strong&gt;hundreds or even thousands of chunks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Generate embeddings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;python&lt;br&gt;
embeddings = embed(chunks)&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Each chunk is converted into a &lt;strong&gt;vector representation&lt;/strong&gt; using the embedding model.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Step 5 — Store everything in ChromaDB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;python&lt;br&gt;
collection.add(&lt;br&gt;
    documents=chunks,&lt;br&gt;
    embeddings=embeddings,&lt;br&gt;
    ids=[str(i) for i in range(len(chunks))]&lt;br&gt;
)&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We store three components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;documents&lt;/strong&gt; → the text chunks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;embeddings&lt;/strong&gt; → vector representations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ids&lt;/strong&gt; → unique identifiers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now our &lt;strong&gt;vector database is ready&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  After the Ingestion
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fziliwu4zcq9ayno02kaa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fziliwu4zcq9ayno02kaa.png" alt=" " width="487" height="98"&gt;&lt;/a&gt;&lt;br&gt;
Once the ingestion process is finished, our database will contain &lt;strong&gt;semantic vectors for every chunk of the BCA Annual Report&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo38hfw9169uh6ryep8jn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo38hfw9169uh6ryep8jn.png" alt=" " width="385" height="219"&gt;&lt;/a&gt;&lt;br&gt;
This means our system can now perform:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic Search&lt;/strong&gt; instead of traditional &lt;strong&gt;Keyword Search&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Happens Next?
&lt;/h1&gt;

&lt;p&gt;Now that our knowledge base has been stored inside &lt;strong&gt;ChromaDB&lt;/strong&gt;, the next step is building the &lt;strong&gt;retrieval pipeline&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the next part we will implement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Convert user question into embedding&lt;/li&gt;
&lt;li&gt;Search the vector database&lt;/li&gt;
&lt;li&gt;Retrieve the most relevant chunks&lt;/li&gt;
&lt;li&gt;Send them as context to Nebula API&lt;/li&gt;
&lt;li&gt;Generate a grounded response&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is where the &lt;strong&gt;actual RAG magic happens&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Nebula Lab
&lt;/h1&gt;

&lt;p&gt;For those who want to build chatbots or other AI applications, you can check &lt;strong&gt;Nebula Lab&lt;/strong&gt; here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2e73g4y89q0rgn1nk6w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2e73g4y89q0rgn1nk6w.png" alt=" " width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nebula-data.ai/" rel="noopener noreferrer"&gt;https://nebula-data.ai/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They offer more than just &lt;strong&gt;API access for multiple models&lt;/strong&gt;, including various tools and features for AI development.&lt;/p&gt;

&lt;p&gt;See you in the next part.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
      <category>python</category>
    </item>
    <item>
      <title>Specialized chatbot using rag (retrieval augmented generation) Part I</title>
      <dc:creator>NEBULA DATA</dc:creator>
      <pubDate>Fri, 27 Feb 2026 07:37:45 +0000</pubDate>
      <link>https://forem.com/nebuladata/specialized-chatbot-using-rag-retrieval-augmented-generation-part-i-53d6</link>
      <guid>https://forem.com/nebuladata/specialized-chatbot-using-rag-retrieval-augmented-generation-part-i-53d6</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ft6lg71gepl48rqunak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ft6lg71gepl48rqunak.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the previous episode, we successfully built an interactive chatbot that can respond to user questions and secure the API key itself. Now, we want to enhance it by implementing Retrieval-Augmented Generation (RAG).&lt;br&gt;
RAG allows us to specialize our chatbot by enabling it to use our own documents as a knowledge source. These documents can belong to specific domains such as finance, law, science, mathematics, or any other specialized field. Instead of relying only on the model’s pre-trained knowledge, we provide it with domain-specific information so it can generate more accurate and relevant responses.&lt;br&gt;
The first step in implementing RAG is preparing the source data. The source consists of the documents we want the chatbot to learn from, such as PDFs, text files, reports, or databases.&lt;br&gt;
However, a language model cannot efficiently process large raw documents directly every time a user asks a question. Large documents may exceed the model’s context limit and would be inefficient to pass into the prompt repeatedly. Therefore, we need to preprocess these documents.&lt;br&gt;
The preprocessing steps typically include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Splitting the documents into smaller chunks
Each document is divided into manageable pieces to fit within the model’s context window.&lt;/li&gt;
&lt;li&gt; Generating embeddings for each chunk
Using an embedding model (for example, from OpenAI), each text chunk is converted into a numerical vector representation. These vectors capture the semantic meaning of the text.&lt;/li&gt;
&lt;li&gt; Storing embeddings in a vector database
The generated embeddings are stored in a vector database such as Pinecone, Weaviate, Chroma, or FAISS. This database allows us to perform similarity searches efficiently.
When a user submits a question:
• The question is converted into an embedding.
• The system searches the vector database to find the most relevant document chunks.
• These retrieved chunks are then provided to the language model as additional context.
• Finally, the model generates an answer grounded in the retrieved information.
By applying RAG, our chatbot becomes more accurate, domain-specific, and capable of providing responses based on our own knowledge base rather than relying solely on general training data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfzrtmbowesois378olg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfzrtmbowesois378olg.png" alt=" " width="800" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, for the source, I’m using Annual Report from BCA (Bank Central Asia):&lt;br&gt;
 This file consists 600 pages and mostly full of text. Now, we’re moving to the next step.&lt;br&gt;
And make sure the structure of our app should be look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuio6oyh544zgd1hce8s3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuio6oyh544zgd1hce8s3.png" alt=" " width="566" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nebula -&amp;gt; Source (Annual Report from BCA), .env , nebula.py (our main program)&lt;br&gt;
So, our program workflow should be like these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Load PDF&lt;/li&gt;
&lt;li&gt; Split into chunks&lt;/li&gt;
&lt;li&gt; Create embeddings&lt;/li&gt;
&lt;li&gt; Store in ChromaDB&lt;/li&gt;
&lt;li&gt; Search relevant chunks&lt;/li&gt;
&lt;li&gt; Send context + question to Nebula API&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Preparing Requirements:&lt;br&gt;
Before we can run our program, we need to install several library in order to support it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  chromadb &lt;/li&gt;
&lt;li&gt;  pip install langchain (Optional but better for chunking)&lt;/li&gt;
&lt;li&gt;  pypdf &lt;/li&gt;
&lt;li&gt;  sentence-transformers &lt;/li&gt;
&lt;li&gt;  tiktoken &lt;/li&gt;
&lt;li&gt;  python-dotenv (We have installed it before)&lt;/li&gt;
&lt;li&gt;  openai (We have installed it before)
Do we need to set up Virtual Environment for this project?
Well, the answer is depend of the scale of our app, if we want to create this chatbot to take way more source, way more capability etc, scared of different environment changes because of inconsistent library version of each update, the answer is YES. But for these type of app that I build to show you guys how to build simple RAG chatbot using Nebula API, might be not necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Okay, now we need to install all the requirement of library inside our environment / local device, the command is very simple ‘pip install our package name’, so if I want to install chroma db, I just need to type ‘pip install chromadb’ on my CLI and hit Enter. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhqjycu48wq2zb6c8ja5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhqjycu48wq2zb6c8ja5a.png" alt=" " width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi24k78dgx2ybk4iz3z05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi24k78dgx2ybk4iz3z05.png" alt=" " width="800" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you guys see, on my cli all the output says “Requirement already satisfied”, it happened because Im already installing all of those package on the past so the program will automatically tell me and skip the process.&lt;/p&gt;

&lt;p&gt;But there’s several way to do installation,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; One by one (like pip install chromadb)&lt;/li&gt;
&lt;li&gt; By Listing (pip install chromadb langchain etc)&lt;/li&gt;
&lt;li&gt; Whole list (put all the library list on the requirements.txt and on the CLI, just type pip install -r requirements.txt and hit enter)
So anything you want to use, its good and its serve different purposes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;OKAY, on the next episode, we will try to ingest the pdf into our database (Chroma DB), it will be a bit difficult at first but I know you guys who read this article will master it easily.&lt;br&gt;
And for you guys who wants to build chatbot or even other things with ai, you can check NEBULA LAB here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjj5yylyqmkeloso5v3qh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjj5yylyqmkeloso5v3qh.png" alt=" " width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nebula-data.ai/" rel="noopener noreferrer"&gt;https://nebula-data.ai/&lt;/a&gt;&lt;br&gt;
There’s much more than just an API KEY FOR ALL MODEL, they also had a ton of other features such as marketing etc.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to secure your api key?</title>
      <dc:creator>NEBULA DATA</dc:creator>
      <pubDate>Fri, 20 Feb 2026 13:00:10 +0000</pubDate>
      <link>https://forem.com/nebuladata/how-to-secure-your-api-key-23ik</link>
      <guid>https://forem.com/nebuladata/how-to-secure-your-api-key-23ik</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0vb283wayum83seg8bw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0vb283wayum83seg8bw.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Hi guys, I'm back!&lt;br&gt;
In the previous episode, we’re successfully create an interactive chatbot, but one critical thing remain, our api key is still inside our python file, which is if we’re publishing our code into public or moving it into bigger scale of development or even production stage, of course its unsafe at all, that’s why im telling you on the next episode, ill show you how to secure our private thing (in this case API key).&lt;br&gt;
Now I'm going to show you how to secure your own API key (Nebula API)!&lt;/p&gt;
&lt;h2&gt;
  
  
  Environment variable
&lt;/h2&gt;

&lt;p&gt;An environment variable is a dynamically named value that can affect the way running processes behave on a computer. Think of them as "global constants" for your operating system’s environment.&lt;br&gt;
Instead of hard-coding a specific file path or a secret API key directly into a program's source code, you store that information in an environment variable. This allows the program to remain generic and adaptable to different computers or users.&lt;/p&gt;

&lt;p&gt;Now, the first thing we need is to create a ‘.env’ file, which will contain our Nebula API key:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlqfs154xje1bomn5u1k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlqfs154xje1bomn5u1k.png" alt=" " width="561" height="163"&gt;&lt;/a&gt;&lt;br&gt;
After we create .env file, now we need to put our Nebula API key inside this file, you can just simply move the variable that contain our key into that file, in this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from openai import OpenAI
client = OpenAI(
    nebula_api_key="sk-xxxxx",
    base_url="https://llm.ai-nebula.com/v1"
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re going to move “ nebula_api_key="sk-xxxxx" ” inside the .env file (don’t forget to remove the double quote symbol in order to system can retrieve the Nebula_api_key as a value, not just a string):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfu1mwrv7dyy87sw7bv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfu1mwrv7dyy87sw7bv6.png" alt=" " width="592" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How can our program retrieve the nebula api key?
&lt;/h2&gt;

&lt;p&gt;Now, we need to do something so our program can read the nebula api key inside the .env files.&lt;br&gt;
There’s why we need to use ‘dotenv’ and ‘os’ library, The os.getenv bridge: Simply having the .env file isn't enough, Python needs that "bridge" command to go grab the value from the system memory.&lt;/p&gt;

&lt;p&gt;So, we need to import 2 more, so it will be like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52mlrqcm96l2d2dzl20z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52mlrqcm96l2d2dzl20z.png" alt=" " width="788" height="372"&gt;&lt;/a&gt;&lt;br&gt;
The ‘load_dotenv()’ function is most important because it retrieves variables from our .env file.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuring the Client
&lt;/h3&gt;

&lt;p&gt;This is where the "bridge" happens. In the original code, the API key was typed directly into the script, a big security risk! Now, we use os.getenv() to look for the key we saved in our .env file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;client = OpenAI(
    nebula_api_key="sk-xxx", # Hard-coded (Unsafe!)
    base_url="https://llm.ai-nebula.com/v1"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Secure Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;client = OpenAI(
    nebula_api_key=os.getenv("NEBULA_API_KEY"), # Fetched from system memory
    base_url="https://llm.ai-nebula.com/v1"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enhancing the Chat Loop
&lt;/h3&gt;

&lt;p&gt;Finally, we can add a small confirmation message. While the logic of the while loop remains the same, having the API key stored externally makes the code much cleaner and ready for professional deployment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print("Chatbot initialized. Type 'exit' to stop.")
while True:
    user_input = input("You: ")
# ... rest of your logic stays the same!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;By making these changes, you have successfully:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Separated Configuration from Code: Your code now tells the computer what to do, while the .env file tells it which credentials to use.&lt;/li&gt;
&lt;li&gt;  Prevented Data Leaks: Even if you share your Python file with a classmate or push it to GitHub, your secret key stays safe on your own machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, all we need is to &lt;strong&gt;test it out if these changes will work or not?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pzp60oxde9ro2x70lif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pzp60oxde9ro2x70lif.png" alt=" " width="800" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you guys can see, these changes is success and the program runs smoothly without any problem, and with these changes, we can continue developing our program into the next stage without worrying about our security.&lt;/p&gt;

&lt;p&gt;And for you guys who want to build a chatbot or even other things with AI, you can check NEBULA LAB here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo09i6pi4dd3k3y0g6cc2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo09i6pi4dd3k3y0g6cc2.png" alt=" " width="800" height="379"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nebula-data.ai/" rel="noopener noreferrer"&gt;Nebula Lab&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s much more than just an API KEY FOR ALL MODELS. They also had tons of other features, such as marketing, etc.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
    </item>
    <item>
      <title>MAKE THE CHATBOT MORE INTERACTIVE USING PYTHON ONLY USING NEBULA API</title>
      <dc:creator>NEBULA DATA</dc:creator>
      <pubDate>Thu, 12 Feb 2026 04:02:11 +0000</pubDate>
      <link>https://forem.com/nebuladata/make-the-chatbot-more-interactive-using-python-only-using-nebula-api-70m</link>
      <guid>https://forem.com/nebuladata/make-the-chatbot-more-interactive-using-python-only-using-nebula-api-70m</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwl8wuj713fzazfq54ovn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwl8wuj713fzazfq54ovn.png" alt=" " width="800" height="999"&gt;&lt;/a&gt;&lt;br&gt;
For today’s episode, I'll continue working on our project to make rag based chatbot using Nebula Data’s api.&lt;br&gt;
Okay, from the previous episode, we already set up the account, api and the billing. Now I want to make a simple chatbot, but using CLI (command line interface) only (maybe in the next article, I will make the interface).&lt;br&gt;
Okay, so we already have the base of our code from the Nebula documentation. Like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from openai import OpenAI
client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://llm.ai-nebula.com/v1"
)

response = client.chat.completions.create(
    model="gpt-5.2",
    messages=[
        {"role": "user", "content": "Hello!"}
    ]
)
print(response.choices[0].message.content)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is for testing the api either they’re working or not, by simply saying “Hello!” to the AI through the nebula api.&lt;/p&gt;

&lt;p&gt;Now, what I wanna do is to make this ai can answer my questions.&lt;br&gt;
Why don’t I just change the string “Hello!” to my question?&lt;/p&gt;

&lt;p&gt;Well, technically it can, but that’s not interactive, because if we just change that part, it won't be possible to keep changing the code again and again each time we need to ask something to the AI. &lt;/p&gt;

&lt;p&gt;So I want to make a loop and create a variable that can contain our questions, so we don’t need to change it again, all we need is just to ask via the CLI.&lt;/p&gt;

&lt;p&gt;Okay, so first things first,&lt;br&gt;
We need to make a variable, let’s name it “user_input”, inside this variable is our question. And this process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;response = client.chat.completions.create(
    model="gpt-5.2",
    messages=[
        {"role": "user", "content": "Hello!"}
    ]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I will wrap them into a loop function, specifically the “while loop”,&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a while loop?
&lt;/h2&gt;

&lt;p&gt;A while loop is a control structure in programming that repeatedly runs a block of code as long as a condition is true.&lt;br&gt;
 The condition is checked before each iteration, so if it’s false from the start, the loop won’t run at all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffstjt11mcbfo2txuefn6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffstjt11mcbfo2txuefn6.png" alt=" " width="451" height="101"&gt;&lt;/a&gt;&lt;br&gt;
Okay, now if I applied the loop function on purpose to keep the AI running, then how can I stop them? Well, all I need is just to make a “Break Condition” that can be applied inside the loop and put a condition that can make the loop stop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslj9obw39knv98pwsbbb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslj9obw39knv98pwsbbb.png" alt=" " width="451" height="141"&gt;&lt;/a&gt;&lt;br&gt;
So the simplest way to do that is to make a conditional statement (if statement) that contains “break function”. So the condition I wanna make as if the user types “quit” or “exit”, the program will activate the break condition and finally call the break function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3nmtpyxsj67s7uakyoh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff3nmtpyxsj67s7uakyoh.png" alt=" " width="451" height="129"&gt;&lt;/a&gt;&lt;br&gt;
This is how you can make the loop function work on a chatbot (it’s the easiest method I can explain). Now, after the loop is True, it will take the user input and process it into the AI using NEBULA API, so for doing that, all we need is just to place the response code inside the while loop condition:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnd81ybm26i5y41hv134.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnd81ybm26i5y41hv134.png" alt=" " width="451" height="230"&gt;&lt;/a&gt;&lt;br&gt;
And the rest or the outer while loop function is just initialize the NEBULA API, URL, and the Print function, so the final version should be like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxuangxghq59dutv85rbn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxuangxghq59dutv85rbn.png" alt=" " width="451" height="295"&gt;&lt;/a&gt;&lt;br&gt;
Okay, all we need now is to run this program,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqleardvg95i1208pbjp8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqleardvg95i1208pbjp8.png" alt=" " width="451" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And to close the program:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmwsje9ov6pwrthaleak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmwsje9ov6pwrthaleak.png" alt=" " width="451" height="139"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And just like that, we can make the chatbot more interactive using the NEBULA API!&lt;br&gt;
But many people use APIs just like that. It's not safe to write the API key in a Python file like that, so in the next article, I will show you how to use .env and the benefits of using it. &lt;br&gt;
And for you guys who want to build a chatbot or even other things with AI, you can check NEBULA LAB here:&lt;br&gt;
&lt;a href="https://nebula-data.ai/" rel="noopener noreferrer"&gt;Nebula Lab&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s much more than just an API KEY FOR ALL MODELS, they also have tons of other features, such as marketing, etc.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>High Performance, Low Cost: Building a Professional RAG Chatbot from Scratch</title>
      <dc:creator>NEBULA DATA</dc:creator>
      <pubDate>Tue, 27 Jan 2026 08:33:08 +0000</pubDate>
      <link>https://forem.com/nebuladata/high-performance-low-cost-building-a-professional-rag-chatbot-from-scratch-1a76</link>
      <guid>https://forem.com/nebuladata/high-performance-low-cost-building-a-professional-rag-chatbot-from-scratch-1a76</guid>
      <description>&lt;h1&gt;
  
  
  Building a RAG Chatbot from Scratch: Part 1
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Choosing the Right Engine
&lt;/h2&gt;

&lt;p&gt;Hello everyone! Today, I’m kicking off a short series where I’ll be documenting my journey of building a specialized chatbot. Unlike a standard chatbot that provides general answers, I want this one to have a very specific "job": answering questions based on the &lt;strong&gt;2024 Indonesian Government Financial Reports&lt;/strong&gt; compiled by the Ministry of Finance.&lt;/p&gt;

&lt;p&gt;You might be wondering: "What’s the difference between a regular chatbot and a RAG-based chatbot?" The primary difference lies in the information source and how the AI formulates its response.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the RAG Difference
&lt;/h2&gt;

&lt;p&gt;In a standard AI setup, the process is quite linear:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6t6p9z4kb4namdlskui4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6t6p9z4kb4namdlskui4.jpg" alt=" " width="651" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the user asks a question, and the AI responds based on the data it was trained on. However, for my project, I am adding a critical component that prevents the AI from needing to "guess" or rely on outdated training data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsfxxutk3pbuqulxuwl5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsfxxutk3pbuqulxuwl5.jpg" alt=" " width="570" height="196"&gt;&lt;/a&gt;&lt;br&gt;
By adding &lt;strong&gt;Stored Information&lt;/strong&gt; (our 2024 Financial Report), the general-purpose AI becomes a &lt;strong&gt;Specialized AI&lt;/strong&gt;. It will only provide answers relevant to the context found in that stored data. We will discuss what happens when a user asks something "out of context" in future articles, but today, my focus is on selecting the right AI model.&lt;/p&gt;


&lt;h2&gt;
  
  
  Selecting the Model: Why Nebula Lab?
&lt;/h2&gt;

&lt;p&gt;When looking for a model, I felt overwhelmed by the different platforms—GPT, Claude, and Gemini all live in different ecosystems. I initially looked at OpenRouter, a popular API aggregator. However, after some research and a tip from a friend, I discovered &lt;strong&gt;Nebula Lab&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nebula Lab&lt;/strong&gt; (&lt;a href="https://ai-nebula.com/" rel="noopener noreferrer"&gt;ai-nebula.com&lt;/a&gt;) is an API aggregator that offers not just LLMs, but also marketing tools. Here is why I decided to switch from OpenRouter to Nebula:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fki37duxq3x1o8yinhost.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fki37duxq3x1o8yinhost.png" alt=" " width="548" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost-Effectiveness:&lt;/strong&gt; Their prices are significantly lower. For example, GPT-5.2 is listed at $1.40 USD per 1M tokens. Compared to official OpenAI pricing, Nebula is genuinely more affordable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1pl4ci4s21khip1dv7r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1pl4ci4s21khip1dv7r.png" alt=" " width="370" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl48iw1i56nzvy1ksn3nt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl48iw1i56nzvy1ksn3nt.png" alt=" " width="752" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Platform Fees:&lt;/strong&gt; Unlike some aggregators that charge a 5% platform fee, Nebula Lab doesn't tack on extra costs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model Variety:&lt;/strong&gt; They host all the heavy hitters, including OpenAI, Google, and Anthropic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean UI:&lt;/strong&gt; The interface is simple and easy to navigate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figl5qbnmsu0zcnskrjne.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figl5qbnmsu0zcnskrjne.png" alt=" " width="602" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear Documentation:&lt;/strong&gt; For a beginner, their documentation is straightforward and easy to implement.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2dgryntq7ycyi03azfz.png" alt=" " width="602" height="282"&gt;
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Testing the API
&lt;/h2&gt;

&lt;p&gt;Getting started was incredibly easy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Model Center&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;API Key&lt;/strong&gt; on the left sidebar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate&lt;/strong&gt; your key.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcw2uozh829cq6sssvrp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcw2uozh829cq6sssvrp.png" alt=" " width="679" height="280"&gt;&lt;/a&gt;&lt;br&gt;
To ensure everything was working, I tested the connection using two methods provided in their documentation:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Testing via CURL
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fojoomvafsv8ufs6t9qx6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fojoomvafsv8ufs6t9qx6.png" alt=" " width="602" height="251"&gt;&lt;/a&gt;&lt;br&gt;
I ran the following command in my terminal (Command Prompt/PowerShell):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://llm.ai-nebula.com/v1/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
        "model": "gpt-5.2",
        "messages": [{"role": "user", "content": "Hello!"}]
    }'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8fx54wy7lc5xndkgox3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8fx54wy7lc5xndkgox3.png" alt=" " width="752" height="202"&gt;&lt;/a&gt;&lt;br&gt;
The response was &lt;strong&gt;instant and normal&lt;/strong&gt;. The "GPT-5.2" model responded perfectly.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Testing via Python
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jne19s3t1m51oze1mkw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jne19s3t1m51oze1mkw.png" alt=" " width="602" height="331"&gt;&lt;/a&gt;&lt;br&gt;
I then used Python (version 3.13.2) for a more integrated test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-xxxxxxxxxxxxxxxxxxx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# Replace with your actual key
&lt;/span&gt;    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://llm.ai-nebula.com/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4m94otyw18zjxm3svxar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4m94otyw18zjxm3svxar.png" alt=" " width="752" height="373"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Success!&lt;/strong&gt; The code ran smoothly without a single hitch. I’m really impressed with Nebula Lab’s variety and ease of use.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;In the next article, we’ll start building the actual chatbot and gradually begin injecting our financial data to transform this from a simple API call into a &lt;strong&gt;full-fledged RAG system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you want to try it out yourself, check out Nebula Lab here: &lt;a href="https://openai-nebula.com/" rel="noopener noreferrer"&gt;https://openai-nebula.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Beyond Loss Curves: Interpreting the Transition from Instability to Structure</title>
      <dc:creator>NEBULA DATA</dc:creator>
      <pubDate>Thu, 22 Jan 2026 06:29:16 +0000</pubDate>
      <link>https://forem.com/nebuladata/beyond-loss-curves-interpreting-the-transition-from-instability-to-structure-3p77</link>
      <guid>https://forem.com/nebuladata/beyond-loss-curves-interpreting-the-transition-from-instability-to-structure-3p77</guid>
      <description>&lt;p&gt;In the previous section, I described an apparent transition during training: volatile representations early on, followed by a phase of rapid structural alignment, and finally a stabilization period where loss improvements slow but internal consistency increases. Assuming this pattern is not an artifact, the next question becomes more fundamental:&lt;br&gt;
What changes in the learning dynamics cause this transition to occur?&lt;br&gt;
Rather than treating training as a smooth, monotonic process, it may be more accurate to view it as a sequence of qualitatively different regimes.&lt;/p&gt;
&lt;h2&gt;
  
  
  A Possible Phase Transition in Learning
&lt;/h2&gt;

&lt;p&gt;One way to interpret the observed behavior is as a phase transition in representation space. Early in training, parameter updates appear dominated by large gradients responding to easy-to-exploit statistical regularities. These updates reshape embeddings aggressively, but not coherently.&lt;br&gt;
To quantify this intuition, I extended the training loop to explicitly track gradient magnitude and representation drift:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def flatten_params(tensor):
    return tensor.view(-1)

prev_embedding = None

for epoch in range(num_epochs):
    optimizer.zero_grad()

    outputs = model(inputs)
    loss = criterion(outputs, targets)

    loss.backward()

    grad_norm = model.encoder.weight.grad.norm().item()
    optimizer.step()

    with torch.no_grad():
        current_embedding = model.encoder.weight.clone()
        emb_norm = current_embedding.norm().item()

        if prev_embedding is not None:
            drift = torch.norm(
                flatten_params(current_embedding) -
                flatten_params(prev_embedding)
            ).item()
        else:
            drift = 0.0

    print(
        f"Epoch {epoch} | "
        f"Loss: {loss.item():.4f} | "
        f"GradNorm: {grad_norm:.2f} | "
        f"EmbNorm: {emb_norm:.2f} | "
        f"Drift: {drift:.4f}"
    )

    prev_embedding = current_embedding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What stood out was that:
&lt;/h2&gt;

&lt;p&gt;• Gradient norms were largest early, even when loss reductions were modest&lt;br&gt;
• Embedding drift was extreme during early epochs&lt;br&gt;
• Drift dropped sharply after a certain point, even though gradients remained non-zero&lt;br&gt;
This suggests that early gradients primarily drive exploration of parameter space rather than refinement of stable structure.&lt;/p&gt;
&lt;h2&gt;
  
  
  Optimization vs. Organization
&lt;/h2&gt;

&lt;p&gt;This observation hints at an important distinction that loss alone does not capture:&lt;br&gt;
• Optimization: minimizing task error&lt;br&gt;
• Organization: imposing structure and consistency on internal representations&lt;br&gt;
Early training is dominated by optimization pressure. Later training appears to emphasize organization, even when the task objective changes little.&lt;br&gt;
To probe this more directly, I tracked pairwise cosine similarity between randomly sampled token embeddings across epochs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import random
import torch.nn.functional as F

def sample_cosine_stats(embeddings, num_samples=100):
    indices = random.sample(range(embeddings.size(0)), num_samples)
    cosines = []
    for i in range(len(indices) - 1):
        a = embeddings[indices[i]]
        b = embeddings[indices[i + 1]]
        cosines.append(F.cosine_similarity(a, b, dim=0).item())
    return sum(cosines) / len(cosines)

with torch.no_grad():
    cosine_mean = sample_cosine_stats(model.encoder.weight)

print(f"Epoch {epoch} | Mean Pairwise Cosine: {cosine_mean:.4f}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During early epochs, cosine statistics fluctuated wildly. Mid-training, they shifted rapidly toward consistent ranges, indicating emerging geometry. Late training showed minimal variance, even when loss had largely saturated.&lt;br&gt;
This reinforces the idea that internal geometry continues evolving long after task performance stabilizes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Representations Stabilize Even When Loss Does Not
&lt;/h2&gt;

&lt;p&gt;One puzzling outcome was that representation similarity between epochs continued increasing even when loss improvement was negligible. This suggests that gradients were still shaping the model—but along dimensions invisible to the objective.&lt;br&gt;
A plausible explanation is that, once the model enters a low-loss basin, gradient descent mostly moves parameters within an equivalence class of solutions. Outputs remain similar, but internal redundancy decreases and representations become smoother.&lt;br&gt;
This can be approximated by tracking singular value decay of the embedding matrix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;with torch.no_grad():
    u, s, v = torch.linalg.svd(model.encoder.weight, full_matrices=False)
    spectral_energy = (s / s.sum()).cpu()

print(
    f"Epoch {epoch} | "
    f"Top-5 Singular Energy: {spectral_energy[:5].sum():.4f}"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Late training often showed:&lt;br&gt;
• Increasing concentration of spectral energy&lt;br&gt;
• Reduced effective rank&lt;br&gt;
• More anisotropic embedding spaces&lt;br&gt;
These changes align with emergent structure rather than improved prediction accuracy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rethinking Overfitting as a Developmental Stage
&lt;/h2&gt;

&lt;p&gt;This lens reframes overfitting. Instead of a terminal failure mode, it may act as a developmental constraint that forces the model to commit to specific distinctions.&lt;br&gt;
Empirically, models that were heavily regularized from the start showed:&lt;br&gt;
• Lower early drift&lt;br&gt;
• Weaker mid-training clustering&lt;br&gt;
• Less stable late-stage representations&lt;br&gt;
Conversely, temporarily allowing overfitting seemed to accelerate representational alignment—suggesting that structure must exist before it can be generalized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signals That May Matter More Than Loss
&lt;/h2&gt;

&lt;p&gt;If loss is insufficient for understanding learning dynamics, other metrics may be more revealing:&lt;br&gt;
• Representation drift between epochs&lt;br&gt;
• Cosine similarity convergence&lt;br&gt;
• Effective rank or spectral entropy&lt;br&gt;
• Gradient-to-drift ratio&lt;br&gt;
• Sensitivity of embeddings to noise perturbations&lt;br&gt;
For example, injecting small Gaussian noise into inputs revealed that late-stage representations were significantly more invariant than early ones, even at identical loss levels.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Lingering Uncertainty
&lt;/h2&gt;

&lt;p&gt;Despite these findings, an uncomfortable possibility remains:&lt;br&gt;
What if stabilization reflects numerical inertia rather than semantic abstraction?&lt;br&gt;
Without transfer tasks or probing classifiers, it is difficult to disambiguate meaningful structure from converged parameterization. Representation stability is likely necessary for abstraction but not sufficient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reframing the Core Question
&lt;/h2&gt;

&lt;p&gt;At this point, the question can be stated more precisely:&lt;br&gt;
Is training best understood as minimizing loss, or as guiding representations through unstable exploratory regimes toward constrained, reusable geometries?&lt;/p&gt;

&lt;p&gt;If the latter is even partially true, then training dynamics—not just end metrics—deserve closer attention.&lt;br&gt;
I still hesitate to claim novelty. These ideas likely overlap with concepts such as neural collapse, spectral bias, or information bottlenecks. What feels distinct is seeing them not as isolated effects, but as successive phases of a single developmental process.&lt;br&gt;
Which leaves the question open, but sharper:&lt;br&gt;
If abstraction only emerges after instability, how many of our training practices are unintentionally optimized to prevent the very conditions that make abstraction possible?&lt;br&gt;
For now, this remains less a conclusion than a suspicion but one increasingly supported by the behavior of the models themselves.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>ai</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Rethinking Learning Dynamics in AI Models: An Early Theory from Experimentation</title>
      <dc:creator>NEBULA DATA</dc:creator>
      <pubDate>Thu, 15 Jan 2026 03:39:37 +0000</pubDate>
      <link>https://forem.com/nebuladata/rethinking-learning-dynamics-in-ai-models-an-early-theory-from-experimentation-4dmp</link>
      <guid>https://forem.com/nebuladata/rethinking-learning-dynamics-in-ai-models-an-early-theory-from-experimentation-4dmp</guid>
      <description>&lt;h1&gt;
  
  
  Observing Representation Instability During Neural Network Training
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72pdu5n4ycgsp9o0f9bu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72pdu5n4ycgsp9o0f9bu.png" alt="Rethinking Learning Dynamics in AI Models.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While experimenting with neural network training behaviors, I started noticing a recurring pattern that does not seem to be explicitly discussed in most mainstream AI literature. This article is not meant to present a finalized solution, but rather a working theory that emerged during development.&lt;/p&gt;

&lt;p&gt;I am sharing this to ask: &lt;strong&gt;does this interpretation make sense, or am I misunderstanding the dynamics at play?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background Assumption
&lt;/h2&gt;

&lt;p&gt;Most modern AI systems, particularly deep learning models, rely on gradient-based optimization. The underlying assumption is relatively straightforward:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Minimize loss → improve performance&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, during a series of experiments, I observed that &lt;strong&gt;loss minimization alone does not always correlate with meaningful representation learning&lt;/strong&gt;, especially in early training phases.&lt;/p&gt;

&lt;p&gt;This led me to hypothesize that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI models may pass through a “representation instability phase” where gradients optimize surface-level patterns before stable internal abstractions emerge.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am not fully confident whether this is already well-known under a different name, or whether I am misinterpreting training noise as structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial Observation
&lt;/h2&gt;

&lt;p&gt;While training a small transformer-like model on synthetic data, I logged intermediate layer activations and noticed something interesting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Early epochs&lt;/strong&gt; show highly volatile embeddings
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mid-training&lt;/strong&gt; shows sudden clustering behavior
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Late training&lt;/strong&gt; stabilizes, even when loss improvement slows down
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a simplified snippet of the training loop I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_epochs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;criterion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;no_grad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;embedding_norm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Epoch &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;epoch&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | Loss: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | Embedding Norm: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;embedding_norm&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;What surprised me is that &lt;strong&gt;embedding norms and cosine similarities changed more drastically than loss values&lt;/strong&gt;, especially early on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tentative Theory
&lt;/h2&gt;

&lt;p&gt;My current theory (and this is where I’m unsure):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gradient descent initially prioritizes optimization shortcuts rather than semantic structure, and only later converges toward representations that are robust and generalizable.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If this is true, then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Early stopping might prevent meaningful abstraction&lt;/li&gt;
&lt;li&gt;Some overfitting phases might actually be necessary&lt;/li&gt;
&lt;li&gt;Regularization might &lt;em&gt;delay&lt;/em&gt;, not prevent, representation collapse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But this raises questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this just an artifact of small datasets?&lt;/li&gt;
&lt;li&gt;Is this already explained by concepts like loss landscape flatness or mode connectivity?&lt;/li&gt;
&lt;li&gt;Am I confusing emergent structure with random alignment?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Small Diagnostic Experiment
&lt;/h2&gt;

&lt;p&gt;To test whether representations actually stabilize, I added a simple cosine similarity tracker:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`python&lt;br&gt;
def cosine_similarity(a, b):&lt;br&gt;
    return torch.nn.functional.cosine_similarity(a, b, dim=0)&lt;/p&gt;

&lt;p&gt;prev_embedding = None&lt;/p&gt;

&lt;p&gt;for epoch in range(num_epochs):&lt;br&gt;
    # training step...&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current_embedding = model.encoder.weight.clone().detach()

if prev_embedding is not None:
    similarity = cosine_similarity(
        prev_embedding.view(-1),
        current_embedding.view(-1)
    )
    print(f"Epoch {epoch} | Embedding Stability: {similarity.item():.4f}")

prev_embedding = current_embedding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The similarity score jumps erratically at first, then begins converging toward &lt;strong&gt;~0.98–0.99&lt;/strong&gt;, even when loss improvement becomes marginal.&lt;/p&gt;

&lt;p&gt;This makes me wonder:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Is loss the wrong primary signal for understanding learning progress?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Open Questions for Discussion
&lt;/h2&gt;

&lt;p&gt;I’m genuinely unsure whether this line of thinking is insightful or redundant, so I’d like to open this up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is this “instability → abstraction → stabilization” pattern formally recognized?&lt;/li&gt;
&lt;li&gt;Could this be explained by information bottleneck theory, or is that a stretch?&lt;/li&gt;
&lt;li&gt;Are there better metrics than loss for tracking learning quality?&lt;/li&gt;
&lt;li&gt;Am I over-interpreting noise due to small-scale experiments?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;I feel like I’m observing something real, but I’m not convinced I’m explaining it correctly yet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If this theory is flawed, I’d like to know where the reasoning breaks.&lt;/li&gt;
&lt;li&gt;If it’s valid, I’d like to understand how others frame it more rigorously.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this stage, I’m treating this less as a claim and more as a question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What exactly is an AI model learning &lt;em&gt;before&lt;/em&gt; it learns what we want it to learn?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>ai</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How Machine Learning Works?</title>
      <dc:creator>NEBULA DATA</dc:creator>
      <pubDate>Tue, 06 Jan 2026 09:23:20 +0000</pubDate>
      <link>https://forem.com/nebuladata/how-machine-learning-works-ijl</link>
      <guid>https://forem.com/nebuladata/how-machine-learning-works-ijl</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxsqunk0czvs29qcjrsf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxsqunk0czvs29qcjrsf7.png" alt="Machine Learning Workflow" width="640" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Machine Learning (ML) is a specialized area of Artificial Intelligence that analyzes data to discover patterns and make predictions about future outcomes. It follows a structured workflow that includes &lt;strong&gt;data collection, preprocessing, model building, training, evaluation, visualization, and deployment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Today, machine learning plays a vital role in industries such as &lt;strong&gt;healthcare, finance, marketing, education&lt;/strong&gt;, and more.&lt;/p&gt;

&lt;p&gt;This article explains machine learning fundamentals, its core concepts, data handling processes, and the ethical responsibilities involved.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Machine Learning?
&lt;/h2&gt;

&lt;p&gt;Machine Learning is a field of Artificial Intelligence that enables systems to learn from data and improve performance &lt;strong&gt;without being explicitly programmed&lt;/strong&gt;. It relies on algorithms and mathematical models to analyze large volumes of data, identify patterns, and make informed decisions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1q88f5daq337luzpzz72.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1q88f5daq337luzpzz72.jpg" alt="Machine Learning Evolution" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over time, machine learning has evolved from basic statistical methods to advanced techniques such as &lt;strong&gt;deep learning and neural networks&lt;/strong&gt;. Its growth has been fueled by increased computational power and the availability of large datasets.&lt;/p&gt;

&lt;p&gt;Today, ML supports technologies such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Natural Language Processing (NLP)&lt;/li&gt;
&lt;li&gt;Computer Vision&lt;/li&gt;
&lt;li&gt;Recommendation Systems&lt;/li&gt;
&lt;li&gt;Autonomous Systems&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Example: Predicting House Prices
&lt;/h2&gt;

&lt;p&gt;A simple machine learning task is predicting house prices using features such as &lt;strong&gt;area, number of rooms, and location&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="c1"&gt;# Sample dataset
&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;area&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1800&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rooms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;200000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;350000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400000&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Key Concepts of Machine Learning
&lt;/h2&gt;

&lt;p&gt;Machine learning is broadly classified into &lt;strong&gt;four categories&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Supervised Learning
&lt;/h3&gt;

&lt;p&gt;Uses labeled data where the output is known. The model learns a mapping between input and output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.linear_model&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LinearRegression&lt;/span&gt;

&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;area&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rooms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LinearRegression&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. Unsupervised Learning
&lt;/h3&gt;

&lt;p&gt;Works with unlabeled data to identify patterns or clusters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.cluster&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;KMeans&lt;/span&gt;

&lt;span class="n"&gt;kmeans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;KMeans&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_clusters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cluster&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kmeans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Semi-Supervised Learning
&lt;/h3&gt;

&lt;p&gt;Combines a small amount of labeled data with a large amount of unlabeled data to improve learning efficiency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Conceptual example
# Libraries such as sklearn-semi-supervised can be used
# Commonly applied in text and image classification
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. Reinforcement Learning
&lt;/h3&gt;

&lt;p&gt;An agent learns by interacting with an environment and receiving rewards or penalties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Conceptual example
# Commonly implemented using OpenAI Gym or Stable-Baselines
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Core Machine Learning Components
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Algorithms
&lt;/h3&gt;

&lt;p&gt;Algorithms define &lt;strong&gt;how learning happens&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.tree&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DecisionTreeRegressor&lt;/span&gt;

&lt;span class="n"&gt;tree_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DecisionTreeRegressor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;tree_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Models
&lt;/h3&gt;

&lt;p&gt;Models store learned relationships and are used for prediction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;predicted_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="mi"&gt;1600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;span class="n"&gt;predicted_price&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Training
&lt;/h3&gt;

&lt;p&gt;Training adjusts model parameters to reduce prediction error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Training already performed using model.fit()
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;Testing evaluates model performance on unseen data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mean_squared_error&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.model_selection&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;train_test_split&lt;/span&gt;

&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train_test_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;predictions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;mean_squared_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How Machine Learning Works (Step-by-Step)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Data Collection
&lt;/h3&gt;

&lt;p&gt;Data can be gathered from APIs, databases, web scraping, or public datasets. &lt;strong&gt;Ethical data usage is essential&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;seaborn&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sns&lt;/span&gt;

&lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tips&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. Data Preprocessing
&lt;/h3&gt;

&lt;p&gt;This step cleans and prepares the data for modeling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Handling missing values
&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numeric_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;inplace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Encoding categorical variables
&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_dummies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drop_first&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Model Training
&lt;/h3&gt;

&lt;p&gt;The dataset is split into training and testing subsets, and a suitable algorithm is applied.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.linear_model&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LogisticRegression&lt;/span&gt;

&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tip&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tip&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LogisticRegression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_iter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. Model Evaluation
&lt;/h3&gt;

&lt;p&gt;Evaluation metrics help assess model performance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;accuracy_score&lt;/span&gt;

&lt;span class="n"&gt;predictions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;accuracy_score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  5. Model Deployment
&lt;/h3&gt;

&lt;p&gt;The trained model is integrated into real-world applications.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;joblib&lt;/span&gt;

&lt;span class="n"&gt;joblib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ml_model.pkl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Visualization and Interpretation
&lt;/h2&gt;

&lt;p&gt;Visualizations help understand model behavior and feature relationships.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;

&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;area&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Area&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Area vs House Price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Challenges and Ethical Considerations in Machine Learning
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Privacy Concerns
&lt;/h3&gt;

&lt;p&gt;Sensitive data must be protected and anonymized.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Removing personal identifiers
&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ignore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inplace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Bias in Data and Algorithms
&lt;/h3&gt;

&lt;p&gt;Biased data can produce unfair predictions. Balanced datasets help reduce this risk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Checking class distribution
&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value_counts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Interpretability and Transparency
&lt;/h3&gt;

&lt;p&gt;Models should be explainable to build trust.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Coefficients of linear regression
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;coef_&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Societal Impact
&lt;/h3&gt;

&lt;p&gt;Machine learning can both empower and disrupt society. Responsible deployment ensures fairness, transparency, and trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Machine learning simplifies complex decision-making across industries, but it must be used responsibly. This article explained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Machine learning fundamentals&lt;/li&gt;
&lt;li&gt;Core learning types&lt;/li&gt;
&lt;li&gt;End-to-end ML workflow&lt;/li&gt;
&lt;li&gt;Ethical challenges and best practices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By combining &lt;strong&gt;technical expertise&lt;/strong&gt; with &lt;strong&gt;ethical responsibility&lt;/strong&gt;, machine learning can drive sustainable innovation and positive societal impact.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>beginners</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
