← All work

Production · education company

Sales and enrollment agent

Built a conversational LangGraph agent with a router, three subagents and tools integrated with internal systems — it answers course questions and drives enrollment, 24/7.

Role
Tech lead · architecture and development
Status
In production, 24/7
Stack
  • Python
  • FastAPI
  • LangGraph
  • LangChain
  • Qdrant
  • Redis
  • MongoDB
  • Celery
  • Langfuse
  • Cloud Run
student“how much? which subjects?”spreadsheets+ documentsfragmented, mixed formatsv1: structuredchunksv2: “course”entitypricessubjectsacademic infoRedis (STM)MongoDB (LTM)session expired →LTM summary returnsrouterserviceenrollmenthandoff to consultanttoolshybrid Qdrant+ rerank70–120 sales/dayrunning 24/7

Problem

Selling a course means answering precisely about prices, subjects, campuses and eligibility rules — information that varies per course and per client. An agent that gets the price or curriculum wrong loses the sale; one that answers generically does not convert.

Available data

The starting point was fragmented documents and spreadsheets: regulations, FAQs, curricula and catalogs with the same information spread across formats. Before any prompt, the work was curation — understand each source, relate the information and decide what was true.

Architecture decisions

Curation in two stages

First, the documents were organized into structured chunks, with ingestion scripts for documents and spreadsheets. Then everything moved to a data management platform where prices, subjects and academic information link to the parent entity “course”.

Explicit routing

A router with structured output picks the path for each message: service, enrollment or handoff to a human consultant. Enrollments already in progress follow a deterministic branch that does not depend on the model.

Hybrid search with a cache

Dense and sparse vectors in Qdrant, result fusion and reranking, with category and course filters. A TTL semantic cache avoids repeating search and reranking for equivalent questions.

Memory that outlives the session

Redis holds the active session (STM); MongoDB holds the durable history. When the session expires, context is rebuilt from history and a cheaper model writes the long-term summary (LTM) used in the next conversation.

Implementation

  • LangGraph graph: router → service, enrollment and notification subagents → final response.
  • Tools for the knowledge base, campuses, course catalog and eligibility, saving and checking enrollment data, and handoff to a consultant.
  • Guardrails that check business rules and compare the values quoted in an answer with what the tools returned.
  • Message buffering, deduplication and time-window spam blocking; remarketing tasks run on Celery, outside the conversation flow.
  • Golden set with an LLM judge, Langfuse tracing and token and cost logging per conversation.

Result

  • 70–120sales a day

The agent runs 24/7 and closes 70 to 120 sales a day.

Limits and lessons

  • The move from chunks to the “course” entity is shown as an architecture decision — I do not publish an isolated improvement metric between the two versions.
  • Integrations, client data and prompts stay out for confidentiality.
Next caseAssignment grading at scale →