Turn Any Topic Into a Quiz Game: Building an AI Learning App on NXagents (DeepSeek Mini-Program Analysis)
Turn Any Topic Into a Quiz Game: What a DeepSeek WeChat Mini-Program Teaches Us About Building AI Learning Apps on NXagents
Deep dive into
liyupi/yu-ai-learn— a fully open-sourced "AI quiz/level-clear learning" WeChat mini-program built with Taro + FastAPI + LangGraph + DeepSeek — and how to rebuild the same product in an afternoon on NXagents.
The Article That Started This
A Chinese dev community post went around recently: "又一个 AI 新项目完结,用 DeepSeek 搞了个微信小程序!" (Another AI project finished — built a WeChat mini-program with DeepSeek!). It's 程序员鱼皮 (Programmer YuPi) announcing the completion of his AI 闯关学习小程序 (AI Quiz-Quest Learning Mini-Program) — a full course project that turns any knowledge into a game.
The premise is genius in its simplicity: learning is boring, games are not. So why not let AI convert whatever you want to learn into a level-based quiz game, complete with instant explanations, AI-generated review reports, XP points, and even AI-illustrated questions?
The whole thing is open source (MIT): github.com/liyupi/yu-ai-learn
In this post I'll:
- Review the project — what it actually does and how it's architected
- Dig into the code — the 7 engineering patterns that make it production-grade
- Rebuild the concept on NXagents — a concrete, step-by-step blueprint for a "Learn anything by quiz or gaming" app you can ship to a live URL
1. The Product: 8 Core Capabilities
This is not a toy CRUD app. It's a full AI agent product with 30+ features:
- AI 出题 (AI question generation) — Type one sentence about what you want to learn. AI web-searches the latest info and generates a set of single-choice, multi-choice, and true/false questions with difficulty levels.
- 闯关答题 (Level-clear answering) — Progress bar + coins/XP at top. Every answer gets instant correct/wrong feedback, the answer explanation, and the knowledge point.
- AI 复盘报告 (AI review report) — After the quiz, AI generates a mastery score, weak knowledge points, a 3-sentence summary, and next-step study suggestions + XP settlement.
- 联网搜索出题 (Web-search-enhanced questions) — LLMs have knowledge cutoff dates. The project upgrades question generation into a ReAct agent that decides whether to search, what to search, and how many rounds — with graceful fallback to model-only generation.
- RAG 私有知识库 (Bring-your-own-docs knowledge base) — Upload PDF/Word/Markdown/TXT, the system chunks + embeds + stores vectors, then generates questions only from your documents. Perfect for corporate training, exam prep, or interview drilling.
- AI 题目配图 (AI-illustrated questions) — Optionally generates an image per question via text-to-image, then re-hosts the temp URL to object storage for a permanent link. With daily quotas + concurrency control to manage cost.
- 微信静默登录 (WeChat silent login) — Zero-friction auth; records, XP, and history persist. Crucially: optional login — guests can play without an account, lowering the first-use barrier.
- 真正上线 (Actually ships) — Docker deployment, cloud MySQL, ICP filing, AI-category approval. Searchable in WeChat.
The killer insight: "This project's skeleton can be reused in any vertical — swap the knowledge source and you have a new product: driving-test prep, interview question banks, corporate training, children's English word games."
2. The Stack
| Layer | Choice |
|---|---|
| Mini-program frontend | Taro 4 · React 18 · TypeScript · Sass |
| Backend | Python 3.11 · FastAPI · Pydantic v2 · Uvicorn · asyncio |
| AI orchestration | LangChain · LangGraph (create_react_agent) |
| LLMs / search / images | DeepSeek (quiz+report) · 阿里云百炼 (embeddings + image gen) · Tavily (web search) |
| Vector store | Chroma (per-user collections) |
| Data | MySQL (async pool) · Tencent COS (object storage) |
| Auth | WeChat jscode2session + JWT |
| Async | quiz_tasks table + background job + status polling |
| Tests | pytest + pytest-asyncio (139 tests!) |
| Deploy | Docker → WeChat Cloud Run |
3. Digging Into The Code — 7 Patterns Worth Stealing
I read through the source. Here are the patterns that separate a student project from a real product.
Pattern 1 — Bulletproof structured JSON output
LLMs love wrapping JSON in markdown fences. This project wins by being paranoid:
def _extract_json(text: str) -> dict:
"""Extract JSON from LLM output, tolerant of ```json fences."""
match = re.search(r"```(?:json)?\s*([\s\S]*?)```", text)
raw = match.group(1).strip() if match else text.strip()
return json.loads(raw)
The system prompt is equally strict: "You are a professional AI learning coach. You may ONLY output valid JSON. Do not output anything outside JSON — no markdown, no comments, no explanation text." Then the result is validated with a Pydantic model (QuizOutput.model_validate(data)). Prompt contract + regex defense + schema validation = three layers of protection.
Pattern 2 — The ReAct agent for fresh knowledge
tools = [
TavilySearch(name="tavily_search_basic", description="Lightweight search...", max_results=10, include_raw_content=False),
TavilySearch(name="tavily_search_deep", description="Deep search...", include_raw_content=True),
TavilyExtract(name="tavily_extract", description="Extract full content from a URL..."),
]
agent = create_react_agent(llm, tools=tools, prompt=SEARCH_AGENT_SYSTEM_PROMPT)
result = await asyncio.wait_for(agent.ainvoke(...), timeout=AGENT_TIMEOUT_SECONDS)
Notice: two search tools with different "depths" — the agent first does a broad summary search, then decides if the topic is niche/confusing enough to go deeper. That's agentic design with intent, not just a blind web fetch. Also: 120s timeout, recursion_limit=10, and — critically — if search fails or is disabled, the function returns "" and the quiz chain falls back to model-only generation. The product never breaks because an optional enhancement failed.
Pattern 3 — Async task + polling (the WeChat 60s timeout killer)
WeChat mini-programs cap request duration at ~60 seconds. AI generation with web search can easily exceed that. The fix:
POST /quiz/generate→ creates aquiz_tasksrow → returnstask_idimmediately- Background async job does the heavy AI work
- Frontend polls
GET /quiz/tasks/{id}every 8 seconds until status =success
This is the canonical pattern for any AI app with slow upstreams. If you're building AI features behind any request-timeout platform, never do heavy generation synchronously — task table + polling (or SSE/WebSocket if the platform allows).
Pattern 4 — Per-user RAG with metadata filtering
def get_user_vector_store(user_id: int, embeddings=None):
return Chroma(collection_name=f"kb_user_{user_id}", ...)
def add_document_chunks(user_id, doc_id, chunks, embeddings=None):
for chunk in chunks:
chunk.metadata = {**chunk.metadata, "doc_id": doc_id, "user_id": user_id}
...
def similarity_search(user_id, doc_id, query, k=None, embeddings=None):
return vector_store.similarity_search(query, k=k, filter={"doc_id": doc_id})
One collection per user, doc_id/user_id stamped on every chunk, retrieval filtered by doc_id. Multi-tenant RAG in ~30 lines. Note the check_embedding_ctx_length=False trick — DashScope's OpenAI-compatible endpoint can't handle tiktoken token-ID arrays, a classic vendor-compat gotcha.
Pattern 5 — Temp URLs → permanent object storage
AI image APIs return temporary URLs that expire. The project downloads each generated image and re-uploads to Tencent COS to get a permanent link stored with the question. Also: daily quota (20 images/user/day) + concurrency limiting + graceful skip (image failure never blocks question generation).
Pattern 6 — Optional login
Guests can generate and answer quizzes immediately. Login (WeChat silent auth) only kicks in to persist records/XP. This is a deliberate product decision: "maximize new-user adoption by removing friction; upgrade later."
Pattern 7 — Spec-Driven Development (OpenSpec) + "Harness Engineering"
The repo's openspec/ folder shows the AI-coding workflow the author teaches: requirements → proposal → design → spec → tasks → implementation. Each feature (web-search, RAG, image-gen) is an archived OpenSpec change with a spec.md. The commit history even reads like a textbook:
2026-04-02 initial commit + AI-generated prototypes (Copilot vs ClaudeCode "race")
2026-04-07 MVP: quiz + report endpoints, Prompt V1, 28 tests
2026-04-08 user system: silent login + JWT + XP rules
2026-04-14 frontend bug-fix sprint
2026-04-17 web search ReAct agent + async task polling
2026-07-22 RAG knowledge base
2026-07-28 AI question images + quota + COS persistence
2026-08-05 Dockerfile + production AppID
2026-08-11 docs + OpenSpec polish
The takeaway: AI-built projects don't have to be messy. Give the AI a harness (docs, specs, skills, MCP, git) and it produces maintainable, tested code. 139 backend tests, folks.
4. Now Let's Build It On NXagents
Here's the fun part. The WeChat mini-program form factor was a distribution decision — the underlying product (AI quiz game) is 100% reproducible on the NXagents platform, often with less infrastructure because NXagents gives you hosting, permanent media CDN, and publishing for free.
The NXagents equivalent architecture
| yu-ai-learn | NXagents version |
|---|---|
| Taro 4 mini-program | SPA (index.html + JS) → deploy to {slug}.nxagents.app |
| FastAPI + MySQL | Bun server + SQLite |
| LangChain/LangGraph ReAct agent | Native fetch + anysearch/research tools, or DeepSeek API calls |
| Tavily web search | anysearch / web_search tools |
| Chroma vector store | SQLite + simple keyword/embedding search, or an in-memory vector index |
| Tencent COS (permanent image URLs) | instant_media CDN URLs are already permanent — zero extra work |
| WeChat silent login + JWT | OTP + JWT (your proven flow) |
| Docker + WeChat Cloud Run | project deploy — one command |
| WeChat search / 流量主 ads | publish_app → nxplace listing |
Step-by-step blueprint
Step 1 — Skeleton. Create the project folder with index.html, app.js, styles.css (or use server_app_bun with the Bun template for a backend + SQLite). Deploy immediately so you have a live URL to iterate on.
Step 2 — The quiz chain. The heart is one endpoint:
// Bun server, POST /api/quiz/generate
const prompt = `
You are an AI learning coach. Output ONLY valid JSON.
Generate ${questionCount} questions (single/multiple/true-false ~3:1:1)
about: "${topic}" (difficulty: ${difficulty})
Schema: { title, summary, questions: [{ id, type, stem, options:[{key,text}], answer:[], explanation, knowledge_point, difficulty }] }
${searchContext ? `Priority base questions on this fresh web research:\n${searchContext}` : ""}
`;
// Call DeepSeek (or any OpenAI-compatible endpoint), then:
const clean = raw.replace(/```json\s*([\s\S]*?)```/g, "$1").trim();
const quiz = JSON.parse(clean); // validate against your TS interface
Step 3 — Fresh knowledge via search. Before generating, kick off a web search (anysearch/web_search). Feed the top snippets into the prompt as "reference material" — exactly like the project's SEARCH_CONTEXT_TEMPLATE. Add a flag enableWebSearch so a search failure silently falls back to model-only generation. The product never breaks.
Step 4 — Beat the timeout with async tasks. Even on NXagents you don't want slow LLM calls blocking request handlers. Same pattern: quiz_tasks table in SQLite (id, status, payload, result), background worker, GET /api/quiz/tasks/{id} polling endpoint. Frontend polls every 3–5s.
Step 5 — The quiz game UI. One page: progress bar, XP counter, question card, option buttons, instant correct/wrong highlight + explanation panel. A final "report" view renders the AI-generated mastery score + weak points. Dark-mode-first, big fonts, mobile-first — it'll feel like a native app.
Step 6 — RAG (optional but wow). Accept PDF/TXT/MD uploads → chunk → embed (DeepSeek or any embeddings API) → store vectors in SQLite or a tiny in-memory store → retrieve top-k chunks on quiz generation with filter by doc. The same 30-line pattern from section 3.
Step 7 — Images that stay alive. The one thing NXagents makes easier than the original: instant_media returns permanent CDN URLs. No COS re-hosting dance. Just call it per question, save the URL, done.
Step 8 — Login (optional). Guest-play by default; OTP + JWT login to persist XP and history. Same "optional login" philosophy.
Step 9 — Ship it. project deploy → live at {slug}.nxagents.app. Then publish_app to nxplace (category: education or utility) so it's discoverable in the apps index. That's your version of "searchable in WeChat" — no ICP filing, no AI-category approval, no app-store review.
Monetization angles (learned from the original)
- 垂直题库 (vertical question banks): interview prep, driving test, certifications, children's English — each is a new product from the same skeleton
- Corporate training: employees upload internal docs → quizzes generated from their own knowledge base (the RAG feature is the enterprise sell)
- Frictionless sharing: quiz results make great share cards → organic growth loop
- Premium tiers: more questions/day, image generation, advanced reports
5. What I Learned (The Inspiration)
- "Learn anything by quiz" is a meta-product. The topic is the input; the game loop is the product. That's why it generalizes to every vertical. When building on NXagents, the same skeleton can be your next 5 products.
- Graceful degradation is a feature, not a hack. Search down? Use model memory. Image gen fails? Skip it. The quiz always ships. AI products live or die by how they handle flaky upstreams.
- Async + polling is the universal AI-app pattern. Platform timeouts (WeChat 60s, or any gateway) are defeated by task tables, not by faster prompts.
- AI-built ≠ spaghetti. Spec-driven development + test suites + AI pair-programming produced a 30-feature product with 139 passing tests. The harness matters more than the model.
- Optional login is a product decision. Lower friction first; upsell the account later.
- The platform is the moat. YuPi chose WeChat for distribution. On NXagents, your moat is being able to go from idea → live URL → published listing in a single session.
TL;DR
The "AI quiz learning mini-program" is a masterclass in practical AI product engineering: strict JSON contracts, ReAct agents for freshness, async task polling, per-user RAG, permanent image re-hosting, optional login, graceful degradation, and spec-driven AI development. Every single pattern ports directly to NXagents — and the platform's SPA hosting, Bun server runtime, permanent media CDN, and one-command publishing make the whole thing simpler than the original stack.
If you've ever wanted to build "Duolingo for X" or "a quiz game for anything" — the blueprint is right here, the skeleton is MIT-licensed, and the deploy button is one project deploy away. Go make your own game.
Project: github.com/liyupi/yu-ai-learn (MIT) · Author: 程序员鱼皮 (YuPi) · Original article: Toutiao
Built on NXagents — where ideas ship before lunch.