Commit ·
86a7fd1
1
Parent(s): 0a9b8d0
Add provider toggle (Groq/Gemini) + global rate limiter to beat free-tier limits
Browse filesDefault to Groq llama-3.1-8b-instant (high TPM) so the batch survives without rate-limit errors; Gemini-2.0-flash selectable via LLM_PROVIDER. Shared InMemoryRateLimiter paces all text-LLM calls. Vision/Whisper stay on Groq.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- .env.example +12 -0
- gaia_agent/config.py +15 -2
- gaia_agent/llm.py +45 -9
- pyproject.toml +1 -0
- requirements.txt +1 -0
.env.example
CHANGED
|
@@ -1,6 +1,18 @@
|
|
| 1 |
# --- Required secrets (fill these in) ---
|
| 2 |
GROQ_API_KEY=
|
| 3 |
TAVILY_API_KEY=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
# --- Optional: LangSmith tracing (nice for debugging the graph) ---
|
| 6 |
# Set TRACING=true and provide the API key to stream runs to smith.langchain.com.
|
|
|
|
| 1 |
# --- Required secrets (fill these in) ---
|
| 2 |
GROQ_API_KEY=
|
| 3 |
TAVILY_API_KEY=
|
| 4 |
+
# Required when LLM_PROVIDER=gemini (default). Free key: aistudio.google.com
|
| 5 |
+
GOOGLE_API_KEY=
|
| 6 |
+
|
| 7 |
+
# --- LLM provider for text/reasoning + judge nodes: "groq" or "gemini" ---
|
| 8 |
+
# Default "groq" + llama-3.1-8b-instant works with the existing key (high TPM).
|
| 9 |
+
# Switch to "gemini" for better quality once you have a free-tier GOOGLE_API_KEY
|
| 10 |
+
# (created in a Google project WITHOUT billing enabled, else free tier = 0).
|
| 11 |
+
LLM_PROVIDER=groq
|
| 12 |
+
GROQ_TEXT_MODEL=llama-3.1-8b-instant
|
| 13 |
+
GEMINI_TEXT_MODEL=gemini-2.0-flash
|
| 14 |
+
# Global pace across all text-LLM calls (req/sec). 0.2 = ~12/min.
|
| 15 |
+
RATE_LIMIT_RPS=0.2
|
| 16 |
|
| 17 |
# --- Optional: LangSmith tracing (nice for debugging the graph) ---
|
| 18 |
# Set TRACING=true and provide the API key to stream runs to smith.langchain.com.
|
gaia_agent/config.py
CHANGED
|
@@ -21,17 +21,30 @@ class Settings(BaseSettings):
|
|
| 21 |
# --- Secrets ---
|
| 22 |
groq_api_key: str = ""
|
| 23 |
tavily_api_key: str = ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
# --- Models (override via env) ---
|
| 26 |
-
|
|
|
|
|
|
|
| 27 |
groq_vision_model: str = "meta-llama/llama-4-scout-17b-16e-instruct"
|
| 28 |
groq_whisper_model: str = "whisper-large-v3"
|
| 29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
# --- API + control knobs ---
|
| 31 |
gaia_api_url: str = "https://agents-course-unit4-scoring.hf.space"
|
| 32 |
max_judge_retries: int = 1
|
| 33 |
recursion_limit: int = 40
|
| 34 |
-
question_timeout: int =
|
| 35 |
|
| 36 |
|
| 37 |
@lru_cache(maxsize=1)
|
|
|
|
| 21 |
# --- Secrets ---
|
| 22 |
groq_api_key: str = ""
|
| 23 |
tavily_api_key: str = ""
|
| 24 |
+
google_api_key: str = ""
|
| 25 |
+
|
| 26 |
+
# --- LLM provider for the text/reasoning + judge nodes ---
|
| 27 |
+
# "groq" (default, works with the existing key) or "gemini" (better quality,
|
| 28 |
+
# needs a free-tier GOOGLE_API_KEY from a project WITHOUT billing enabled).
|
| 29 |
+
# Vision + Whisper always use Groq.
|
| 30 |
+
llm_provider: str = "groq"
|
| 31 |
|
| 32 |
# --- Models (override via env) ---
|
| 33 |
+
gemini_text_model: str = "gemini-2.0-flash"
|
| 34 |
+
# 8b-instant has ~30k TPM free (vs 70B's ~12k) so it survives the batch.
|
| 35 |
+
groq_text_model: str = "llama-3.1-8b-instant"
|
| 36 |
groq_vision_model: str = "meta-llama/llama-4-scout-17b-16e-instruct"
|
| 37 |
groq_whisper_model: str = "whisper-large-v3"
|
| 38 |
|
| 39 |
+
# --- Rate limiting (requests/sec across all text-LLM calls) ---
|
| 40 |
+
# Gemini 2.0-flash free tier ~15 RPM; 0.2 rps = ~12/min keeps headroom.
|
| 41 |
+
rate_limit_rps: float = 0.2
|
| 42 |
+
|
| 43 |
# --- API + control knobs ---
|
| 44 |
gaia_api_url: str = "https://agents-course-unit4-scoring.hf.space"
|
| 45 |
max_judge_retries: int = 1
|
| 46 |
recursion_limit: int = 40
|
| 47 |
+
question_timeout: int = 300
|
| 48 |
|
| 49 |
|
| 50 |
@lru_cache(maxsize=1)
|
gaia_agent/llm.py
CHANGED
|
@@ -1,33 +1,69 @@
|
|
| 1 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
from __future__ import annotations
|
| 4 |
|
| 5 |
from functools import lru_cache
|
| 6 |
|
| 7 |
-
from
|
| 8 |
|
| 9 |
from gaia_agent.config import get_settings
|
| 10 |
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
@lru_cache(maxsize=4)
|
| 13 |
-
def get_text_llm(temperature: float = 0.0)
|
| 14 |
-
"""Return the
|
| 15 |
s = get_settings()
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
temperature=temperature,
|
| 20 |
-
max_retries=
|
|
|
|
| 21 |
)
|
| 22 |
|
| 23 |
|
| 24 |
@lru_cache(maxsize=1)
|
| 25 |
-
def get_vision_llm()
|
| 26 |
"""Return the Groq multimodal model used for image understanding."""
|
|
|
|
|
|
|
| 27 |
s = get_settings()
|
| 28 |
return ChatGroq(
|
| 29 |
model=s.groq_vision_model,
|
| 30 |
api_key=s.groq_api_key,
|
| 31 |
temperature=0.0,
|
| 32 |
max_retries=2,
|
|
|
|
| 33 |
)
|
|
|
|
| 1 |
+
"""Text/vision LLM factories with a shared global rate limiter.
|
| 2 |
+
|
| 3 |
+
The text model is provider-switchable (Gemini or Groq). A single process-wide
|
| 4 |
+
``InMemoryRateLimiter`` paces every text-LLM call so we never trip per-minute
|
| 5 |
+
request limits. Vision + Whisper always use Groq (rare calls, low volume).
|
| 6 |
+
"""
|
| 7 |
|
| 8 |
from __future__ import annotations
|
| 9 |
|
| 10 |
from functools import lru_cache
|
| 11 |
|
| 12 |
+
from langchain_core.rate_limiters import InMemoryRateLimiter
|
| 13 |
|
| 14 |
from gaia_agent.config import get_settings
|
| 15 |
|
| 16 |
|
| 17 |
+
@lru_cache(maxsize=1)
|
| 18 |
+
def _rate_limiter() -> InMemoryRateLimiter:
|
| 19 |
+
"""Shared limiter so all text-LLM instances draw from one token bucket."""
|
| 20 |
+
rps = get_settings().rate_limit_rps
|
| 21 |
+
return InMemoryRateLimiter(
|
| 22 |
+
requests_per_second=rps,
|
| 23 |
+
check_every_n_seconds=0.1,
|
| 24 |
+
max_bucket_size=1,
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
@lru_cache(maxsize=4)
|
| 29 |
+
def get_text_llm(temperature: float = 0.0):
|
| 30 |
+
"""Return the rate-limited text/reasoning model for the configured provider."""
|
| 31 |
s = get_settings()
|
| 32 |
+
limiter = _rate_limiter()
|
| 33 |
+
|
| 34 |
+
if s.llm_provider.lower() == "groq":
|
| 35 |
+
from langchain_groq import ChatGroq
|
| 36 |
+
|
| 37 |
+
return ChatGroq(
|
| 38 |
+
model=s.groq_text_model,
|
| 39 |
+
api_key=s.groq_api_key,
|
| 40 |
+
temperature=temperature,
|
| 41 |
+
max_retries=3,
|
| 42 |
+
rate_limiter=limiter,
|
| 43 |
+
)
|
| 44 |
+
|
| 45 |
+
# Default: Gemini (high free-tier TPM).
|
| 46 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 47 |
+
|
| 48 |
+
return ChatGoogleGenerativeAI(
|
| 49 |
+
model=s.gemini_text_model,
|
| 50 |
+
google_api_key=s.google_api_key,
|
| 51 |
temperature=temperature,
|
| 52 |
+
max_retries=3,
|
| 53 |
+
rate_limiter=limiter,
|
| 54 |
)
|
| 55 |
|
| 56 |
|
| 57 |
@lru_cache(maxsize=1)
|
| 58 |
+
def get_vision_llm():
|
| 59 |
"""Return the Groq multimodal model used for image understanding."""
|
| 60 |
+
from langchain_groq import ChatGroq
|
| 61 |
+
|
| 62 |
s = get_settings()
|
| 63 |
return ChatGroq(
|
| 64 |
model=s.groq_vision_model,
|
| 65 |
api_key=s.groq_api_key,
|
| 66 |
temperature=0.0,
|
| 67 |
max_retries=2,
|
| 68 |
+
rate_limiter=_rate_limiter(),
|
| 69 |
)
|
pyproject.toml
CHANGED
|
@@ -14,6 +14,7 @@ dependencies = [
|
|
| 14 |
"langchain>=0.3.0",
|
| 15 |
"langchain-core>=0.3.0",
|
| 16 |
"langchain-groq>=0.2.0",
|
|
|
|
| 17 |
"langchain-tavily>=0.1.0",
|
| 18 |
"langchain-community>=0.3.0",
|
| 19 |
"wikipedia>=1.4.0",
|
|
|
|
| 14 |
"langchain>=0.3.0",
|
| 15 |
"langchain-core>=0.3.0",
|
| 16 |
"langchain-groq>=0.2.0",
|
| 17 |
+
"langchain-google-genai>=2.0.0",
|
| 18 |
"langchain-tavily>=0.1.0",
|
| 19 |
"langchain-community>=0.3.0",
|
| 20 |
"wikipedia>=1.4.0",
|
requirements.txt
CHANGED
|
@@ -8,6 +8,7 @@ langgraph>=1.0.0
|
|
| 8 |
langchain>=0.3.0
|
| 9 |
langchain-core>=0.3.0
|
| 10 |
langchain-groq>=0.2.0
|
|
|
|
| 11 |
langchain-tavily>=0.1.0
|
| 12 |
langchain-community>=0.3.0
|
| 13 |
wikipedia
|
|
|
|
| 8 |
langchain>=0.3.0
|
| 9 |
langchain-core>=0.3.0
|
| 10 |
langchain-groq>=0.2.0
|
| 11 |
+
langchain-google-genai>=2.0.0
|
| 12 |
langchain-tavily>=0.1.0
|
| 13 |
langchain-community>=0.3.0
|
| 14 |
wikipedia
|