Technology stack¶
Actual dependencies and rationale. This reflects what ships today, not every option considered during design.
Stack by maturity stage¶
| Stage | Components | Status |
|---|---|---|
| 1 — Data Foundation | PyMuPDF ingest, Qdrant, manifest metadata, vector + payload filters | Done (MVP) |
| 2 — Trusted Agent Layer | LangGraph, FastAPI, Streamlit, Pydantic tools, sentence-transformers, eval | Done |
| 3 — Solver Orchestration | Docker, Celery/Redis or k8s Jobs, Solver Agent, result parsers | Deferred |
Overview (Stage 2 — shipped)¶
| Layer | Technology | Role |
|---|---|---|
| Orchestration | LangGraph + langchain-core | State graph, routing, tool loops |
| API | FastAPI + uvicorn | POST /ask, /ask/stream (SSE), feedback, kb stats |
| UI | Streamlit | Chat front-end; HTTP client only (SSE streaming) |
| Vector store | Qdrant | Embeddings + metadata payloads |
| Embeddings | sentence-transformers | intfloat/multilingual-e5-base |
| LLM | OpenRouter / OpenAI / Anthropic | Intent, tool selection, report synthesis |
| Config | pydantic-settings | CAEC_* environment variables |
| Portfolio services | ask_service.py, follow_ups.py, suggest_questions.py, rate_limit.py |
SSE orchestration, follow-ups, starters, rate limit |
| Deps | PDM + mamba | pyproject.toml + environment.yml |
| CI/CD | GitLab CI | env-dev image, lint, test, k8s deploy |
| Docs | MkDocs Material | GitLab Pages |
Why LangGraph¶
| Option | Verdict |
|---|---|
| LangGraph | Chosen — explicit state, conditional edges, retry loops, debuggable |
| LangChain agents | Too opaque for engineering workflows with validation |
| CrewAI / AutoGen | Anti-goal — extra framework without added control |
LangGraph covers intent routing, tool calling, and error retry without a second agent framework.
Why Qdrant¶
| Option | Verdict |
|---|---|
| Qdrant | Chosen — Rust performance, payload filters, self-hosted or cloud |
| Pinecone | Managed only; no self-hosted for portfolio demo |
| Chroma | Fine for prototypes; weaker production story |
| In-memory | Implemented as offline fallback when CAEC_QDRANT_URL is empty |
Embeddings¶
- Model:
intfloat/multilingual-e5-base(configurable viaCAEC_EMBEDDING_MODEL) - Library:
sentence-transformers - Prefixes: E5
query:/passage:convention inrag/embeddings.py
Supports Russian and English engineering documents without separate indexes.
LLM providers¶
See also Usage economics on the home page (production pricing and order-of-magnitude cost per request).
Configured via CAEC_LLM_PROVIDER and CAEC_LLM_API_KEY:
| Provider | Typical use |
|---|---|
| OpenRouter | Local dev default (qwen/qwen3-coder:free) |
| Anthropic | Claude for long-context RAG synthesis |
| OpenAI | GPT-4o class models for tool calling |
Without an API key the graph uses keyword intent and regex tool dispatch.
Model-agnostic / on-prem: set CAEC_LLM_BASE_URL to a compatible local endpoint
(Qwen-class, YandexGPT-class, LM Studio) — no code changes required.
Key settings¶
| Variable | Purpose |
|---|---|
CAEC_QDRANT_URL |
Qdrant endpoint; empty → in-memory retriever |
CAEC_REQUIRE_CITATIONS |
Report must cite sources |
CAEC_REFUSE_UNSAFE_CALCULATIONS |
Guardrail for stress without FoS context |
CAEC_DEMO_ENABLED |
Kill switch — returns 503 on /ask when false |
CAEC_RATE_LIMIT_PER_MINUTE |
POST /ask rate limit (default 30) |
Full list: src/cae_copilot/config.py · deployment.
Stage 1 target (not yet in dependencies)¶
| Component | Role |
|---|---|
| Unstructured.io | PDF/GOST parsing, table extraction into governed chunks |
Stage 3 target (deferred)¶
| Component | Role |
|---|---|
| Docker | Isolated solver containers |
| Celery + Redis or k8s Jobs | Async job queue |
| Result parsers | .dat, .rst, solver-specific output |
Spec: solver-agent-skill.md.
Not in the MVP stack¶
These were considered or appear in early notes but are not dependencies:
| Item | Reason excluded |
|---|---|
| LlamaIndex | Direct qdrant-client + langchain retrievers suffice |
| CrewAI / AutoGen | Anti-goals — see requirements |
| Poetry | PDM is source of truth |
| GitHub Actions | GitLab CI only |
| Chainlit | Replaced by Streamlit for portfolio UI |
Local development¶
mamba activate cae-copilot
pdm install
make dev-stack # Qdrant + API + Streamlit
make ingest # load Rocky PDFs via manifest
Docker images install from pre-exported requirements-*.txt (not pdm install
in CI). Regenerate after dependency changes:
make requirements
Related¶
- Roadmap — stage model
- Data-First — ingestion and routing
- Quickstart — environment setup
- Deployment — production layout
- Data flow — how Qdrant fits the graph