# jain-brain/ayr-answer-engine architecture

> Architecture diagram of the GitHub repository jain-brain/ayr-answer-engine, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-11). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/jain-brain/ayr-answer-engine
- Repository: https://github.com/jain-brain/ayr-answer-engine

## Overview

This repository is an engineering-document answer engine. Its main workflow ingests PDFs and DOCX files into searchable, page-linked text, table rows, and figure descriptions; a user question then triggers document retrieval and, when appropriate, a structured-data SQL route before answer generation and citation checking. A separate evaluation workflow scores extraction, retrieval, answers, and citations. The graph reflects documented behavior and sampled calls; the corpus and external model service are shown as external dependencies, while unsampled subsystem details are kept at directory level.

Main entry points: [`answer_engine/engine.py`](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py) (Answer engine), [`answer_engine/llm.py`](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/llm.py) (Model client), [`answer_engine/ingest.py`](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ingest.py) (Document extraction), [`answer_engine/evaluate.py`](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/evaluate.py) (Evaluation runner)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_ingest["Document ingestion"]
  node_ingest_cli["Ingest runner<br/>[ingest.py]"]
  node_extract["Document extraction<br/>[ingest.py]"]
  node_figure_describe["Figure description<br/>[ingest.py]"]
end

subgraph group_answer["Question answering"]
  node_ask_cli["Question interface<br/>[ask.py]"]
  node_answer_all["Batch answering<br/>[ask.py]"]
  node_engine["Answer engine<br/>[engine.py]"]
  node_retrieval["BM25 retrieval<br/>[engine.py]"]
  node_sql_router["SQL routing<br/>[engine.py]"]
  node_citation_check["Citation check<br/>[engine.py]"]
  node_config["Settings and prompts<br/>[config.py]"]
  node_llm_client["Model client<br/>[llm.py]"]
end

subgraph group_data["Corpus and models"]
  node_extracted[("Extracted documents")]
  node_corpus[("Source corpus")]
  node_sqlite[("SQLite tables<br/>[engine.py]")]
  node_model_service{{"OpenAI-compatible API"}}
  node_results[("Evaluation results")]
end

subgraph group_eval["Evaluation"]
  node_eval_runner["Evaluation runner<br/>[evaluate.py]"]
  node_extract_eval["Extraction scores<br/>[evaluate.py]"]
  node_qa_eval["Retrieval and answer scores<br/>[evaluate.py]"]
end

node_user(("Engineer"))

node_user -->|"requests extraction"| node_ingest_cli
node_ingest_cli -->|"processes files"| node_extract
node_extract -->|"reads documents"| node_corpus
node_extract -->|"describes figures"| node_figure_describe
node_figure_describe -->|"requests descriptions"| node_llm_client
node_extract -->|"writes JSON and Markdown"| node_extracted
node_user -->|"asks question"| node_ask_cli
node_ask_cli -->|"calls ask"| node_engine
node_ask_cli -->|"answers question sets"| node_answer_all
node_answer_all -->|"calls ask"| node_engine
node_engine -->|"searches units"| node_retrieval
node_retrieval -->|"loads JSON"| node_extracted
node_engine -->|"routes question"| node_sql_router
node_sql_router -->|"queries tables"| node_sqlite
node_sql_router -->|"requests route"| node_llm_client
node_engine -->|"generates answer"| node_llm_client
node_llm_client -->|"calls API"| node_model_service
node_engine -->|"checks citations"| node_citation_check
node_engine -->|"loads structured files"| node_corpus
node_user -->|"runs evaluation"| node_eval_runner
node_eval_runner -->|"scores extraction"| node_extract_eval
node_eval_runner -->|"scores answers"| node_qa_eval
node_qa_eval -->|"runs questions"| node_answer_all
node_qa_eval -->|"judges answers"| node_llm_client
node_eval_runner -->|"writes scores"| node_results

click node_ingest_cli "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ingest.py"
click node_extract "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ingest.py"
click node_figure_describe "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ingest.py"
click node_extracted "https://github.com/jain-brain/ayr-answer-engine/tree/main/extracted"
click node_ask_cli "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ask.py"
click node_answer_all "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ask.py"
click node_engine "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py"
click node_retrieval "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py"
click node_sql_router "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py"
click node_citation_check "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py"
click node_config "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/config.py"
click node_sqlite "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py"
click node_llm_client "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/llm.py"
click node_eval_runner "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/evaluate.py"
click node_extract_eval "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/evaluate.py"
click node_qa_eval "https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/evaluate.py"
click node_results "https://github.com/jain-brain/ayr-answer-engine/tree/main/results"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_ingest_cli,node_extract,node_figure_describe toneBlue
class node_ask_cli,node_answer_all,node_engine,node_retrieval,node_sql_router,node_citation_check,node_config,node_llm_client toneAmber
class node_extracted,node_corpus,node_sqlite,node_model_service,node_results toneMint
class node_eval_runner,node_extract_eval,node_qa_eval toneRose
class node_user toneIndigo
```

## Components

### Document ingestion

- [Ingest runner](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ingest.py): `answer_engine/ingest.py`
- [Document extraction](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ingest.py): `answer_engine/ingest.py`
- [Figure description](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ingest.py): `answer_engine/ingest.py`

### Question answering

- [Question interface](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ask.py): `answer_engine/ask.py`
- [Batch answering](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/ask.py): `answer_engine/ask.py`
- [Answer engine](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py): `answer_engine/engine.py`
- [BM25 retrieval](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py): `answer_engine/engine.py`
- [SQL routing](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py): `answer_engine/engine.py`
- [Citation check](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py): `answer_engine/engine.py`
- [Settings and prompts](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/config.py): `answer_engine/config.py`
- [Model client](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/llm.py): `answer_engine/llm.py`

### Corpus and models

- [Extracted documents](https://github.com/jain-brain/ayr-answer-engine/tree/main/extracted): `extracted`
- **Source corpus**
- [SQLite tables](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/engine.py): `answer_engine/engine.py`
- **OpenAI-compatible API**
- [Evaluation results](https://github.com/jain-brain/ayr-answer-engine/tree/main/results): `results`

### Evaluation

- [Evaluation runner](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/evaluate.py): `answer_engine/evaluate.py`
- [Extraction scores](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/evaluate.py): `answer_engine/evaluate.py`
- [Retrieval and answer scores](https://github.com/jain-brain/ayr-answer-engine/blob/main/answer_engine/evaluate.py): `answer_engine/evaluate.py`

### Other components

- **Engineer**

## Connections

- Engineer → Ingest runner: requests extraction (evidence: `README.md`)
- Ingest runner → Document extraction: processes files (evidence: `answer_engine/ingest.py`)
- Document extraction → Source corpus: reads documents (evidence: `answer_engine/ingest.py`)
- Document extraction → Figure description: describes figures (evidence: `answer_engine/ingest.py`)
- Figure description → Model client: requests descriptions (evidence: `answer_engine/ingest.py`)
- Document extraction → Extracted documents: writes JSON and Markdown (evidence: `answer_engine/ingest.py`)
- Engineer → Question interface: asks question (evidence: `README.md`)
- Question interface → Answer engine: calls ask (evidence: `answer_engine/ask.py`)
- Question interface → Batch answering: answers question sets (evidence: `answer_engine/ask.py`)
- Batch answering → Answer engine: calls ask (evidence: `answer_engine/ask.py`)
- Answer engine → BM25 retrieval: searches units (evidence: `answer_engine/engine.py`)
- BM25 retrieval → Extracted documents: loads JSON (evidence: `answer_engine/engine.py`)
- Answer engine → SQL routing: routes question (evidence: `answer_engine/engine.py`)
- SQL routing → SQLite tables: queries tables (evidence: `answer_engine/engine.py`)
- SQL routing → Model client: requests route (evidence: `answer_engine/engine.py`)
- Answer engine → Model client: generates answer (evidence: `answer_engine/engine.py`)
- Model client → OpenAI-compatible API: calls API (evidence: `answer_engine/llm.py`)
- Answer engine → Citation check: checks citations (evidence: `answer_engine/engine.py`)
- Answer engine → Source corpus: loads structured files (evidence: `answer_engine/engine.py`)
- Engineer → Evaluation runner: runs evaluation (evidence: `README.md`)
- Evaluation runner → Extraction scores: scores extraction (evidence: `answer_engine/evaluate.py`)
- Evaluation runner → Retrieval and answer scores: scores answers (evidence: `answer_engine/evaluate.py`)
- Retrieval and answer scores → Batch answering: runs questions (evidence: `answer_engine/evaluate.py`)
- Retrieval and answer scores → Model client: judges answers (evidence: `answer_engine/evaluate.py`)
- Evaluation runner → Evaluation results: writes scores (evidence: `README.md`)
