Instrumented LLM Batch CLI
Build a command-line tool that sends a batch of prompts to any OpenAI-compatible endpoint over raw HTTP, keeps keys out of code, retries sensibly, logs every call and profiles where the time goes.
Lessons this project uses
What you'll build
A small CLI, ask.py, that reads prompts from a text file, sends each one to a chat completions endpoint using raw HTTP, and writes answers plus timing data to JSON lines. It reads secrets only from the environment, handles authentication errors, rate limits and timeouts the way a production script should, logs to a file, and comes with offline tests and a shell one-liner report. You will also profile a run and explain where the time actually goes.
Requirements
- Secrets. Configuration comes from environment variables
LLM_BASE_URL,LLM_MODELandLLM_API_KEY, optionally loaded from a.envfile that is gitignored. Commit a.env.examplewith placeholder values only. The key is never printed or written to logs (log only whether it is set). - Raw HTTP. Calls go to
{LLM_BASE_URL}/chat/completionsusingurllib.requestorrequests, with an explicit timeout. No vendor SDK is required. - Batch CLI.
python ask.py --prompts prompts.txt --out results/answers.jsonlprocesses at least 10 prompts you wrote yourself about a topic you care about. Each output line contains: prompt id, status (ok or error), HTTP status code, attempts, latency in ms, the answer text, and token counts when the response includes ausagefield. - Error handling. 401 or 403 prints a clear "check your API key" message and exits with code 2 without retrying. 429, 5xx and timeouts are retried with exponential backoff (for example 1s, 2s, 4s) up to 3 attempts. Any other failure is logged and the batch continues.
- Logging. Use the
loggingmodule with timestamps and levels, writing to both the console andlogs/run.log. - Offline tests.
tests/test_client.pyreplaces the HTTP call with a fake function and checks three cases without any network: 429 then 200 succeeds on attempt 2, 401 stops immediately, and a timeout on every attempt ends in an error record after 3 attempts. Runnable withpython -m pytestor plainpython tests/test_client.py. - Shell report.
scripts/summarize.shusesgrep,awk,sortorjqoverresults/answers.jsonlto print total calls, error count, mean latency and max latency. - Profiling. Run the batch once under
python -m cProfile -s cumtimeand save the top 15 lines toresults/profile.txt. Use aTimercontext manager to report network time vs JSON parsing and file writing time for the run. - Lint.
ruff check .passes with no errors.
Constraints
- Any OpenAI-compatible endpoint is fine: a local model served by Ollama or LM Studio (free, runs on a laptop CPU with a small model), the KatalockAi API, or any provider's free tier. No paid key is required; say in the README which one you used.
- CPU only, ordinary laptop, Python 3.11+ in a project virtual environment.
- Keep the batch small (10 to 30 prompts) and short answers (set
max_tokensaround 200) so a local CPU model finishes in a few minutes.
Stretch goals
- Run the batch in a tmux session or with
nohup ... &, then watchlogs/run.logwithtail -ffrom another pane. - Add a
--concurrencyflag with a thread pool and compare total wall time. - Use
tracemallocto report peak memory of a 100-prompt batch.
How to submit
Public GitHub repo with README.md, ask.py (or src/), .env.example, prompts.txt, tests/test_client.py, scripts/summarize.sh, results/answers.jsonl, results/profile.txt, and a pyproject.toml or requirements.txt. The README must give setup and run commands, name the endpoint and model you used, show your summary numbers, explain what the profile shows about where time goes, and describe one bug you hit while building it and how you found it. Never commit a real key.
How it's reviewed
Professor Katalock reads your repository and the evidence you paste, and scores each criterion out of 100. You pass with a weighted total of 70 or more and no criterion below 40. A copied or padded submission is flagged and fails.
Submit
Push your work to a public GitHub repository with a README that explains how to run it, then paste the evidence below. Up to 3 reviews a day, free.
- Link to the public GitHub repo
- Full terminal output of the batch run, `python ask.py --prompts prompts.txt --out results/answers.jsonl`
- Output of running with a deliberately wrong API key, plus `echo $?` showing exit code 2
- Full output of the offline tests and of `ruff check .`
- Output of `bash scripts/summarize.sh` and the first 15 lines of results/profile.txt
Reviews are done by AI against the rubric above. They check the evidence in your repository; they are not a substitute for a human code review, and a review can be wrong. If you think it is, improve the README so the evidence is unmistakable and resubmit.