# ── LLM configuration ───────────────────────────────────────────────────────── # Two independent profiles, one per pipeline stage. Each accepts the same keys: # provider: openai | anthropic | gemini # openai_model / anthropic_model / gemini_model / max_tokens / temperature llm: # Part_One: vector-search query synthesis (small structured JSON in, # 1-2 short queries out). A lighter/cheaper model is sufficient here. query_synthesis: provider: gemini openai_model: gpt-4o-mini anthropic_model: claude-haiku-4-5 gemini_model: gemini-2.5-flash max_tokens: 8192 temperature: 0.0 # Part_Two: the farmer-facing advisory generator. Receives the full # json_for_advice_generation payload (weather, phenology, model output, # applied treatments, product labels) and returns the structured advice # JSON stored in the advice table. Needs a more capable model. advice_generation: provider: gemini openai_model: gpt-4o anthropic_model: claude-opus-4-5 gemini_model: gemini-2.5-pro max_tokens: 16384 temperature: 0.0 # ── Crop-first worklist ──────────────────────────────────────────────────────── # `python -m pipeline batch` discovers jobs from this list: for every crop, it # finds all fields growing it (AI_agrosupport_cmp_layers ⨝ an_colture) that also # have a matching row in AI_agrosupport_agro_models for each listed disease's # model_name, and runs the full single-field pipeline for every resulting # (field, disease) pair. `disease` is the canonical English name used for the # product prefilter, the vector search, and the advice/prompt lookup; it must # exist in vocab/diseases.yaml. `model_name` is matched (case-insensitively) # against AI_agrosupport_agro_models.anmod_model. # # Each crop-disease pair needs a matching prompt directory under # prompts/advice/__/ (see prompts/README or the pipeline # README for the exact slug rules); pairs without one fall back to # prompts/advice/_default/ and are logged at startup. crops: - crop: grapevine diseases: - model_name: PERONOSPORA disease: downy mildew # ── Worklist filters ─────────────────────────────────────────────────────────── worklist: # AI_agrosupport_agro_models.anmod_enabled is True for every model row in the # current database; keep this on so a disabled model never generates advice. require_enabled_model: true # Restrict the batch to specific field IDs while testing; empty = no filter. field_allowlist: [] # ── Concurrency & rate limiting ──────────────────────────────────────────────── # One "gemini" budget covers both direct LLM calls (query synthesis, advice # generation) and Weaviate near_text search, because the ProductProfile # collection is vectorised with text2vec-palm (gemini-embedding-001) using the # same GEMINI_API_KEY — they share one quota. concurrency: workers: 8 limits: sql: 6 gemini: 4 gemini_requests_per_minute: 60 # ── Retry policy for transient LLM / Weaviate / SQL failures ────────────────── retry: attempts: 3 initial_backoff_seconds: 2 max_backoff_seconds: 30 # ── Daily SLA ─────────────────────────────────────────────────────────────────── # The batch must not still be running after this local time; jobs not yet # started by then are skipped (status skipped_deadline) rather than risking a # late advisory. Schedule the run itself no earlier than ~07:00 so weather is # fresh (see README). schedule: deadline: "09:00" # ── Single-field debug mode (`python -m pipeline one`) ──────────────────────── # Not used by `batch`; kept for ad-hoc single-field runs and debugging. field_id: 4012 disease_name: "PERONOSPORA" # ── Vocabulary paths ────────────────────────────────────────────────────────── vocab: crops: vocab/crops.yaml diseases: vocab/diseases.yaml