DEV Community

Victor Aguilar C.
Victor Aguilar C.

Posted on

Apex D. OpenClaw, Mejorar la Busqueda.

Ampliar las capacidades de búsqueda de OpenClaw

Este apéndice cubre cómo ir más allá de Brave Search con proveedores de búsqueda alternativos: Exa.ai (custom skill) y Perplexity (opción built-in).

Por qué Exa.ai no es un simple “swap”

OpenClaw trae web search built-in impulsado por Brave. Podrías preguntarte: “¿Puedo solo cambiar un setting para usar Exa.ai en su lugar?” La respuesta corta es no, pero por buenas razones.

La configuración de OpenClaw solo soporta dos search providers built-in:

  • Brave Search (default)
  • Perplexity

Estas son integraciones “native”, o sea, OpenClaw sabe cómo hablar con ellas out of the box.

Exa.ai es diferente. Es un neural/semantic search engine que requiere su propio formato de API, método de autenticación y manejo de respuestas. En vez de esperar a que OpenClaw agregue soporte nativo, podemos agregarlo nosotros usando una skill. Piensa en las skills como “plugins” o “extensions” para tu AI assistant. Una skill es un folder con instrucciones sobre cuándo usarla y scripts que hacen el trabajo real. Las skills te permiten extender las capacidades de OpenClaw sin modificar su core code.

Brave vs. Exa: cuándo usar cada uno

  • Usa Brave cuando: necesitas una respuesta rápida, verificar facts, o buscar websites específicos.

  • Usa Exa cuando: estás investigando un tema, necesitas fuentes de alta calidad, o quieres resultados semánticamente relevantes (no solo keyword matches).


Configurar la skill de Exa.ai

Prerequisites: una instalación funcional de OpenClaw, una Exa.ai API key (consigue una en https://exa.ai), y comodidad básica con la command line.

Step 1: Crear el folder de la skill

mkdir -p ~/.openclaw/workspace/skills/exa-search/scripts
Enter fullscreen mode Exit fullscreen mode

Step 2: Crear la definición de la skill

Crea un archivo llamado SKILL.md dentro del folder de la skill:

nano ~/.openclaw/workspace/skills/exa-search/SKILL.md
Enter fullscreen mode Exit fullscreen mode

Pega el siguiente contenido:

---
name: exa-search
description: Neural/semantic web search using Exa.ai API. Use for research queries requiring high-quality, semantically relevant results. Better than keyword search for conceptual queries, finding similar content, or research-heavy tasks. Requires EXA_API_KEY environment variable.
---

# Exa Search

Neural search via Exa.ai. Returns semantically relevant results, not just keyword matches.

## When to Use

- Research queries needing deep relevance (not just keywords)
- Finding articles/papers on specific concepts
- Semantic similarity searches
- When Brave search results aren't cutting it

## Usage

python3 scripts/exa_search.py "your search query"
python3 scripts/exa_search.py "your query" --num-results 10 --summary

## Options

| Flag | Description | Default |
|------|-------------|---------|
| --num-results N | Number of results | 5 |
| --text | Include page text snippets | off |
| --summary | Include AI summaries | off |
| --type TYPE | Search type: auto, neural, keyword | auto |
Enter fullscreen mode Exit fullscreen mode

Guarda y cierra el archivo (en nano: Ctrl+X, luego Y, luego Enter).

Step 3: Crear el script de búsqueda

Este es el script en Python que llama al API de Exa:

nano ~/.openclaw/workspace/skills/exa-search/scripts/exa_search.py
Enter fullscreen mode Exit fullscreen mode

Pega este código:

#!/usr/bin/env python3
"""Exa.ai neural search CLI."""

import argparse
import json
import os
import urllib.request
import urllib.error
from pathlib import Path

API_URL = "https://api.exa.ai/search"

# Load .env file if present
def load_env():
    env_path = Path(__file__).parent.parent / ".env"
    if env_path.exists():
        for line in env_path.read_text().strip().split("\n"):
            if "=" in line and not line.startswith("#"):
                key, val = line.split("=", 1)
                if key.strip() not in os.environ:
                    os.environ[key.strip()] = val.strip()

load_env()


def search(query, num_results=5, include_text=False, include_summary=False, search_type="auto"):
    """Execute Exa search."""
    api_key = os.environ.get("EXA_API_KEY")
    if not api_key:
        return {"error": "EXA_API_KEY not set. Add it to .env file or environment."}

    payload = {
        "query": query,
        "numResults": num_results,
        "type": search_type,
    }

    contents = {}
    if include_text:
        contents["text"] = True
    if include_summary:
        contents["summary"] = True
    if contents:
        payload["contents"] = contents

    headers = {
        "x-api-key": api_key,
        "Content-Type": "application/json",
        "User-Agent": "OpenClaw/1.0",
        "Accept": "application/json",
    }

    req = urllib.request.Request(
        API_URL,
        data=json.dumps(payload).encode("utf-8"),
        headers=headers,
        method="POST"
    )

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        return {"error": f"HTTP {e.code}: {e.read().decode('utf-8', errors='replace')}"}
    except urllib.error.URLError as e:
        return {"error": f"Request failed: {e.reason}"}


def format_results(data):
    """Format results for display."""
    if "error" in data:
        return f"Error: {data['error']}"

    results = data.get("results", [])
    if not results:
        return "No results found."

    lines = [f"Found {len(results)} results:\n"]

    for i, r in enumerate(results, 1):
        lines.append(f"## {i}. {r.get('title', 'Untitled')}")
        lines.append(f"URL: {r.get('url', 'N/A')}")

        if r.get("publishedDate"):
            lines.append(f"Published: {r['publishedDate'][:10]}")
        if r.get("author"):
            lines.append(f"Author: {r['author']}")
        if r.get("summary"):
            lines.append(f"\nSummary: {r['summary']}")
        if r.get("text"):
            text = r["text"][:500] + "..." if len(r.get("text", "")) > 500 else r.get("text", "")
            lines.append(f"\nText: {text}")
        lines.append("")

    if data.get("costDollars"):
        lines.append(f"Cost: ${data['costDollars'].get('total', 0):.4f}")

    return "\n".join(lines)


def main():
    parser = argparse.ArgumentParser(description="Exa.ai neural search")
    parser.add_argument("query", help="Search query")
    parser.add_argument("--num-results", "-n", type=int, default=5)
    parser.add_argument("--text", "-t", action="store_true", help="Include text snippets")
    parser.add_argument("--summary", "-s", action="store_true", help="Include AI summaries")
    parser.add_argument("--type", choices=["auto", "neural", "keyword"], default="auto")
    parser.add_argument("--json", "-j", action="store_true", help="Output raw JSON")

    args = parser.parse_args()

    result = search(
        query=args.query,
        num_results=args.num_results,
        include_text=args.text,
        include_summary=args.summary,
        search_type=args.type,
    )

    print(json.dumps(result, indent=2) if args.json else format_results(result))


if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

Guarda y cierra el archivo.

Step 4: Hacer el script ejecutable

chmod +x ~/.openclaw/workspace/skills/exa-search/scripts/exa_search.py
Enter fullscreen mode Exit fullscreen mode

Step 5: Agregar tu API key

Crea un archivo .env para guardar tu API key de forma segura:

nano ~/.openclaw/workspace/skills/exa-search/.env
Enter fullscreen mode Exit fullscreen mode

Agrega tu key (reemplaza por tu key real):

EXA_API_KEY=your-api-key-here
Enter fullscreen mode Exit fullscreen mode

Guarda y cierra.

Security Note: El archivo .env mantiene tu API key fuera del script. Nunca hagas commit de API keys en version control ni las compartas públicamente.

Step 6: Probar la skill

Corre una búsqueda de prueba:

cd ~/.openclaw/workspace/skills/exa-search
python3 scripts/exa_search.py "artificial intelligence in healthcare"
Enter fullscreen mode Exit fullscreen mode

Deberías ver resultados formateados. Prueba con summaries:

python3 scripts/exa_search.py "artificial intelligence in healthcare" --summary --num-results 3
Enter fullscreen mode Exit fullscreen mode

Cómo usa tu IA la skill de Exa

Una vez que la skill está configurada, tu OpenClaw assistant va a:

  1. Detectar automáticamente cuándo usarla basándose en la descripción de la skill
  2. Elegir Exa sobre Brave para consultas research-heavy o conceptuales
  3. Hacer fall back a Brave para lookups rápidos donde la velocidad importa

También puedes pedir explícitamente: “use Exa search for…” si quieres asegurarte de que use el neural search.

Exa Skill File Summary


Exa Cost Considerations

Exa.ai cobra por búsqueda:

  • Basic search: ~$0.005 por query
  • Con summaries: ~$0.01 por query
  • Deep search: ~$0.015 por query

Para la mayoría de usuarios que hacen unas pocas research queries al día, esto cuesta centavos. Un uso intenso podría estar en $1–5/mes. Compáralo con el valor: una búsqueda de alta calidad en Exa puede reemplazar 10+ búsquedas en Brave cuando estás tratando de entender un tema complejo.


Cambiar a Perplexity (alternativa built-in)

A diferencia de Exa, Perplexity es un provider built-in en OpenClaw. No requiere skill: solo un cambio de config.

Perplexity es un AI-powered search engine que devuelve respuestas sintetizadas (no solo links), incluye citations a fuentes, y maneja follow-up questions de forma conversacional. Piensa en esto como “ChatGPT que busca en la web”, no como un search engine tradicional.

  • Elige Perplexity cuando: quieres una respuesta directa con fuentes, no una lista de links para leer.

  • Elige Exa cuando: necesitas source documents de alta calidad para research, no summaries pre-digeridos.

Step 1: Conseguir un API key

Ve a https://www.perplexity.ai/settings/api, crea una cuenta o sign in, y genera un API key (empieza con pplx-).

Step 2: Actualizar OpenClaw config

Abre tu archivo de configuración de OpenClaw:

nano ~/.openclaw/openclaw.json
Enter fullscreen mode Exit fullscreen mode

Encuentra la sección tools.web.search y actualízala:

"tools": {
  "web": {
    "search": {
      "enabled": true,
      "provider": "perplexity",
      "perplexity": {
        "apiKey": "pplx-your-api-key-here",
        "model": "sonar-pro"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Guarda el archivo.

Important: Debes especificar "model": "sonar-pro" cuando uses un Perplexity API key directo (pplx-). El model name default de OpenClaw (perplexity/sonar-pro) está formateado para OpenRouter, no para el Perplexity API directo. Sin este fix, obtendrás un error 400 “Invalid model”.

Step 3: Reiniciar OpenClaw

openclaw gateway restart
Enter fullscreen mode Exit fullscreen mode

Listo. Tu assistant ahora usará Perplexity para web searches en lugar de Brave.

Volver a Brave: para revertir, cambia el provider de vuelta a "brave" en la misma sección y actualiza el API key al de Brave Search.


Usar múltiples search providers

OpenClaw solo** soporta un built-in search provider** a la vez. Sin embargo, puedes combinar un built-in provider con la Exa skill:

  1. Usar Perplexity como built-in provider (para respuestas rápidas AI-summarized)
  2. Agregar la Exa skill (para deep research cuando haga falta)

Esto te da lo mejor de ambos mundos sin estar cambiando configs todo el tiempo. Tu agent usará Perplexity para consultas generales y automáticamente recurrirá a Exa cuando necesite resultados más profundos y semánticamente relevantes.


Exa y Perplexity Troubleshooting

  • “EXA_API_KEY not set.” Asegúrate de que tu .env esté en ~/.openclaw/workspace/skills/exa-search/.env, que tenga tu key como EXA_API_KEY=your-key-here, y que no haya espacios extra alrededor del =.

  • “HTTP 403” o “error code: 1010” desde Exa. Es un error de protección de Cloudflare. El script incluye headers para evitarlo, pero si aún aparece, espera unos segundos e intenta de nuevo, y revisa que tu API key sea válida en https://exa.ai.

  • No devuelve resultados Exa. Prueba una consulta más amplia, revisa que tu cuenta Exa.ai tenga créditos, o usa --type neural para forzar neural search mode.

  • Perplexity “Invalid model” error (400). Si ves algo como Invalid model 'perplexity/sonar-pro'... significa que OpenClaw está usando el formato de OpenRouter, pero tu pplx- API key va al Perplexity API directo. Arréglalo seteando el model explícitamente a "sonar-pro" (no "perplexity/sonar-pro"). Ver los pasos de setup de Perplexity arriba.

Top comments (0)