Llevar a cabo una campaña de investigación
El manifiesto, los dos archivos que escribe una campaña, los campos que hacen útil el informe y cómo interrogar con campagne.py un corpus ya recopilado.
campagne.py se sitúa por encima del núcleo de navegación: búsqueda con
SearXNG, recopilación HTTP ligera, paso a rpa.py/shot.py solo para las
páginas que necesitan un navegador, y un informe que un modelo redacta a partir
de las páginas recopiladas.
# Instalación por clon de Git
/opt/dinoer/venv/bin/python3 /opt/dinoer/campagne.py --manifeste manifeste.json
# Paquete .deb
dinoer-campaign --manifeste manifeste.json
El manifiesto
Solo id_campagne y cibles son obligatorios; los demás campos tienen un
valor por defecto. El ejemplo documentado en campagne.py:
{
"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 (recopilar varias páginas candidatas sobre algo con nombre y
hacer que el modelo elija la que de verdad trata de ello), table_reference
(crear o reutilizar una lista guardada de sitios de confianza para un tema y
buscar después en cada uno).
Cada objetivo se procesa por separado: uno que falla no detiene a los demás, mientras que la lista de acciones de un escenario se detiene en el primer fallo.
Dos archivos, dos usos
operations.jsonl es el registro de operaciones que comparten todos los
programas de Dinoer. Una campaña añade una línea por intento, con éxito o sin
él, marcada con intention="dinoer-campagne".
<directorio de campañas>/<id_campagne>/collecte.jsonl tiene una línea
por página conservada, y solo esas. El informe se construye a partir de él, y
es el archivo que hay que abrir para comprobar que una afirmación procede de
una página recopilada. El directorio de campañas es
/var/log/dinoer/campagnes, salvo que DINOER_CAMPAGNES_DIR o la clave
campagnes_dir de la configuración indiquen otro.
Reordenar las páginas antes de que el informe las corte
Por defecto, el paso del informe une las páginas en el orden en que se escribieron y corta a los 60 000 caracteres, sin clasificación. Dos campos opcionales del manifiesto reordenan las páginas; ninguno elimina ninguna:
{
"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 un filtro de texto, sin modelo alguno: las
páginas que claramente no mencionan el periodo pedido pasan al final. Incluya
en la lista formas numéricas como /08, porque algunas páginas de agenda nunca
escriben el mes con letras. sujet_synthese ordena las páginas por su cercanía
de significado con esa frase, mediante embeddings de Ollama. Use los dos.
En la campaña de referencia, el filtro de texto dejaba por sí solo el programa
oficial de actos en el puesto 27 de las 29 páginas conservadas, más allá del
corte; la clasificación por significado lo subió al puesto 4.
Hacer una pregunta abierta a un corpus ya recopilado
/opt/dinoer/venv/bin/python3 /opt/dinoer/campagne.py --extraire-cible "<question>" \
--id-campagne <id> --format-extraction markdown
--extraire-cible acepta cualquier pregunta en lenguaje natural, no solo la
búsqueda de un dato; --corpus <archivo> lo dirige a un collecte.jsonl
situado en otro lugar. En la campaña territorial de agosto de 2026, 47 llamadas
con una pregunta abierta dieron 17 respuestas positivas. En una página, la
pregunta estrecha solo había conservado una fecha de un festival de cinco
días; la abierta devolvió el programa entero y otros cuatro eventos del mismo
texto.
Para agrupar los resultados que describen el mismo evento en varias páginas,
lib/extraction.py::fusionner_evenements() los fusiona y conserva cada
dirección de origen. Aplicada de nuevo a las 15 extracciones positivas de esa
campaña, encontró los mismos 11 eventos que el recuento hecho a mano. Una
página que describe varios eventos se cita en cada grupo al que pertenece.
El modelo que redacta el informe se mantiene fuera de la web
En cada llamada, Dinoer retira al modelo sus herramientas websearch y
webfetch, sea cual sea el directorio desde el que se lanza la campaña. Sin
esto, un modelo lanzó una vez por su cuenta doce búsquedas web, invisibles en
el texto que devolvió.
Qué cubre esto, y la brecha que queda →
Ritmo y actualidad
delai_min_secondes/delai_max_secondes fijan una pausa aleatoria antes de
cada consulta a SearXNG y antes de cada página obtenida.
revisite_apres_jours (30 por defecto) impide que una campaña vuelva a obtener
una página recopilada hace poco.
Las mismas reglas, completas →
La caché de búsqueda
lib/cache_recherche.py guarda en ChromaDB las páginas recopiladas para cada
consulta. Una consulta posterior de significado cercano se sirve desde ella,
sin nueva búsqueda ni nueva obtención; esas páginas llevan
"source": "cache" en el corpus. --desactiver-cache omite la caché en una
ejecución; --purger-cache y --purger-cache-avant-jours N la vacían. Si
ChromaDB u Ollama no están disponibles, la caché simplemente falla y la
campaña continúa.
En resumen
- Solo
id_campagneyciblesson obligatorios. - Cuatro tipos de objetivo:
query,url,produit,table_reference. collecte.jsonles el archivo al que remite una afirmación: ábralo en lugar de fiarse solo del informe.- Indique juntos
motifs_annee/motifs_moisysujet_synthesepara que el informe no corte las páginas útiles. - Una pregunta abierta a
--extraire-cible, página por página, saca más de un corpus que una estrecha. - El modelo que redacta el informe se mantiene fuera de la web, salvo por
bash.