Un límite de presupuesto de búsqueda evita que un agente de IA consuma créditos de API en un único bucle desbocado. El patrón envuelve su función de búsqueda con un decorador que rastrea el gasto acumulado y genera una excepción cuando se alcanza el límite.
Requisitos previos
- Python 3.9+
- Clave API de Scavio
- solicita biblioteca
Guia paso a paso
Paso 1: Crear la clase de seguimiento de presupuesto
Una clase simple mantiene el recuento de créditos y aumenta BudgetExceeded cuando se alcanza el límite.
class BudgetExceeded(Exception):
def __init__(self, used, cap):
super().__init__(f"Search budget exceeded: {used}/{cap} credits used")
self.used = used
self.cap = cap
class SearchBudget:
def __init__(self, cap_credits: float):
self.cap = cap_credits
self.used = 0.0
def charge(self, credits: float):
self.used += credits
if self.used > self.cap:
raise BudgetExceeded(self.used, self.cap)
def remaining(self) -> float:
return max(0, self.cap - self.used)Paso 2: Cree el decorador de búsqueda que tenga en cuenta el presupuesto
Envuelva la llamada API sin formato. Cada solicitud cuesta 1 crédito por defecto; ajústelo si utiliza puntos finales masivos.
import functools
import requests
def with_budget(budget: SearchBudget, credits_per_call: float = 1.0):
def decorator(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
budget.charge(credits_per_call)
return fn(*args, **kwargs)
return wrapper
return decoratorPaso 3: Aplicar a su función de búsqueda
Cree un presupuesto de sesión y decore la llamada de búsqueda antes de pasársela a su agente.
API_KEY = "your-scavio-api-key"
def _raw_search(query: str, **kwargs) -> dict:
payload = {"query": query, "num_results": kwargs.get("num_results", 10)}
if kwargs.get("platform"):
payload["platform"] = kwargs["platform"]
r = requests.post(
"https://api.scavio.dev/api/v1/search",
json=payload,
headers={"x-api-key": API_KEY},
timeout=15
)
r.raise_for_status()
return r.json()
# Cap at 20 credits per agent run (~$0.10)
budget = SearchBudget(cap_credits=20)
search = with_budget(budget)(_raw_search)
try:
results = search("python async best practices")
print(f"Credits remaining: {budget.remaining()}")
except BudgetExceeded as e:
print(f"Stopped: {e}")Paso 4: Integrar con un bucle de agente
Pase la búsqueda con límite de presupuesto a su agente y capture BudgetExceeded para devolver resultados parciales correctamente.
def run_research_agent(topic: str, max_credits: int = 15):
budget = SearchBudget(cap_credits=max_credits)
search = with_budget(budget)(_raw_search)
findings = []
subtopics = [topic, f"{topic} tutorial", f"{topic} examples", f"{topic} best practices"]
for subtopic in subtopics:
try:
data = search(subtopic)
findings.extend(data.get("organic_results", [])[:3])
print(f"Searched '{subtopic}' | {budget.remaining():.0f} credits left")
except BudgetExceeded as e:
print(f"Budget cap hit after {e.used} credits. Returning partial results.")
break
return findings
results = run_research_agent("vector databases", max_credits=5)
print(f"Got {len(results)} results")Ejemplo en Python
import functools
import requests
class BudgetExceeded(Exception):
def __init__(self, used, cap):
super().__init__(f"Search budget exceeded: {used:.1f}/{cap} credits")
self.used = used
self.cap = cap
class SearchBudget:
def __init__(self, cap_credits: float):
self.cap = cap_credits
self.used = 0.0
def charge(self, credits: float = 1.0):
self.used += credits
if self.used > self.cap:
raise BudgetExceeded(self.used, self.cap)
def remaining(self) -> float:
return max(0.0, self.cap - self.used)
API_KEY = "your-scavio-api-key"
def _raw_search(query: str, platform: str = None, num_results: int = 10) -> dict:
payload = {"query": query, "num_results": num_results}
if platform:
payload["platform"] = platform
r = requests.post(
"https://api.scavio.dev/api/v1/search",
json=payload,
headers={"x-api-key": API_KEY},
timeout=15
)
r.raise_for_status()
return r.json()
def make_capped_search(cap_credits: float):
budget = SearchBudget(cap_credits)
def search(query: str, **kwargs) -> dict:
budget.charge(1.0)
result = _raw_search(query, **kwargs)
result["_budget"] = {"used": budget.used, "remaining": budget.remaining()}
return result
search.budget = budget
return search
if __name__ == "__main__":
search = make_capped_search(cap_credits=5)
queries = [
"best vector databases 2026",
"vector database comparison",
"pinecone vs weaviate vs chroma",
"vector db benchmarks",
"vector database pricing",
"vector db tutorial", # This should trigger BudgetExceeded
]
for q in queries:
try:
data = search(q)
top = data.get("organic_results", [{}])[0]
print(f"[{search.budget.used:.0f}/{search.budget.cap}] {top.get('title', 'no title')}")
except BudgetExceeded as e:
print(f"Stopped: {e}")
breakEjemplo en JavaScript
const API_KEY = 'your-scavio-api-key';
class BudgetExceeded extends Error {
constructor(used, cap) {
super(`Search budget exceeded: ${used}/${cap} credits`);
this.used = used;
this.cap = cap;
}
}
function makeCappedSearch(capCredits) {
let used = 0;
async function search(query, { platform, numResults = 10 } = {}) {
used += 1;
if (used > capCredits) throw new BudgetExceeded(used, capCredits);
const payload = { query, num_results: numResults };
if (platform) payload.platform = platform;
const res = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-api-key': API_KEY },
body: JSON.stringify(payload)
});
if (!res.ok) throw new Error(`Search failed: ${res.status}`);
const data = await res.json();
data._budget = { used, remaining: Math.max(0, capCredits - used) };
return data;
}
search.getUsed = () => used;
return search;
}
const search = makeCappedSearch(5);
const queries = ['vector databases 2026', 'pinecone vs chroma', 'vector db pricing', 'weaviate tutorial', 'qdrant setup', 'overflow query'];
for (const q of queries) {
try {
const data = await search(q);
const top = data.organic_results?.[0];
console.log(`[${data._budget.used}/${5}] ${top?.title ?? 'no title'}`);
} catch (e) {
if (e instanceof BudgetExceeded) { console.log(`Stopped: ${e.message}`); break; }
throw e;
}
}Salida esperada
[1/5] Top 10 Vector Databases in 2026
[2/5] Vector Database Comparison: Pinecone vs Chroma vs Weaviate
[3/5] Vector Database Pricing Guide 2026
[4/5] Weaviate Getting Started Tutorial
[5/5] Qdrant Setup and Configuration
Stopped: Search budget exceeded: 6/5 credits