DriptoBhattacharyya Claude Opus 4.8 commited on
Commit
86a7fd1
·
1 Parent(s): 0a9b8d0

Add provider toggle (Groq/Gemini) + global rate limiter to beat free-tier limits

Browse files

Default 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>

Files changed (5) hide show
  1. .env.example +12 -0
  2. gaia_agent/config.py +15 -2
  3. gaia_agent/llm.py +45 -9
  4. pyproject.toml +1 -0
  5. 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
- groq_text_model: str = "llama-3.3-70b-versatile"
 
 
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 = 180
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
- """Groq chat-model factories."""
 
 
 
 
 
2
 
3
  from __future__ import annotations
4
 
5
  from functools import lru_cache
6
 
7
- from langchain_groq import ChatGroq
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) -> ChatGroq:
14
- """Return the Groq text/reasoning model used by most nodes."""
15
  s = get_settings()
16
- return ChatGroq(
17
- model=s.groq_text_model,
18
- api_key=s.groq_api_key,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  temperature=temperature,
20
- max_retries=2,
 
21
  )
22
 
23
 
24
  @lru_cache(maxsize=1)
25
- def get_vision_llm() -> ChatGroq:
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