The gap between "I learned AI" and "I built AI" is a single deployed app. This lesson is the bridge — pick a problem, ship a solution, write the README, share the link. Recruiters care more about this one shipped link than your GPA, your bootcamp certificate, or 47 unfinished GitHub repos combined.
The single fastest way to go from "AI student" to "AI engineer" is to ship something live on the internet. Not a notebook. Not a Streamlit demo on your laptop. A real URL that strangers can hit, with metrics in a dashboard somewhere. This lesson walks you through building, deploying, and sharing exactly that — in one weekend.
Learning Objectives
After this lesson, you will be able to:
Pick a project idea that solves a real problem instead of chasing impressive-sounding tech
Build an MVP using ~80 lines of Python + FastAPI + Claude API, with proper error handling and config
Deploy to a real internet URL using Railway or Vercel and verify it works from a phone
Share the project on LinkedIn / Twitter / Hacker News in a way that triggers actual conversations, not crickets
The deploy step is where 90% of learners stop — making it your edge. Most ML curricula end at the notebook. Anyone who can also deploy, measure, and iterate becomes a real engineer.
Build this → By the end of this lesson, you'll have a deployed Claude-API-powered application running on a public URL, documented on GitHub, and ready to share — built in approximately 80 lines of Python.
#Step 1: Pick a Real Problem (Not Impressive Tech)
The biggest mistake new builders make is choosing projects by how impressive the tech sounds. "I'll fine-tune a 70B model and deploy it on Kubernetes." Six months later: nothing shipped.
The right framing is the opposite. Pick a problem so small and so concrete that you can finish a v1 in a weekend. The tech is secondary.
Walk through your week. Identify one thing a friend, family member, or coworker complains about repeatedly. That's your project.
Worked examples of the pattern — each one starts from a specific annoyance a real person had, which is the part that matters:
Project
Problem
Tech used
Build time
PaperSorter
Friend in grad school had 400 unread arxiv papers
Embeddings + Claude API + CLI
6 hrs
SlackSummarizer
Coworker missed long Slack threads while on PTO
Slack API + Claude API + cron
8 hrs
VoiceTranslator
Telegram bot for parents who only speak Tamil
Whisper API + Claude + Telegram bot
10 hrs
MeetingActionItems
Manager wanted action items extracted from Zoom transcripts
Zoom transcript + Claude + Notion API
12 hrs
RecipeFromFridge
Roommate asked "what can I cook?" looking at the fridge
Image + Claude vision + recipes
8 hrs
Notice: none of these required novel research. All required taste — picking a real problem, building a clean MVP, measuring whether it actually helped.
"AI for X" with no X user in sight. Pick a real user, even if that user is just you.
Reinventing GPT. Don't try to train a foundation model.
The mega-project. "I'll build a full ChatGPT clone with auth, payments, multi-modal, agents…" Ship the smallest possible version. Add features only after v1 is in use.
The leaderboard chase. Beating SOTA on MNIST by 0.3% won't help you get a job in 2026. Shipping a useful tool will.
The MVP cycle has four stages. Most beginners only do "build." That's why they never ship.
Build (Day 1): Smallest possible thing that solves the problem end-to-end.
Deploy (Day 1, same day): Get it on a real URL. Do not skip.
Measure (Day 2): Add logging. Run the eval. Get one real user trying it.
Iterate (Days 3-5): Fix the obvious issues. Add one feature at a time.
Notice: deploy is on Day 1. Not Day 14. The reason: deployment is where things break. Configs, environment variables, dependency mismatches, port issues. Fix all of that on Day 1, when the codebase is small, not Day 14, when it's tangled.
Let's build something real. We'll build "AskMyPDF" — a small app where a user uploads a PDF, the app extracts text, indexes it, and answers questions about it using Claude.
This is intentionally a common project type. Hiring managers see hundreds of RAG demos. What separates yours: clean code, real evals, public deployment, written-up methodology.
"""
AskMyPDF — a minimal RAG app over a single PDF.
Endpoints:
POST /upload — upload a PDF, return a doc_id
POST /ask — ask a question about an uploaded doc
Run locally: uvicorn main:app --reload
"""
import os
import uuid
from typing import Annotated
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from pypdf import PdfReader
from anthropic import Anthropic
from rag import build_index, retrieve
# ----- config -----
ANTHROPIC_API_KEY = os.environ["ANTHROPIC_API_KEY"]
MODEL = "claude-opus-4-5"
MAX_PDF_PAGES = 200
# ----- app -----
app = FastAPI(title="AskMyPDF")
app.add_middleware(
CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]
)
client = Anthropic(api_key=ANTHROPIC_API_KEY)
INDEX: dict[str, dict] = {} # in-memory; swap for Postgres in v2
class AskRequest(BaseModel):
doc_id: str
question: str
@app.get("/")
def health() -> dict:
return {"status": "ok", "docs_indexed": len(INDEX)}
@app.post("/upload")
async def upload_pdf(file: Annotated[UploadFile, File()]) -> dict:
if not file.filename or not file.filename.lower().endswith(".pdf"):
raise HTTPException(400, "Please upload a .pdf file.")
reader = PdfReader(file.file)
if len(reader.pages) > MAX_PDF_PAGES:
raise HTTPException(400, f"PDF too long (max {MAX_PDF_PAGES} pages).")
text = "\n".join(page.extract_text() or "" for page in reader.pages)
if not text.strip():
raise HTTPException(400, "Could not extract any text from PDF.")
doc_id = str(uuid.uuid4())[:8]
INDEX[doc_id] = build_index(text)
return {"doc_id": doc_id, "pages": len(reader.pages), "chunks": len(INDEX[doc_id]["chunks"])}
@app.post("/ask")
def ask_question(req: AskRequest) -> dict:
if req.doc_id not in INDEX:
raise HTTPException(404, f"Unknown doc_id {req.doc_id}")
if not req.question.strip():
raise HTTPException(400, "Question cannot be empty.")
relevant = retrieve(INDEX[req.doc_id], req.question, k=4)
context = "\n\n---\n\n".join(relevant)
prompt = (
"You are a careful assistant answering questions strictly from the provided "
"document excerpts. If the answer is not in the excerpts, say 'I cannot find "
"that in the document.'\n\n"
f"=== Document excerpts ===\n{context}\n\n"
f"=== Question ===\n{req.question}\n\n"
"Answer concisely (2-4 sentences), citing the excerpt number when you use it."
)
response = client.messages.create(
model=MODEL,
max_tokens=512,
messages=[{"role": "user", "content": prompt}],
)
return {
"answer": response.content[0].text,
"chunks_used": len(relevant),
"tokens_in": response.usage.input_tokens,
"tokens_out": response.usage.output_tokens,
}
Railway: free tier covers ~500 hours/month of execution time. Once you're past hobby usage, expect $5-15/month.
Anthropic API: this small app costs roughly $0.003-0.01 per question (input tokens dominate). 1,000 questions ≈ $5. Set a usage limit on your Anthropic dashboard so a viral moment doesn't bankrupt you.
Total cost to host this project for 6 months while job hunting: $15-50. Less than two takeout dinners.
Your README is the second thing people see after the live URL. Treat it like the resume bullet for the project — but with room to breathe.
A README that converts:
markdown
# AskMyPDF
> Upload a PDF. Ask questions. Get answers grounded in the document.
**Live demo:** https://askmypdf-production.up.railway.app
**60-second Loom:** https://loom.com/share/xxxxx
## What it does
Upload a PDF (up to 200 pages). The app chunks it, embeds it with BGE-small,
indexes it in-memory, and answers your questions using Claude — citing the
exact excerpts it used. If the answer isn't in the document, it says so
instead of hallucinating.
## Why it exists
I built this for my partner, who works in policy and reads 30+ government
reports per week. She wanted a "Ctrl-F that understands meaning."
## Metrics
Evaluated on a hand-labeled 50-question test set over 3 different PDFs
(a textbook, a legal contract, and a scientific paper):
| | Accuracy | p95 Latency | Cost/question |
|----------------|----------|-------------|---------------|
| Naive baseline | 64% | 1.2s | $0.011 |
| AskMyPDF v1 | 89% | 1.6s | $0.013 |
## How it works (one paragraph)
PDF text is chunked into 600-char windows with 80-char overlap, embedded
with `BAAI/bge-small-en-v1.5`, and stored as normalized NumPy vectors. At
query time we embed the question, take top-4 by cosine similarity, and
pass the chunks + question to Claude with a strict "answer only from the
excerpts" system prompt.
## Run locally
pip install -r requirements.txt
export ANTHROPIC_API_KEY=sk-ant-...
uvicorn main:app --reload
## What I'd build next
- Persistent storage (Postgres + pgvector) — currently in-memory
- LLM-as-judge eval instead of keyword matching
- Streaming responses
- Multi-PDF corpus
Notice what the README does: lead with a demo link, explain the why, show metrics, and admit limits. That last part — "what I'd build next" — signals self-awareness and is one of the most respected things on a resume project.
Post 24-48 hours after deployment, while you're still excited. Format:
I just shipped my first end-to-end AI app: AskMyPDF.
The problem: my partner reads 30+ policy reports per week and asked for a "Ctrl-F that understands meaning."
v1 (deployed at [URL]) chunks a PDF, embeds with BGE-small, retrieves the top-4 chunks, and lets Claude answer — strictly from the document. On my 50-question eval set: 89% accuracy vs. 64% for a naive baseline.
A few things I learned: [1-3 specific technical lessons].
Code on GitHub: [link]. Try the demo here: [link]. Feedback welcome.
This kind of post regularly draws 5-20 thoughtful comments and 1-3 inbound recruiter DMs in the first 48 hours.
Shorter version of the same post, with a screenshot or 30-second video. Tag the model provider (e.g., @AnthropicAI). Some posts get reposted by the official accounts, which drives serious traffic.
Post once you have a real demo and a strong README. Title format: Show HN: AskMyPDF – a minimal RAG over a single PDF. The HN community is harsh but if 5 people upvote and 2 leave critique, you've gotten more product feedback than most paying products ever do.
DM 5 engineers you respect at companies you'd want to work at. Template:
Hi [Name], I built this small project ([link]) that solves [problem]. Given your work on [their thing], curious whether you'd see any obvious holes in the design. Either way, your work has been a useful reference — thank you.
About 1 in 3 reply. About 1 in 10 leads to a substantive conversation. Several lead to job referrals.