darkforensic-7b / README.md
jmpicon2026's picture
docs: huggingface-cli como método principal de descarga + troubleshooting Error: EOF
2bd2f4d verified
---
license: other
license_name: darkforensic-dual
license_link: LICENSE
language:
- es
- en
tags:
- threat-intelligence
- darkweb
- cybersecurity
- spanish
- qwen2.5
- lora
- gguf
base_model: Qwen/Qwen2.5-7B-Instruct
pipeline_tag: text-generation
inference: false
---
# darkforensic-7b
> Asistente threat-intelligence dark-web para CISOs y DPOs europeos.
> Spanish-first. Defensive role only.
> Construido por [Neural Ghost](https://neural-ghost.com) — equipo
> pequeño, plataforma de threat-intel alojada en Europa.
`darkforensic-7b` es un fine-tune LoRA de
[Qwen2.5-7B-Instruct](https://huggingface.co/Qwen/Qwen2.5-7B-Instruct)
entrenado sobre un corpus curado de hallazgos reales de dark-web (Tor +
I2P, 3 290 sitios cubriendo 11 categorías: marketplace, fraud, hacking,
forum, leak, cyberattack, services, etc.) con pares Q&A sintéticos
generados por Anthropic Claude Sonnet 4.6 y filtrados por calidad,
relevancia e intención defensiva.
**Versión actual: v2 (mayo 2026).**
v3 está en entrenamiento continuo — ver sección [Roadmap](#roadmap).
## Qué hace
Responde preguntas operativas que un CISO, DPO o analista SOC se hace
sobre hallazgos de dark-web:
- *"Hemos visto credenciales nuestras en un combo-list de RaidForums.
¿Qué hacemos en las próximas 24h?"*
- *"¿Qué IOCs se extraen de esta venta IAB?"*
- *"¿Cómo documentamos esto al comité de cumplimiento?"*
- *"¿Es activo este foro post-RaidForums hoy?"*
En castellano. Con citas a la fuente cuando aplica. Sin inventar hechos
cuando el hallazgo no los contiene.
## Qué NO hace
- ❌ Explicar cómo atacar sistemas, comprar datos robados, o acceder a
marketplaces. Todo el dataset se filtró por intención defensiva.
- ❌ Atribuir hechos a estados-nación o personas concretas.
- ❌ Procesar o generar contenido clasificado como CSAM. Kill-switch
heredado de la política CSAM-001 de Neural Ghost.
## Uso previsto
Asistentes de threat-intel internos para **organizaciones medianas
europeas reguladas** (banca cooperativa, mutualidades sanitarias,
hospitales privados, ayuntamientos medianos). Específicamente diseñado
para el contexto regulatorio europeo (Schrems II, RGPD, NIS2, DORA).
NO destinado para:
- Chatbots de propósito general (usa Qwen2.5-7B-Instruct base directamente).
- Threat-intel en inglés (la cobertura inglesa es incidental, no
optimizada).
- Análisis forense sin contexto RAG (el modelo se apoya fuertemente en
hallazgos recuperados; las respuestas standalone son más débiles).
## Cómo instalar y ejecutar darkforensic-7b en local
Hay tres formas, según tu hardware. Si no sabes cuál elegir, usa la
**Opción A (Ollama)**: es la más rápida y funciona en cualquier laptop
con 8 GB de RAM o más.
### Requisitos por opción
| Opción | RAM mínima | GPU | Disco | Velocidad típica |
|---|---|---|---|---|
| A. Ollama (Q4_K_M) | 8 GB | no necesaria | ~5 GB | 5–15 tok/s en CPU; 30–60 con GPU |
| B. llama.cpp (Q4_K_M) | 8 GB | no necesaria | ~5 GB | igual que Ollama, sin server |
| C. Transformers + LoRA | 24 GB GPU | sí, A100/H100 ideal | ~16 GB | 20–40 tok/s en H100 |
---
### Opción A — Ollama (recomendada)
Funciona en Linux, macOS, Windows. Es lo que usamos en producción en el
VPS de Neural Ghost.
**1. Instala Ollama** (1 comando):
```bash
# Linux / macOS
curl -fsSL https://ollama.com/install.sh | sh
# Windows: descarga el instalador desde https://ollama.com/download
```
Verifica que está instalado:
```bash
ollama --version # debe imprimir "ollama version is X.Y.Z"
```
**2. Descarga el GGUF Q4_K_M y el Modelfile** de este repo:
**Recomendado: usa `huggingface-cli`** (gestiona redirects de HF, hace
resume si se corta la conexión, valida checksum):
```bash
mkdir darkforensic && cd darkforensic
# Instala el cliente HF si no lo tienes
pip install -U "huggingface_hub[cli]"
# En Debian/Ubuntu/Kali reciente puede pedir --break-system-packages
# o usa --user en su lugar:
# pip install -U --user "huggingface_hub[cli]"
# Descarga sólo los 2 archivos que necesitas (no todo el repo)
huggingface-cli download neuralghost/darkforensic-7b \
darkforensic-7b-v2-q4_k_m.gguf Modelfile \
--local-dir . --local-dir-use-symlinks False
# Verifica el tamaño (debe imprimir 4.4G — Hugging Face muestra 4.68 GB
# pero `ls -lh` redondea a unidades binarias)
ls -lh darkforensic-7b-v2-q4_k_m.gguf
```
<details>
<summary>Alternativa: `wget` o `curl` (si no puedes instalar `pip`)</summary>
```bash
mkdir darkforensic && cd darkforensic
# wget — usa el flag ?download=true para evitar el redirect de HF que
# rompe descargas silenciosas con curl. -c permite reanudar si se corta.
wget -c -O darkforensic-7b-v2-q4_k_m.gguf \
"https://huggingface.co/neuralghost/darkforensic-7b/resolve/main/darkforensic-7b-v2-q4_k_m.gguf?download=true"
wget -O Modelfile \
"https://huggingface.co/neuralghost/darkforensic-7b/raw/main/Modelfile"
# Verifica que el GGUF NO está vacío:
ls -lh darkforensic-7b-v2-q4_k_m.gguf # debe imprimir 4.4G
```
`curl -L -o ...` también funciona en la mayoría de equipos, pero hemos
visto casos (VMs Kali con NAT inestable, máquinas con TLS antiguo) en
los que curl crea el archivo destino, sigue un redirect 302 al CDN de
HF y luego falla silenciosamente sin reportar error. Resultado:
archivo de 0 bytes y `Error: EOF` al hacer `ollama create`. Si te
pasa, usa `wget -c` o `huggingface-cli` y se resuelve.
</details>
**3. Importa el modelo a Ollama**:
```bash
ollama create darkforensic-7b -f Modelfile
```
Esto tarda 30 s – 2 min la primera vez (Ollama indexa el GGUF y lo deja
listo). Verifica que está:
```bash
ollama list
# debe aparecer "darkforensic-7b" con el tag latest
```
**4. Pruébalo**:
```bash
ollama run darkforensic-7b "Hemos detectado credenciales de empleados \
nuestros en un combo-list publicado en RaidForums. ¿Qué hago en las \
próximas 24 horas?"
```
Te debería responder en castellano con un plan estructurado:
resumen → acciones inmediatas → IOCs → marco regulatorio (RGPD/NIS2).
**5. Para usarlo desde tu aplicación** (Python, etc.) — Ollama expone una
API REST en `http://localhost:11434`:
```python
import httpx, json
resp = httpx.post(
"http://localhost:11434/api/generate",
json={
"model": "darkforensic-7b",
"prompt": "Pregunta operativa CISO/DPO aquí…",
"stream": False,
},
timeout=120,
)
print(resp.json()["response"])
```
**6. Detenerlo / liberar memoria** cuando no lo uses:
```bash
ollama stop darkforensic-7b
```
---
### Opción B — llama.cpp (sin servidor, ideal si quieres scriptear)
Si prefieres no levantar el daemon de Ollama, puedes cargar el GGUF
directamente con `llama.cpp`:
```bash
# Instalar llama-cpp-python con soporte CUDA (omite CMAKE_ARGS si no tienes GPU)
CMAKE_ARGS="-DGGML_CUDA=on" pip install llama-cpp-python --upgrade --force-reinstall --no-cache-dir
```
Y úsalo así desde Python:
```python
from llama_cpp import Llama
llm = Llama(
model_path="darkforensic-7b-v2-q4_k_m.gguf",
n_ctx=8192,
n_gpu_layers=-1, # -1 = todas las capas en GPU; 0 = solo CPU
chat_format="chatml", # Qwen2.5 usa ChatML
)
response = llm.create_chat_completion(
messages=[
{"role": "system", "content":
"Eres darkforensic, asistente threat-intel dark-web para CISOs/DPOs "
"europeos. Responde en castellano, conciso, con acciones operativas y "
"el marco regulatorio (RGPD/NIS2/DORA) si aplica."},
{"role": "user", "content":
"¿Qué IOCs debo extraer de este finding y cómo los cruzo con mi SIEM?"},
],
temperature=0.3,
max_tokens=1024,
)
print(response["choices"][0]["message"]["content"])
```
---
### Opción C — Transformers + LoRA (necesitas GPU)
Esta opción carga el **modelo base** (Qwen2.5-7B-Instruct, ~16 GB en
bfloat16) **y aplica el LoRA adapter encima** (162 MB). Útil si quieres
seguir entrenando, mergear con otro adapter, o tener máxima precisión.
**1. Instalar dependencias**:
```bash
pip install transformers peft accelerate bitsandbytes torch
```
**2. Cargar y usar**:
```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
# Base model en bf16 (16 GB VRAM) — o en 4-bit con bnb si tienes menos
base = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen2.5-7B-Instruct",
torch_dtype=torch.bfloat16,
device_map="auto",
)
model = PeftModel.from_pretrained(base, "neuralghost/darkforensic-7b")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-7B-Instruct")
messages = [
{"role": "system", "content": "Eres darkforensic, asistente threat-intel..."},
{"role": "user", "content": "Tu pregunta aquí"},
]
inputs = tokenizer.apply_chat_template(
messages, return_tensors="pt", add_generation_prompt=True
).to(model.device)
out = model.generate(inputs, max_new_tokens=600, do_sample=True, temperature=0.3)
print(tokenizer.decode(out[0][inputs.shape[-1]:], skip_special_tokens=True))
```
**Si tienes menos de 24 GB de VRAM** — carga el base en 4-bit:
```python
from transformers import BitsAndBytesConfig
bnb = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16)
base = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen2.5-7B-Instruct", quantization_config=bnb, device_map="auto",
)
# (el resto igual)
```
Con 4-bit cabe en ~6 GB de VRAM (RTX 3060 12 GB, RTX 4060 8 GB con stretching).
---
## Troubleshooting
| Síntoma | Causa probable | Solución |
|---|---|---|
| **`ollama create` → `Error: EOF`** o `parsing GGUF` falla | **El GGUF está vacío o incompleto.** Comprueba con `ls -lh darkforensic-7b-v2-q4_k_m.gguf`: si imprime `0` o un número menor a `4.4G`, la descarga falló silenciosamente (típico en VMs con NAT inestable cuando se usa `curl`). | Re-descargar con `huggingface-cli download …` (gestiona redirects + resume + checksum). Ver paso 2 de la instalación. Si solo tienes `wget`/`curl`, usa el sufijo `?download=true` en la URL y `wget -c` para reanudar. |
| `ollama create` se queda colgado en `gathering model components` | El Modelfile referencia un GGUF que no existe en esa carpeta | Verifica que `darkforensic-7b-v2-q4_k_m.gguf` está en el mismo directorio que el `Modelfile`: `ls` debe mostrar ambos |
| `Error: out of memory` al usarlo | Estás cargando fp16/bf16 en GPU pequeña, o varios modelos a la vez en Ollama | Usa Q4_K_M; `ollama stop` los otros modelos; o reduce `num_ctx` en el Modelfile (8192 → 4096) |
| Respuestas muy lentas (< 2 tok/s) | Corriendo en CPU sin AVX2, o el modelo no cabe en RAM y está paginando a disco | Verifica `grep avx2 /proc/cpuinfo`; baja a 4 hilos con `OLLAMA_NUM_PARALLEL=1`; cierra otras apps con memoria pesada |
| Responde en inglés cuando le hablas en castellano | Faltó el system prompt o el primer mensaje es muy corto | Asegúrate de pasar el system del Modelfile (Ollama lo aplica automáticamente con `ollama run`); con la API REST mándalo explícito |
| "Permission denied" al ejecutar | Falta permisos en `~/.ollama` | `chmod -R u+rw ~/.ollama` |
| El modelo alucina IOCs específicos (BTC addresses, hashes) | El modelo describe IOCs, NO los memoriza — por diseño | Es el comportamiento correcto, no un bug. Para IOCs verbatim necesitas el RAG sobre tu corpus indexado, no el LLM solo |
| Estás en una **VM** y la descarga se corta a mitad | NAT/throughput inestable + curl + archivo de 4.7 GB es un combo malo | Usa `huggingface-cli download` (con resume automático), o `wget -c` para reanudar si se corta. Aumenta la RAM de la VM a 8 GB+ y el disco a 50 GB+ para tener margen tras descargar |
## Integración con un pipeline RAG (recomendado para producción)
DarkForensic-7B está pensado para responder **con contexto recuperado** de
tu propio corpus de hallazgos. Sin RAG es un asistente; con RAG es una
herramienta de análisis. El patrón básico:
```python
# 1. El usuario pregunta algo sobre un finding
question = "¿Cómo respondo a este leak de credenciales?"
# 2. Tu sistema RAG recupera los k findings más relevantes del corpus
context_findings = your_rag.retrieve(question, k=5)
context_text = "\n\n".join(
f"[finding {f.id}] {f.title}\n{f.snippet}" for f in context_findings
)
# 3. Se manda al modelo en el system o como contexto previo
prompt = f"""CONTEXTO (5 findings relevantes de tu corpus dark-web):
{context_text}
PREGUNTA DEL ANALISTA: {question}
Responde citando los finding IDs cuando uses información de ellos.
Si los findings no contienen información suficiente, dilo explícitamente."""
# 4. Llama al modelo (Ollama u otro)
response = httpx.post("http://localhost:11434/api/generate",
json={"model": "darkforensic-7b", "prompt": prompt, "stream": False},
timeout=120).json()["response"]
```
La plataforma completa que envuelve esto (crawler Tor/I2P, scoring,
RAG vectorial, alertas, UI) es **GhostNet Intelligence Platform** y se
comercializa por separado. Contacto: neural@neural-ghost.com.
## Detalles del entrenamiento
| | |
|---|---|
| Base model | Qwen2.5-7B-Instruct (Apache-2.0) |
| Método | QLoRA r=32, alpha=64, dropout=0.05 |
| Target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
| Sequence length | 2048 |
| Effective batch size | 16 |
| Learning rate | 2e-4 cosine, warmup 3% |
| Epochs | 3 |
| Hardware | 1× H100 80GB (RunPod), ~10h |
| Coste training | ~$30 USD compute + ~$36 generación dataset = ~$66 total |
| Datos training | 3 290 hallazgos dark-web → 9 376 pares Q&A sintéticos filtrados |
| Split eval | 937 pares held-out (10%) |
## Evaluación
Evaluación head-to-head contra el **teacher (Claude Sonnet 4.6)** sobre
15 preguntas representativas tomadas del corpus de producción, juzgadas
por Claude Sonnet 4.6 sobre una rúbrica de 4 dimensiones (escala 1–10).
Ambos modelos limitados a `max_tokens = 1500` para comparación justa.
| Dimensión | Claude Sonnet 4.6 (teacher) | **darkforensic-7b** |
|---|---:|---:|
| Exactitud | 6.73 | **5.67** |
| Profundidad | 6.93 | **5.13** |
| Accionabilidad | 7.20 | **6.20** |
| Claridad | 7.60 | **7.13** |
| **Avg** | **7.12** | **6.03** |
| Respuestas críticas (avg ≤ 3.0) | 0/15 | **0/15** |
**Interpretación honesta**:
- **vs Claude Sonnet 4.6 (teacher)**: alcanza el ~85% de la calidad de
un modelo ~100× más caro y que requiere API externa. Pierde sobre
todo en profundidad analítica — un 7B no es un trillón-parámetros.
Diferencia en claridad casi nula (7.13 vs 7.60).
- **vs base (qwen2.5:3b)**: mejora consistente en todas las
dimensiones; ganancia media geométrica +7.4% (ver paper).
- **Críticos**: 0 de 15. Operativamente no produce respuestas vacías
o dañinas.
**Caveats metodológicos** (declarados para transparencia):
- 15 preguntas es muestra pequeña. Estadísticamente preliminar.
- Single-judge eval: Claude Sonnet 4.6 fue teacher Y juez — sesgo
conocido en literatura (favorece su propio style). v3 introducirá un
segundo juez independiente y reportará inter-judge agreement.
- El primer run del eval incluyó Gemini 2.5 Flash como referencia
comercial peer, pero las respuestas se truncaron por un problema
de configuración del cliente (`max_tokens` insuficiente,
respuestas <150 caracteres en la mitad de las preguntas). Para
no sesgar la comparación con un cliente mal configurado, **Gemini
se excluyó** del chart final. Se re-ejecutará en v3 con
configuración correcta.
**v3** ampliará el eval a 100+ preguntas con dos jueces independientes.
## Roadmap
**v2 (publicado, mayo 2026)** — modelo actual. Cumple el caso de uso
principal (asistente de un analista con RAG sobre hallazgos), pero hay
margen para mejorar en profundidad de análisis y en categorías
minoritarias del corpus.
**v3 (en entrenamiento)** — objetivos:
- Doblar el corpus a ~18 000 pares Q&A.
- Incorporar feedback real de los analistas que usan v2 (preferencias
thumbs-up/down vía DPO).
- Ampliar cobertura de árabe y mandarín (categorías minoritarias hoy).
- Reducir la brecha vs Claude Sonnet 4.6 a < 10%.
Si quieres recibir aviso cuando se publique v3, sigue este repo en
HuggingFace o suscríbete vía neural@neural-ghost.com.
## License
Dual:
1. **Uso research / academic / personal**: gratis bajo
[CC-BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/).
Cita como abajo.
2. **Uso comercial**: requiere licencia de Neural Ghost.
Contacto: neural@neural-ghost.com o vía
[neural-ghost.com](https://neural-ghost.com).
Precio en función del caso (reventa a clientes, integración en
producto comercial, uso interno en empresa con ánimo de lucro).
Típicamente ~€500-€2 500/año. Los ingresos de licencia financian
directamente las próximas versiones open-weight.
El enfoque dual-license es intencional: gratis para la comunidad que
da feedback, compensación justa cuando se usa para hacer dinero. Si
tienes duda de cuál te aplica, pregunta — somos razonables.
## Cita
```bibtex
@misc{darkforensic-7b-v2-2026,
title={DarkForensic-7B: A Spanish threat-intelligence dark-web assistant},
author={Pic\'on, Jos\'e and {Neural Ghost contributors}},
year={2026},
version={v2},
howpublished={\\url{https://huggingface.co/neuralghost/darkforensic-7b}},
}
```
## Limitaciones
- **Spanish-first**. Las respuestas en inglés existen en el corpus pero
no están optimizadas; para casos en inglés preferir Qwen2.5-7B-Instruct
base con RAG.
- **Corte de conocimiento**: corpus indexado hasta 2026-04-30. Los
actores rebrand-ean con frecuencia; verifica atribución actual contra
fuentes frescas.
- **Origen sintético del dataset**: los pares Q&A fueron generados por
Claude Sonnet sobre hallazgos reales, luego filtrados. Patrones de
estilo heredados de Sonnet están presentes.
- **No para decisiones autónomas**. El modelo es un asistente para un
analista humano, no un sustituto.
- **Riesgo de alucinación**: como cualquier LLM, puede fabricar hechos
plausibles. Verifica siempre afirmaciones de alta apuesta contra el
hallazgo fuente o fuentes externas autoritativas (BleepingComputer,
Krebs, CCN-CERT, advisories de vendor).
## Agradecimientos
- [Qwen team](https://github.com/QwenLM/Qwen2.5) por el modelo base.
- [Anthropic](https://anthropic.com) por las APIs de distillation.
- [Axolotl](https://github.com/axolotl-ai-cloud/axolotl) por el
pipeline de training.
---
Construido con paciencia por José Picón como parte de
[Neural Ghost](https://neural-ghost.com).
Threat-intel europeo para organizaciones a las que los gigantes
americanos no atienden.