Dinoer

Llevando a cabo una campaña de investigación

Un manifiesto, un modelo delegado contenido en opencode.jsonc, y un informe que rastrea cada afirmación a una página realmente recopilada. La guía para campagne.py— el uso principal real de la herramienta.

campagne.py es una capa por encima del núcleo del navegador existente, no un reemplazo de este: Descubrimiento de SearXNG, recolección HTTP ligera, escalamiento a rpa.py/shot.py solo para las páginas que lo necesiten, y un informe que un modelo delegado escribe a partir de lo que realmente se recopiló.

python3 /opt/dinoer/campagne.py --manifeste manifeste.json

El manifiesto

Solo id_campagne y cibles son obligatorios — todo lo demás tiene un valor por defecto.

{
  "id_campagne": "concerts-finistere-2026-07-28",
  "cibles": [
    {"type": "query", "valeur": "concerts finistere sud ete"},
    {"type": "url", "valeur": "https://exemple.fr/agenda"},
    {"type": "produit", "valeur": "boulangerie Corentin a Quimper", "max_candidats": 5},
    {"type": "table_reference", "valeur": "mairies du Finistere sud", "cle_thematique": "mairies_finistere_sud"}
  ],
  "max_resultats": 15,
  "max_pages_par_hostname": 3,
  "delai_min_secondes": 4.5,
  "delai_max_secondes": 8.5,
  "revisite_apres_jours": 30
}

Cuatro tipos de objetivo: query (una búsqueda en SearXNG), url (una página fija), produit (descubrir y comparar candidatos para un elemento específico), table_reference (crear o extender una tabla persistente y con fuentes de sitios conocidos sobre un tema).

Cada objetivo es una llamada completamente aislada; el fallo de un objetivo nunca compromete a los demás, a diferencia de la lista de acciones de un único escenario, que se detiene en el primer fallo.

Dos artefactos, dos propósitos

operations.jsonl (compartido, solo escritura) registra cada intento, ya sea exitoso o no, con la etiqueta intention="dinoer-campagne"—el mismo registro al que escriben otras herramientas de Dinoer.

<campaigns_dir>/<id_campagne>/collecte.jsonl (por campaña, nuevo) tiene una línea por cada extracción exitosa únicamente. Este es el elemento base del que se construye el informe, y es el que se consulta para verificar que una reclamación realmente proviene de una página recopilada.

Reordena el informe automático antes de que se trunque.

El informe predeterminado concatena el corpus en el orden de escritura de los archivos, truncado a 60,000 caracteres; no incluye clasificación. Dos campos opcionales del manifiesto corrigen esto, ambos reorganizan, ninguno excluye:

{
  "motifs_annee": ["2026"],
  "motifs_mois": ["août", "aout", "/08", "-08-"],
  "sujet_synthese": "concerts and festivals, south Finistère, summer 2026"
}

motifs_annee/motifs_mois es una fase textual de cero llamadas al modelo: páginas que claramente no mencionan el término buscado y se muestran hasta el final, incluyendo formatos de fecha numéricos que algunos widgets de agenda utilizan en lugar del nombre completo del mes. sujet_synthese es una fase semántica: una llamada agrupada a la incrustación de Ollama, que clasifica las páginas según la similitud coseno con esa frase. Utilice ambas, no solo una. En una campaña de referencia real, la fase textual por sí sola aún dejó un PDF genuinamente relevante clasificado en el puesto 27 de 29 «páginas probables», lo que sigue estando fuera del presupuesto de truncamiento. La fase semántica lo movió dentro de ese rango. Medido contra ese corpus, no asumiendo nada.

Una pregunta abierta es mejor que una pregunta limitada

Para una extracción individual y específica, fuera de una campaña completa:

python3 /opt/dinoer/campagne.py --extraire-cible "<demande>" \
  --id-campagne <id> --format-extraction markdown

--extraire-cible acepta cualquier solicitud en lenguaje natural, no solo una búsqueda de hechos estrictos trouve/valeur/url. En una campaña de referencia real, una pregunta abierta y descriptiva permitió que el modelo delegado juzgara por sí mismo si estaba leyendo un hecho aislado o un evento de varios días: 17 de las 47 llamadas arrojaron resultados positivos y más completos que los producidos con una formulación más restrictiva en el mismo corpus.

Para resultados que describen el mismo evento real en varias páginas, lib/extraction.py::fusionner_evenements() los agrupa — invóquela sobre los resultados positivos filtrados antes de escribir un informe final, en lugar de consolidarlos manualmente. Una única fuente que describe legítimamente varios eventos distintos no es un error; la misma fuente se cita en cada grupo al que pertenece.

El corpus es lo que el modelo está autorizado a usar

Dinoer niega al modelo delegado sus propias websearch/webfetch herramientas para toda la fase de síntesis, sea cual sea el directorio desde el que se ejecuta la campaña (opencode.jsonc en la raíz del repositorio dice lo mismo, y OPENCODE_CONFIG_CONTENT lo lleva en cada llamada) — sin ellas, una ejecución real realizaba doce búsquedas propias, invisibles en el texto resultante. El informe completo, incluyendo lo que no cubre →

Respetando el objetivo, a escala de campaña

delai_min_secondes/delai_max_secondes Espacio cada vez que se realiza una llamada a rechercher(), no solo las solicitudes de página que la siguen; una campaña real descubrió esta laguna de la manera más difícil, y ahora se ha corregido en todas partes donde se pretendía aplicar este retraso. revisite_apres_jours (30 por defecto) evita que una campaña vuelva a analizar una página simplemente porque un objetivo posterior la referencia nuevamente. El mismo principio, en detalle →

La caché de búsqueda vectorial

lib/cache_recherche.py, respaldado por ChromaDB, evita volver a consultar para solicitudes casi duplicadas. --desactiver-cache lo omite durante una ejecución; --purger-cache o --purger-cache-avant-jours N lo borran explícitamente.

En resumen

  • Solo id_campagne y cibles son obligatorios; todos los demás campos tienen un valor por defecto documentado.
  • Cuatro tipos de objetivo: query, url, produit, table_reference.
  • collecte.jsonl es el artefacto al que se remonta una afirmación — consúltelo, no confíe únicamente en el informe.
  • motifs_annee/motifs_mois junto con sujet_synthese, no cada uno por separado, corrigen el punto ciego de truncamiento del informe predeterminado.
  • Una pregunta abierta con --extraire-cible supera a una búsqueda de hechos estricta en corpus reales.
  • opencode.jsonc es lo que mantiene el informe trazable hasta el corpus — conozca su límite real, no solo su promesa.