{{ availability }}

Backend engineer for things that can't go down.

I am SaiReddy. I take products from a blank repo to something running: I architected an enterprise RAG platform for four terabytes of unstructured documents, ship full stack on MERN, and have shipped production services in .NET. I own the decisions, write down the trade offs, and hand you a system you can operate.

Résumé (PDF)
JAVASCRIPTPYTHONMERNC# / .NETOPENSEARCHDOCKERAZURE
SaiReddy Annamareddy
open to work
Backend and AI engineer
B.Tech CSE, AI/ML and DS, 2026
Full-time · Internship · Contract
4 TB
raw multi format data the pipeline is designed for
90s to 4s
restart ingestion, via a SHA-256 manifest
95%
heuristic triage confidence, no manual labels
12
file formats parsed, OCR'd and indexed
Prototype measurements on sample data. 4 TB is the production design target.
Case studies

Full stories: constraints, trade offs, hindsight.

scroll →
Architecture · the ingestion pipeline I designed

Any file in, citable knowledge out

Seven stages, each isolated so one bad file cannot stop the batch. Only changed files run: the manifest diffs the filesystem on every start.

01 SCANNER
Repository walk
SHA-256 content IDs
02 PARSER
12 formats
per page PDF text
03 OCR
Tesseract, gated
only under 50 chars
04 TRIAGE AI
4 tier cascade
folder, name, regex, LLM
05 CHUNKER
Page aware
1500 with 150 overlap
06 EMBEDDER
bge-large-en
1024 dims, local
07 INDEX
OpenSearch HNSW
cosine, m=16
manifest diff: only new, modified or deleted files enter the pipeline
How I work

Give me the problem, not the ticket.

Small teams do not need someone waiting to be told what to build. Here is what you actually get.

01 OWNERSHIP

I scope it myself

On the RAG platform nobody handed me a spec. I defined the target scale, the file formats to support, the confidence thresholds and the failure behaviour, then built to them.

02 DECISIONS

Trade offs written down

Every case study here lists the options I rejected and why. You will never inherit a design decision from me that has no reason attached to it.

03 END TO END

Frontend to infrastructure

React and Node on the front, Python or .NET services behind it, Docker and a queue in the middle, deployed and monitored. One person can carry a feature the whole way.

Fundamentals in practice

System design and DSA, applied to shipped code.

Not interview trivia. These are the specific places in the RAG platform where a data structure or a design decision was the difference between working and not working.

HASH MAPS AND DIFFING

Incremental change detection, O(1) lookups per file

The manifest is a hash map keyed by SHA-256 content ID. Deciding whether a file needs reprocessing is a constant time lookup instead of a rescan, which is exactly what turns a 90 second restart into 4 seconds.

GRAPH SEARCH

Approximate nearest neighbours over 100k vectors

HNSW is a navigable small world graph, so choosing m=16 and cosine distance is a recall against memory trade off, not a default. Exhaustive search over 1024 dimensional vectors would not return inside a request.

EARLY EXIT CASCADES

Order the cheap checks first

Triage is a four tier cascade and gated OCR is a guard clause. Both are the same idea: put the O(1) deterministic test ahead of the expensive one so cost tracks the hard cases, not the volume.

FAILURE ISOLATION

Idempotent stages and atomic writes

Every stage is independently recoverable, manifest writes are temp file plus atomic replace, and the vector store has a numpy fallback. A crash mid batch costs you the current file, never the state.

Top 5%
college coding contest
7 stages
independently recoverable
1024 d
vectors indexed for sub second recall
Every number on this site traces back to a decision I can walk you through in an interview.

Stack and story

Two internships, one degree, and a habit of reading the whole architecture before touching it.

FEB 2026 to JUL 2026
SWE Intern · EverUptime Technologies
Backend modules in C# and .NET on a live telemetry platform, with Azure Service Bus, Event Grid, Event Hub, MQTT and AMQP.
APR 2025 to JAN 2026
AI Agent and Automation Intern · Growstack
LLM agent workflows and the automation framework behind 30% faster QA.
2023 to 2026
B.Tech CSE, AI/ML and Data Science
Aditya College of Engineering and Technology · CGPA 7.5 of 10
Core, used in shipped work Familiar
AI and retrieval
RAG pipelines AI agents OpenSearch k-NN bge embeddings CrossEncoder rerank Llama 3.3 via Groq Tesseract OCR
Backend
Python C# and .NET Java FastAPI Node and Express REST and JWT Pydantic
Full stack, MERN
JavaScript (ES6+) TypeScript MongoDB Express.js React.js Node.js REST and JWT auth Mongoose Vercel and Docker deploys
AI/ML and data science
PyTorch Transformers BERT fine tuning scikit-learn pandas and NumPy NLP and OCR Model evaluation
Fundamentals
System design DSA in Java and Python Caching and indexing Concurrency Schema design Observability
Infra and distributed
Docker Compose Kubernetes Azure messaging MQTT and AMQP Kafka AWS Bedrock path
Honors
Winner of the AI Agent Competition at Growstack, which came with an internship and a Certificate of Excellence. Top 5% in the college coding contest.

Have a system that needs to hold?

Full stack and AI engineering, end to end. Open to startups in India, the US and Europe, on site in Hyderabad or remote in your hours. Full time or contract.

© 2026 Jyothi SaiReddy Annamareddy {{ phoneLine }}
Flagship · designed and built end to end

Enterprise Content Intelligence

A production ready, fully Dockerized RAG platform that ingests enterprise documents in any format, builds a searchable vector knowledge base with automatic metadata classification, and delivers grounded answers with source citations. Everything runs locally except LLM inference.

View the repository
4 TB
target repository scale
90s to 4s
restart ingestion time
100k+
chunks the index holds
0
manual labels required
Prototype, measured on a 200-file sample. 4 TB is the production target it was designed for.
In one line

What I actually built

Drop in a pile of enterprise files in almost any format, readable or scanned, organised or not. The system reads them, works out what each one is, makes the whole repository searchable, and answers plain questions with citations back to the exact file and page.

Any file in, citable knowledge out. Technical deep dive below.

System architecture

Two pipelines, one index

Ingestion runs offline and incrementally, writing to a vector index. Queries read from that same index online. A SHA-256 file manifest is what lets a restart skip everything that has not changed.

OFFLINE · INGESTION ONLINE · QUERY Scanner SHA-256 IDs Parser per-page text OCR gated, under 50 chars Triage 4-tier cascade Chunker page-aware Embedder bge, 1024-dim OpenSearch index HNSW · cosine · m=16 vector + metadata index File manifest SHA-256, JSON new / changed / deleted / skip diff on restart Query natural language Intent + embed metadata filters Hybrid search top 15 candidates Reranker CrossEncoder, top 5 LLM Groq, 3-layer context Answer + citations read
The public prototype runs every model locally except the LLM (Groq). In production these were moved behind AWS, covered below.
The problem

Terabytes of documents nobody organised

Enterprise repositories are not clean datasets. The brief I designed for was roughly four terabytes of raw material: scanned invoices as JPGs, PDFs with no extractable text layer, spreadsheets, Markdown notes, XML exports, and folders named random_dump. No schema, no labels, no guarantee a file is even readable.

Anyone can wire an embedding model to a vector store. The hard part is everything around it: getting text out of the unreadable half, classifying documents that arrive with no metadata, keeping ingestion cheap enough to restart daily, and making answers trustworthy enough that a finance team will act on them.

Unreadable inputs
Scans and images carry no text layer at all.
No metadata
Type and department have to be inferred, not read.
Answers need proof
A plausible paragraph with no citation is worthless.
Decision one

Classification: three options, one cascade

Every document needs a type and a department before it is indexed, so retrieval can filter instead of guessing. I explored three routes.

Explored, not shipped

Train a classifier

Fine tune a BERT style model on document types.

Why not: needs labelled data the client does not have, and every new document type means retraining.
Explored, not shipped

LLM classifies everything

Send every document to the model and let it decide.

Why not: one API call per file across terabytes is slow, costly, and non deterministic on re runs.
Shipped

A 4 tier triage cascade

Cheap deterministic signals first, the LLM only as a last resort.

Result: 95% confidence when folders are meaningful, graceful fallback when they are not, and the LLM bill scales with novelty rather than volume.
TIER 1 · 95%
Folder path
/shipping_orders/ to shipping_order
TIER 2 · 85 to 92%
Filename keywords
invoice_10256.pdf to invoice
TIER 3 · 75 to 88%
Content regex
body text patterns
TIER 4 · 80%
LLM discovery
invents new types on the fly
Quality scoring stays deterministic and separate: low text and noisy OCR push a document below the 0.60 threshold and flag it as degraded, whatever its type.
Decision two

Only pay for OCR when the file forces you to

OCR on every page would have dominated ingestion time. Instead the parser extracts first and OCR is gated: it runs only when extracted text falls under 50 characters, then renders the page at 200 DPI and reads it.

trade off: a handful of text light but legible pages get OCR'd unnecessarily. Cheap compared to OCR'ing everything.
Decision three

A file manifest, so restarts cost seconds

Every file is hashed with SHA-256 and recorded in a JSON manifest with its status and metadata. On startup the scanner diffs the filesystem against it: new files are processed, modified files have old chunks deleted first, deleted files are cleaned out of the index, unchanged files are skipped entirely.

90s
first run, 200 files
4s
restart, no changes
6s
five new files
The query path

Retrieve wide, rerank narrow, cite everything

Pure vector search answered content questions but failed on counting and on questions about one named file. So the online path parses intent first, then assembles three layers of context into a single prompt.

01 INTENT
Parse filters
type, department, folder, extension
02 EMBED
Same model
query and corpus aligned
03 HYBRID SEARCH
k-NN plus terms
top 15 candidates
04 RERANK
CrossEncoder
top 5 survive
05 ANSWER
3 layer prompt
full document, analytics, retrieval
Analytics questions
"How many invoices do we have?" is answered from metadata aggregation, with no vector search at all.
File specific questions
Name a file and every chunk of it is retrieved, so the model sees the whole document, not five fragments.
Follow ups
The last four exchanges ride along in context, and chat history persists across container restarts.
Constraints I built under
  • Runs on a laptop with 4 GB allocated to Docker, so GPU inference was off the table and PyTorch is CPU only.
  • Data cannot leave the machine except for LLM calls, so embedding and reranking are local models.
  • One command to start. Anyone should be able to run docker-compose up and get a working system.
  • It must stay useful when OpenSearch is down, which is why there is a numpy cosine fallback.
Reliability decisions
  • Per stage try and except, so one corrupt file fails alone instead of killing the batch.
  • Manifest writes go to a temp file then atomic replace, so a crash cannot corrupt state.
  • Periodic saves every 25 documents during long ingestions.
  • Failed files are recorded with their error message instead of vanishing.
  • Content hashing deduplicates the same file living in two folders.
From prototype to production

I designed the prototype, then led the team that shipped it

The repository above is the exact prototype we deployed. It is public because I built it deliberately on free and open-source tools, so it could be shared. Taking it to production for the client was a different job, and I led it.

The public prototype

I designed and built it end to end on open tools: Groq for the LLM, BAAI/bge for embeddings, Tesseract for OCR, OpenSearch for the vector index. Everything runs from one docker-compose up.

The numbers on this page were measured here, on sample data, not at full scale.

What shipped to the client

I led a 10-engineer team that took this exact prototype to production on AWS. We moved every model in-account, so there are no external LLM calls, and the client's data, up to the 4 TB target, never leaves their environment. At scale we swap in more accurate models than the free ones the prototype ships with.

Designed the prototype · led the migration · delivered to the client.
10
engineers I led on the production migration
0
external LLM calls in production, all in-account
100%
of client data kept inside their AWS account
What I would do differently

Three things, next time

Build the retrieval eval set on day one
I tuned chunk size, overlap and rerank depth by reading answers. A fixed set of question and expected source pairs would have turned that into a measurable regression test instead of a judgement call.
Separate ingestion from the UI process earlier
Ingestion currently runs alongside the dashboard. Splitting it into a worker service from the start would let ingestion scale horizontally without touching the front end, which is exactly the change the scaling plan calls for.
Version the triage rules like code
When the LLM discovers a new document type, that decision should be reviewable and diffable rather than absorbed silently into the manifest.
View the repository
Growstack Inc. · Apr 2025 to Jan 2026

Agent workflows, and the framework that tested them

I joined Growstack by winning their internal AI Agent Competition, then spent ten months on two sides of the same problem: making LLM agents automate real backend workflows, and making the testing around them fast enough that nobody dreaded a release.

30%
faster QA turnaround
1st
AI Agent Competition, which became the internship
2
reusable frameworks, UI and API
10 mo
shipping alongside the platform team
The problem

Manual regression was the release bottleneck

Every release meant a human clicking through the same flows and firing the same API calls by hand. It was slow, it was inconsistent between testers, and the parts that broke most often were the integrations between services, exactly where manual testing is weakest.

In parallel the product needed agents: LLM driven workflows that could take a backend task, call the existing APIs, and complete it without a person in the loop. Both problems shared a root cause, nothing was described in a reusable way.

The decision

Write tests as behaviour, not as scripts

The obvious route was to record and replay flows. I argued for BDD instead, and the trade off was real.

Considered, rejected

Record and replay scripts

Fastest to a first green run. Anyone can record a flow.

Why not: every selector change breaks it, and nothing is reusable between flows. Coverage grows linearly with effort forever.
Shipped

Cucumber steps as a shared vocabulary

Slower to the first test, because the step library has to exist first.

Payoff: new scenarios are written from existing steps, so the second month of coverage cost far less than the first. That compounding is where the 30% came from.
UI LAYER

Selenium plus JUnit

Page objects keep locators in one place, so a redesign touches one file instead of forty scenarios.

API LAYER

REST Assured plus Postman

Integration paths get asserted at the contract level, where the failures actually were. Postman for the exploratory pass first.

AGENT LAYER

Modular LLM workflows

Agents composed from small steps that call existing APIs, so each step is testable on its own rather than one opaque prompt.

Collaboration that changed the work

The backend team pushed back on my first agent design: it called APIs the way a person would, one at a time, and it was too slow to sit in a real workflow. Their suggestion was to batch and to fail fast on validation before any LLM call.

I also stopped writing test documentation for testers and started writing it for the developers who would run the suite. Same content, different reader, and adoption changed completely.

Constraints
  • An existing product, mid flight. No refactoring the app to make it testable.
  • Shared staging environment, so tests had to tolerate data they did not create.
  • A team of one on QA tooling, which is precisely why reuse mattered more than coverage count.
What I would do differently

Two honest lessons

Wire it into CI on week one
The suite ran on demand for too long. A test nobody runs automatically decays, and I lost time re fixing things that a nightly run would have caught the day they broke.
Instrument the agents before scaling them
I added tracing to agent runs after the workflows were already in use. Building that in first would have made debugging a bad run a five minute job instead of an afternoon.
admin

Sign in to edit your details

Only you see this route. Checked against the server; never stored in the page.

Wrong passcode. Try again.
admin · signed in

Edit your details

Changes save to the server instantly and show across the site for everyone. Use Download JSON to keep a backup copy.

Profile photo
Résumé (PDF)
Preview current file
Or link to a hosted file instead
{{ saveNote }}
How this saves

Edits save to the server and are live for every visitor immediately, not just this browser. The passcode is never stored in the page itself. Change it any time below.

Change passcode
{{ pinChangeError }} {{ pinChangeNote }}
EverUptime Technologies · contributor, not architect

What a live telemetry platform taught me

Honest framing first: I did not design the OOPDAAS platform. I joined a globally deployed system as a backend intern, owned modules inside it, and learned how a 2 second SLA changes every decision you make. These are notes, not a portfolio piece about my architecture.

What I actually did
  • Built backend modules in C# and .NET for data centre telemetry processing, held to the platform's 2 second end to end budget.
  • Shrank each telemetry payload from 95 to 59 bytes by dropping a redundant key, so a fixed 256 KB/s channel carries 4,338 signals per second instead of 2,694.
  • Integrated production microservices across Azure Service Bus, Event Grid, Event Hub, MQTT, AMQP and Mosquitto.
  • Read the end to end architecture before contributing, then delivered components that fit it rather than fighting it.
What it taught me
  • A latency budget is a design constraint, not a metric. It decides what you are allowed to do per message.
  • In a distributed system, reading the whole path first is faster than starting to code sooner.
  • Protocol choice is mostly about delivery guarantees and backpressure, not throughput headlines.
  • It taught me to think at the byte level: one key removed from a payload compounds into thousands more signals a second, the kind of gain no architecture diagram shows.

This is the experience I lean on when I design my own systems, and it is why the RAG platform is built around isolation, restartability and measurable budgets. That case study is the one to read if you want to see what I do when the architecture is mine.