★ Interactive Demo · AI Hub

SLM for Webex Assistant

A lightweight, tightly-scoped language-model assistant for Webex Calling and Contact Center — helping engineers explore configuration, troubleshoot flows, and plan migrations. This page includes a working demo and the full build approach: high-level design, low-level design, and reference code.

Webex Calling Contact Center Migration Planning RAG + Fine-tuning
Try It

Interactive Demo

Click any sample question to see how the assistant responds. This demo runs on pre-written, expert-reviewed answers — no live model calls — so it is free to run and safe to share.

Sample Questions

These mirror the kind of queries the assistant is designed to handle.

SLM for Webex Assistant Demo mode
Pick a question on the left to start.

Planning document. The design and code below describe how this assistant will be built. Full implementation documentation will be published once the tool is developed and lab-validated.

Overview

Two Ways to Build It

"SLM" — Small Language Model — refers to a deliberately narrow, focused assistant rather than a general chatbot. There are two viable build paths, and this project documents both so the right one can be chosen for the deployment context.

Approach A

Hosted API + RAG

Use a hosted model (e.g. Claude Haiku) behind a secure proxy, grounded with Retrieval-Augmented Generation over Webex documentation. The "small" comes from tight scoping and retrieval, not model size. Fast to stand up, broad coverage, pay-per-use.

Approach B

Local LLM + Fine-tuning

Run a genuinely small open model (1–4B parameters) on local hardware, fine-tuned on a Webex corpus with QLoRA. Fully on-premise, no per-query cost, no data leaving the network — at the cost of training effort and infrastructure.

Side-by-Side Comparison

FactorA · Hosted API + RAGB · Local LLM + Fine-tuning
Setup speedFast — daysSlower — weeks
Cost modelPay-per-query (low with Haiku)Upfront compute, then free inference
Data privacyQueries leave your networkFully on-premise
Answer qualityHigh — frontier modelGood for the trained domain
HardwareNone requiredGPU for training; modest box for serving
MaintenanceLow — vendor maintains modelHigher — retrain, host, monitor
Best fitQuick demo, broad coverageOffline, privacy-sensitive deployments
Architecture

High-Level Design (HLD)

The HLD describes the major components and how data flows through the system for each approach.

Approach A — Hosted API + RAG

The browser never touches the model directly. An edge proxy holds the API key, enforces limits, and grounds each query with retrieved Webex documentation before calling the model.

Chat UIStatic page
Edge ProxyKey + rate limit
RetrieverTop-k chunks
Vector StoreWebex docs
Hosted LLMClaude Haiku
Approach B — Local LLM + Fine-tuning

Two pipelines: an offline training pipeline that produces a fine-tuned model, and an inference pipeline that serves it locally.

Webex DocsSource corpus
Data PrepQ/A pairs
QLoRA Fine-tuneBase model
EvaluateHeld-out set
GGUF ModelQuantized
Chat UILocal app
API WrapperFastAPI
Ollama / llama.cppFine-tuned SLM
Detailed Design

Low-Level Design (LLD)

The LLD breaks each component into concrete, implementable detail.

Approach A — Component Detail

Edge Proxy

Cloudflare Pages Function. API key stored as an encrypted environment secret. Validates request shape, enforces per-IP daily rate limit via KV, caps max_tokens.

RAG Pipeline

Webex docs chunked (~400 words), embedded with a sentence-transformer, stored in a vector index. At query time the top 3–4 chunks are retrieved and injected as grounding context.

Prompt & Guardrails

System prompt locks scope to Webex topics, instructs the model to answer only from retrieved context and to recommend verifying against Cisco documentation. Off-topic queries are politely declined.

Approach B — Component Detail

Base Model

A 1–4B instruction model — e.g. Phi-3-mini, Llama 3.2 3B, or Qwen 2.5 3B — small enough to fine-tune on a single GPU and serve on a modest box.

Training Data

Webex documentation converted into instruction/response pairs (JSONL). Cleaned, de-duplicated, and split into train and held-out evaluation sets.

Fine-tuning & Serving

QLoRA — 4-bit quantization plus low-rank adapters — keeps memory low. The trained adapter is merged, converted to GGUF, and served via Ollama or llama.cpp behind a small FastAPI wrapper.

Approach

Build Steps

The end-to-end sequence for each path, from raw documentation to a working assistant.

Approach A · Hosted API
1

Collect Webex docs

Gather Webex Calling and Contact Center documentation as the knowledge source.

2

Chunk & embed

Split docs into passages and generate embeddings.

3

Build vector index

Store embeddings in a searchable vector store.

4

Build edge proxy

Create the function that holds the key and calls the model.

5

Add guardrails

Rate limits, token caps, topic scoping, off-topic refusal.

6

Wire the chat UI

Connect the front-end to the proxy endpoint.

7

Test & deploy

Validate answers, set a Console spend cap, ship.

Approach B · Local LLM
1

Select base model

Choose a 1–4B instruction model that fits available hardware.

2

Build training data

Convert Webex docs into instruction/response pairs.

3

Clean & split

De-duplicate and separate train vs evaluation sets.

4

QLoRA fine-tune

Train low-rank adapters on the quantized base model.

5

Evaluate

Score answers on the held-out set; iterate if needed.

6

Merge & quantize

Merge the adapter and export to GGUF format.

7

Serve & connect

Run via Ollama, wrap with an API, link the UI.

Implementation

Reference Code

Starter snippets for the core of each approach. These are illustrative — production use requires testing, error handling, and validation.

A · Secure Edge Proxy — Cloudflare Pages Function
functions/api/ask.js
// API key stays server-side as an encrypted env secret.
const RATE = 5; // questions per IP per day

export async function onRequestPost({ request, env }) {
  const ip  = request.headers.get('CF-Connecting-IP') || 'anon';
  const day = new Date().toISOString().slice(0, 10);
  const key = `rl:${ip}:${day}`;

  // per-IP daily rate limit via Workers KV
  const used = parseInt(await env.RL.get(key) || '0', 10);
  if (used >= RATE)
    return Response.json({ error: 'Daily demo limit reached.' }, { status: 429 });

  const { question, context } = await request.json();

  const r = await fetch('https://api.anthropic.com/v1/messages', {
    method: 'POST',
    headers: {
      'content-type':     'application/json',
      'x-api-key':        env.ANTHROPIC_API_KEY,
      'anthropic-version': '2023-06-01'
    },
    body: JSON.stringify({
      model:      'claude-haiku-4-5-20251001',
      max_tokens: 350,                       // hard output cap
      system:     'You are a Webex assistant. Answer ONLY Webex ' +
                  'Calling and Contact Center questions, grounded in ' +
                  'the supplied context. Decline anything off-topic.',
      messages: [{ role: 'user',
                   content: `Context:\n${context}\n\nQ: ${question}` }]
    })
  });

  const data = await r.json();
  await env.RL.put(key, String(used + 1), { expirationTtl: 86400 });
  return Response.json({ answer: data.content?.[0]?.text || '' });
}
A · Build the RAG Index
build_index.py
import glob, json
from sentence_transformers import SentenceTransformer

embed = SentenceTransformer('all-MiniLM-L6-v2')
chunks = []

for path in glob.glob('webex_docs/*.md'):
    words = open(path).read().split()
    # chunk into ~400-word passages
    for i in range(0, len(words), 400):
        chunks.append(' '.join(words[i:i + 400]))

vectors = embed.encode(chunks).tolist()
json.dump([{'text': c, 'vec': v} for c, v in zip(chunks, vectors)],
          open('index.json', 'w'))
B · Training Data Format — instruction pairs (JSONL)
webex_train.jsonl
{"instruction": "How do I migrate an Avaya hunt group to Webex Calling?",
 "output": "Map it to a Webex Calling Hunt Group or Call Queue ..."}
{"instruction": "What ports does Webex Calling use?",
 "output": "SIP signalling, a UDP media range, and HTTPS ..."}
B · QLoRA Fine-tuning Script
train.py
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model
from datasets import load_dataset
from trl import SFTTrainer

BASE = 'microsoft/Phi-3-mini-4k-instruct'   # ~3.8B params

# 4-bit quantization keeps GPU memory low
bnb = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type='nf4')
model = AutoModelForCausalLM.from_pretrained(BASE, quantization_config=bnb,
                                             device_map='auto')
tok = AutoTokenizer.from_pretrained(BASE)

# low-rank adapters — only these weights are trained
lora = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05,
                  target_modules=['q_proj', 'v_proj'],
                  task_type='CAUSAL_LM')
model = get_peft_model(model, lora)

data = load_dataset('json', data_files='webex_train.jsonl')['train']

trainer = SFTTrainer(model=model, tokenizer=tok, train_dataset=data,
                     max_seq_length=1024)
trainer.train()
model.save_pretrained('webex-slm-adapter')
B · Serve the Fine-tuned Model — Ollama
Modelfile
# after merging the adapter and exporting to GGUF
FROM ./webex-slm-merged.gguf

PARAMETER temperature 0.3
PARAMETER num_ctx 4096

SYSTEM """You are the SLM for Webex Assistant. Answer Webex
Calling and Contact Center questions concisely, and recommend
verifying against official Cisco documentation."""
terminal
# register and run the model locally
ollama create webex-slm -f Modelfile
ollama run webex-slm

Next step. Once the assistant is built and lab-validated, this page will expand into full documentation — covering data sourcing, evaluation results, deployment, and operations — and convert into the standard AbhavTech documentation framework.