akashub
feat(Initial project setup): Added code for initial setup
b20698b
raw
history blame
5.02 kB
"""
Stage 1: Query Router - Intelligent Server Selection
"""
import json
from typing import Dict, Any
from openai import OpenAI
class QueryRouter:
"""Stage 1: Routes queries to appropriate MCP servers"""
def __init__(self, client: OpenAI, registry: Dict[str, Any]):
self.client = client
self.registry = registry
def route(self, query: str, location: Dict[str, Any]) -> Dict[str, Any]:
"""
Analyze query and determine which MCP servers are needed
Returns:
{
"intent": str,
"required_servers": List[str],
"reasoning": str
}
"""
# Create registry summary
registry_text = "Available MCP Servers:\n"
for server_id, info in self.registry.items():
registry_text += f"\n{server_id}:\n"
registry_text += f" Description: {info['description']}\n"
registry_text += f" Use for: {', '.join(info['use_for'][:5])}\n"
system_prompt = f"""You are a query router for Farmer.chat agricultural system.
Your task: Analyze the farmer's query and select which MCP servers are needed.
{registry_text}
Location: {location['name']} ({location['lat']}°N, {location['lon']}°E)
CRITICAL RULES:
1. Select ALL servers that provide data relevant to answering the query completely
2. Consider IMPLICIT needs - look for context clues in the query
3. Keywords that trigger elevation: "elevation", "slope", "terrain", "my land", "my field", "drainage", "waterlogged", "frost risk", "wind exposure"
4. For crop decisions: ALWAYS include soil_properties + water + weather (comprehensive assessment)
5. For weather risk questions (wind, frost, flood): Include weather + elevation (terrain affects risk)
6. For pest questions with weather context: Include pests + weather
7. Be generous - better to have extra data than miss critical information
8. When farmer mentions location characteristics (height, slope, elevation), ALWAYS include elevation
FEW-SHOT EXAMPLES:
Example 1:
Query: "Are strong winds expected at my land elevation?"
Required: ["weather", "elevation"]
Reasoning: Wind forecast from weather, but elevation affects wind exposure and risk. Farmer explicitly mentions elevation.
Example 2:
Query: "Should I plant rice today?"
Required: ["weather", "soil_properties", "water"]
Reasoning: Planting decisions need weather conditions, soil suitability, and water availability for comprehensive assessment.
Example 3:
Query: "Is there risk of frost tonight?"
Required: ["weather", "elevation"]
Reasoning: Frost risk depends on temperature from weather AND elevation (cold air sinks to lower areas).
Example 4:
Query: "What's my soil composition?"
Required: ["soil_properties"]
Reasoning: Direct soil query, only soil data needed. No implicit needs.
Example 5:
Query: "Can I grow tomatoes here?"
Required: ["soil_properties", "water", "weather"]
Reasoning: Crop suitability requires soil type, water availability, and climate conditions.
Example 6:
Query: "My field gets waterlogged after rain"
Required: ["elevation", "soil_properties", "weather"]
Reasoning: Waterlogging relates to drainage (elevation/slope), soil permeability, and rainfall patterns.
Example 7:
Query: "Should I spray pesticides now?"
Required: ["pests", "weather"]
Reasoning: Need to know pest presence AND weather conditions for optimal application timing.
Example 8:
Query: "How's the weather?"
Required: ["weather"]
Reasoning: Direct weather query, no implicit needs.
Example 9:
Query: "Give me complete farm status"
Required: ["weather", "soil_properties", "water", "elevation", "pests"]
Reasoning: Comprehensive assessment requires all available data sources.
Example 10:
Query: "Will it be too windy on my elevated farm?"
Required: ["weather", "elevation"]
Reasoning: Wind from weather, elevation affects exposure. "Elevated" is explicit context clue.
Response format (JSON only):
{{
"intent": "brief description of farmer's need",
"required_servers": ["server_id1", "server_id2"],
"reasoning": "why these servers"
}}
"""
try:
response = self.client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": query}
],
temperature=0.3
)
result_text = response.choices[0].message.content.strip()
result_text = result_text.replace("```json", "").replace("```", "").strip()
routing_decision = json.loads(result_text)
return routing_decision
except Exception as e:
print(f"❌ Routing error: {e}")
# Fallback - include common servers
return {
"intent": "general_inquiry",
"required_servers": ["weather", "soil_properties", "water"],
"reasoning": "Fallback routing due to error"
}