Haggle uses xAI’s Grok LLM to automatically understand user requests and infer the type of service professional needed. This eliminates the need for users to navigate complex category menus or know exactly what type of service provider they need.
The AI task inference system is powered by Grok 3 Fast for real-time classification with minimal latency.
The core inference logic uses the xAI SDK with streaming responses:
async def infer_task(query: str) -> str: """ Use Grok LLM to infer the service task from a user query. Args: query: User's free text query (e.g., "fix my toilet") Returns: Inferred task type (e.g., "plumber", "electrician", "cleaner") """ # Use fallback if no API key is configured if not XAI_API_KEY: print("⚠️ No XAI_API_KEY set - using fallback task inference") return _fallback_infer_task(query) system_prompt = """You are a service task classifier. Given a user's request, identify the type of service professional needed. Respond with ONLY a single word or short phrase for the service type, such as:- plumber- electrician - house cleaner- painter- handyman- HVAC technician- locksmith- carpenter- landscaper- appliance repair- pest control- roofer- moving company- auto mechanicBe specific but concise. Just the service type, nothing else.""" try: # Initialize xAI Client client = Client(api_key=XAI_API_KEY) # Create Chat chat = client.chat.create(model="grok-3-fast") # Add messages chat.append(system(system_prompt)) chat.append(user(f"What type of service professional is needed for: {query}")) # Get response full_response = "" for response, chunk in chat.stream(): if chunk.content: full_response += chunk.content task = full_response.strip().lower() return task except Exception as e: print(f"Grok API exception: {e}") return _fallback_infer_task(query)
After inferring the task type, Haggle generates contextual clarifying questions:
Generation Flow
Question Examples
grok_llm.py:109-211
async def generate_clarifying_questions( task: str, query: str, zip_code: str, date_needed: str, price_limit: Union[float, str]) -> List[Dict[str, str]]: """ Generate up to 5 clarifying questions to better understand the job. Rules: - Max 5 questions - Do NOT ask for zip code, date needed, or price again - Keep questions minimal and necessary - No duplicate questions """ system_prompt = """You are a service request specialist helping to understand job requirements.Generate 3-5 clarifying questions to better understand the specific job needs.IMPORTANT RULES:1. Do NOT ask about location, zip code, or address - already provided2. Do NOT ask about timing, date, or schedule - already provided 3. Do NOT ask about budget or price - already provided4. Keep questions specific to the actual work needed5. Questions should help a service provider give an accurate estimate6. Be concise - one clear question per line7. Maximum 5 questionsRespond with ONLY the questions, one per line, numbered 1-5.""" user_prompt = f"""Service type: {task}User's request: "{query}"Generate clarifying questions to understand this job better.""" try: client = Client(api_key=XAI_API_KEY) chat = client.chat.create(model="grok-3-fast") chat.append(system(system_prompt)) chat.append(user(user_prompt)) # Get response and parse questions full_response = "" for response, chunk in chat.stream(): if chunk.content: full_response += chunk.content # Parse numbered questions from response questions = [] lines = content.split("\n") for i, line in enumerate(lines): # Remove numbering and extract question # ... parsing logic questions.append({ "id": f"q{len(questions) + 1}", "question": line }) return questions if questions else _fallback_questions(task) except Exception as e: return _fallback_questions(task)
Plumber Questions
What is the specific issue you’re experiencing?
Is water actively leaking right now?
How old is the fixture or pipe with the issue?
Have you tried any fixes yourself?
Is this affecting multiple fixtures?
Electrician Questions
What electrical issue are you experiencing?
Is this a new installation or a repair?
Are any outlets or switches not working?
Have you experienced any power outages or tripped breakers?
What is the age of your home’s electrical system?
House Cleaner Questions
How many bedrooms and bathrooms need cleaning?
What is the approximate square footage?
Is this a one-time deep clean or regular service?
Do you have pets?
Are there any specific areas that need extra attention?
Haggle converts the user’s query into a professional problem statement for providers:
grok_llm.py:259-336
async def format_problem_statement(original_query: str, task: str) -> str: """ Format a problem statement from the original query and task using Grok LLM. Returns a single line problem description in second person. Examples: - "my lawn is too long" -> "your lawn needs to be mowed" - "fix my toilet" -> "your toilet needs to be fixed" - "my faucet is leaking" -> "your faucet is leaking" """ system_prompt = """You are a problem statement formatter. Convert the user's query into a clear, concise problem description in second person.The output should be a single line describing the problem naturally.Rules:1. Convert first person to second person (e.g., "my lawn" -> "your lawn")2. Make it clear and concise - one sentence only3. Use natural language4. Keep it short and direct5. Use phrases like "needs to be fixed", "needs to be mowed", "is leaking", etc.Respond with ONLY the problem description, nothing else. One line only.""" client = Client(api_key=XAI_API_KEY) chat = client.chat.create(model="grok-3-fast") chat.append(system(system_prompt)) chat.append(user(f"User query: {original_query}")) # Stream and return formatted statement full_response = "" for response, chunk in chat.stream(): if chunk.content: full_response += chunk.content return full_response.strip()
The system includes robust fallback mechanisms when the API is unavailable:
If the XAI_API_KEY is not configured or the API fails, Haggle automatically falls back to pattern matching for task inference.
Fallback Pattern Matching
# Keyword-based task classificationif any(word in query_lower for word in ["toilet", "pipe", "leak", "faucet"]): return "plumber"elif any(word in query_lower for word in ["electric", "outlet", "wire"]): return "electrician"# ... more patternselse: return "handyman" # Default fallback