# arjunisaac/policy-rag architecture

> Architecture diagram of the GitHub repository arjunisaac/policy-rag, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-05). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/arjunisaac/policy-rag
- Repository: https://github.com/arjunisaac/policy-rag

## Overview

#### Purpose and Entry Points
Policy-RAG is a local insurance-policy question-answering system. It indexes a policy document library, retrieves relevant content, and uses a locally served Qwen3 model to generate answers and extract policy attributes.

Primary entry points:
- `ingest_library.py` builds or refreshes the searchable policy corpus.
- `main.py` launches the Streamlit user interface.
- `vllm_env.sh` prepares Linux environment settings for the separate vLLM inference server.

#### Runtime Topology
The application runs as two cooperating processes:
- Streamlit hosts the interactive RAG application via `main.py`.
- vLLM exposes an OpenAI-compatible API serving `Qwen/Qwen3-4B-AWQ`, configured externally through the README launch command and `vllm_env.sh`.

The Python application depends on the model service being available before query processing. Hugging Face authentication may be required to obtain gated model artifacts.

#### Ingestion and Corpus Boundary
Library ingestion is isolated from interactive querying:
- `ingest_library.py`
- `src/ingestor.py`
- `src/vector_store.py`

The ingestion path loads policy-library content, prepares it for retrieval, and persists/vectorizes it through the vector-store layer. This creates the durable boundary between raw policy documents and query-time retrieval; the Streamlit process should consume the indexed corpus rather than reprocess source documents per request.

#### Retrieval and RAG Orchestration
Query-time retrieval is split between retrieval infrastructure and policy-specific orchestration:
- `src/retrieval.py`
- `src/vector_store.py`
- `src/policy_chain.py`

`retrieval.py` and `vector_store.py` form the document-search boundary. `policy_chain.py` is the likely composition layer that turns a user question plus retrieved policy context into a model request and final response. It is the primary control-flow boundary between UI interaction, evidence retrieval, and LLM generation.

#### Attribute Extraction Pipeline
The repository contains a dedicated structured-extraction subsystem rather than relying solely on free-form RAG answers:
- `src/extract_attribute/extraction_engine.py`
- `src/extract_attribute/retrieval_engine.py`
- `src/extract_attribute/post_processor.py`

This subsystem retrieves relevant policy evidence for a target attribute, runs extraction, then normalizes or validates output in post-processing. Supporting strategies include regex extraction and summarization:
- `src/extract_attribute/regex_extractor.py`
- `src/extract_attribute/summary_engine.py`

This separation enables deterministic or hybrid extraction for policy fields where generated prose alone is insufficient.

#### Domain Model and Presentation Boundary
Shared policy concepts, types, and output formatting are centralized outside the UI and retrieval implementations:
- `src/concepts.py`
- `src/datatypes.py`
- `src/formatting.py`

`main.py` should remain the presentation/controller boundary, coordinating user input with the policy chain and extraction capabilities. `styles.css` supplies UI styling without participating in core retrieval or model logic.

#### Key Data Flow
1. `ingest_library.py` invokes ingestion and vector-store persistence for policy documents.
2. A user submits a question through `main.py`.
3. The policy chain retrieves relevant indexed policy passages.
4. Retrieved context and the user query are sent to the vLLM-hosted Qwen model.
5. The response is formatted for Streamlit; attribute-oriented requests may pass through the dedicated retrieval → extraction → post-processing pipeline.

Main entry points: [`src/extract_attribute/extraction_engine.py`](https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/extraction_engine.py) (Extraction engine), [`src/policy_chain.py`](https://github.com/arjunisaac/policy-rag/blob/main/src/policy_chain.py) (Policy chain), [`main.py`](https://github.com/arjunisaac/policy-rag/blob/main/main.py) (Streamlit app), [`src/extract_attribute/retrieval_engine.py`](https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/retrieval_engine.py) (Attribute retrieval)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_ingestion["Corpus ingestion"]
  node_policy_docs["Policy document library<br/>source documents"]
  node_ingest_entry["Ingestion entry point<br/>Python script<br/>[ingest_library.py]"]
  node_ingestor["Content ingestor<br/>ingestion layer<br/>[ingestor.py]"]
  node_vector_store[("Vector store<br/>search storage<br/>[vector_store.py]")]
end

subgraph group_query["Interactive RAG"]
  node_main["Streamlit app<br/>UI controller<br/>[main.py]"]
  node_styles["UI styles<br/>stylesheet<br/>[styles.css]"]
  node_policy_chain["Policy chain<br/>RAG orchestrator<br/>[policy_chain.py]"]
  node_retrieval["Document retrieval<br/>retrieval layer<br/>[retrieval.py]"]
  node_formatting["Response formatting<br/>presentation layer<br/>[formatting.py]"]
  node_concepts["Policy concepts<br/>domain model<br/>[concepts.py]"]
  node_datatypes["Shared data types<br/>domain types<br/>[datatypes.py]"]
end

subgraph group_extraction["Attribute extraction"]
  node_attribute_retrieval["Attribute retrieval<br/>evidence retrieval"]
  node_extraction_engine["Extraction engine<br/>structured extraction"]
  node_regex_extractor["Regex extractor<br/>extraction strategy<br/>[regex_extractor.py]"]
  node_summary_engine["Summary engine<br/>extraction strategy<br/>[summary_engine.py]"]
  node_post_processor["Post-processor<br/>normalization layer<br/>[post_processor.py]"]
end

subgraph group_model["Model serving"]
  node_vllm_env["vLLM environment<br/>server setup<br/>[vllm_env.sh]"]
  node_vllm{{"vLLM API<br/>OpenAI-compatible server"}}
  node_qwen["Qwen3 model<br/>local LLM"]
end

node_policy_docs -->|"source content"| node_ingest_entry
node_ingest_entry -->|"invokes"| node_ingestor
node_ingestor -->|"vectorizes and persists"| node_vector_store
node_main -->|"applies"| node_styles
node_main -->|"user question"| node_policy_chain
node_policy_chain -->|"requests evidence"| node_retrieval
node_retrieval -->|"searches indexed corpus"| node_vector_store
node_policy_chain -->|"query and context"| node_vllm
node_vllm -->|"serves"| node_qwen
node_vllm_env -.->|"configures"| node_vllm
node_policy_chain -->|"answer"| node_formatting
node_formatting -->|"rendered response"| node_main
node_main -->|"attribute request"| node_attribute_retrieval
node_attribute_retrieval -->|"retrieves evidence"| node_vector_store
node_attribute_retrieval -->|"evidence"| node_extraction_engine
node_extraction_engine -.->|"deterministic strategy"| node_regex_extractor
node_extraction_engine -.->|"summarization strategy"| node_summary_engine
node_extraction_engine -->|"extraction prompt"| node_vllm
node_extraction_engine -->|"raw attribute"| node_post_processor
node_post_processor -->|"normalized result"| node_main
node_concepts -.->|"shared policy semantics"| node_policy_chain
node_datatypes -.->|"shared types"| node_policy_chain
node_datatypes -.->|"shared types"| node_extraction_engine

click node_ingest_entry "https://github.com/arjunisaac/policy-rag/blob/main/ingest_library.py"
click node_ingestor "https://github.com/arjunisaac/policy-rag/blob/main/src/ingestor.py"
click node_vector_store "https://github.com/arjunisaac/policy-rag/blob/main/src/vector_store.py"
click node_main "https://github.com/arjunisaac/policy-rag/blob/main/main.py"
click node_styles "https://github.com/arjunisaac/policy-rag/blob/main/styles.css"
click node_policy_chain "https://github.com/arjunisaac/policy-rag/blob/main/src/policy_chain.py"
click node_retrieval "https://github.com/arjunisaac/policy-rag/blob/main/src/retrieval.py"
click node_formatting "https://github.com/arjunisaac/policy-rag/blob/main/src/formatting.py"
click node_concepts "https://github.com/arjunisaac/policy-rag/blob/main/src/concepts.py"
click node_datatypes "https://github.com/arjunisaac/policy-rag/blob/main/src/datatypes.py"
click node_attribute_retrieval "https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/retrieval_engine.py"
click node_extraction_engine "https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/extraction_engine.py"
click node_regex_extractor "https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/regex_extractor.py"
click node_summary_engine "https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/summary_engine.py"
click node_post_processor "https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/post_processor.py"
click node_vllm_env "https://github.com/arjunisaac/policy-rag/blob/main/vllm_env.sh"

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_policy_docs,node_ingest_entry,node_ingestor,node_vector_store toneBlue
class node_main,node_styles,node_policy_chain,node_retrieval,node_formatting,node_concepts,node_datatypes toneAmber
class node_attribute_retrieval,node_extraction_engine,node_regex_extractor,node_summary_engine,node_post_processor toneMint
class node_vllm_env,node_vllm,node_qwen toneRose
```

## Components

### Corpus ingestion

Builds the durable searchable policy corpus.

- **Policy document library**: source documents · Raw policy content indexed offline.
- [Ingestion entry point](https://github.com/arjunisaac/policy-rag/blob/main/ingest_library.py): Python script · `ingest_library.py`
- [Content ingestor](https://github.com/arjunisaac/policy-rag/blob/main/src/ingestor.py): ingestion layer · `src/ingestor.py`
- [Vector store](https://github.com/arjunisaac/policy-rag/blob/main/src/vector_store.py): search storage · Persists embeddings and serves policy passage search. · `src/vector_store.py`

### Interactive RAG

Serves questions against the indexed corpus.

- [Streamlit app](https://github.com/arjunisaac/policy-rag/blob/main/main.py): UI controller · Interactive application entry point. · `main.py`
- [UI styles](https://github.com/arjunisaac/policy-rag/blob/main/styles.css): stylesheet · `styles.css`
- [Policy chain](https://github.com/arjunisaac/policy-rag/blob/main/src/policy_chain.py): RAG orchestrator · Combines questions, retrieved evidence, and model responses. · `src/policy_chain.py`
- [Document retrieval](https://github.com/arjunisaac/policy-rag/blob/main/src/retrieval.py): retrieval layer · `src/retrieval.py`
- [Response formatting](https://github.com/arjunisaac/policy-rag/blob/main/src/formatting.py): presentation layer · `src/formatting.py`
- [Policy concepts](https://github.com/arjunisaac/policy-rag/blob/main/src/concepts.py): domain model · `src/concepts.py`
- [Shared data types](https://github.com/arjunisaac/policy-rag/blob/main/src/datatypes.py): domain types · `src/datatypes.py`

### Attribute extraction

Produces normalized structured policy fields.

- [Attribute retrieval](https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/retrieval_engine.py): evidence retrieval · Finds evidence for a requested policy field. · `src/extract_attribute/retrieval_engine.py`
- [Extraction engine](https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/extraction_engine.py): structured extraction · `src/extract_attribute/extraction_engine.py`
- [Regex extractor](https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/regex_extractor.py): extraction strategy · `src/extract_attribute/regex_extractor.py`
- [Summary engine](https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/summary_engine.py): extraction strategy · `src/extract_attribute/summary_engine.py`
- [Post-processor](https://github.com/arjunisaac/policy-rag/blob/main/src/extract_attribute/post_processor.py): normalization layer · Normalizes or validates extracted attributes. · `src/extract_attribute/post_processor.py`

### Model serving

Separate local inference process.

- [vLLM environment](https://github.com/arjunisaac/policy-rag/blob/main/vllm_env.sh): server setup · Prepares Linux settings for model serving. · `vllm_env.sh`
- **vLLM API**: OpenAI-compatible server · Serves the local Qwen/Qwen3-4B-AWQ model.
- **Qwen3 model**: local LLM · May require Hugging Face authentication for artifacts.

## Connections

- Policy document library → Ingestion entry point: source content
- Ingestion entry point → Content ingestor: invokes
- Content ingestor → Vector store: vectorizes and persists
- Streamlit app → UI styles: applies
- Streamlit app → Policy chain: user question
- Policy chain → Document retrieval: requests evidence
- Document retrieval → Vector store: searches indexed corpus
- Policy chain → vLLM API: query and context
- vLLM API → Qwen3 model: serves
- vLLM environment → vLLM API: configures
- Policy chain → Response formatting: answer
- Response formatting → Streamlit app: rendered response
- Streamlit app → Attribute retrieval: attribute request
- Attribute retrieval → Vector store: retrieves evidence
- Attribute retrieval → Extraction engine: evidence
- Extraction engine → Regex extractor: deterministic strategy
- Extraction engine → Summary engine: summarization strategy
- Extraction engine → vLLM API: extraction prompt
- Extraction engine → Post-processor: raw attribute
- Post-processor → Streamlit app: normalized result
- Policy concepts → Policy chain: shared policy semantics
- Shared data types → Policy chain: shared types
- Shared data types → Extraction engine: shared types
