This is a submission for Weekend Challenge: Passion Edition
What I Built
Gardener's Assistant — a grounded RAG chat for horticulture.
My father spent decades as a plant breeder and researcher (Doctor of Agricultural Sciences, North Caucasus mountain horticulture institute). His articles — and his colleagues' — live in journal PDFs, not in anything a generic LLM can cite reliably. I built an assistant so growers and agronomists can ask questions and get answers grounded in those papers, with numbers verified before they reach the user.
The intended goal: make scientific horticulture queryable without hallucination. If retrieval cannot support an answer, the bot refuses. It does not invent rootstock codes, spray rates, or cultivar names.
What it does today:
- Text chat over ~500 scientific articles (apple, pear, plum) via hybrid retrieval
- Telegram Mini App + browser client (Docker, one
compose up) - 68-question retrieval regression suite — the gate I run before trusting any LLM output
- Numeric verifier in Go — dosages in the answer must appear in retrieved context
Demo
Gardener's Assistant chat: three horticulture questions in Russian receive grounded answers from scientific articles via RAG, with streaming response in a Telegram-style UI:
Admin panel: login, upload horticulture articles into the RAG corpus, trigger reindex, and review 👍/👎 answer ratings — filter by likes or dislikes, see totals, and inspect each rated Q&A with crop, timestamp, and session/message ID to trace who gave feedback:
GIF: see above — Russian UI and Russian source articles (working demo today). English corpus and UI copy are being rolled out next.
Run locally:
git clone https://github.com/kantik001/grounded_horticulture_en
cd grounded_horticulture_en
cp .env.example .env # LLM_API_KEY required
docker compose up -d --build
→ Chat: http://localhost/
→ Admin (article upload): http://localhost/admin.html
Three questions from the recording (Russian — matches the indexed corpus):
- Какие признаки парши на листьях яблони? — disease + glossary expansion
- Как густота посадки влияет на Айдаред на подвое СК 4? — exact identifier (BM25)
- Какие подвои подходят для интенсивного сада на склоне? — semantic + lexical blend
English equivalents (for the upcoming EN launch — same retrieval paths, translated articles):
- What are signs of apple scab on leaves?
- How does planting density affect Aidared on SK 4 rootstock?
- What rootstocks work for intensive orchards on slopes?
The public repo ships demo articles only (EN samples for quick start); the full journal corpus stays local for licensing. The pipeline, eval harness, and Docker stack are all there.
Code
kantik001
/
grounded_horticulture_en
Grounded RAG horticulture assistant (English public portfolio, demo data only).
🍏 grounded-horticulture — horticulture assistant
Grounded RAG for horticulture: answers grounded in scientific articles with fact checking, not LLM hallucinations. Telegram Mini App and browser chat with API key.
Demo
▶ Full chat recording (MP4) · ▶ Full admin recording (MP4)
What it is
An assistant for gardeners and agronomists: text → hybrid search over articles → LLM answer with verification of numbers and dosages; photo → CV + recommendation (beta, no production weights in this repo).
| Component | Role |
|---|---|
Go (server/) |
Auth, Postgres sessions, RAG+LLM orchestration, verify, rate limit, /metrics
|
Python (api/, rag/) |
Hybrid retrieval (Chroma + BM25 + reranker), CV /classify
|
Web (webapp/) |
Chat, article upload admin, nginx in Docker |
Access: Telegram initData or browser X-API-Key (see .env.example).
Public repository: git contains demo data only (
data/demo_hr/,data/apple/sample_*.txt). Full article…
Key paths:
| Path | What |
|---|---|
rag/ + api/
|
Hybrid retrieval (Chroma, BM25, RRF, reranker) |
server/ |
Go orchestration, SSE chat, numeric verifier |
eval/*.jsonl |
68 retrieval regression questions |
scripts/run_rag_eval.py |
One-command eval runner |
webapp/ |
Browser chat UI |
How I Built It
Passion → engineering constraint
The personal motivation came first: my father's horticulture papers should be queryable, not buried in PDF archives. The engineering rule followed: I don't trust the LLM until retrieval is measurable. Before tuning models or UI, I wrote a 68-question JSONL eval suite — rootstock codes, diseases, out-of-scope refusals — and made it a regression gate.
Why hybrid retrieval (not "better embeddings")
Pure vector search understood topic but missed tokens that matter — cultivar names, rootstock codes like SK 4, OCR-noisy spellings.
Example eval question: "How does planting density affect Aidared on SK 4 rootstock?"
Vector-only returned paragraphs about rootstocks but not the Aidared token:
Fix: per-crop hybrid pipeline:
query → glossary expansion (domain synonyms)
→ Chroma (multilingual-e5-small) top-16
→ BM25 top-16
→ RRF merge
→ conditional cross-encoder rerank (rootstock / disease / variety only)
→ diversify (≤2 chunks per article) → top-8 to the LLM
Result: 68/68 on the retrieval suite:
Re-verify anytime:
python scripts/run_rag_eval.py --suite all --in-process --fast
Decisions worth calling out:
- RRF over score normalization — BM25 and cosine similarities live on different scales; ranks merge cleanly.
- Category-gated reranker — the cross-encoder helps dense technical questions but costs CPU; "when should I water?" skips it.
- Eval retrieval separately from generation — no LLM tokens, ~20s locally, catches regressions before users do.
Go + Python split
-
Python (
rag/,api/): embeddings, Chroma, BM25, reranker,POST /rag/context -
Go (
server/): auth (Telegram + API key), Postgres sessions, SSE streaming, numeric verifier (numbers in the answer must appear in retrieved context)
If retrieval is weak, Go short-circuits before paying for generation.
What broke (and what saved me)
| Change | Symptom | Eval caught it? |
|---|---|---|
| Chunking split tables from headers | Apple pass_rate −7 | Yes — reverted in minutes |
| BM25 not rebuilt after corpus update | Exact-code questions failed | Yes |
| Glossary entry too aggressive | MRR dropped, pass_rate unchanged | Yes |
Passion projects still need discipline. The interesting work wasn't the chat bubble — it was making scientific archives answerable without lying.
What I learned
- Passion without measurement ships fairy tales. A 20-second eval run changed how I work more than any embedding upgrade.
- Hybrid search (BM25 + vectors + RRF) beat "just use a better model" for scientific text with rare codes.
- The hard problem was never the chat UI — it was making PDF archives answerable without lying.
Disclaimer: assistant output is informational; field decisions require local experts and compliant product labels. CV classification is beta.






Top comments (0)