Enterprise Customer-Experience Agents — Customer Onboarding + Customer Training.
Minimal LangChain ReAct agent service. Two agents, one FastAPI app, no database, no monitoring stack. Pairs with vxstudio_enterprise_llm which provides the FAISS-backed customer-support knowledge base both agents call as a tool.
vxstudio_enterprise_agent/
├── app.py # FastAPI on port 8002
├── requirements.txt # base deps (incl. Ollama provider)
├── requirements-local.txt # local HuggingFace provider (transformers + torch)
├── requirements-dev.txt # test deps (pytest, respx)
├── .env.example # all config knobs, documented
├── pytest.ini
├── tests/
│ ├── test_unit.py # provider routing, tools, persona (mocked)
│ └── test_integration.py # FastAPI TestClient + real Ollama/HF (auto-skip)
└── services/
└── ai/
├── llm_provider.py # shared provider factory (anthropic|openai|ollama|huggingface)
├── onboarding_agent/
│ ├── agent.py # LangChain ReAct agent (Aria)
│ ├── soul.md # persona + boundaries
│ └── skill.md # tools + patterns
└── training_agent/
├── agent.py # LangChain ReAct agent (Theo)
├── soul.md
└── skill.md
python -m venv venv
venv\Scripts\activate # Windows (or: source venv/bin/activate on Unix)
pip install -r requirements.txt
# Pick a provider (or set nothing and let it auto-detect — see below):
$env:ANTHROPIC_API_KEY = "sk-ant-..." # PowerShell, cloud
# or $env:OPENAI_API_KEY = "sk-..."
# or $env:LLM_PROVIDER = "ollama" # local daemon, no key
# or $env:LLM_PROVIDER = "huggingface" # local model, no key (needs requirements-local.txt)
python app.pyServer listens on port 8002. Pair-deployed with vxstudio_enterprise_llm on port 8001.
The agents' reasoning LLM is provider-agnostic. Select it with LLM_PROVIDER:
LLM_PROVIDER |
Needs | Key? | Default model | Notes |
|---|---|---|---|---|
anthropic |
requirements.txt |
yes | claude-sonnet-4-6 |
ANTHROPIC_MODEL to override |
openai |
requirements.txt |
yes | gpt-4o-mini |
OPENAI_MODEL to override |
ollama |
requirements.txt + running Ollama daemon |
no | qwen2.5:0.5b |
OLLAMA_MODEL / OLLAMA_BASE_URL; ollama pull qwen2.5:0.5b first |
huggingface |
requirements-local.txt (transformers + torch) |
no | Qwen/Qwen2.5-0.5B-Instruct |
fully local/offline; HF_MODEL to override (base models work too — a fallback chat template is auto-installed) |
Auto-detect (LLM_PROVIDER=auto, the default): ANTHROPIC_API_KEY → OPENAI_API_KEY → reachable Ollama daemon → local HF stack. If none are available, /chat returns 503 with a message telling you what to set.
Small models are the default for both local providers so the service runs cheaply or fully offline.
For the local HuggingFace provider:
pip install -r requirements-local.txt
$env:LLM_PROVIDER = "huggingface"
# optional: a tiny cached model for offline smoke tests
$env:HF_MODEL = "distilgpt2"
python app.pypip install -r requirements-dev.txt
pytest # full suite
pytest -m "not real_ollama and not real_hf" # mocked only — no daemon/model needed- Unit tests (
tests/test_unit.py) — provider routing/auto-detection, the agents' pure-function tools (KB lookup mocked withrespx), and persona loading. No network, no keys, no model downloads. - Integration tests (
tests/test_integration.py) — every FastAPI route viaTestClient, with a fake ReAct chat model injected so the full HTTP → AgentExecutor → tool-grammar path runs deterministically. - Real-provider tests —
test_real_ollama_generates(live daemon) andtest_real_huggingface_generates(real local model). Both auto-skip when the resource isn't present, so the suite stays green anywhere.
| Method | Path | Purpose |
|---|---|---|
| GET | /health |
Readiness probe + provider/LLM-URL status |
| GET | /agents/{name}/persona |
Inspect the loaded soul.md + skill.md |
| POST | /agents/onboarding/chat |
Talk to Aria (onboarding) |
| POST | /agents/training/chat |
Talk to Theo (training) |
Request body for /chat:
{ "message": "I just signed up, where do I start?" }See .env.example for the full annotated list.
| Env var | Default | Purpose |
|---|---|---|
LLM_PROVIDER |
auto |
auto | anthropic | openai | ollama | huggingface |
ANTHROPIC_API_KEY / OPENAI_API_KEY |
unset | Cloud BYOK keys |
ANTHROPIC_MODEL |
claude-sonnet-4-6 |
Override Anthropic model |
OPENAI_MODEL |
gpt-4o-mini |
Override OpenAI model |
OLLAMA_MODEL |
qwen2.5:0.5b |
Ollama model id |
OLLAMA_BASE_URL |
http://localhost:11434 |
Ollama daemon URL (also reads OLLAMA_HOST) |
HF_MODEL |
Qwen/Qwen2.5-0.5B-Instruct |
Local HuggingFace model id |
HF_MAX_NEW_TOKENS |
256 |
Generation cap for the local HF model |
KB_LLM_URL |
http://localhost:8001/v1 |
OpenAI-compatible base URL of the KB SLM. Works against vxstudio_enterprise_llm, vLLM, Ollama, LM Studio, TGI, or OpenAI itself. |
KB_LLM_MODEL |
vxstudio-enterprise-slm |
Model id sent in the chat-completion request |
- No database. Customer state (onboarding milestones, lesson progress) is stubbed in the agent files so demos are deterministic without infra. Plug in a real backend when you hand it to a client.
- No monitoring, no Celery, no Kafka, no Redis. Deliberate. This is a starter, not a platform.
- LangChain ReAct with
max_iterations=4andhandle_parsing_errors=Trueso agents fail gracefully instead of looping. - Tools are pure functions in
agent.py— easy to swap for real implementations without touching the FastAPI layer. - Persona is data, not code. Edit
soul.md/skill.mdto re-tune Aria or Theo without touching Python. - Provider is pluggable.
services/ai/llm_provider.pyis the single place provider selection lives — cloud (Anthropic/OpenAI) or local (Ollama/HuggingFace), with small-model defaults so it runs cheaply or offline.build_*_agent(llm=...)accepts an injected model, which is how the tests run without any provider.