Pipalskill commited on
Commit
f3ffb14
Β·
verified Β·
1 Parent(s): 5c29129

Update agent_langchain.py

Browse files
Files changed (1) hide show
  1. agent_langchain.py +153 -28
agent_langchain.py CHANGED
@@ -5,7 +5,6 @@ os.environ["HF_HOME"] = "/tmp/huggingface"
5
  os.environ["SENTENCE_TRANSFORMERS_HOME"] = "/tmp/sentence_transformers"
6
  os.environ["TORCH_HOME"] = "/tmp/torch"
7
 
8
- import json
9
  import requests
10
  import torch
11
  import time
@@ -29,25 +28,18 @@ GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
29
  ROUTING_URL = os.environ.get("ROUTING_URL")
30
  SPACE_URL = os.environ.get("SPACE_URL", "http://localhost:7860")
31
  FIREBASE_CREDS_PATH = os.environ.get("FIREBASE_CREDS_PATH")
32
- firebase_creds_json = os.getenv("FIREBASE_CREDS_JSON")
33
 
34
  # Initialize Firebase
35
  db = None
36
- if firebase_creds_json:
37
  try:
38
- creds_dict = json.loads(firebase_creds_json)
39
- cred = credentials.Certificate(creds_dict)
40
-
41
  if not firebase_admin._apps:
 
42
  firebase_admin.initialize_app(cred)
43
  db = firestore.client()
44
- print("βœ… Firebase initialized from FIREBASE_CREDS_JSON")
45
  except Exception as e:
46
- import traceback
47
  print(f"⚠️ Firebase init failed: {e}")
48
- traceback.print_exc()
49
- else:
50
- print("⚠️ FIREBASE_CREDS_JSON not found in environment variables")
51
 
52
  # Label Dictionary
53
  LABEL_DICTIONARY = {
@@ -189,6 +181,45 @@ def escalation_tool(reason: str) -> str:
189
  ticket_id = f"TKT-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
190
  return f"ESCALATED: Ticket {ticket_id} created. Reason: {reason}. Human agent will respond in 2-4 hours."
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  # Define Tools with better descriptions
193
  tools = [
194
  Tool(
@@ -206,10 +237,20 @@ tools = [
206
  func=kb_tool,
207
  description="Searches internal knowledge base for solutions. Returns answer with confidence score (0-1). Use this when you need to find technical solutions or troubleshooting steps."
208
  ),
 
 
 
 
 
 
 
 
 
 
209
  Tool(
210
  name="EscalateToHuman",
211
  func=escalation_tool,
212
- description="Creates an escalation ticket for human agent review. Use this ONLY when: 1) KB confidence score is below 0.75, 2) Issue is highly complex or unusual, 3) User confirms solution didn't work."
213
  )
214
  ]
215
 
@@ -224,32 +265,70 @@ TOOL NAMES: {tool_names}
224
  GUIDING PRINCIPLES:
225
  1. **Think autonomously** - Decide which tools you need based on the situation, not a fixed sequence
226
  2. **Be efficient** - Only use tools when they add value to solving the user's problem
227
- 3. **Trust high-confidence solutions** - If KB returns confidence >= 0.75, provide that solution
228
- 4. **Escalate wisely** - Only escalate when truly necessary (low KB confidence, complex issues, or failed solutions)
229
- 5. **Maintain context** - Remember previous conversation history when handling follow-ups
230
- 6. **Be empathetic** - Users are frustrated when things break; be professional and supportive
231
-
232
- DECISION FRAMEWORK:
233
- - For a NEW ticket: You might need to classify, route, search KB - but decide based on what's needed
234
- - For FOLLOW-UPS: If user says solution worked β†’ close positively. If it failed β†’ search KB again or escalate
235
- - For SIMPLE questions: You may not need all tools - use your judgment
236
- - For COMPLEX issues: Use multiple tools to gather information before providing solution
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
238
  FORMAT:
239
  Question: the user's input
240
  Thought: your reasoning about what to do next
241
  Action: the tool to use (must be one of [{tool_names}])
242
  Action Input: the input for that tool
243
- Observation: the tool's output
244
  ... (repeat Thought/Action/Observation as needed)
245
  Thought: I now have enough information to respond
246
  Final Answer: your complete response to the user
247
 
 
 
 
 
 
 
 
248
  IMPORTANT:
249
  - Don't mention tool names or technical process to users
250
  - Provide clear, step-by-step instructions
251
- - Ask clarifying questions if needed
 
252
  - Be conversational and helpful
 
253
 
254
  Begin!
255
 
@@ -322,16 +401,25 @@ def process_with_agent(
322
  status = "in_progress"
323
  should_save = False
324
 
325
- # Check for resolution indicators
326
- if any(phrase in agent_response.lower() for phrase in ["resolved", "you're all set", "should work now", "problem solved"]):
 
 
 
 
327
  status = "resolved"
328
  should_save = True
329
- elif "ESCALATED" in agent_response or "TKT-" in agent_response:
 
330
  status = "escalated"
331
- should_save = True
332
 
333
  # Extract ticket info from tools
334
  ticket_info = conv.get("ticket_info", {})
 
 
 
 
335
  for action, observation in intermediate_steps:
336
  if action.tool == "ClassifyTicket":
337
  # Parse classification
@@ -343,10 +431,47 @@ def process_with_agent(
343
  ticket_info["urgency"] = part.split(": ")[1]
344
  elif "Type:" in part:
345
  ticket_info["type"] = part.split(": ")[1]
 
346
  elif action.tool == "RouteTicket":
347
  ticket_info["department"] = str(observation).replace("Department: ", "")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
 
349
  conv["ticket_info"] = ticket_info
 
 
 
 
 
 
350
  conv["status"] = status
351
 
352
  reasoning_trace = []
 
5
  os.environ["SENTENCE_TRANSFORMERS_HOME"] = "/tmp/sentence_transformers"
6
  os.environ["TORCH_HOME"] = "/tmp/torch"
7
 
 
8
  import requests
9
  import torch
10
  import time
 
28
  ROUTING_URL = os.environ.get("ROUTING_URL")
29
  SPACE_URL = os.environ.get("SPACE_URL", "http://localhost:7860")
30
  FIREBASE_CREDS_PATH = os.environ.get("FIREBASE_CREDS_PATH")
 
31
 
32
  # Initialize Firebase
33
  db = None
34
+ if FIREBASE_CREDS_PATH and os.path.exists(FIREBASE_CREDS_PATH):
35
  try:
 
 
 
36
  if not firebase_admin._apps:
37
+ cred = credentials.Certificate(FIREBASE_CREDS_PATH)
38
  firebase_admin.initialize_app(cred)
39
  db = firestore.client()
40
+ print("βœ… Firebase initialized")
41
  except Exception as e:
 
42
  print(f"⚠️ Firebase init failed: {e}")
 
 
 
43
 
44
  # Label Dictionary
45
  LABEL_DICTIONARY = {
 
181
  ticket_id = f"TKT-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
182
  return f"ESCALATED: Ticket {ticket_id} created. Reason: {reason}. Human agent will respond in 2-4 hours."
183
 
184
+ def clarifying_questions_tool(issue_summary: str) -> str:
185
+ """Generates clarifying questions when more information needed. Use when: User description is vague, Need to diagnose issue better, Before searching KB."""
186
+ prompt = f"""You are an IT helpdesk expert. Based on this issue, generate 2-3 specific clarifying questions to better diagnose the problem.
187
+
188
+ Issue: {issue_summary}
189
+
190
+ Generate focused questions that would help identify:
191
+ - Specific symptoms or error messages
192
+ - When the issue started
193
+ - What the user has already tried
194
+ - Environment details (OS, browser, device)
195
+
196
+ Questions (numbered list):"""
197
+
198
+ try:
199
+ response = llm.invoke(prompt)
200
+ return f"CLARIFYING QUESTIONS:\n{response.content.strip()}"
201
+ except Exception as e:
202
+ return "Please provide more details: 1) What specific error do you see? 2) When did this start? 3) Have you tried any solutions yet?"
203
+
204
+ def check_solution_tool(user_feedback: str) -> str:
205
+ """Analyzes user feedback to determine if provided solution worked. Use after: Giving a solution, User responds with feedback."""
206
+ feedback_lower = user_feedback.lower()
207
+
208
+ # Success indicators
209
+ success_keywords = ["worked", "fixed", "solved", "resolved", "success", "thank", "thanks", "great", "perfect", "awesome"]
210
+ # Failure indicators
211
+ failure_keywords = ["didn't work", "not working", "still", "failed", "broken", "issue persists", "same problem", "no luck", "doesn't work"]
212
+
213
+ success_count = sum(1 for kw in success_keywords if kw in feedback_lower)
214
+ failure_count = sum(1 for kw in failure_keywords if kw in feedback_lower)
215
+
216
+ if success_count > failure_count and success_count > 0:
217
+ return "SOLUTION_WORKED: User confirmed the solution resolved their issue. You can close this ticket positively."
218
+ elif failure_count > success_count and failure_count > 0:
219
+ return "SOLUTION_FAILED: User confirmed the solution did NOT work. You should try alternative solutions or escalate."
220
+ else:
221
+ return "UNCLEAR: Cannot determine if solution worked. Ask the user directly: 'Did that solution work for you?'"
222
+
223
  # Define Tools with better descriptions
224
  tools = [
225
  Tool(
 
237
  func=kb_tool,
238
  description="Searches internal knowledge base for solutions. Returns answer with confidence score (0-1). Use this when you need to find technical solutions or troubleshooting steps."
239
  ),
240
+ Tool(
241
+ name="AskClarifyingQuestions",
242
+ func=clarifying_questions_tool,
243
+ description="Generates 2-3 specific questions to better understand the user's problem. Use when: user's description is vague, you need more details to diagnose, or before searching KB with unclear symptoms."
244
+ ),
245
+ Tool(
246
+ name="CheckSolutionEffectiveness",
247
+ func=check_solution_tool,
248
+ description="Analyzes user's feedback to determine if the provided solution worked. Use AFTER giving a solution and user responds. Returns SOLUTION_WORKED, SOLUTION_FAILED, or UNCLEAR."
249
+ ),
250
  Tool(
251
  name="EscalateToHuman",
252
  func=escalation_tool,
253
+ description="Creates an escalation ticket for human agent review. Use this ONLY when: 1) KB confidence score is below 0.75, 2) Issue is highly complex or unusual, 3) User confirms solution didn't work, 4) User explicitly requests human help."
254
  )
255
  ]
256
 
 
265
  GUIDING PRINCIPLES:
266
  1. **Think autonomously** - Decide which tools you need based on the situation, not a fixed sequence
267
  2. **Be efficient** - Only use tools when they add value to solving the user's problem
268
+ 3. **Trust high-confidence solutions** - If KB returns confidence >= 0.75, provide that solution directly
269
+ 4. **Exhaust KB options first** - Try searching KB before escalating. Only escalate if KB truly cannot help
270
+ 5. **Escalate wisely** - Only escalate when truly necessary (low KB confidence, complex issues, or failed solutions)
271
+ 6. **Maintain context** - Remember previous conversation history when handling follow-ups
272
+ 7. **Be empathetic** - Users are frustrated when things break; be professional and supportive
273
+ 8. **Be Useful** - If low KB confidence, try answering using general knowledge and escalate
274
+
275
+ CRITICAL DECISION FRAMEWORK FOR KB CONFIDENCE:
276
+
277
+ **KB Confidence >= 0.75 (HIGH):**
278
+ - βœ… PROVIDE THE SOLUTION IMMEDIATELY
279
+ - ❌ DO NOT escalate
280
+ - ❌ DO NOT use EscalateToHuman tool
281
+ - This is a good solution - trust it!
282
+
283
+ **KB Confidence 0.5-0.74 (MEDIUM):**
284
+ - Consider the issue complexity
285
+ - For common issues (password, printer, etc): Provide the solution
286
+ - For critical issues: Provide solution + mention you can escalate if it doesn't work
287
+ - DO NOT immediately escalate - give the solution a chance first
288
+
289
+ **KB Confidence < 0.5 (LOW) OR No KB Match:**
290
+ - Try to help with general IT knowledge if possible
291
+ - If you cannot help OR issue is highly complex β†’ Then escalate
292
+ - Use EscalateToHuman tool only as last resort
293
+
294
+ WORKFLOW FOR NEW TICKETS:
295
+ 1. Understand the issue (classify if needed)
296
+ 2. Search KB for solutions
297
+ 3. Evaluate KB confidence:
298
+ - High (β‰₯0.75): Provide solution, DON'T escalate
299
+ - Medium (0.5-0.74): Provide solution, offer escalation as backup
300
+ - Low (<0.5): Try general knowledge OR escalate
301
+ 4. Only use EscalateToHuman if KB has no solution AND you can't help
302
+
303
+ WORKFLOW FOR FOLLOW-UPS:
304
+ - If user says solution worked β†’ Close positively, NO escalation needed
305
+ - If user says solution failed β†’ Try searching KB with different query OR escalate
306
+ - For clarification questions β†’ Answer directly
307
 
308
  FORMAT:
309
  Question: the user's input
310
  Thought: your reasoning about what to do next
311
  Action: the tool to use (must be one of [{tool_names}])
312
  Action Input: the input for that tool
313
+ Observation: the result of the action
314
  ... (repeat Thought/Action/Observation as needed)
315
  Thought: I now have enough information to respond
316
  Final Answer: your complete response to the user
317
 
318
+ CRITICAL: When you have enough information to answer the user, you MUST use this EXACT format:
319
+
320
+ Thought: I now have enough information to respond
321
+ Final Answer: [your complete response to the user]
322
+
323
+ Do NOT add any additional "Action:" or "Thought:" after "Final Answer:". The conversation ends with "Final Answer:".
324
+
325
  IMPORTANT:
326
  - Don't mention tool names or technical process to users
327
  - Provide clear, step-by-step instructions
328
+ - Don't escalate if you have a working solution (confidence β‰₯ 0.75)
329
+ - Trust high-confidence KB solutions - they are tested and verified
330
  - Be conversational and helpful
331
+ - STOP after "Final Answer:" - do not continue the loop
332
 
333
  Begin!
334
 
 
401
  status = "in_progress"
402
  should_save = False
403
 
404
+ # Check for escalation FIRST (higher priority)
405
+ if "ESCALATED" in agent_response or "TKT-" in agent_response:
406
+ status = "escalated"
407
+ should_save = True # βœ… FIX: Save escalated tickets too!
408
+ # Then check for resolution indicators
409
+ elif any(phrase in agent_response.lower() for phrase in ["resolved", "you're all set", "should work now", "problem solved", "glad that worked"]):
410
  status = "resolved"
411
  should_save = True
412
+ # If agent explicitly mentions escalation/forwarding to team
413
+ elif any(phrase in agent_response.lower() for phrase in ["sent your request to", "forwarded to", "escalated to", "will be in touch", "team will contact"]):
414
  status = "escalated"
415
+ should_save = True # βœ… FIX: Save when forwarded to team
416
 
417
  # Extract ticket info from tools
418
  ticket_info = conv.get("ticket_info", {})
419
+ used_escalation_tool = False # Track if escalation tool was used
420
+ kb_confidence = 0.0 # Track KB confidence
421
+ kb_was_searched = False # Track if KB was searched
422
+
423
  for action, observation in intermediate_steps:
424
  if action.tool == "ClassifyTicket":
425
  # Parse classification
 
431
  ticket_info["urgency"] = part.split(": ")[1]
432
  elif "Type:" in part:
433
  ticket_info["type"] = part.split(": ")[1]
434
+
435
  elif action.tool == "RouteTicket":
436
  ticket_info["department"] = str(observation).replace("Department: ", "")
437
+
438
+ elif action.tool == "SearchKnowledgeBase":
439
+ # βœ… Track KB search
440
+ kb_was_searched = True
441
+ obs_str = str(observation)
442
+ if "[KB Confidence:" in obs_str:
443
+ try:
444
+ # Extract confidence score
445
+ import re
446
+ match = re.search(r'\[KB Confidence: ([\d.]+)\]', obs_str)
447
+ if match:
448
+ kb_confidence = float(match.group(1))
449
+ ticket_info["kb_confidence"] = kb_confidence
450
+ except:
451
+ pass
452
+
453
+ elif action.tool == "EscalateToHuman":
454
+ # βœ… SAFEGUARD: Check if escalation was premature
455
+ if kb_was_searched and kb_confidence >= 0.75:
456
+ print(f"⚠️ WARNING: Agent escalated despite high KB confidence ({kb_confidence})")
457
+ # Don't set used_escalation_tool = True
458
+ # This prevents premature escalation from being treated as valid
459
+ else:
460
+ used_escalation_tool = True
461
+ # Extract ticket ID from observation
462
+ if "TKT-" in str(observation):
463
+ import re
464
+ ticket_match = re.search(r'TKT-\d{8}-\d{6}', str(observation))
465
+ if ticket_match:
466
+ ticket_info["escalation_ticket_id"] = ticket_match.group(0)
467
 
468
  conv["ticket_info"] = ticket_info
469
+
470
+ # βœ… FIX: If escalation tool was used, force status to escalated
471
+ if used_escalation_tool:
472
+ status = "escalated"
473
+ should_save = True
474
+
475
  conv["status"] = status
476
 
477
  reasoning_trace = []