- Posted on
- • Artificial Intelligence
Artificial Intelligence Website Performance
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Artificial Intelligence Website Performance from the Bash Shell: Measure, Tune, Repeat
AI-powered features are hot—personalized recommendations, chatbots, semantic search. But if your site stalls while “thinking,” users bounce. The problem: AI workloads are compute-heavy, spiky (cold starts), and network/chat-stream oriented, which can wreck Time to First Byte (TTFB), Largest Contentful Paint (LCP), and overall conversion.
This post gives you a practical, terminal-first toolkit to benchmark, analyze, and improve AI website performance, all with Linux and Bash. You’ll get repeatable commands, minimal scripts, and caching strategies you can deploy today.
Note: Always load test only what you own or have explicit permission to test.
Why AI performance needs special care
Inference latency is variable: cold vs. warm model paths, batching, tokenizer overhead, and external API queues.
Payload sizes balloon: verbose JSON, token streams, embeddings, and logs.
Traditional page-performance tools don’t fully capture AI endpoint behavior (e.g., streaming SSE vs. full JSON responses).
Small fixes—caching repeated prompts, streaming responses, compressing JSON—can drastically improve perceived speed.
Prerequisites: Install CLI tools
You don’t need a big stack to start. The commands below install everything we’ll use: ApacheBench (ab), Siege, jq, NGINX, Redis, Node.js/npm, and Chromium.
- Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y apache2-utils siege jq nginx redis-server nodejs npm chromium
# Enable and start Redis
sudo systemctl enable --now redis-server
# Enable and start NGINX
sudo systemctl enable --now nginx
- Fedora/RHEL/CentOS (dnf):
sudo dnf install -y httpd-tools siege jq nginx redis nodejs npm chromium
# Enable and start Redis
sudo systemctl enable --now redis
# Enable and start NGINX
sudo systemctl enable --now nginx
- openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y apache2-utils siege jq nginx redis nodejs npm chromium
# Enable and start Redis
sudo systemctl enable --now redis
# Enable and start NGINX
sudo systemctl enable --now nginx
Optional but recommended:
# Install Lighthouse globally (Node-based)
sudo npm install -g lighthouse
1) Establish a fast, repeatable baseline
Before tuning, measure. Use both page-level and API-level tools.
- Static/dynamic page throughput with ab:
ab -n 200 -c 20 https://your-site.example/ > ab.txt
grep -E 'Requests per second|Time per request|Transfer rate' ab.txt
- Concurrency and basic stress with Siege:
siege -c25 -r10 -b https://your-site.example/
- Quick sanity check JSON endpoints:
curl -sS -o /dev/null -w "status=%{http_code} ttfb=%{time_starttransfer}s total=%{time_total}s\n" \
https://your-site.example/api/health
Capture these outputs and keep them in version control to track improvements/regressions.
2) Time the AI endpoint like a pro (p50/p95, cold vs. warm)
AI endpoints often run behind third-party APIs or model servers. You need granular timings to isolate DNS/connect/TTFB/total.
- Collect detailed curl timings:
URL="https://api.your-site.example/ai/complete"
DATA='{"prompt":"Hello, world"}'
printf "trial,namelookup,connect,starttransfer,total\n" > timings.csv
for i in $(seq 1 50); do
curl -sS -o /dev/null \
-H 'Content-Type: application/json' \
-X POST "$URL" \
--data "$DATA" \
--max-time 60 \
-w "$i,%{time_namelookup},%{time_connect},%{time_starttransfer},%{time_total}\n" || echo "$i,NA,NA,NA,NA"
done >> timings.csv
- Compute p50/p95/max from CSV:
awk -F, 'NR>1 && $5!="NA"{print $5}' timings.csv | sort -n | awk '
{a[NR]=$1}
END{
p50=a[int(NR*0.50)];
p95=a[int(NR*0.95)];
printf("p50=%ss p95=%ss max=%ss (n=%d)\n", p50, p95, a[NR], NR)
}'
- Compare cold vs. warm:
- Run once after restarting the model server (cold).
- Run again after several requests (warm).
- Keep both CSVs for reference.
Tip: If TTFB is high but total is only slightly higher, focus on backend processing start time (queueing, cold start). If total dwarfs TTFB, optimize payload size and streaming.
3) Slash latency with a simple Redis prompt cache (Bash wrapper)
Many AI prompts repeat (FAQs, product specs, docs). Cache deterministic responses for minutes to hours. This Bash wrapper checks Redis before hitting your AI provider. It’s drop-in and language-agnostic.
- Save as ai-cache.sh:
#!/usr/bin/env bash
set -euo pipefail
AI_URL="${AI_URL:-https://api.example.ai/complete}" # export AI_URL to override
TTL="${TTL:-3600}" # 1 hour default
PROMPT="${1:-}"
if [ -z "$PROMPT" ]; then
echo "Usage: $0 'your prompt here'" >&2
exit 2
fi
KEY="ai:resp:$(printf "%s" "$PROMPT" | sha256sum | awk '{print $1}')"
HIT="$(redis-cli GET "$KEY" 2>/dev/null || true)"
if [ -n "$HIT" ] && [ "$HIT" != "(nil)" ]; then
printf "%s\n" "$HIT"
exit 0
fi
RESP="$(curl -sS -X POST "$AI_URL" \
-H 'Content-Type: application/json' \
--max-time 60 \
--retry 2 --retry-delay 1 \
--data "{\"prompt\": \"${PROMPT//\"/\\\"}\"}")"
redis-cli SETEX "$KEY" "$TTL" "$RESP" >/dev/null || true
printf "%s\n" "$RESP"
- Make executable and test:
chmod +x ./ai-cache.sh
./ai-cache.sh "What is your return policy?"
- Distro-specific Redis service commands were provided in the install section. Be sure Redis is running.
You can front your app or edge functions with this script, or reimplement the same logic server-side with your app’s Redis client. For non-idempotent prompts (chat with state), cache only safe, deterministic queries.
4) Stream and compress responses with NGINX
Don’t hold the entire AI response before sending it. Stream it. Also compress JSON and event streams to reduce payload size.
- Minimal NGINX reverse proxy snippet for streaming AI responses:
# /etc/nginx/conf.d/ai.conf
server {
listen 443 ssl http2;
server_name your-site.example;
# gzip helps JSON and SSE
gzip on;
gzip_types application/json text/event-stream text/plain application/javascript text/css;
gzip_min_length 256;
# Forward to your AI app/model server
location /ai/ {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Connection "";
# Stream as data arrives (great for SSE/token streaming)
proxy_buffering off;
# Generous timeouts for long generations; tune to your SLO
proxy_read_timeout 300s;
proxy_send_timeout 300s;
# Optional: pass through flushes
chunked_transfer_encoding on;
}
}
- Test and reload:
sudo nginx -t && sudo systemctl reload nginx
- Client-side tip: If you use Server-Sent Events (SSE), set the right headers in your app:
Content-Type: text/event-stream
Cache-Control: no-cache
X-Accel-Buffering: no
Streaming improves perceived performance dramatically—even if total time is unchanged, users see tokens appear immediately.
5) Automate regressions with Lighthouse + jq
Even if your AI endpoints are fast, you still need solid Core Web Vitals. Run Lighthouse headlessly in CI and fail builds that degrade performance.
- Pick a Chrome/Chromium binary:
CHROME=$(command -v chromium || command -v chromium-browser || command -v google-chrome || command -v google-chrome-stable)
- Run Lighthouse and parse LCP with jq:
URL="https://your-site.example/"
lighthouse "$URL" --quiet --output json --output html \
--output-path ./lh-report.html \
--chrome-path="$CHROME" \
--chrome-flags="--headless --no-sandbox" > lh-report.json
LCP_MS=$(jq '.audits["largest-contentful-paint"].numericValue' lh-report.json)
TTI_MS=$(jq '.audits["interactive"].numericValue' lh-report.json)
echo "LCP(ms)=$LCP_MS TTI(ms)=$TTI_MS"
# Fail CI if LCP > 3500ms (tune threshold to your SLO)
awk -v lcp="$LCP_MS" 'BEGIN { if (lcp>3500) { print "LCP regression: " lcp "ms"; exit 1 } }'
- Keep artifacts:
lh-report.htmlis a full interactive report you can publish as a CI artifact.
Pro tip: Run Lighthouse against pages that exercise your AI features (e.g., a chatbot page) to catch how scripts, streaming, and hydration affect UX.
Real-world patterns that just work
Cache what you can: Prompt+parameters → response. Even 60 seconds can absorb spikes and slash p95.
Stream everything: Send headers immediately and flush tokens/events as they’re ready.
Keep JSON small: Remove unused fields server-side; compress; prefer newline-delimited events for streams.
Budget timeouts: Set max time for upstream AI calls and degrade gracefully (fallback copy, cached response, or “ask later”).
Monitor p95/p99, not just averages: Tail latencies matter most.
Conclusion and next steps (CTA)
You don’t need a GPU cluster to fix AI performance—you need measurements, a cache, and smart delivery. From Bash you can:
Baseline with ab/siege.
Pinpoint AI bottlenecks with curl micro-timings.
Add a Redis-backed cache for deterministic prompts.
Stream and compress with NGINX for instant feedback.
Guard your Core Web Vitals with Lighthouse in CI.
Next steps:
Drop the commands into your repo as scripts and wire them into CI.
Set explicit latency/error budgets and alerts based on p95.
Iterate weekly: measure, tweak, and commit the deltas.
If you want a starter pack of the scripts in this post, wrap them into a Makefile or a small bash toolkit so your whole team can run the same checks with one command.