Spaces:
Sleeping
Sleeping
File size: 5,019 Bytes
b20698b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
"""
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"
} |