Grounding significa inyectar resultados de búsqueda en vivo en el prompt antes de que el modelo responda, para que cite datos reales y actuales en lugar de adivinar a partir del entrenamiento. El arreglo para un agente que cita con seguridad los precios del año pasado son tres líneas: golpea una API de búsqueda, mete los primeros resultados en el contexto, dile al modelo que responda solo a partir de ellos. Abajo tienes la versión que funciona en Python y JS contra el endpoint /api/v1/google de Scavio, la forma exacta del JSON que devuelve (comprobada en vivo el 2026-06-26) y las cuentas de coste para que sepas cuánto te sale cada respuesta con grounding.
Requisitos previos
- Una clave de API de Scavio (50 créditos gratis al registrarte en scavio.dev)
- Python 3.9+ o Node 18+
- Cualquier SDK de LLM (OpenAI, Anthropic) para el paso de respuesta
- Familiaridad básica con peticiones POST y variables de entorno
Guia paso a paso
Paso 1: 1. Llama a la API de búsqueda con la pregunta del usuario
Haz POST de la consulta a /api/v1/google con la cabecera Bearer. Pon light_request:false cuando quieras el knowledge graph, las búsquedas relacionadas y los bloques de noticias junto a los resultados orgánicos. Esa llamada factura 2 créditos; la versión ligera (solo orgánicos) es 1 crédito. Verificado en vivo: esta llamada exacta devolvió 7 resultados orgánicos y 8 búsquedas relacionadas.
import os, requests
KEY = os.environ['SCAVIO_API_KEY']
resp = requests.post(
'https://api.scavio.dev/api/v1/google',
headers={'Authorization': f'Bearer {KEY}', 'Content-Type': 'application/json'},
json={'query': 'current openai api pricing', 'light_request': False},
).json()
results = resp['results'] # organic results array
print(len(results), 'organic results,', resp['credits_used'], 'credits')Paso 2: 2. Da forma a los resultados como contexto de grounding
Cada elemento de results tiene position, title, url, domain y content (el snippet). Coge los 5 primeros en un bloque compacto. Mantenlo corto: más snippets significa más tokens, y los primeros resultados llevan casi toda la señal.
context = '\n'.join(
f"[{r['position']}] {r['title']} ({r['domain']})\n{r.get('content','')}"
for r in results[:5]
)Paso 3: 3. Obliga al modelo a responder solo desde el contexto
Mete el contexto en el mensaje de sistema o de usuario e indica al modelo que responda a partir de él y cite el dominio. Si la respuesta no está en el contexto, el modelo debe decirlo en lugar de recurrir a los datos de entrenamiento. Esa instrucción es lo que de verdad frena la alucinación.
prompt = (
'Answer using ONLY the search results below. '
'Cite the domain in brackets. If the answer is not present, say so.\n\n'
f'{context}\n\nQuestion: current openai api pricing'
)
# send `prompt` to your LLM of choicePaso 4: 4. Cachea y presupuesta las llamadas
Hacer grounding en cada turno es un desperdicio. Cachea los resultados por consulta normalizada de unos minutos a una hora según lo rápido que se muevan los datos. Precios y noticias de última hora necesitan TTLs cortos; las definiciones pueden cachearse un día. A 2 créditos por SERP completa y $0.005/crédito, 1.000 respuestas con grounding son unos $10 de búsqueda, o aproximadamente $4.30/1k en el plan de $30/7.000 créditos.
# pseudocode: check cache before calling
key = query.strip().lower()
if key in cache and not cache[key].expired:
results = cache[key].value
else:
results = call_scavio(query)
cache[key] = Entry(results, ttl=600)Ejemplo en Python
import os, requests
KEY = os.environ['SCAVIO_API_KEY']
def ground(question: str) -> str:
r = requests.post(
'https://api.scavio.dev/api/v1/google',
headers={'Authorization': f'Bearer {KEY}'},
json={'query': question, 'light_request': False},
).json()
ctx = '\n'.join(
f"[{x['position']}] {x['title']} ({x['domain']}): {x.get('content','')}"
for x in r['results'][:5]
)
return ctx
print(ground('current openai api pricing'))Ejemplo en JavaScript
const KEY = process.env.SCAVIO_API_KEY;
async function ground(question) {
const r = await fetch('https://api.scavio.dev/api/v1/google', {
method: 'POST',
headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ query: question, light_request: false }),
}).then((x) => x.json());
return r.results
.slice(0, 5)
.map((x) => `[${x.position}] ${x.title} (${x.domain}): ${x.content ?? ''}`)
.join('\n');
}
console.log(await ground('current openai api pricing'));Salida esperada
Un bloque de contexto con los 5 primeros resultados orgánicos, cada uno con position, title, domain y snippet. La respuesta cruda también lleva related_searches (8 en nuestra prueba), más los bloques knowledge_graph, news_results y shopping_ads, y reporta credits_used: 2 y credits_remaining para que sigas el gasto por llamada.