Inspiration
My colleagues and I are preparing for IELTS. We have full-time jobs, families, and lives that don't pause for exam prep. Several colleagues gave up entirely — losing money to physical classes they could never consistently attend. For those who persisted, it took an average of three attempts before passing.
That experience made me look deeper at the problem. What I found confirmed it was not just my circle:
- 3.5 million people sit the IELTS exam every year
- ~65% of them are Jugglers — working professionals studying in stolen windows between jobs, families, and commutes, not full-time students with structured time
- The average candidate sits the exam 2.4 times before achieving their required band — meaning the majority are paying resit fees and repeating months of preparation, not because they lack ability, but because existing tools cannot adapt to a life that won't pause for them
- The market is growing at ~5% year-on-year — and IELTS is just one of dozens of high-stakes English proficiency exams with the same structural problem
The problem was never intelligence or effort. It was preparation tools built for the ideal learner — someone with fixed schedules, consistent time, and a blank slate every session. The Juggler gets none of that. Generic apps forget them the moment they close the tab. Physical classes demand attendance they cannot guarantee.
I saw this not just as a problem but as an opportunity: a large, growing, underserved market where the right tool — one that remembers the learner, fits around their life, and gets smarter with every session — could make a meaningful difference.
Qonda is that tool. And IELTS is just the beginning.
What it does
Qonda is a memory-grounded IELTS coaching platform powered entirely by Qwen and Alibaba Cloud. It remembers everything about the learner across sessions and uses that memory to make every session smarter than the last.
- Writing Coach — submit essays for live Qwen evaluation against official IELTS band descriptors. After scoring, a second Qwen pass extracts coaching observations and stores them as persistent memories. Supports typed essays and handwritten image uploads (Qwen-VL extracts text via a pre-signed Alibaba Cloud OSS URL)
- Memory Dashboard — a living coaching profile built across all sessions. Each memory has a confidence score weighted by recency and repetition. Weaknesses reinforce. Mastered skills archive. The coach never forgets
- Skill Mastery — 40 sub-skills across all 4 IELTS sections, each with a rank (1–5), band estimate (4.0–8.5), and current learning stage derived live from performance history
- IELTS Tutor — adaptive sessions that read the memory layer, identify the weakest skill, select the right teaching framework for this learner's stage, and quote the learner's own writing back to them. Support fades automatically as mastery is demonstrated
- Reading Coach — academic passages with per-skill accuracy tracking across comprehension, inference, TFNG, and vocabulary
- Speaking Coach — 3-part examiner sessions with Qwen ASR transcription and fluency evaluation
- Listening Coach — Qwen TTS (Cherry voice) generates the audio; learner answers and receives instant skill-level feedback
- Study Scheduler — generates a personalised weekly schedule targeting the weakest skill and books it directly into Google Calendar via PKCE-secured OAuth
- Telegram Bot — a Qwen agent with tool-calling that brings the full coaching context into Telegram. The learner's memory follows them to their phone — and a keyword pre-filter blocks any attempt to use the bot outside its IELTS scope before it ever reaches the model
How we built it
The entire platform runs on Alibaba Cloud using six distinct Qwen APIs:
- Qwen-Plus — essay scoring, coaching responses, memory extraction, feedback generation
- Qwen-VL-Plus — extracts text from handwritten essay images (image uploaded privately to OSS, passed to the model as a pre-signed URL, deleted after processing)
- Qwen3-ASR — speaking coach transcription
- Qwen3-TTS (Cherry voice) — listening coach audio generation, cached permanently in OSS after the first request so TTS quota is consumed exactly once per track regardless of how many learners use it
- DashScope Text Embeddings (text-embedding-v3) — semantic memory search and hybrid retrieval
- Qwen agent with tool-calling — powers the Telegram coaching bot
- Alibaba Cloud ECS — production server at ielts.qonda.xyz (Docker + Nginx, Singapore region)
- Alibaba Cloud OSS — TTS audio cache, temporary image hosting for Qwen-VL, and database backup
The backend is FastAPI with PostgreSQL. The frontend is React + Vite + Tailwind CSS. The pedagogy layer is deterministic Python — Qwen delivers the sessions but the system controls which skill is targeted, which teaching framework is selected, and how support fades as the learner progresses. This separation was a deliberate architectural decision: the model never controls pedagogical logic.
Challenges we ran into
1. JSON parsing from Qwen responses (hardest)
The most persistent problem throughout the build. Qwen would return perfectly valid essay feedback but with apostrophes inside example text that broke JSON parsing. We ended up needing: safe_parse_json() — multiple fallback strategies extract_json_from_text() — for malformed responses fix_broken_json() — asks Qwen to repair its own output This is also why we split into 3 separate Qwen calls per submission — so one failure couldn't cascade to the others.
2. The MCP server lifespan integration
FastMCP 3.4.3 required its lifespan to be passed to FastAPI in a specific way. The error was clear but the solution wasn't obvious: RuntimeError: FastMCP's StreamableHTTPSessionManager task group was not initialized.
Merging two lifespans (MCP + TTS warmup) into one @asynccontextmanager cleanly
took several iterations.
3. The DashScope API key confusion
The sk-ws- key works for Model Studio text generation but not for ASR/TTS
WebSocket connections locally — this wasn't documented clearly anywhere:
sk-ws- key → Model Studio HTTP - Okay
sk-ws- key → DashScope WebSocket locally - Bad
sk-ws- key → DashScope WebSocket on ECS - Okay (inside Alibaba Cloud network)
This caused persistent websocket closed 401 errors locally that kept appearing
even after the app was working correctly in production.
4. OSS smart quotes breaking credentials
UnicodeEncodeError: 'latin-1' codec can't encode '\u201d'
Smart/curly quotes getting into the .env file from copying credentials through
chat interfaces. Silent failure — OSS appeared configured but requests failed at
the HTTP header encoding level.
5. The streaming SSE implementation
Getting Server-Sent Events to work end-to-end required coordination across three layers simultaneously: FastAPI: StreamingResponse with media_type="text/event-stream" Nginx: proxy_buffering off (without this tokens batch, not stream) React: fetch() not axios (axios doesn't support SSE streaming) Manual buffer management for incomplete SSE chunks
Missing any one of these broke the streaming silently.
6. Qwen-VL and image delivery
The DashScope multimodal endpoint rejects base64 data URIs — it only accepts
https:// URLs. We solved this by uploading essay images privately to Alibaba
Cloud OSS, generating a 5-minute pre-signed GET URL for Qwen-VL to fetch, then
deleting the temporary object after processing. No public ACL required, no data
retained beyond the inference call.
7. Google Calendar OAuth with PKCE
Google now mandates PKCE for all OAuth flows including server-side web
applications. Because our callback is stateless, we encoded the PKCE code
verifier inside the OAuth state parameter (base64 JSON) so the callback could
retrieve it and complete the token exchange — no server-side session storage needed.
8. The session caching vs navigation bug
Chat Coach was making a new Qwen API call every time the learner navigated away and back. The fix (sessionStorage caching) was simple but the root cause diagnosis took a while: React useEffect with no dependency array → fires on every mount → every navigation = new expensive Qwen call → burns through API budget fast
9. The free tier / account verification maze
The Alibaba Cloud free tier required identity verification that took time to activate. We went through: RDS PostgreSQL → 7 days only (rejected) DuckDB → wrong tool for write-heavy app (rejected) SQLite on Docker volume → correct decision OSS → payment method required to activate ECS free tier → verification delay
Each dead end cost time but led to the right architecture decisions.
10. Maintaining context across a very long build
The build spanned multiple sessions and thousands of lines of code. Keeping track of which files were replaced vs new, which changes were local vs production, which bugs were environment-specific vs code bugs, and the correct branch workflow was a genuine engineering challenge in itself. Structured handoff summaries at session boundaries were what made it manageable.
Accomplishments that we're proud of
- A memory system that genuinely compounds — each session makes the next one more personalised, not just more recent
- 40 sub-skills tracked across all 4 IELTS sections with live band estimates derived from performance streaks — not stored, always computed from real evidence
- A pedagogy layer that separates teaching logic from AI delivery, producing consistent, structured sessions that adapt to each learner's stage
- A Telegram bot where the full coaching context — memories, skill ranks, weakest skill — travels with the learner into chat via Qwen tool-calling, with a scope guardrail that blocks off-topic and adversarial requests before they reach the model
- A fully deployed production application on Alibaba Cloud ECS serving real users at ielts.qonda.xyz, using six distinct Qwen APIs across text, vision, speech, and embeddings
What we learned
- Qwen's multimodal suite (text, vision, ASR, TTS, embeddings) is powerful enough to carry an entire educational platform — we didn't need any other AI provider
- Persistent memory changes the learner relationship fundamentally. Users engage differently when the system remembers them — they invest in it because it invests in them
- Pedagogy and AI generation must be kept separate. The model is an excellent teacher when told exactly what to teach. It is an inconsistent one when left to decide
- Building for the constrained user — the juggler with 20 minutes and a phone — produces better product decisions than building for the ideal user with unlimited time
- Scope guardrails matter from day one. Without explicit, layered refusals in every prompt and a pre-filter at the entry point, any open-ended AI interface will be probed for unintended uses
What made the architecture hold up:
- Separating concerns early — 3 Qwen calls, BackgroundTasks, and a deterministic rank engine meant failures were isolated and never cascaded
- Structured logging with request IDs — made debugging production issues possible without SSH access for every investigation
- Docker volumes for persistence — database and audio cache survived every rebuild
- Graceful degradation everywhere — OSS falls back to disk, TTS fails silently, classification errors don't block feedback delivery
- Testing incrementally — login → essay → memory → skills, rather than building everything then testing ---
What's next for Qonda IELTS
- Chat-native coaching — full practice sessions directly in WhatsApp and Telegram, not just coaching summaries. The juggler's phone becomes the classroom
- Voice selection and personalised voice creation — using Alibaba's CosyVoice 2 (available via DashScope), learners will be able to choose from a library of coaching voices or create a custom voice from a short audio sample. CosyVoice 2's zero-shot voice cloning makes it possible with seconds of reference audio — no training required
- Live voice tutor with your preferred voice — preparing for your Speaking exam with a conversational tutor delivered in the voice of your choice. The tutor listens via Qwen ASR, responds in your chosen voice via CosyVoice 2, and coaches you in real time — all within Qonda
- Teacher and institution dashboard — language schools and corporate HR teams can onboard learners, monitor progress, assign sessions, and track band improvement across cohorts
- Spaced repetition for memories — memories that haven't been reinforced in a set period trigger targeted practice sessions automatically
- Mobile app — native iOS and Android so the juggler doesn't need a browser at all
Built With
- alibaba-cloud-ecs
- alibaba-cloud-oss
- css
- dashscope
- docker
- fastapi
- google-calendar-api
- nginx
- postgresql
- python
- qwen
- qwen-asr
- qwen-tts
- qwen-vl
- react
- sqlalchemy
- tailwind
- telegram-bot-api
- vite

Log in or sign up for Devpost to join the conversation.