Skip to content

hemchdev/rag-support-assistant

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AI Customer Support Agent

An industry-oriented monorepo for a multi-tenant AI customer support assistant for SaaS companies. The system answers customer questions from company knowledge sources such as documentation, FAQs, PDFs, and historical tickets. When confidence is low, it escalates to a human support team by creating a ticket.

This repository intentionally starts with architecture, service boundaries, deployment wiring, and runnable application foundations. Detailed RAG business logic, ingestion workers, ranking strategies, billing, and admin workflows should be implemented incrementally on top of this base.

Features

  • Multi-tenant SaaS support architecture
  • JWT-based authentication with owner organization registration
  • Retrieval-augmented generation over organization-specific knowledge bases
  • Document ingestion foundation for docs, FAQs, PDFs, and past tickets
  • Confidence-based human escalation path
  • PostgreSQL for relational product data
  • Redis for cache, rate limiting, queues, and worker coordination
  • Qdrant for vector search
  • OpenAI-compatible AI provider configuration
  • Docker Compose stack for local development
  • React, TypeScript, and Vite frontend shell
  • FastAPI backend with versioned API routing

Tech Stack

Layer Technology
Frontend React, TypeScript, Vite
Backend FastAPI, Python
Database PostgreSQL, SQLAlchemy, Alembic
Cache and Queue Redis
Vector Database Qdrant
AI Provider OpenAI-compatible API
Auth JWT, bcrypt password hashing
Deployment Docker, Docker Compose

Repository Structure

.
|-- apps
|   |-- backend
|   |   |-- app
|   |   |   |-- api
|   |   |   |-- core
|   |   |   |-- db
|   |   |   |-- models
|   |   |   |-- repositories
|   |   |   |-- schemas
|   |   |   |-- services
|   |   |   |-- tenants
|   |   |   |-- utils
|   |   |   `-- workers
|   |   |-- scripts
|   |   |-- tests
|   |   |-- Dockerfile
|   |   |-- alembic.ini
|   |   `-- requirements.txt
|   `-- frontend
|       |-- src
|       |-- Dockerfile
|       `-- package.json
|-- docs
|   `-- architecture.md
|-- infra
|   `-- docker-compose.yml
|-- .env.example
`-- README.md

Local Setup

Prerequisites

  • Docker and Docker Compose
  • Node.js 20+ for frontend development outside Docker
  • Python 3.12+ for backend development outside Docker

Run with Docker Compose

  1. Copy the environment template:
cp .env.example .env
  1. Update .env with local secrets and provider keys.

  2. Start the stack:

docker compose -f infra/docker-compose.yml up --build
  1. Open the services:
  • Frontend: http://localhost:5173
  • Backend API: http://localhost:8000
  • Backend health check: http://localhost:8000/health
  • Backend API docs: http://localhost:8000/api/v1/docs
  • Qdrant dashboard/API: http://localhost:6333

Environment Variables

The complete local template lives in .env.example. Key groups:

  • App metadata: APP_ENV, APP_NAME, API_V1_PREFIX
  • Frontend API config: VITE_API_BASE_URL
  • Database: POSTGRES_*, DATABASE_URL, DB_POOL_SIZE, DB_MAX_OVERFLOW
  • Redis: REDIS_URL
  • Qdrant: QDRANT_URL, QDRANT_COLLECTION_PREFIX
  • AI provider: OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MODEL, OPENAI_EMBEDDING_MODEL, EMBEDDING_VECTOR_SIZE, EMBEDDING_MAX_RETRIES
  • Auth: JWT_SECRET_KEY, JWT_ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
  • RAG behavior: RAG_TOP_K, RAG_MIN_CONFIDENCE, DOCUMENT_CHUNK_SIZE, DOCUMENT_CHUNK_OVERLAP, MAX_DOCUMENT_UPLOAD_SIZE_BYTES
  • Organization controls: DEFAULT_ORGANIZATION_SLUG, ORGANIZATION_HEADER_NAME
  • Seed data: DEMO_ORGANIZATION_*, DEMO_ADMIN_*

Do not commit real secrets. Use a secret manager or deployment platform variables outside local development.

Development Workflow

Backend

cd apps/backend
python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
alembic upgrade head
python scripts/seed_demo.py
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

Expected backend layers:

  • api: HTTP routers, dependencies, request validation, auth guards
  • core: settings, security, logging, application configuration
  • db: PostgreSQL sessions and Alembic migrations
  • models: SQLAlchemy persistence models
  • schemas: API and internal DTOs
  • repositories: tenant-scoped data access helpers
  • services: RAG, ticketing, ingestion, AI provider orchestration
  • tenants: organization resolution and isolation policies
  • workers: background jobs for ingestion, embeddings, and ticket sync

Run backend tests:

cd apps/backend
pytest

Auth Usage

Register creates an organization and an owner user:

curl -X POST http://localhost:8000/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "organization_name": "Acme Support",
    "organization_slug": "acme-support",
    "email": "owner@acme.example",
    "password": "StrongPass123!",
    "full_name": "Acme Owner"
  }'

Login returns a JWT, user details, and organization details:

curl -X POST http://localhost:8000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"owner@acme.example","password":"StrongPass123!"}'

Use the returned JWT from the frontend as a bearer token on authenticated requests:

Authorization: Bearer <access_token>

Fetch the authenticated user:

curl http://localhost:8000/api/v1/auth/me \
  -H "Authorization: Bearer <access_token>"

Knowledge Document API

Owners and admins can create, update, and delete knowledge documents. Owners, admins, and agents can list and read documents. Customers cannot access the document management API.

Create a document from raw text:

curl -X POST http://localhost:8000/api/v1/knowledge/documents \
  -H "Authorization: Bearer <access_token>" \
  -F "title=Billing FAQ" \
  -F "source_type=text" \
  -F "content_text=Billing questions and answers live here."

Upload a text, Markdown, or PDF file:

curl -X POST http://localhost:8000/api/v1/knowledge/documents \
  -H "Authorization: Bearer <access_token>" \
  -F "title=Support Runbook" \
  -F "source_type=pdf" \
  -F "file=@./support-runbook.pdf;type=application/pdf"

List documents with pagination:

curl "http://localhost:8000/api/v1/knowledge/documents?limit=20&offset=0" \
  -H "Authorization: Bearer <access_token>"

Update a document:

curl -X PATCH http://localhost:8000/api/v1/knowledge/documents/<document_id> \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{"title":"Updated Billing FAQ","content_text":"Updated content."}'

Delete a document:

curl -X DELETE http://localhost:8000/api/v1/knowledge/documents/<document_id> \
  -H "Authorization: Bearer <access_token>"

Document status starts as uploaded. Use the indexing endpoint to move documents through processing, indexed, or failed.

Frontend

cd apps/frontend
npm install
npm run dev

Expected frontend layers:

  • API client and auth state
  • Organization-aware routing
  • Support chat widget
  • Admin knowledge-base management
  • Ticket escalation dashboard
  • Observability and feedback views

Quality Gates

Add these as implementation grows:

  • Backend: pytest, ruff, mypy
  • Frontend: vitest, eslint, prettier, tsc --noEmit
  • Infrastructure: compose validation and container health checks
  • Security: dependency scanning and secret scanning

Next Implementation Milestones

  1. Add background ingestion workers for PDF, FAQ, website, and ticket imports.
  2. Add support ticket assignment notifications and external helpdesk adapters.
  3. Build admin UI for knowledge-base uploads, ticket review, and analytics.
  4. Add observability dashboards for confidence, deflection, and escalation quality.

Document Indexing

Index a document after upload:

curl -X POST http://localhost:8000/api/v1/knowledge/documents/<document_id>/index \
  -H "Authorization: Bearer <access_token>"

List persisted chunks:

curl http://localhost:8000/api/v1/knowledge/documents/<document_id>/chunks \
  -H "Authorization: Bearer <access_token>"

Indexing sets the document to processing, writes overlapping chunks to PostgreSQL, generates embeddings with the configured OpenAI-compatible provider, upserts vectors to Qdrant, and then marks the document indexed. If processing fails, the document is marked failed. Re-indexing deletes old chunks and old vectors for the same organization/document before writing the new index.

Qdrant collection: organization_knowledge by default. Each point payload includes organization_id, document_id, chunk_id, title, and source_type.

Chat API

Create a conversation:

curl -X POST http://localhost:8000/api/v1/chat/conversations \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{"title":"Password help"}'

Ask a question:

curl -X POST http://localhost:8000/api/v1/chat/conversations/<conversation_id>/messages \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{"message":"How do I reset my password?"}'

Example response:

{
  "assistant_message": {
    "id": "...",
    "sender_type": "assistant",
    "content": "You can reset your password from Account Settings.",
    "confidence_score": 0.795,
    "sources": [
      {
        "document_id": "...",
        "document_title": "Password Reset FAQ",
        "chunk_id": "...",
        "similarity_score": 0.91
      }
    ]
  },
  "confidence_score": 0.795,
  "sources": [
    {
      "document_id": "...",
      "document_title": "Password Reset FAQ",
      "chunk_id": "...",
      "similarity_score": 0.91
    }
  ],
  "should_escalate": false
}

Confidence combines the top retrieved chunk similarity scores, the number of relevant chunks, and whether the answer says it does not know. If confidence is below RAG_MIN_CONFIDENCE, should_escalate is true and the conversation is marked escalated.

Ticket Escalation API

Create a support ticket manually from a conversation:

curl -X POST http://localhost:8000/api/v1/tickets \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_id": "<conversation_id>",
    "priority": "high"
  }'

Customers can explicitly request a human for their own conversation:

curl -X POST http://localhost:8000/api/v1/chat/conversations/<conversation_id>/escalate \
  -H "Authorization: Bearer <customer_access_token>"

Agents, admins, and owners can list and inspect organization tickets:

curl "http://localhost:8000/api/v1/tickets?status=open&priority=urgent&assigned_agent_id=<agent_id>" \
  -H "Authorization: Bearer <access_token>"

Update ticket status, priority, or assignment:

curl -X PATCH http://localhost:8000/api/v1/tickets/<ticket_id> \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{"status":"assigned","assigned_agent_id":"<agent_id>"}'

Manual escalation always creates a ticket and marks the conversation escalated. Low-confidence chat answers return should_escalate: true; they create a ticket only when AUTO_CREATE_TICKET_ON_LOW_CONFIDENCE=true. Generated ticket descriptions include the conversation title, latest customer message, assistant answer, confidence score, and source references.

About

Multi-tenant AI customer support agent with RAG, document indexing, chat history, confidence scoring, and ticket escalation.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages