ishaq101's picture
feat/Analysis State & Report Rework (#4)
0e02a0f
|
Raw
History Blame Contribute Delete
11.1 kB

Data Eyond β€” Python Agentic Service: Business Requirements & Design (BRD)

Status: draft for review Β· Date: 2026-06-26 Β· Branch: pr/4 Audience: Harry (Go gateway) + leads/stakeholders. Scope: the Python agentic LLM service (Agentic-Service-Data-Eyond-Catalog) only β€” its requirements, capabilities, architecture, data, and integration contract. Companions (source of truth, not duplicated here): REPO_STATUS.md (current built state) Β· API_ENDPOINTS.md (FE-callable API) Β· DEV_PLAN.md (in-flight plan). This BRD synthesizes those into a stakeholder-facing document; convert to PDF/Word for distribution.


1. Purpose & scope

Data Eyond is an "AI data scientist" for business analytics, modelled on CRISP-DM (Business Understanding β†’ Data Understanding β†’ Preparation β†’ Modeling β†’ Evaluation β†’ Deployment). A user sets a goal, connects data (databases or files), asks natural-language analytical questions, and receives CRISP-DM-structured answers that can be exported as a versioned report. The aim is a "junior data scientist that hands back a decision-ready deliverable," not a "chatbot over a database."

This document covers the Python service β€” the agentic reasoning layer. It does not specify the Go gateway or the React frontend except at their integration boundaries (Β§9, Β§11).

2. Business context & objectives

  • Target users: executives doing self-serve deep-dives; analysts offloading routine work.
  • Value: turn a business question + connected data into auditable, CRISP-DM-structured findings and a formal report, without the user writing SQL or code.
  • Objectives: (a) accurate, grounded analysis over the user's own data; (b) a decision-ready, versioned report artifact; (c) safe, read-only access to user data; (d) a clean service contract the Go gateway can integrate against.

3. Stakeholders & actors

Actor Role
End user (exec/analyst) Defines the analysis goal, asks questions, generates reports (via the FE)
Frontend (React/Vite) Talks to Go for everything; to Python only for chat streaming
Go gateway (Orchestrator-Agent-Service) Auth/JWT, rooms, documents, DB-credential storage, catalog ingestion, all DB migrations, and now all analysis-state writes
Python agentic service (this repo) Router, skills, slow analytical path, structured query engine, RAG, report generation
Harry Owns the Go gateway + dedorch DB migrations

4. Solution overview

Request flow is FE β†’ Go β†’ Python; the FE calls Python directly only for chat streaming. The Python service is a FastAPI app that classifies each user message and dispatches it to the right capability, streaming results back over SSE. Heavy analysis runs through a deterministic slow path (plan β†’ execute β†’ assemble) whose structured output is persisted and later rendered into reports.

5. Functional requirements (capabilities)

ID Capability Description
FR-1 Intent routing One GPT-4o call classifies each message into one of 5 intents β€” chat, help, check, unstructured_flow, structured_flow β€” with history-aware query rewriting (EN/ID).
FR-2 Help skill State-aware, next-step guidance (LLM, streamed); only offers actions the current state allows (e.g., a report only when one is generatable).
FR-3 Check skill No-LLM inventory of available structured data + uploaded documents.
FR-4 Structured analysis (slow path) Planner β†’ TaskRunner β†’ Assembler: a static DAG of tool-call chains, degrade-and-continue execution, narrative authored by one LLM call; produces a structured run record.
FR-5 Structured query engine Catalog-driven JSON IR β†’ deterministic SQL/pandas compiler β†’ read-only executor, with single-level FK joins (DB sources).
FR-6 Unstructured RAG Retrieval over PGVector document chunks, answered by the chatbot.
FR-7 Analytics tools Composite analyze_* (descriptive, aggregate, correlation, trend) over data-access tools (check_*, retrieve_*).
FR-8 Report generation Deterministic assembly of findings/EDA/limitations/method from persisted run records + one LLM call for the executive summary; versioned, formal markdown.
FR-9 Analysis sessions One session = one analysis = one chat room (analysis_id == room_id); per-analysis data-source binding.

Goal capture (post-2026-06-24 pivot): the analysis goal is two user-entered fields β€” objective + business_questions β€” captured at onboarding, both mandatory, no agent validation. The former agent-validated "problem statement" + its gate are removed.

6. Analysis & report lifecycle

  1. Create analysis (via Go) β€” session row + chat room + chosen data-source bindings; goal = objective + business_questions.
  2. Ask questions β€” POST /chat/stream; the router dispatches; structured_flow questions run the slow path and persist one report_inputs row per run (the report's source of truth).
  3. Generate report β€” the report skill reads the session's report_inputs, assembles the structured sections + an executive summary, and persists an immutable versioned report (markdown).
  4. Read reports β€” list versions / fetch a version.

Reports are records-based (never from chat history) and require the slow path to have run (enable_slow_path=true) so records exist.

7. System architecture (subsystems)

FastAPI + async SQLAlchemy + LangChain (Azure GPT-4o) + Redis + Azure Blob + PGVector. Key subsystems (detail in REPO_STATUS Β§9):

  • Router (agents/orchestration.py) β€” 5-intent classifier.
  • Skills (agents/handlers/) β€” help (LLM), check (no-LLM).
  • Slow path (agents/slow_path/ + agents/planner/) β€” Planner, TaskRunner, Assembler.
  • Structured query engine (query/) β€” IR validate β†’ compile β†’ read-only execute (never raises).
  • Report (agents/report/) β€” generator, store (advisory-locked versioning), readiness floor.
  • Observability β€” Langfuse tracing (PII-masked); Redis caching; pooled DB engines.

8. Data model

SQLAlchemy models in src/db/postgres/models.py (detail in REPO_STATUS Β§8). The service is moving to the shared dedorch DB (Go owns migrations; Python is consumer-only β€” Β§11).

Table Purpose Owner
users accounts (incl. fullname for report authorship) Go
analyses (plural) per-analysis session state: objective/business_questions (pivot), user_id, status, data_bind(+version), report_collection, report_id Go (dedorch)
analyses_messages the analysis chat room (user Q + agent A) β€” replaces deprecated chat_messages/rooms Go (dedorch)
report_inputs one jsonb row per slow-path run β€” the report's source of truth (was analysis_records) Python (schema handed to Go)
reports versioned report artifacts (markdown) Go (dedorch)
data_sources per-analysis source bindings Go (dedorch)
documents, databases, data_catalog uploads, DB credentials (Fernet), per-user catalog Go ingestion
langchain_pg_embedding PGVector document chunks Go ingestion

9. API surface (FE-callable)

Full contract + request/response examples in API_ENDPOINTS.md. The FE-callable surface is 4 things:

  1. call_agent β€” POST /api/v1/chat/stream (SSE).
  2. list_skills β€” GET /api/v1/tools (slash-command catalog; cacheable).
  3. skill: help β€” via call_agent (router intent; no dedicated endpoint).
  4. skill: report β€” POST /api/v1/report + GET list/version.

analysis_id == room_id. Auth is terminated at Go; Python trusts user_id/room_id.

10. Non-functional requirements

Area Requirement / mechanism
Security β€” data access All structured queries are read-only: IR validation + SQL compiler whitelist + sqlglot SELECT-only guard + read-only session + LIMIT/timeout. DB credentials are Fernet-encrypted with an owner check.
Security β€” PII PII columns carry no sample values into prompts; Langfuse masks PII on assembler/chatbot spans.
Reliability Never-throw seams across tools/query/executors/state/report β€” failures degrade to soft output rather than crashing a turn.
Performance Redis response cache (stateless chat only) + retrieval cache; pooled DB engines + speculative prewarm; warm Azure clients per process.
Observability Langfuse: one trace per request (router/planner/assembler/chatbot + tool spans), tokens + latency.
Portability Runs on HuggingFace Spaces (Linux) and Windows (run.py sets the selector event-loop policy for psycopg3 async).

11. Integrations & dependencies

  • Two-repo boundary: Python is edited independently; Go + FE are reference-only. Python reads/writes shared Postgres, reads Azure Blob (Parquet for tabular sources), uses Redis.
  • dedorch migration: Python is moving from the dataeyond DB to dedorch. Go owns all migrations; Python is consumer-only β€” if Python needs a table, it hands Go the schema. Table names are plural (analyses, analyses_messages); rooms/chat_messages are deprecated there.
  • State writes via Go: all analysis-state writes move behind Go; Python's per-turn state access becomes a read-only get (in progress).
  • External services: Azure OpenAI (GPT-4o + embeddings), Azure Blob, Postgres (+ PGVector), Redis, Langfuse.

12. Constraints & assumptions

  • The slow path must be enabled (enable_slow_path=true) for reports to have content.
  • report_inputs is Python-owned but its schema is provided to Go so the dedorch migration creates it (so it survives the SKIP_INIT_DB cutover).
  • Charts and images are out of scope for now β€” reports are markdown (tables/bold/italic/separators); charts (Plotly JSON) and images (table + bucket) are deferred.
  • The frontend has no dedicated UI designer; UI is being researched in parallel.

13. Open items & roadmap

Tracked in DEV_PLAN.md Β§4. Headlines: finish Go-side state ownership (#7/#18), the dedorch analyses migration (#3, mostly done), HF deploy + playground test (#13), chat-path migration to analyses_messages (#25), and the deferred charts/images/UI work (#26/#27/#28).

14. Glossary

  • Slow path β€” the deterministic Plannerβ†’TaskRunnerβ†’Assembler analytical pipeline.
  • report_inputs β€” the jsonb table of slow-path run records the report reads (formerly analysis_records).
  • dedorch β€” the shared Postgres DB the service is migrating to; Go owns its migrations.
  • CRISP-DM β€” the cross-industry standard data-mining process the analysis is structured around.
  • analysis_id == room_id β€” one analysis session is one chat room, identified by the same id.