AI-powered IT help-desk assistant. Users describe a problem in plain English — the agent searches a knowledge base, checks for existing tickets, and creates new ones automatically.
Browser (5173)
│
▼
Frontend — React + Vite + shadcn/ui
│ POST /api/chat { message }
▼
Orchestrator — Express + TypeScript
│ LangGraph ReAct agent (Groq / llama-3.3-70b)
│ ├── Tool: search_knowledge_base → RAG Service (8000)
│ ├── Tool: search_open_tickets → Ticket Service (8001)
│ └── Tool: create_ticket → Ticket Service (8001)
│
├── RAG Service — FastAPI + sentence-transformers + Weaviate
│ POST /rag/query → embed → semantic search → ranked KB articles
│
└── Ticket Service — FastAPI + SQLAlchemy + SQLite + Weaviate
POST /api/tickets (create, with 0.85 dedup check)
POST /api/tickets/find-similar (cosine similarity check)
POST /api/tickets/search (hybrid BM25 + vector search)
PATCH /api/tickets/{id} (update status)
Weaviate (8080) — vector DB shared by both Python services
Langfuse — LLM observability (traces, prompts, token counts)
Agent workflow
- Always search the knowledge base first
- If the KB answers the question → summarise and reply
- If the user reports a bug/outage and KB doesn't help → check for an open ticket using cosine similarity (threshold 0.75)
- If a similar ticket exists → cite it; otherwise create a new one
| Service | Port | Stack |
|---|---|---|
| Frontend | 5173 | React 18, Vite, TypeScript, Tailwind, shadcn/ui |
| Orchestrator | 3000 | Node.js, Express, TypeScript, LangGraph, Groq |
| RAG Service | 8000 | Python, FastAPI, sentence-transformers (all-MiniLM-L6-v2) |
| Ticket Service | 8001 | Python, FastAPI, SQLAlchemy, SQLite, aiosqlite |
| Weaviate | 8080 | Vector DB (internal only) |
- Docker + Docker Compose
- A free Groq API key (for the LLM)
- A free Langfuse account (optional, for observability)
cp .env.example .envEdit .env with your keys (see the Environment variables section below).
docker-compose up --buildOpen http://localhost:5173.
npm run migrateThis reads data/data.txt, wipes any stale data, and re-ingests all articles into Weaviate.
| Command | What it does |
|---|---|
npm install |
Installs deps for frontend + orchestrator |
npm run build |
Compiles orchestrator → dist/, builds frontend |
npm run dev |
Starts Vite (5173) + ts-node-dev (3000) locally |
npm run watch |
Watches orchestrator src/, recompiles to dist/ on save |
npm run migrate |
Wipes + re-ingests knowledge base from data/data.txt |
rag-serviceandticket-serviceare Python — no npm commands apply.
| Method | Path | Description |
|---|---|---|
POST |
/api/chat |
Send a message; returns { reply: string } |
GET |
/health |
Health check |
curl -X POST http://localhost:3000/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "How do I reset my password?"}'| Method | Path | Description |
|---|---|---|
POST |
/rag/ingest |
Ingest documents into the knowledge base |
POST |
/rag/query |
Semantic search — returns ranked KB articles |
DELETE |
/rag/source/{source} |
Delete all articles by source label |
GET |
/health |
Health check |
All routes require x-api-key header.
| Method | Path | Description |
|---|---|---|
POST |
/api/tickets |
Create ticket (0.85 cosine dedup check) |
PATCH |
/api/tickets/{id} |
Update ticket status |
POST |
/api/tickets/find-similar |
Cosine similarity check (absolute threshold) |
POST |
/api/tickets/search |
Hybrid BM25 + vector search |
GET |
/health |
Health check |
Copy .env.example to .env. Never commit .env.
| Variable | Service | Required | Description |
|---|---|---|---|
WEAVIATE_API_KEY |
rag-service, ticket-service, weaviate | Yes | Auth key for Weaviate |
WEAVIATE_API_USER |
weaviate | Yes | Username mapped to the API key |
TICKET_API_KEY |
orchestrator, ticket-service | Yes | Auth key for ticket service |
GROQ_API_KEY |
orchestrator | Yes | Groq API key for the LLM |
LANGFUSE_PUBLIC_KEY |
orchestrator | No | Langfuse public key (tracing) |
LANGFUSE_SECRET_KEY |
orchestrator | No | Langfuse secret key (tracing) |
LANGFUSE_HOST |
orchestrator | No | Langfuse host (default: cloud.langfuse.com) |
Generate secure random values with:
openssl rand -hex 32When Langfuse keys are set, every chat request is traced:
- Full LLM prompt + completion
- Each tool call with inputs and outputs
- Token counts and latency per step
- Session tagged with
deskmate+orchestrator
View traces at cloud.langfuse.com.
All services communicate over the deskmate-net Docker bridge network:
| Caller | Target | Internal URL |
|---|---|---|
| Frontend | Orchestrator | http://localhost:3000 (via browser) |
| Orchestrator | RAG Service | http://rag-service:8000 |
| Orchestrator | Ticket Service | http://ticket-service:8001 |
| RAG Service | Weaviate | http://weaviate:8080 |
| Ticket Service | Weaviate | http://weaviate:8080 |
deskmate/
├── frontend/ React + Vite + shadcn/ui chat interface
│ └── src/
│ ├── App.tsx Chat UI (messages, input, auto-scroll)
│ └── components/ui/ shadcn components (ChatBubble, ChatInput, etc.)
├── orchestrator/ Node.js agent service
│ └── src/
│ ├── modules/
│ │ ├── agent/ LangGraph ReAct agent (graph, tools, runner)
│ │ ├── rag-client/ HTTP client for RAG service
│ │ ├── ticket-client/ HTTP client for ticket service
│ │ └── logging/ Pino structured logging + request context
│ └── routes/
│ └── chat.route.ts
├── rag-service/ Python knowledge base service
│ └── app/
│ ├── api/routes/ ingest, query, admin
│ ├── controllers/ ingestion + query pipelines
│ ├── repositories/ Weaviate client
│ └── utils/ embeddings, ingestion helpers, logger
├── ticket-service/ Python ticketing service
│ └── app/
│ ├── api/ REST routes
│ ├── services/ ticket logic, embedding, vector operations
│ ├── db/ SQLAlchemy models + async session
│ └── schemas/ Pydantic request/response models
├── data/
│ └── data.txt IT handbook source documents
├── scripts/
│ └── migrate.js KB ingestion script
├── docker-compose.yml
├── package.json Root workspace (frontend + orchestrator)
└── .env.example