Skip to main content

Best practices

Best Practices for Building AI/RAG Applications on Botanical Data

Recommended practices for developers building information retrieval systems, classifiers and conversational agents on floristic and botanical data.

> Educational information - not a substitute for expert advice. For any application in scientific, medical or legal contexts related to plants, consult a qualified botanist.

Validate every scientific name against GBIF or POWO before inserting it into the corpus

Every scientific plant name in the corpus must be verified against GBIF (/v1/species/match?name=...&kingdom=Plantae) or POWO (powo.science.kew.org/api/2/search?q=...). Names not found in either source must not be used. Include the GBIF usageKey or POWO ID in the corpus record as a provenance field. This prevents propagation of invented or obsolete names into the RAG.

Do: GET /v1/species/match?name=Fagus+sylvatica&kingdom=Plantae → verify that matchType != "NONE" and status == "ACCEPTED". Don't: insert LLM-generated Latin names into the corpus without external verification.

Use the scientific name as the primary key, with aliases for common names

In multilingual retrieval systems, the primary key for each botanical entity must be the scientific name (in normalized form: Genus + specific epithet + abbreviated author). Common names (in 18 or more languages) are stored as aliases. This ensures that a query in Italian ("quercia farnia") and one in German ("Stieleiche") resolve to the same entity (_Quercus robur_ L.) without ambiguity.

Do: build a plant_aliases table with columns scientific_name, language, common_name. Don't: use the common name as the primary key in embedding vectors.

Add an explicit disclaimer to every chunk describing plant properties

Every corpus chunk mentioning any plant property (ecological, toxicological, medicinal, alimentary in a broad sense) must contain the educational disclaimer. Even a single sentence about a species being "toxic upon ingestion" must be accompanied by an in-chunk disclaimer, not only in the system documentation. The disclaimer ensures that even a retriever extracting a single chunk preserves the safety context.

> Educational information - not a substitute for expert advice.

Do: add the disclaimer as the first or last sentence of every chunk matching tox|medicin|edib|food. Don't: put the disclaimer only on the pack overview page.

Separate premium artefacts from free artefacts in the filesystem

Premium artefacts (eval.jsonl, corpus.jsonl, data.jsonl, prompts/, schema.sql) must reside in knowledge-packs-premium//v1.0.0//, never in frontend/public/. The structural gate find frontend/public/content/knowledge-packs// -name "eval.jsonl" must return empty output before each commit. This separation ensures paid content is not publicly downloadable.

Do: verify with find before every domain commit. Don't: use a single directory tree for both free and premium content.

Build the corpus with self-contained chunks of 300–600 characters

Every corpus.jsonl row must be a self-contained text chunk: a paragraph or definition that makes sense without external context. The optimal size for botany is 300–600 characters (approximately 80–120 words), compatible with cosine retrieval MiniLM-L6-v2 (dim 384) and with the context window of LLM models used as judges. Chunks that are too short lose context; those too long dilute the semantic signal.

Do: split artefacts into chunks by paragraph or definition; always add the source_url field in the corpus. Don't: insert entire artefacts as a single chunk.

Ensure that every eval.jsonl answer is fully entailed by its contexts

Every eval.jsonl entry must have the answer field entailed (logically deducible) from the provided contexts alone. This is the RAGAS Faithfulness requirement. For botany, an answer citing a scientific name must be supported by at least one context containing that name. Verify with eval_pack.py (RAGAS Faithfulness, threshold ≥ 0.5 on sample).

Do: for each QA pair, manually check that the answer can be found in the context before running RAGAS. Don't: insert answers with information not present in the contexts (even if technically correct).

Periodically update GBIF distribution data with scheduled API pulls

GBIF distribution data changes: new occurrences are recorded, invasive species reports are updated, taxonomic revisions change synonyms. For production biodiversity applications, set up a periodic job (e.g. monthly) that updates GBIF records for the key corpus species. Use the GBIF Occurrence Download endpoint with filters for updates after a specific date (lastInterpreted).

Do: use the GBIF API with modifiedSince for incremental pulls. Don't: load a GBIF dump once and never update it.

Handle common name polysemy with entity linking towards GBIF

Many common names are ambiguous: "walnut" can refer to _Juglans regia_ L. (common walnut) or _Juglans nigra_ L. (black walnut). "Lavender" can indicate _Lavandula angustifolia_ Mill. or _Lavandula latifolia_ Medik. (both on GBIF). A botanical RAG system must implement entity linking: when the user uses a common name, the system resolves the most probable scientific entity given geographical context and question. The GBIF API /v1/species/suggest?q= provides candidates with usageKey.

Do: implement an entity linker that maps common name → GBIF candidates → selection based on context. Don't: use the common name as a direct retrieval query without disambiguation.

Structure system prompts with explicit no-fabrication rules

System prompts for botanical agents must include explicit rules: "Do not invent scientific names. If you do not know the Latin name, state the uncertainty. Do not provide guidance on edibility, toxicity or medicinal use without citing a source. Every scientific name must be verifiable on GBIF or POWO." These rules significantly reduce the invented species failure mode.

Do: include no-fabrication rules in every system prompt for the botany domain. Don't: rely solely on "you are a botany expert" instructions without explicit constraints.

Monitor corpus coverage across major botanical families

The RAG corpus must have balanced coverage across the main plant families present in the target territory. For Italian flora, the richest families are Asteraceae (>800 species), Fabaceae, Poaceae, Orchidaceae, Rosaceae. An unbalanced corpus (e.g. 80% Orchidaceae) produces poor quality retrieval for questions about other families. Monitor family distribution with a GBIF aggregated query.

Do: verify family distribution with group_by family during corpus analysis. Don't: build the corpus only from the most "famous" species (e.g. only medicinal plants or cultivated species).

Use the Darwin Core format for floristic data exchange

Darwin Core (DwC) is the international standard for sharing biodiversity data. Key fields for botany include scientificName, scientificNameAuthorship, taxonRank, family, decimalLatitude, decimalLongitude, eventDate, institutionCode. GBIF and most digital herbaria export in DwC. Using DwC as the exchange format ensures interoperability with global aggregation systems.

Do: use standardized DwC fields in the corpus import interface. Don't: create a proprietary format for occurrence data.

Implement a cache layer for GBIF and POWO API calls

The GBIF and POWO APIs have rate limits (GBIF: 1000 req/min for non-authenticated users). For applications that perform many name resolutions (e.g. indexing a digital herbarium), implement a cache layer (Redis or SQLite) storing results for 30+ days. Taxonomic data changes rarely; occurrence data changes more frequently. Configure different TTLs for the two categories.

Do: cache TTL 30 days for taxonomic data; 7 days for occurrences. Don't: call GBIF API for every user request in production without caching.