Skip to content

Repository files navigation

Personal AI Chatbot — RAG on Cloudflare Edge

This project is an LLM-powered chatbot with a custom RAG system, deployed on Cloudflare's edge network. Check out the live demo at chienliu.com — the chatbot can answer questions about the author, Chien Liu 😺

Tech stack

Cloudflare Workers Workers AI D1 Vectorize Workflows JavaScript Hono

  • Cloudflare Workers: Edge runtime hosting the chatbot API
  • Workers AI: LLM inference for chat responses
  • D1: Relational store for RAG note metadata
  • Vectorize: Vector store for RAG embeddings/retrieval
  • Workflows: Orchestrates the RAG note sync process
  • Hono: Lightweight router for the Worker

Architecture diagram

Architecture and workflow diagram

Conversation history

The chatbot supports multi-turn conversations. It can answer follow-up questions like "Elaborate on that" or "What else?" because each request optionally carries an array of prior messages.

Design decision: frontend vs backend storage

Frontend storage (this project) Backend storage
Where history lives Browser memory — sent on each request Server session or database
Worker statefulness Stateless — each request is self-contained Stateful — Worker must read/write per-user state
Implementation cost None — client accumulates and sends history Session IDs, a KV/D1 table, and an eviction strategy
Privacy History never persists beyond the tab session History persists server-side
Cloudflare cost No extra bindings or reads/writes D1 or KV reads and writes on every turn

For a simple personal chatbot, frontend storage is the better call. Leveraging frontend storage is simpler, cheaper, and more privacy-compliant.

Cloudflare deployment

  • This repository is integrated with Cloudflare Workers.
  • The deployed Worker is built from the code in src/, with src/worker.js as the entrypoint.
  • The production route is https://api.chienliu.com/chatbot.
  • The local maintenance assets in notes/ and scripts/ support RAG content management, but they are not the Worker code that gets deployed from src/.

Rate limiting

  • POST /chatbot is rate limited per client IP using the native Cloudflare Workers Rate Limiting binding (CHATBOT_RATE_LIMITER, configured in wrangler.jsonc).
  • Limit: 5 requests per 60 seconds per IP (identified via the CF-Connecting-IP header).
  • Requests over the limit receive 429 Too Many Requests.

How it manages RAG

  • Each markdown file in notes/ is the source of truth for one RAG note.
  • The filename must follow this format:
${id}_${name_for_human_editor}.md

Examples:

1_chiens_work_experience.md
2_projects.md
15_publications.md
  • ${id} must be a positive integer.
  • The sync script normalizes the filename ID before sending it to the API.
  • The resulting ID is reused as the note ID in D1 and Vectorize.
  • Remote note writes happen through PUT /notes/:id (local only) with a JSON body shaped like { "text": "..." }. In production, only /chatbot requests reach the Worker, so /notes/:id is unreachable at the edge.
  • Renaming or deleting local files affects remote data on the next sync.

Workflow: Update RAG notes

  1. Create or edit markdown files in notes/.
  2. Copy .env.local.example to .env.local (first time only):
cp .env.local.example .env.local
  1. Start the local Worker:
npx wrangler dev
  1. In another terminal, run the sync:
npm run sync:notes

The workflow may take a moment to process. Monitor the npx wrangler dev output to confirm the upload has completed.

Sync behavior

The sync script is scripts/sync-rag-notes.sh.

It will:

  1. Scan notes/ for *.md files.
  2. Validate that every filename matches ${id}_*.md.
  3. Compute a SHA-256 hash for each file.
  4. Upload only notes whose content changed since the last successful sync.
  5. Delete remote notes whose IDs existed in the previous sync state but no longer exist locally.
  6. Save sync state in .rag-sync-state.

Because of this behavior:

  • Editing a file updates the remote note
  • Adding a file creates a remote note
  • Deleting a file deletes the remote note
  • Changing only the human-readable suffix keeps the same remote note if the numeric ID stays the same

Troubleshooting

  • Missing env variable: ensure .env.local exists and contains ADMIN_API_ENABLED=true.
  • Notes directory not found: create notes/ or set RAG_SYNC_NOTES_DIR.
  • Invalid note filename: rename the file to ${id}_name.md.
  • Duplicate note id: ensure only one markdown file uses each numeric ID.

Notes on safety

wrangler dev in this project is configured with remote Cloudflare bindings. A live sync updates the bound D1 and Vectorize resources, so use the sync flow carefully.

About

LLM-powered chatbot with a custom RAG system, deployed on Cloudflare's edge network

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages