An automated multi-agent framework for early-stage water treatment train design with retrieval augmentation and critic-based refinement
Hanzhang Liua,f,1, Zhaorui Jianga,b,d,1,*, Huiling Zhongc, Jinshuo Lib,e, Wei Pangb, Yingfang Yuanb,*
1 Equal contribution | * Corresponding authors: Zhaorui Jiang, Yingfang Yuan
Paper Release GitHub stars License: MIT Python Hugging Face
FastAPI Streamlit RAG Multi-Agent WContBench OpenRouter
Paper · Release · Dataset · Installation · Quick Start · Evaluation · Citation
OpenAqua frameworkFigure 1. OpenAqua framework: a five-agent pipeline with retrieval augmentation and critic-based refinement.
OpenAqua is a research system for early-stage water treatment train design. Given source water, target contaminants, effluent goals, and operating constraints, a five-agent pipeline parses the request, retrieves unit-level and case-level evidence, proposes taxonomy-constrained process chains, critiques them against hard engineering rules, and returns ranked recommendations with citations.
The runnable system lives in water_treatment_agent/. Raw knowledge assets, processed corpora, and the WContBench benchmark are hosted on Hugging Face:
- [2026-08] Our paper is published in Water Research.
- [2026-08] v1.0.0 released. See the release notes.
- [2026-08] Knowledge base, raw crawls, and WContBench are served from the Hugging Face dataset.
- [2026-03] OpenAqua code and WContBench released.
| Five specialized agents | Parser, Retriever, Planner, Critic, and Explainer run as a typed pipeline with an optional critic–planner retry loop. |
| Dual knowledge base | Unit-level treatment records (TDB) plus case-level plant reports, indexed for hybrid retrieval. |
| Taxonomy lock | Candidate units must come from the controlled process vocabulary; unknown units are dropped, not silently kept. |
| Constraint critic | Rule library checks disinfection, brine disposal, energy, and taxonomy compliance, then auto-revises when possible. |
| Interpretable ranking | Score = coverage (0.35) + constraint (0.30) + evidence (0.25) − risk. |
| Graceful degradation | Without an OpenRouter key the system still runs via rule- and template-based fallbacks. |
| WContBench | 337 design cases in Easy / Middle / Difficult splits, with gold trains and evidence lists. |
The overview figure above is the system architecture. Agents run as a typed pipeline; the critic can send failed trains back to the planner when every candidate is dropped.
| Agent | Role |
|---|---|
| Parser | Maps free-text or structured input to a NormalizedQuery (source, contaminants, targets, constraints). |
| Retriever | Hybrid BM25 + token-overlap search over unit and case corpora. |
| Planner | Generates candidate trains inside the process taxonomy, using retrieved cases as context. |
| Critic | Applies the rule library; auto-fixes missing disinfection / brine conflicts; drops remaining failures. |
| Explainer | Binds evidence, computes the decomposed rank score, and writes a rationale with uncertainty. |
Serving stack:
- FastAPI —
GET /health,POST /recommend,POST /ingest - Streamlit — recommend / health / ingest pages
- LLM — OpenRouter (
anthropic/claude-3-haikudefault; stronger models for planning and explanation)
All data are on Hugging Face, not in this Git repository.
| Asset | Path on Hub | Contents |
|---|---|---|
| Processed knowledge base | data.zip |
App-ready unit-level TDB, taxonomy, and case KB |
| Raw crawls | RawData.zip |
Source crawls used to build the KB |
| WContBench Easy | WContBench/WContBench_Easy |
92 single-contaminant / conventional cases |
| WContBench Middle | WContBench/WContBench_Middle |
117 multi-constraint cases |
| WContBench Difficult | WContBench/WContBench_Difficult |
128 high-conflict design cases |
Each WContBench item is a JSON case with:
- influent quality, treatment goal, and engineering constraints
- gold ranked process trains with unit functions
- evidence lists and evaluation targets (rank pattern, constraint fit, grounding)
# Option A — Hugging Face CLI pip install -U "huggingface_hub[cli]" huggingface-cli download zhaorui-bi/OpenAqua --repo-type dataset --local-dir ./hf_openaqua # Option B — snapshot in Python python - <<'PY' from huggingface_hub import snapshot_download snapshot_download( repo_id="zhaorui-bi/OpenAqua", repo_type="dataset", local_dir="./hf_openaqua", ) PY
Place the processed KB where the agent expects it, then build indexes:
mkdir -p water_treatment_agent/data
unzip hf_openaqua/data.zip -d water_treatment_agent/data
cd water_treatment_agent
python scripts/build_indexes.pyKeep hf_openaqua/WContBench/ for evaluation. RawData.zip is optional and only needed if you want the original crawl tree.
git clone https://github.com/zhaorui-bi/OpenAqua.git cd OpenAqua/water_treatment_agent python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt cp .env.example .env
Edit .env and set an OpenRouter key if you want LLM parsing / planning / explanation:
OPENROUTER_API_KEY=sk-or-v1-your-key-here
Without a key the pipeline still runs, with lower-quality natural-language parsing and template explanations.
Download the dataset (see above), unzip data.zip into water_treatment_agent/data/, then:
cd water_treatment_agent
python scripts/build_indexes.pyuvicorn app.api.main:app --reload --host 0.0.0.0 --port 8000
Docs: http://localhost:8000/docs
| Method | Endpoint | Status |
|---|---|---|
GET |
/health |
Ready — service, index, and LLM flags |
POST |
/recommend |
Ready — full five-agent pipeline |
POST |
/ingest |
Ready — add a KB entry and rebuild indexes |
POST |
/evaluate |
Stub — response model only |
curl -X POST http://localhost:8000/recommend \ -H "Content-Type: application/json" \ -d '{ "query": { "raw_query": "Groundwater with arsenic around 150 ug/L, low budget, no brine disposal", "source_water": "groundwater", "contaminants": ["arsenic"], "treatment_targets": { "arsenic_ug_L": 10, "compliance_standard": "WHO" }, "constraints": { "budget": "low", "brine_disposal": false } }, "top_k": 3 }'
cd water_treatment_agent
streamlit run gui/app.pycd water_treatment_agent
python scripts/run_full_demo.pyWContBench scoring does not require exact full-chain match. Predicted units are compared to the reference key units after synonym canonicalization.
| Script | Metrics |
|---|---|
test_openaqua.py |
Precision, Recall, F1, Coverage, Hit Rate, Case-level Acceptability (CLA) |
test_retrieval.py |
Precision@k, Recall@k, Hit@k against gold evidence_list |
# Treatment-train evaluation python test_openaqua.py \ --benchmark-dir hf_openaqua/WContBench/WContBench_Easy \ --predictions predictions.json \ --output eval_easy.json # Retrieval evaluation python test_retrieval.py \ --benchmark-dir hf_openaqua/WContBench/WContBench_Easy \ --predictions retrieval_preds.json
Write a starter prediction file:
python test_openaqua.py --write-example-predictions example_preds.json
Unit tests (no Hugging Face download required for schema / rule checks):
cd water_treatment_agent
pytest tests -vOpenAqua/
├── assets/ # logo + framework figure (paper-resolution + web preview)
├── CHANGELOG.md
├── test_openaqua.py # WContBench train-level metrics
├── test_retrieval.py # WContBench retrieval metrics
└── water_treatment_agent/
├── app/
│ ├── agents/ # parser, retrieval, planner, critic, explainer
│ ├── api/ # FastAPI entrypoint and routes
│ ├── core/ # schemas, config, taxonomy, rules
│ ├── rag/ # corpus builder, hybrid retriever, reranker
│ ├── utils/ # scoring, evidence binding
│ └── workflows/ # end-to-end orchestration
├── gui/ # Streamlit recommend / health / ingest
├── scripts/ # build_indexes, parse_pdf_cases, run_full_demo
├── tests/
├── requirements.txt
└── .env.example
After dataset download, the runtime tree is:
water_treatment_agent/data/
├── unit-level/tdb/ # from data.zip
├── unit-level/taxonomy.json
├── case-level/kb_cases.json
└── processed/indexes/ # created by scripts/build_indexes.py
If you use OpenAqua or WContBench, please cite:
@article{liu2026openaqua, title = {OpenAqua: An automated multi-agent framework for early-stage water treatment train design with retrieval augmentation and critic-based refinement}, author = {Liu, Hanzhang and Jiang, Zhaorui and Zhong, Huiling and Li, Jinshuo and Pang, Wei and Yuan, Yingfang}, journal = {Water Research}, pages = {126761}, year = {2026}, issn = {0043-1354}, doi = {10.1016/j.watres.2026.126761}, url = {https://doi.org/10.1016/j.watres.2026.126761}, note = {Equal contribution: Hanzhang Liu and Zhaorui Jiang. Corresponding authors: Zhaorui Jiang and Yingfang Yuan. Code: https://github.com/zhaorui-bi/OpenAqua. Dataset: https://huggingface.co/datasets/zhaorui-bi/OpenAqua} }
This project is released under the MIT License. Dataset files on Hugging Face follow the same MIT license.
OpenAqua builds on public water-treatment guidance and case material (including EPA-style reports and unit-process records). LLM calls go through OpenRouter. Retrieval uses BM25 over a locally built corpus.