Source code for evoproc_procedures.ollama

# projects/procedures/src/evoproc_procedures/ollama.py
"""
Ollama-backed query helpers for structured procedure generation and repair.

These functions implement the `QueryFn`/`RepairFn` style expected by the GA core:
    - `query(...)`: general-purpose text → JSON call, optionally constrained by a JSON Schema.
    - `hard_query(...)`: strict/low-temperature variant useful for repair passes.
    - `query_repair_structured(...)`: loop that validates a procedure JSON and issues
    minimal repair prompts until it passes (or exhausts retries).
    - `create_and_validate_procedure_structured(...)`: one-shot convenience that creates
    a procedure JSON for a task and validates/repairs it before returning.

All functions are pure client wrappers around `ollama.generate`.
They return **strings** (for raw model responses) or **dicts** (for JSON payloads).
"""

from __future__ import annotations

from typing import Any, Dict, Optional, Tuple

import ollama  # pip install ollama

from evoproc_procedures.builders import create_and_validate_procedure_structured
from evoproc_procedures.repairs import repair_procedure_structured
from evoproc_procedures.pipelines import run_full_procedure_structured as _run_full
from evoproc_procedures.schemas import get_schema

__all__ = [
    "query", "hard_query",
    "repair_fn_ollama", "create_and_validate_procedure_ollama",
    "run_full_procedure_ollama",
]

[docs] def hard_query( prompt: str, model: str, fmt: Optional[Dict[str, Any]] = None, seed: Optional[int] = 1234, ) -> str: """Call Ollama with *strict* decoding settings. Use this when you need the model to adhere tightly to `fmt` (a JSON Schema), e.g., repair steps. Temperature is set to 0. Args: prompt: Full prompt text. model: Ollama model name (e.g., ``"gemma3:latest"``). fmt: Optional JSON Schema dict for structured output. seed: Optional random seed for reproducibility. Returns: The raw string response (usually JSON text when `fmt` is provided). """ res = ollama.generate( model=model, prompt=prompt, format=fmt, # Ollama expects a schema dict here options={"temperature": 0, "seed": seed}, ) return res["response"]
[docs] def query( prompt: str, model: str, fmt: Optional[Dict[str, Any]] = None, seed: Optional[int] = 1234, ) -> str: """General-purpose Ollama call. This is your default structured call. When `fmt` is supplied, Ollama will attempt to return an object matching that schema. Args: prompt: Full prompt text. model: Ollama model name. fmt: Optional JSON Schema dict used as a response format. seed: Optional random seed for reproducibility. Returns: Raw string response (often JSON text when `fmt` is provided). """ res = ollama.generate( model=model, prompt=prompt, format=fmt, options={"temperature": 1, "seed": seed}, ) return res["response"]
[docs] def repair_fn_ollama(proc: Dict[str, Any], model: str) -> Dict[str, Any]: """Adapter for GA's `repair_fn(proc, model)` using Ollama backend.""" return repair_procedure_structured(proc, model=model, query_fn=hard_query, print_diagnostics=False)
[docs] def create_and_validate_procedure_ollama(idx: int, task: str, *, model: str, seed: int = 1234, print_diagnostics: bool = False) -> Dict[str, Any]: """Convenience creator that uses Ollama under the hood.""" return create_and_validate_procedure_structured(idx, task, model=model, query_fn=query, seed=seed, print_diagnostics=print_diagnostics)
[docs] def run_full_procedure_ollama( idx: int, question: str, *, model: str = "gemma3:latest", answer_schema_name: str = "gsm", run_steps_fn=None, seed: Optional[int] = 1234, print_diagnostics: bool = False, ) -> Tuple[Dict[str, Any], Dict[str, Any]]: """Ollama-backed 'create → repair → execute' helper for one question. Args mirror the backend-agnostic version; this just wires in the Ollama `query` and fetches the answer schema by name. """ from evoproc_procedures.ollama import query # local import to avoid cycles if run_steps_fn is None: raise ValueError("run_steps_fn must be provided (executor for your steps).") schema = get_schema(answer_schema_name) return _run_full( idx, question, model=model, query_fn=query, run_steps_fn=run_steps_fn, answer_schema=schema, seed=seed, print_diagnostics=print_diagnostics, )