Dar acceso a un agente de IA a toda la web produce resultados ruidosos. El agente desperdicia fichas en datos irrelevantes y las tasas de alucinaciones aumentan. Determinar a qué plataformas y tipos de resultados puede acceder el agente mejora la calidad de la respuesta, reduce la latencia y reduce los costos. Este tutorial crea una capa de búsqueda con alcance que restringe el acceso a los datos del agente según el tipo de tarea. Un agente de comparación de productos sólo ve Amazon y Walmart. Un agente de sentimiento solo ve Reddit. Un agente de noticias sólo ve Google News.
Requisitos previos
- Python 3.9+ instalado
- solicita biblioteca instalada
- Una clave API de Scavio de scavio.dev
- Comprensión básica de las llamadas a herramientas de agentes de IA
Guia paso a paso
Paso 1: Definir perfiles de alcance para diferentes tareas de agentes
Cree configuraciones de alcance predefinidas que restrinjan a qué plataformas y tipos de resultados puede acceder un agente. Cada perfil está ajustado para un caso de uso específico.
import os, requests
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
URL = 'https://api.scavio.dev/api/v1/search'
H = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}
SCOPE_PROFILES = {
'product_research': {
'platforms': ['amazon', 'walmart'],
'max_results': 5,
'description': 'Product pricing and availability'
},
'sentiment': {
'platforms': ['reddit'],
'max_results': 10,
'description': 'Community opinions and discussions'
},
'news': {
'platforms': ['google'],
'query_suffix': ' news 2026',
'max_results': 5,
'description': 'Current news and events'
},
'technical': {
'platforms': ['google'],
'site_restrict': ['stackoverflow.com', 'github.com', 'docs.python.org'],
'max_results': 5,
'description': 'Technical documentation and Q&A'
},
'video': {
'platforms': ['youtube'],
'max_results': 5,
'description': 'Video tutorials and reviews'
}
}
for name, profile in SCOPE_PROFILES.items():
print(f'{name}: {profile["description"]} ({profile["platforms"]})')Paso 2: Cree la función de búsqueda con ámbito
Una función de búsqueda que aplica el perfil de alcance. Se niega a buscar plataformas fuera de la lista permitida y aplica restricciones de consulta.
def scoped_search(query: str, scope: str, override_num: int = None) -> list:
"""Search within a defined scope profile."""
profile = SCOPE_PROFILES.get(scope)
if not profile:
return [{'error': f'Unknown scope: {scope}. Available: {list(SCOPE_PROFILES.keys())}'}]
num = override_num or profile['max_results']
all_results = []
for platform in profile['platforms']:
q = query
# Apply query suffix if defined
if 'query_suffix' in profile:
q += profile['query_suffix']
# Apply site restrictions
if 'site_restrict' in profile:
for site in profile['site_restrict']:
site_q = f'site:{site} {q}'
resp = requests.post(URL, headers=H,
json={'query': site_q, 'country_code': 'us', 'num_results': 2})
for r in resp.json().get('organic_results', []):
all_results.append({'title': r['title'], 'url': r['link'],
'snippet': r.get('snippet', ''), 'platform': platform, 'scope': scope})
continue
# Platform-specific site prefix
site_map = {'amazon': 'amazon.com', 'youtube': 'youtube.com',
'walmart': 'walmart.com', 'reddit': 'reddit.com'}
if platform in site_map:
q = f'site:{site_map[platform]} {q}'
resp = requests.post(URL, headers=H,
json={'query': q, 'country_code': 'us', 'num_results': num})
for r in resp.json().get('organic_results', []):
all_results.append({'title': r['title'], 'url': r['link'],
'snippet': r.get('snippet', ''), 'platform': platform, 'scope': scope})
return all_results[:num]
results = scoped_search('noise cancelling headphones', scope='product_research')
print(f'Product scope: {len(results)} results')
for r in results:
print(f' [{r["platform"]}] {r["title"][:60]}')Paso 3: Crear definiciones de herramientas que tengan en cuenta el alcance para el agente
Genere definiciones de herramientas dinámicamente según el alcance activo. El agente solo ve herramientas para su alcance asignado, lo que evita búsquedas fuera de alcance.
def make_scoped_tool(scope: str) -> dict:
"""Generate a tool definition locked to a specific scope."""
profile = SCOPE_PROFILES[scope]
return {
'type': 'function',
'function': {
'name': f'search_{scope}',
'description': f'Search for {profile["description"]}. '
f'Platforms: {", ".join(profile["platforms"])}. '
f'Max {profile["max_results"]} results.',
'parameters': {
'type': 'object',
'properties': {
'query': {'type': 'string', 'description': 'Search query'}
},
'required': ['query']
}
}
}
def make_agent_tools(scopes: list[str]) -> list:
"""Create tool set for an agent with specific scopes."""
return [make_scoped_tool(s) for s in scopes]
# Product comparison agent: only Amazon + Walmart
product_tools = make_agent_tools(['product_research'])
print('Product agent tools:', [t['function']['name'] for t in product_tools])
# Research agent: news + technical + sentiment
research_tools = make_agent_tools(['news', 'technical', 'sentiment'])
print('Research agent tools:', [t['function']['name'] for t in research_tools])Paso 4: Agregar validación de alcance y seguimiento de costos
Valide que cada solicitud de búsqueda permanezca dentro del alcance. Realice un seguimiento de los costos por alcance para identificar qué patrones de acceso cuestan más.
class ScopedSearchManager:
def __init__(self, allowed_scopes: list[str]):
self.allowed_scopes = set(allowed_scopes)
self.usage = {s: {'calls': 0, 'results': 0} for s in allowed_scopes}
def search(self, query: str, scope: str) -> list:
if scope not in self.allowed_scopes:
raise PermissionError(
f'Scope "{scope}" not allowed. Allowed: {self.allowed_scopes}')
results = scoped_search(query, scope)
self.usage[scope]['calls'] += 1
self.usage[scope]['results'] += len(results)
return results
def report(self) -> str:
lines = ['Scope Usage Report:', '-' * 40]
total_cost = 0
for scope, stats in self.usage.items():
cost = stats['calls'] * 0.005
total_cost += cost
lines.append(f'{scope}: {stats["calls"]} calls, '
f'{stats["results"]} results, ${cost:.3f}')
lines.append(f'Total cost: ${total_cost:.3f}')
return '\n'.join(lines)
# Product comparison agent: restricted scope
agent = ScopedSearchManager(['product_research', 'sentiment'])
results = agent.search('Sony WH-1000XM6', 'product_research')
results = agent.search('Sony WH-1000XM6 review', 'sentiment')
print(agent.report())
# This would raise PermissionError:
# agent.search('sony stock price', 'news')Paso 5: Implementar escalamiento de alcance dinámico
A veces un agente necesita un alcance más amplio. Agregue un mecanismo de escalamiento controlado que registre los cambios de alcance y requiera aprobación explícita.
class EscalatableScopedSearch(ScopedSearchManager):
def __init__(self, allowed_scopes, escalation_scopes=None):
super().__init__(allowed_scopes)
self.escalation_scopes = set(escalation_scopes or [])
self.escalation_log = []
def request_escalation(self, scope: str, reason: str) -> bool:
"""Request access to a scope outside the default set."""
if scope not in self.escalation_scopes:
print(f'Escalation denied: {scope} not in escalation list')
return False
self.allowed_scopes.add(scope)
self.usage[scope] = {'calls': 0, 'results': 0}
self.escalation_log.append({'scope': scope, 'reason': reason})
print(f'Escalation approved: {scope} ({reason})')
return True
# Agent starts with product scope only
agent = EscalatableScopedSearch(
allowed_scopes=['product_research'],
escalation_scopes=['sentiment', 'news']
)
# Normal search works
results = agent.search('laptop 2026', 'product_research')
print(f'Product search: {len(results)} results')
# Escalate to sentiment when needed
agent.request_escalation('sentiment', 'User asked about community opinions')
results = agent.search('laptop 2026 reddit opinions', 'sentiment')
print(f'Sentiment search: {len(results)} results')
print(f'Escalations: {agent.escalation_log}')Ejemplo en Python
import os, requests
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
URL = 'https://api.scavio.dev/api/v1/search'
H = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}
SCOPES = {
'product': {'sites': ['amazon.com', 'walmart.com'], 'num': 5},
'opinion': {'sites': ['reddit.com'], 'num': 8},
'tech': {'sites': ['stackoverflow.com', 'github.com'], 'num': 5},
}
def scoped_search(query, scope='product'):
cfg = SCOPES[scope]
results = []
for site in cfg['sites']:
resp = requests.post(URL, headers=H,
json={'query': f'site:{site} {query}', 'country_code': 'us', 'num_results': 3})
results.extend(resp.json().get('organic_results', []))
return [{'title': r['title'], 'url': r['link']} for r in results[:cfg['num']]]
for scope in ['product', 'opinion']:
results = scoped_search('mechanical keyboard', scope)
print(f'{scope}: {len(results)} results')Ejemplo en JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
const URL = 'https://api.scavio.dev/api/v1/search';
const SCOPES = {
product: { sites: ['amazon.com', 'walmart.com'], num: 5 },
opinion: { sites: ['reddit.com'], num: 8 },
tech: { sites: ['stackoverflow.com', 'github.com'], num: 5 },
};
async function scopedSearch(query, scope = 'product') {
const cfg = SCOPES[scope];
const results = [];
for (const site of cfg.sites) {
const resp = await fetch(URL, {
method: 'POST',
headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `site:${site} ${query}`, country_code: 'us', num_results: 3 })
});
results.push(...((await resp.json()).organic_results || []));
}
return results.slice(0, cfg.num).map(r => ({ title: r.title, url: r.link }));
}
(async () => {
for (const scope of ['product', 'opinion']) {
const results = await scopedSearch('mechanical keyboard', scope);
console.log(`${scope}: ${results.length} results`);
}
})();Salida esperada
Product scope: 5 results
[amazon] Sony WH-1000XM6 Wireless Noise Cancelling Headphones
[walmart] Sony WH-1000XM6 - Best Price Guarantee
Scope Usage Report:
----------------------------------------
product_research: 1 calls, 5 results, $0.005
sentiment: 1 calls, 8 results, $0.005
Total cost: $0.010
Escalation approved: sentiment (User asked about community opinions)