Bengaluru, India · open to AI and full-stack internships

I build AI products, and I measure*0.99 answer faithfulness, 0.95 retrieval Hit@1, 20/20 on the agent eval. Every number comes from a test you can re-run. them before I ship.

I'm Rudra, a computer science student at Cambridge Institute of Technology (VTU). Until October I was the founding software engineering intern at FERMOR, where the pages I redesigned brought in a month's usual traffic on launch day.

I work across the stack, from React interfaces to RAG pipelines and tool-calling agents.

i.

About

I like building a product end to end, from the interface to the model. Most of what I know I learned by shipping something, watching it break, and finding out why.

I don't trust a feature until I've measured it, so every project number on this page comes from an eval or a test you can re-run from the code.

— Rudra

Experience

  • Founding Software Engineer Intern, FERMORSep – Oct 2026

    Bengaluru, hybrid

    • Redesigned key website pages end to end for a cleaner, more usable UI.
    • Reworked page structure, headings, metadata and content for SEO.
    • Launch day brought about 30 times the usual daily traffic, a month's worth in one day; I used analytics to measure it and decide what to do next.

Education

  • B.E. Computer Science and Engineering2024 – 2028

    Cambridge Institute of Technology, North Campus (VTU). CGPA 8.0, now in the 5th semester.

  • Class XII, CBSE (PCM)74%

    Physics, Chemistry and Mathematics.

  • Class X, CBSE74%

Now: learning LangGraph and building a Python text-to-SQL agent over real Indian public data, with Postgres, pgvector and an accuracy eval.

ii.

Skills

What I work with, and where you can see it used.

AI / LLM

RAG, tool-calling agents, embeddings, semantic and hybrid search (BM25, RRF), LLM-as-a-judge evaluation, structured outputs, prompt engineering, Gemini API, Groq API

Used in AyurIP-Sahayak and NestFinder
Backend

FastAPI, Node.js, Express.js, REST APIs, MongoDB, JWT authentication

FastAPI in AyurIP-Sahayak; Express, MongoDB and JWT in NestFinder
Frontend

React, Vite, Tailwind CSS, HTML, CSS

The interfaces of both projects, and the website redesign at FERMOR
DevOps & tools

Docker, GitHub Actions, Git, Linux, pytest, Vercel, Render, Langfuse, OpenTelemetry

Docker, 47 tests and CI on AyurIP-Sahayak; Vercel, Render and Langfuse tracing on NestFinder
Languages

Python, Java, JavaScript, SQL

Python for AyurIP-Sahayak, JavaScript for NestFinder
Core CS

Object-oriented programming, operating systems, DBMS, computer networks

From my B.E. coursework
iii.

Selected work

Two systems in production. Each one has a method, measured results, and a public record of what went wrong.

  1. 01AyurIP-SahayakMultilingual RAG assistant that cites the page behind every claimPython · live
  2. 02NestFinderTool-calling AI agent that finds and checks flats in BengaluruNode.js · live

AyurIP-Sahayak

RAG system · Python · live

A research assistant for Ayurveda, traditional knowledge and Indian IP law. Ask in English, हिन्दी, ಕನ್ನಡ or Hinglish; it answers only from its sources and cites the exact page behind every claim.

0.99answer faithfulness0.95retrieval Hit@14 languagesEnglish, Hindi, Kannada, Hinglish

AyurIP-Sahayak answering 'What happened in the turmeric patent case?' with numbered citations and a sources list
Fig. 1. The answer screen. 1 Questions in Hindi or Kannada still find English passages. 2 Every claim carries a numbered citation. 3 Sources arrive in under a second, first words in under two. 4 Each source opens with its page, section and similarity score.
Read the full write-up architecture, method, results, what broke
AyurIP-Sahayak architecture PDFs are chunked by section, embedded with Gemini and stored as a NumPy matrix. Each question is embedded, the top six passages are found by cosine similarity, and Gemini Flash-Lite streams a cited answer. A retrieval eval and an LLM judge measure quality. Index, built once PDF sources2 docs · 54 pages Chunkerby section, page-safe Gemini embeddings768 dimensions Vector indexNumPy · 229 × 768 · 0.7 MB Every question QuestionEN · हि · ಕ · Hinglish Retrievercosine top-6 · 0.03 ms GeneratorGemini Flash-Lite Streamsources first React UIcited answer passage vectors Quality, re-run on changes Retrieval evalHit@1 0.95 · MRR 0.97 LLM judge · gpt-oss-120bfaithfulness 0.99 · 15/15 planted errors caught

Press play, or hover a box, to follow one question through the system.

Fig. 2. Architecture. The red path is one question, end to end.

How it works

  1. Retrieval written by hand. Section-aware PDF chunks, Gemini embeddings and NumPy cosine search, plus BM25 and Reciprocal Rank Fusion built from scratch to compare against.
  2. Decisions from data. Hybrid search is the usual advice. On 38 labelled questions it lowered MRR from 0.97 to 0.93, so dense search stayed the default.
  3. Answers judged, and the judge tested. A model from a different family checks every answer claim against its passages. I planted 15 false sentences to test it; it caught all 15.

Built with Python, FastAPI, Google Gemini API, NumPy, React, Docker, GitHub Actions, and pytest (47 tests).

Results

MeasureResult
Answer faithfulness166 of 167 claims supported0.99
Citation precisioncited passage backs the claim0.98
Retrieval MRR0.93 with hybrid search0.97
Off-topic questions refusedsays "not covered" instead of guessing5/5
Dense (chosen)0.95
Hybrid (RRF)0.87
BM25 keywords0.47
Fig. 3. Retrieval Hit@1 on 38 labelled questions.

What broke, and how I fixed it

  1. 01

    The first deploy ran out of memoryAyurIP

    A local PyTorch embedding model went past the free server's 512 MiB. I moved to an embeddings API and plain NumPy search.

    Down to 5 runtime packages
  2. 02

    The "best practice" made search worseAyurIP

    Fusing in keyword search pushed correct passages down a rank or two. Dense search stayed the default; hybrid is one setting away.

    MRR 0.97 vs 0.93
  3. 03

    Kannada answers showed broken lettersAyurIP

    The model slipped Devanagari letters into Kannada words. I mapped them across Unicode blocks (they sit 0x380 apart), with tests.

    4/15 → 0/15
  4. 04

    English questions came back in KannadaAyurIP

    A Kannada example in my own prompt pulled the model off course. The code now picks the reply language and states it in the prompt.

    15/15 correct

NestFinder

Tool-calling agent · Node.js · live

An AI flat finder for Bengaluru. Describe how you live, and an agent decides which tools to call to find flats that fit, check whether the rent is fair, and compare a shortlist.

20/20tool choice on the eval2.4 smedian replyRefusedprompt injection

Read the full write-up screenshot, architecture, method, results, what broke
NestFinder's assistant replying to 'I work at Manyata Tech Park, budget 25k, I have a dog' with three scored flats while the filter form fills itself
Fig. 4. The match screen. 1 One plain message in English, Hindi or Hinglish. 2 The agent calls the search tool and the filters fill themselves. 3 A unit-tested rules engine, not the model, computes every match score. 4 Each flat lists its main drawback, so the reply can't oversell it.
NestFinder architecture The React app calls an Express API through a Vercel rewrite. An agent loop talks to a Groq model with a fallback, and calls five tools. The tools use a tested rules engine and MongoDB. Every model call is traced in Langfuse, and an eval and unit tests check quality. Request path React UIchat · filters Vercel rewrite/api → Render Express APIrate limits · JWT Agent loop≤ 3 rounds · repair Groq LLM120b, 20b fallback Tools, rules, data MongoDB Atlas120 flats · geo index Rules enginematch · fair rent · geo 5 toolssearch, rent, compare LangfuseOpenTelemetry Quality Unit tests26 · node:test Tool-choice eval · 20 cases20/20 exact · median 2.4 s · injection refused

Press play, or hover a box, to follow one chat message through the agent.

Fig. 5. Architecture. The red path is one chat message, end to end.

How it works

  1. An agent loop from scratch. Five tools, streamed replies, at most three tool rounds, a repair step when the provider rejects a call, and a fallback model when the rate limit hits.
  2. The AI talks, the code decides. Match scores, fair-rent medians and distances come from rules with tests, so every number on screen has a reason.
  3. Observable and safe. Every model call is traced with OpenTelemetry in Langfuse, phone numbers masked. The agent can suggest a visit; only the user can book it.

Built with Node.js, Express.js, React, MongoDB, Groq API, Langfuse, OpenTelemetry, and node:test (26 tests).

  1. "I work at Manyata, budget 25k, I have a dog"
  2. search_flats(techPark: "Manyata Tech Park", budget: 25000, pets: true)
  3. top 3 flats, each split into fits and problems
  4. reply streamed from those facts only
Fig. 6. One assistant turn, simplified.

Results

MeasureResult
Tool-choice eval18/20 before the fix20/20
Median reply timestreamed word by word~2.4 s
Prompt injectiona case in the eval setRefused
Rules engine testsscores, medians, name lookup26
$npm run eval:agent
    20/20 exactmedian 2.4 sgpt-oss-120b
    Fig. 7. The agent eval, replayed case by case from its results file.

    What broke, and how I fixed it

    1. 01

      "My office is in Whitefield" got an empty replyNestFinder

      A strict enum made the provider reject the whole tool call, silently. Free-text names are now resolved in code, with a repair loop.

      18/20 → 20/20
    2. 02

      Every visitor would have shared one rate limitNestFinder

      I guessed two proxy hops; the live deploy had four. I measured the hops on production and set the proxy trust to match.

      Measured, not guessed

    Let's build something that works.

    I'm looking for an AI or full-stack internship where I can ship real features and measure them. Email is the fastest way to reach me.