KRONECTOR DataAgent Architecture
Overview
The DataAgent (agents/data_agent.py) transforms natural-language F1 queries into prediction-ready DataFrames compatible with the ML pipeline. It bridges user intent with model-ready data.
User Query β Groq LLM (parse) β Extract Intent β Query Data β DataFrame β predict_dataframe()
Components
1. Query Intent Extraction
Function: parse_query_with_groq(query: str) -> QueryIntent
Uses Groq llama3-70b-8192 to parse natural language and extract:
season(int): F1 season yearround(int): Race round numberdriver_id(str | None): 3-letter FastF1 driver codedriver_name(str | None): Driver full namequery_intent(str | None): What the user is asking
Prompt Strategy:
- Strict JSON-only output (zero temperature)
- Uses FastF1 3-letter driver codes (VER, HAM, etc.)
- Fails safely with clear error messages
Example:
intent = parse_query_with_groq("What was Max's win probability at Monaco 2023?")
# Returns: {"season": 2023, "round": 6, "driver_id": "VER", "driver_name": "Max Verstappen"}
2. Data Filtering & Assembly
Functions:
_load_feature_data(path)- Load parquet dataset_filter_by_intent(df, intent)- Filter by season/round/driverbuild_prediction_dataframe(intent, data_path)- Complete filtering pipeline
Input Schema (from fastf1_pipeline.py):
season, round, driver_id, driver_name, team
grid_position, finish_position, circuit_id
sector_1_time, sector_2_time, sector_3_time
avg_lap_time_practice
tire_compound, tire_age_laps, fresh_tire
pit_stop_count, team_pit_speed
weather_temp_track, weather_rainfall
championship_standing
3. Data Pipeline Integration
The returned DataFrame flows directly into:
# DataAgent output
result = data_agent("Verstappen Monaco 2023")
df = result["dataframe"]
# Compatible with ML pipeline
bundle, encoders = prepare_model_data(df)
predictions = predict_dataframe(df, model, encoders)
No intermediate transformations needed β the agent returns FastF1-schema data that feature_engineering.py handles.
API Reference
Main Entry Point
def data_agent(
query: str,
data_path: str | Path = DEFAULT_DATA_PATH,
parser: IntentParser | None = None,
) -> DataAgentOutput:
"""
Parse natural-language query and return prediction-ready rows.
Args:
query: Natural-language F1 query
data_path: Path to fastf1_races.parquet
parser: Optional custom parser (for testing/offline use)
Returns:
DataAgentOutput with:
- query (str): Original user query
- intent (QueryIntent): Parsed season/round/driver
- rows (list[PredictionInputRow]): Matching race rows as dicts
- dataframe (pd.DataFrame): Full DataFrame for ML pipeline
"""
CLI Usage
# Parse and display results
python -m agents.data_agent "Verstappen Monaco 2023"
# Output as JSON
python -m agents.data_agent "Hamilton Silverstone 2023" --json
# Custom data path
python -m agents.data_agent "Norris Austin 2024" --data-path /path/to/races.parquet
Testing
Run tests:
python -m pytest tests/test_data_agent.py -v
Test fixtures include:
- Groq API mocking for unit tests
- Temporary parquet datasets
- Prediction pipeline compatibility checks
Error Handling
| Error | Cause | Resolution |
|---|---|---|
GROQ_API_KEY is required |
Missing env var | Set GROQ_API_KEY in .env |
No rows found for season=X round=Y |
Race doesn't exist in data | Check calendar/data availability |
No rows matched driver intent |
Driver not in race | Verify driver code and race round |
JSON parse error |
Groq returned invalid JSON | Retry with lower temperature |
Design Decisions
Plain Python (No LangGraph)
- Groq API is lightweight and doesn't require orchestration framework
- Single synchronous call for query parsing
- Future: LangGraph can wrap this for multi-turn conversations
TypedDict Schema
- Ensures type safety across data pipeline
- Explicit columns prevent silent failures
- Compatible with mypy strict mode
Groq for Intent Extraction
- Fast: 70B model with 8K context window
- Accurate: Instruction-tuned for structured output
- Cost: $0.19/$0.39 per million tokens (vs Claude)
Example Workflows
Single Race Prediction
from agents.data_agent import data_agent
from ml.predict import load_model_and_encoders, predict_dataframe
agent = DataAgent()
result = agent.query("Will Verstappen win Monza 2023?")
model, encoders = load_model_and_encoders(run_id="abc123")
predictions = predict_dataframe(result["dataframe"], model, encoders)
print(predictions[["driver_id", "driver_name", "win_probability"]])
Batch Queries (future)
queries = [
"Verstappen Monaco 2023",
"Hamilton Silverstone 2023",
"Norris Spa 2023",
]
for q in queries:
result = data_agent(q)
pred = predict_dataframe(result["dataframe"], model, encoders)
print(f"{q}: {pred.iloc[0]['win_probability']:.2%}")
Testing with Mock Parser
from agents.data_agent import data_agent, QueryIntent
def mock_parser(query: str) -> QueryIntent:
return {
"season": 2023,
"round": 1,
"driver_id": "VER",
}
result = data_agent("test query", parser=mock_parser)
# Works without GROQ_API_KEY
Future Enhancements
- LangGraph Integration β Multi-turn clarification ("Which Hamilton race?")
- Result Summarization β "Max has 87% win probability at Monaco"
- Model Explanations β Attach SHAP values to predictions
- Context Awareness β Current standings, form, tire strategy
- Caching β Avoid re-parsing identical queries
Files
- Main: agents/data_agent.py
- Tests: tests/test_data_agent.py
- Upstream (Input Schema): data/fastf1_pipeline.py
- Downstream (ML Pipeline): ml/feature_engineering.py, ml/predict.py