Updated: 2026-06-11
This runbook matches the current NTU Pool codebase and deployment scripts.
Required:
DATABASE_URLOPENAI_API_KEYSUPABASE_URLSUPABASE_SERVICE_ROLE_KEY
Optional (defaults in code):
OPENAI_BASE_URL(OpenRouter example:https://openrouter.ai/api/v1)OPENAI_CHAT_MODEL(defaultgpt-4o-mini)OPENAI_EMBED_MODEL(defaulttext-embedding-3-small)CHATBOT_INTENT_API_KEY(default fallback:OPENROUTER_API_KEY, thenOPENAI_API_KEY)CHATBOT_INTENT_BASE_URL(defaulthttps://openrouter.ai/api/v1)CHATBOT_INTENT_MODEL(defaultliquid/lfm-2.5-1.2b-thinking:free)SUPABASE_DOCS_TABLE(defaultpool_documents)SUPABASE_MATCH_FUNCTION(defaultmatch_documents)SUPABASE_CHAT_LOG_TABLE(defaultchatbot_conversations)CHATBOT_TOP_K(default3)CHATBOT_MIN_SCORE(default0.45)CHATBOT_MAX_CONTEXT_CHARS(default4000)CHATBOT_DB_TOOL_MAX_CALLS(default4)NEA_API_KEY(weather module)SECRET_KEY(if missing, deploy script auto-generates)SUPABASE_INTENT_LLM_FAILURE_TABLE(defaultchatbot_intent_model_failures)SUPABASE_QA_LLM_FAILURE_TABLE(defaultchatbot_qa_model_failures)
Practical recommendation:
- Start from
CHATBOT_MIN_SCORE=0.45; lower to0.3or0only when recall is still too strict.
/api/chatrequires login. Unauthenticated requests return401./api/chatruntime now routes by intent classification first (dedicated model):small_talk: direct LLM replydatabase: tool-use/function-calling -> direct DB query -> LLM summaryknowledge_base: RAG retrieval + LLM generationfallback: out-of-scope fallback reply
- For backend rules/config questions (for example lightning/rain thresholds, persistence windows, consensus logic, runtime settings), knowledge path prioritizes backend snapshot context before generic vector similarity retrieval.
- Replies follow the user's language (Chinese question -> Chinese reply, English question -> English reply).
- For unknown answers, fallback text is language-aware (Chinese/English).
- Every successful chat is persisted to Supabase (
chatbot_conversations) with:- timestamp, user id, user/assistant messages
message_counter,sources, request metadata- feedback fields (
feedback_requested,rating_score,rating_submitted_at)
- Every 5th cumulative user message (5/10/15...) returns feedback metadata; frontend renders 5-star rating UI.
- Rating submission uses
POST /api/chat/feedbackand stores a 1-5 score in Supabase. - Non-English input translation now uses intent model first and falls back to QA model when primary translation fails.
- Every model invocation failure is logged in Supabase:
- intent model failures ->
chatbot_intent_model_failures - QA model failures ->
chatbot_qa_model_failures
- CSRF recovery for browser clients:
GET /api/csrf-tokenreturns a fresh token (Cache-Control: no-store)- frontend chat/report flows refresh token and retry once when a CSRF
400is returned
- Open Supabase SQL Editor.
- Run
init_supabase.sql. - Verify:
- table
pool_documents - table
chatbot_conversations - table
chatbot_intent_model_failures - table
chatbot_qa_model_failures - function
match_documents
- table
Long-term maintenance policy: run all Python commands in this repository with .venv.
Recommended entrypoint on Windows: dev.bat.
CMD:
python -m venv .venv
.venv\Scripts\python.exe -m pip install --upgrade pip
.venv\Scripts\python.exe -m pip install -r requirements.txtPowerShell:
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install -r requirements.txtdev.bat syncRecommended preflight checks:
dev.bat doctor --strict
dev.bat doctor --require-release-tools
dev.bat doctor --require-deploy-toolsNotes:
sync_knowledge_base.pyrequiresOPENAI_API_KEY,SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY.- Default mode is incremental sync (doc hash based): only inserts new docs/chunks, updates changed docs, and removes deleted docs.
- Sources include website pages, runtime status snapshot, community posts/reports, backend non-sensitive info, and local Markdown files in
knowledge_base/. - Default sitemap is
https://ntupool.org/sitemap.xml. - If sitemap is unavailable, sync script auto-discovers public GET routes from Flask app and crawls those URLs as fallback.
Double-click workflow (Windows Explorer):
sync_knowledge_base.batOptional debug query preview:
dev.bat sync --debug-query "泳池什么时候开放"Force full namespace rebuild when needed:
dev.bat sync --full-rebuild- Start app locally.
- Use browser flow or test client flow that includes
X-CSRFToken. - For manual API calls, first request
GET /api/csrf-tokenand use returned token inX-CSRFToken. - Verify unauthenticated
POST /api/chatreturns401. - Verify unauthenticated
POST /api/chat/feedbackreturns401.
- Open homepage.
- Confirm
NTU Pool Assistantlauncher button appears and can open chat panel. - As guest, open chatbot and confirm input area is replaced by login prompt.
- After login, ask a question and confirm reply/sources render.
- Send a small-talk message like
hi; confirm reply is returned with emptysources. - Ask one Chinese and one English question; confirm reply language follows input.
- Continue chatting until user cumulative count reaches 10, then confirm 5-star feedback widget appears.
- Submit a star rating and confirm no second submission is allowed for the same message.
deploy_update.batEnvironment check only (no build/deploy):
deploy_update.bat --check-only.\deploy_update.batDeploy scripts behavior:
- Check required env vars.
- Run
.venvdoctor precheck (scripts/venv_doctor.py --require-deploy-tools). - Verify Vercel CLI availability through
npx. - Deploy the current source to Vercel production with
npx vercel deploy --prod --yes. - Output the production URL printed by Vercel.
Important:
- The production platform is Vercel. Do not use gcloud, Docker, or Cloud Run for routine deploys.
- If GitHub integration is enabled in Vercel, pushing the production branch may already deploy automatically.
- If you double-click
deploy_update.bat, it auto-loads project.envvariables for local checks. - If
DATABASE_URLis missing butSQLALCHEMY_DATABASE_URIexists,deploy_update.batwill use it as fallback. - First-time manual CLI deploys may require
npx vercel loginandnpx vercel link. - CI/non-interactive deploys should provide
VERCEL_TOKEN. - If you need a non-default chat log table name, include
SUPABASE_CHAT_LOG_TABLEexplicitly in your deploy command env vars.
- Homepage loads and shows chatbot panel.
- Guest sees login prompt in chatbot panel (no send textarea).
- Unauthenticated
POST /api/chatreturns401. - Unauthenticated
POST /api/chat/feedbackreturns401. - Logged-in
POST /api/chatreturns200for valid message. - Invalid payload returns
400. - Missing config returns
503. - Unknown question returns polite language-matched fallback text.
sourcescontains URLs when retrieval succeeds via RAG.- Small-talk input (
hi,hello,你好) returns direct chat reply withsources=[]. - Post/comment/report data queries should route to database tool-use path.
- Backend rules/config questions (for example lightning logic settings) should route to knowledge path with backend-priority context.
- Chat input should support
Enterto send andCtrl/Cmd + Enterfor newline. - On message count
5/10/15..., response includesfeedback_required=trueand a validconversation_id. - Rating submit to
/api/chat/feedbackstores score successfully.
- Ensure dependencies were installed into
.venv:dev.bat setup - Ensure commands are executed with
.venv\Scripts\python.exerather than systempython.
- Corpus may be too small or score threshold too strict.
- Lower
CHATBOT_MIN_SCORE(for example0.45 -> 0.3) and redeploy.
- Check
CHATBOT_INTENT_API_KEY,CHATBOT_INTENT_BASE_URL, andCHATBOT_INTENT_MODEL. - Confirm intent model can return valid JSON with intent in:
small_talk|database|knowledge_base|fallback. - If intent model is unstable, system falls back to local heuristics in
app/services/chatbot/graph.py.
- Confirm knowledge sync includes
backend_non_sensitiveandrealtime_status_snapshotdocuments. - Ensure latest
graph.pyis deployed; backend rules questions should prioritize runtime/backend snapshot context before generic vector retrieval.
- Current code has RPC fallback in
graph.py; ensure latest code is deployed.
- Frontend sends
X-CSRFToken, and now auto-refreshes token viaGET /api/csrf-tokenwith one retry on CSRF400. - For manual API tests, fetch a fresh token from
GET /api/csrf-tokenand include it in request headers.
- Confirm chat rows are actually inserted into
chatbot_conversations. - Confirm
message_counterincrements per user andfeedback_requested=trueon the 10th row. - Confirm
/api/chatresponse containsfeedback_required=trueandconversation_id.
- Check
/api/chat/feedbackrequest carries a valid UUIDconversation_idand integerrating(1-5). - Confirm the row belongs to current user and has
feedback_requested=true. - A row can only be rated once (
rating_scoremust be null before submit).