Les agents LangChain peuvent épuiser rapidement les crédits d'API de recherche lorsqu'ils bouclent ou réessayent agressivement. Ce tutoriel construit un outil de recherche compatible LangChain avec limitation de débit intégrée, suivi des crédits et contrôle du budget. Il empêche les coûts incontrôlables tout en maintenant une recherche fiable à $0,005/requête.
Prérequis
- Python 3.8+
- bibliothèque langchain
- Une clé API Scavio de scavio.dev
- Configuration de base de l'agent LangChain
Parcours
Étape 1: Construire l'outil de recherche avec limitation de débit
Créer un outil LangChain qui applique les limites de débit et suit l'utilisation des crédits.
import os, requests, time, json, threading
from datetime import datetime
API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
class RateLimitedSearch:
def __init__(self, max_per_minute=30, daily_budget=500):
self.max_per_minute = max_per_minute
self.daily_budget = daily_budget
self.calls = []
self.daily_calls = 0
self.daily_reset = datetime.now().strftime('%Y-%m-%d')
self.lock = threading.Lock()
def _check_limits(self):
now = time.time()
# Reset daily counter
today = datetime.now().strftime('%Y-%m-%d')
if today != self.daily_reset:
self.daily_calls = 0
self.daily_reset = today
# Check daily budget
if self.daily_calls >= self.daily_budget:
return False, f'Daily budget ({self.daily_budget}) reached. Cost: ${self.daily_calls * 0.005:.2f}'
# Check per-minute rate
self.calls = [t for t in self.calls if now - t < 60]
if len(self.calls) >= self.max_per_minute:
wait = 60 - (now - self.calls[0])
return False, f'Rate limit: {self.max_per_minute}/min. Wait {wait:.0f}s.'
return True, 'OK'
def search(self, query, num_results=5):
with self.lock:
allowed, reason = self._check_limits()
if not allowed:
return {'error': reason, 'results': []}
self.calls.append(time.time())
self.daily_calls += 1
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': query, 'country_code': 'us'}, timeout=10)
resp.raise_for_status()
data = resp.json()
results = [{'title': r.get('title', ''), 'url': r.get('link', ''),
'snippet': r.get('snippet', '')} for r in data.get('organic_results', [])[:num_results]]
return {'results': results, 'count': len(results),
'credits_used': self.daily_calls, 'budget_remaining': self.daily_budget - self.daily_calls}
rl_search = RateLimitedSearch(max_per_minute=30, daily_budget=500)
result = rl_search.search('langchain search tool tutorial')
print(f'Results: {result.get("count", 0)}')
print(f'Credits used today: {result.get("credits_used", 0)}')
print(f'Budget remaining: {result.get("budget_remaining", 0)}')Étape 2: Créer l'encapsuleur d'outil LangChain
Encapsuler la recherche limitée en débit en tant qu'outil LangChain approprié.
# LangChain tool definition
# from langchain.tools import Tool
def langchain_search(query: str) -> str:
"""Search the web with rate limiting and budget controls.
Use for finding documentation, current information, or verifying facts."""
result = rl_search.search(query)
if 'error' in result:
return f'Search blocked: {result["error"]}'
output = []
for r in result['results']:
output.append(f'Title: {r["title"]}')
output.append(f'URL: {r["url"]}')
output.append(f'Snippet: {r["snippet"]}')
output.append('')
output.append(f'[Credits: {result["credits_used"]}/{rl_search.daily_budget} today]')
return '\n'.join(output)
# Register with LangChain:
# search_tool = Tool(
# name='web_search',
# func=langchain_search,
# description='Search the web. Rate limited to prevent runaway costs.'
# )
# Test
print(langchain_search('how to build langchain agent with tools'))
print(f'\nRate: {rl_search.max_per_minute}/min, Budget: {rl_search.daily_budget}/day')
print(f'Cost cap: ${rl_search.daily_budget * 0.005:.2f}/day')Étape 3: Ajouter la surveillance et les alertes de coût
Suivre les modèles d'utilisation et alerter lorsque les coûts approchent la limite budgétaire.
def usage_report():
print(f'\n=== Search Usage Report ===')
print(f' Date: {datetime.now().strftime("%Y-%m-%d %H:%M")}')
print(f' Calls today: {rl_search.daily_calls}')
print(f' Budget: {rl_search.daily_calls}/{rl_search.daily_budget}')
print(f' Cost today: ${rl_search.daily_calls * 0.005:.3f}')
print(f' Budget remaining: ${(rl_search.daily_budget - rl_search.daily_calls) * 0.005:.3f}')
# Usage rate
pct = rl_search.daily_calls / rl_search.daily_budget * 100
print(f' Usage: {pct:.0f}%')
if pct > 80:
print(f' WARNING: Over 80% of daily budget used!')
elif pct > 50:
print(f' NOTE: Over 50% of daily budget used.')
# Projected monthly cost
monthly = rl_search.daily_calls * 0.005 * 30
print(f'\n Projected monthly cost: ${monthly:.2f}')
print(f' Max monthly cost: ${rl_search.daily_budget * 0.005 * 30:.2f}')
# Simulate multiple searches
for i in range(5):
rl_search.search(f'test query {i}')
usage_report()
print(f'\n Rate limit: {rl_search.max_per_minute} calls/minute')
print(f' Daily budget: {rl_search.daily_budget} calls (${ rl_search.daily_budget * 0.005:.2f})')
print(f' Per call: $0.005')Exemple Python
import os, requests, time
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
last_call = 0
def rate_limited_search(query, min_interval=2):
global last_call
wait = min_interval - (time.time() - last_call)
if wait > 0: time.sleep(wait)
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': query, 'country_code': 'us'}, timeout=10).json()
last_call = time.time()
return data.get('organic_results', [])[:5]
results = rate_limited_search('langchain tools')
print(f'Results: {len(results)}')Exemple JavaScript
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
let lastCall = 0;
async function rateLimitedSearch(query, minInterval = 2000) {
const wait = minInterval - (Date.now() - lastCall);
if (wait > 0) await new Promise(r => setTimeout(r, wait));
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: SH,
body: JSON.stringify({ query, country_code: 'us' })
}).then(r => r.json());
lastCall = Date.now();
return (data.organic_results || []).slice(0, 5);
}
const results = await rateLimitedSearch('langchain tools');
console.log(`Results: ${results.length}`);Sortie attendue
Results: 5
Credits used today: 1
Budget remaining: 499
Title: LangChain Search Tool Tutorial - Official Docs
URL: https://python.langchain.com/docs/...
Snippet: Learn how to create custom search tools for LangChain agents...
[Credits: 1/500 today]
Rate: 30/min, Budget: 500/day
Cost cap: $2.50/day
=== Search Usage Report ===
Calls today: 6
Budget: 6/500
Cost today: $0.030
Usage: 1%
Projected monthly cost: $0.90
Max monthly cost: $75.00