mgbam commited on
Commit
3a36946
Β·
verified Β·
1 Parent(s): b856671

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +41 -84
agent.py CHANGED
@@ -4,9 +4,8 @@ from langchain_openai import ChatOpenAI
4
  from langchain.agents import AgentExecutor, create_openai_functions_agent
5
 
6
  from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
7
- from langchain_core.messages import AIMessage, HumanMessage # SystemMessage can be implicitly created
8
 
9
- # --- Import your defined tools FROM THE 'tools' PACKAGE ---
10
  from tools import (
11
  BioPortalLookupTool,
12
  UMLSLookupTool,
@@ -16,32 +15,25 @@ from tools import (
16
  from config.settings import settings
17
  from services.logger import app_logger
18
 
19
- # --- Initialize LLM (OpenAI) ---
20
  llm = None
21
  try:
22
  if not settings.OPENAI_API_KEY:
23
  app_logger.error("CRITICAL: OPENAI_API_KEY not found in settings. Agent cannot initialize.")
24
  raise ValueError("OpenAI API Key not configured. Please set it in Hugging Face Space secrets as OPENAI_API_KEY.")
25
-
26
  llm = ChatOpenAI(
27
- model_name="gpt-4-turbo-preview", # More capable for complex instruction following
28
- temperature=0.1, # Low temperature for more deterministic and structured output for tool calls
29
  openai_api_key=settings.OPENAI_API_KEY
30
  )
31
  app_logger.info(f"ChatOpenAI ({llm.model_name}) initialized successfully for agent.")
32
-
33
  except Exception as e:
34
  detailed_error_message = str(e)
35
- user_facing_error = f"OpenAI LLM initialization failed: {detailed_error_message}. Check API key and model name."
36
  if "api_key" in detailed_error_message.lower() or "authenticate" in detailed_error_message.lower():
37
- user_facing_error = "OpenAI LLM initialization failed: API key issue. Ensure OPENAI_API_KEY is correctly set in Hugging Face Secrets and is valid."
38
- app_logger.error(user_facing_error + f" Original: {detailed_error_message}", exc_info=False)
39
- else:
40
- app_logger.error(user_facing_error, exc_info=True)
41
  raise ValueError(user_facing_error)
42
 
43
-
44
- # --- Initialize Tools List ---
45
  tools_list = [
46
  UMLSLookupTool(),
47
  BioPortalLookupTool(),
@@ -49,20 +41,19 @@ tools_list = [
49
  ]
50
  app_logger.info(f"Agent tools initialized: {[tool.name for tool in tools_list]}")
51
 
52
-
53
- # --- Agent Prompt (for OpenAI Functions Agent - Enhanced System Prompt) ---
54
- OPENAI_SYSTEM_PROMPT_TEXT_ENHANCED = (
55
- "You are 'Quantum Health Navigator', an AI assistant for healthcare professionals. "
56
  "Your primary goal is to assist with medical information lookup, treatment optimization queries, and general medical Q&A. "
57
- "You have access to a set of specialized tools (their names are: {tool_names}). Their detailed descriptions are available to you: {tools}. Use them when a user's query can be best answered by one of them.\n"
58
  "Disclaimers: Always state that you are for informational support and not a substitute for clinical judgment. Do not provide direct medical advice for specific patient cases without using the 'quantum_treatment_optimizer' tool if relevant.\n"
59
- "Patient Context for this session (if provided by the user earlier): {patient_context}\n" # This variable is passed from invoke
60
 
61
  "Tool Usage Guidelines:\n"
62
  "1. When using the 'quantum_treatment_optimizer' tool, its 'action_input' argument requires three main keys: 'patient_data', 'current_treatments', and 'conditions'.\n"
63
  " - The 'patient_data' key MUST be a dictionary. Populate this dictionary by extracting relevant details from the {patient_context}. "
64
  " For example, if {patient_context} is 'Age: 50; Gender: Male; Key Medical History: Hypertension; Chief Complaint: headache', "
65
- " then 'patient_data' could be {{\"age\": 50, \"gender\": \"Male\", \"relevant_history\": [\"Hypertension\"], \"symptoms\": [\"headache\"]}}. " # Added symptoms to example
66
  " Include details like age, gender, chief complaint, key medical history, and current medications from {patient_context} within this 'patient_data' dictionary. If a value is not present in context, omit the key or use null/None if appropriate for the tool, but prioritize providing what is available.\n"
67
  " - 'current_treatments' should be a list of strings derived from the 'Current Medications' part of {patient_context}.\n"
68
  " - 'conditions' should be a list of strings, including primary conditions from the 'Key Medical History' or 'Chief Complaint' parts of {patient_context}, and any conditions explicitly mentioned or implied by the current user query.\n"
@@ -74,18 +65,16 @@ OPENAI_SYSTEM_PROMPT_TEXT_ENHANCED = (
74
  )
75
 
76
  prompt = ChatPromptTemplate.from_messages([
77
- ("system", OPENAI_SYSTEM_PROMPT_TEXT_ENHANCED),
78
  MessagesPlaceholder(variable_name="chat_history"),
79
  ("human", "{input}"),
80
  MessagesPlaceholder(variable_name="agent_scratchpad")
81
  ])
82
- app_logger.info("Agent prompt template (enhanced for OpenAI Functions) created.")
83
 
84
- # --- Create Agent ---
85
  if llm is None:
86
- app_logger.critical("LLM object is None at agent creation (OpenAI). Application cannot proceed.")
87
  raise SystemExit("Agent LLM failed to initialize.")
88
-
89
  try:
90
  agent = create_openai_functions_agent(llm=llm, tools=tools_list, prompt=prompt)
91
  app_logger.info("OpenAI Functions agent created successfully.")
@@ -93,83 +82,51 @@ except Exception as e:
93
  app_logger.error(f"Failed to create OpenAI Functions agent: {e}", exc_info=True)
94
  raise ValueError(f"OpenAI agent creation failed: {e}")
95
 
96
-
97
- # --- Create Agent Executor ---
98
  agent_executor = AgentExecutor(
99
  agent=agent,
100
  tools=tools_list,
101
  verbose=True,
102
- handle_parsing_errors=True, # Important for robust function calling
103
- max_iterations=7, # Good to have a limit
104
- # return_intermediate_steps=True, # Enable this for deeper debugging of agent steps
105
  )
106
  app_logger.info("AgentExecutor with OpenAI agent created successfully.")
107
 
108
-
109
- # --- Getter Function for Streamlit App ---
110
  _agent_executor_instance = agent_executor
111
-
112
  def get_agent_executor():
113
  global _agent_executor_instance
114
  if _agent_executor_instance is None:
115
- app_logger.critical("CRITICAL: Agent executor is None when get_agent_executor is called (OpenAI). Initialization likely failed.")
116
- raise RuntimeError("Agent executor (OpenAI) was not properly initialized. Check application startup logs for errors.")
117
- if not settings.OPENAI_API_KEY: # Final check
118
  app_logger.error("OpenAI API Key is missing at get_agent_executor call. Agent will fail.")
119
  raise ValueError("OpenAI API Key not configured.")
120
  return _agent_executor_instance
121
 
122
- # --- Example Usage (for local testing) ---
123
  if __name__ == "__main__":
124
  if not settings.OPENAI_API_KEY:
125
- print("🚨 Please set your OPENAI_API_KEY in .env file or as an environment variable to run the test.")
126
  else:
127
  print("\nπŸš€ Quantum Health Navigator (OpenAI Agent Test Console) πŸš€")
128
- print("-----------------------------------------------------------")
129
- print("Type 'exit' or 'quit' to stop.")
130
- print("Example topics: medical definitions, treatment optimization (will use simulated patient context).")
131
- print("-" * 59)
132
-
133
- try:
134
- test_executor = get_agent_executor()
135
- except ValueError as e_init:
136
- print(f"⚠️ Agent initialization failed during test startup: {e_init}")
137
- print("Ensure your API key is correctly configured and prompt variables are set.")
138
- exit()
139
-
140
- current_chat_history_for_test_run = []
141
- test_patient_context_summary_str = (
142
- "Age: 60; Gender: Male; Chief Complaint: general fatigue and occasional dizziness; "
143
- "Key Medical History: Type 2 Diabetes, Hypertension; "
144
- "Current Medications: Metformin 1000mg daily, Lisinopril 20mg daily; Allergies: None."
145
- )
146
- print(f"ℹ️ Simulated Patient Context for this test run: {test_patient_context_summary_str}\n")
147
-
148
  while True:
149
- user_input_str = input("πŸ‘€ You: ").strip()
150
- if user_input_str.lower() in ["exit", "quit"]:
151
- print("πŸ‘‹ Exiting test console.")
152
- break
153
- if not user_input_str:
154
- continue
155
-
156
  try:
157
- app_logger.info(f"__main__ test (OpenAI): Invoking with input: '{user_input_str}'")
158
- response_dict = test_executor.invoke({
159
- "input": user_input_str,
160
- "chat_history": current_chat_history_for_test_run,
161
- "patient_context": test_patient_context_summary_str
162
  })
163
-
164
- ai_output_str = response_dict.get('output', "Agent did not produce an 'output' key.")
165
- print(f"πŸ€– Agent: {ai_output_str}")
166
-
167
- current_chat_history_for_test_run.append(HumanMessage(content=user_input_str))
168
- current_chat_history_for_test_run.append(AIMessage(content=ai_output_str))
169
-
170
- if len(current_chat_history_for_test_run) > 10:
171
- current_chat_history_for_test_run = current_chat_history_for_test_run[-10:]
172
-
173
- except Exception as e_invoke:
174
- print(f"⚠️ Error during agent invocation: {type(e_invoke).__name__} - {e_invoke}")
175
- app_logger.error(f"Error in __main__ OpenAI agent test invocation: {e_invoke}", exc_info=True)
 
4
  from langchain.agents import AgentExecutor, create_openai_functions_agent
5
 
6
  from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
7
+ from langchain_core.messages import AIMessage, HumanMessage
8
 
 
9
  from tools import (
10
  BioPortalLookupTool,
11
  UMLSLookupTool,
 
15
  from config.settings import settings
16
  from services.logger import app_logger
17
 
 
18
  llm = None
19
  try:
20
  if not settings.OPENAI_API_KEY:
21
  app_logger.error("CRITICAL: OPENAI_API_KEY not found in settings. Agent cannot initialize.")
22
  raise ValueError("OpenAI API Key not configured. Please set it in Hugging Face Space secrets as OPENAI_API_KEY.")
 
23
  llm = ChatOpenAI(
24
+ model_name="gpt-4-turbo-preview",
25
+ temperature=0.1,
26
  openai_api_key=settings.OPENAI_API_KEY
27
  )
28
  app_logger.info(f"ChatOpenAI ({llm.model_name}) initialized successfully for agent.")
 
29
  except Exception as e:
30
  detailed_error_message = str(e)
31
+ user_facing_error = f"OpenAI LLM initialization failed: {detailed_error_message}."
32
  if "api_key" in detailed_error_message.lower() or "authenticate" in detailed_error_message.lower():
33
+ user_facing_error = "OpenAI LLM initialization failed: API key issue. Check HF Secrets."
34
+ app_logger.error(user_facing_error, exc_info=True)
 
 
35
  raise ValueError(user_facing_error)
36
 
 
 
37
  tools_list = [
38
  UMLSLookupTool(),
39
  BioPortalLookupTool(),
 
41
  ]
42
  app_logger.info(f"Agent tools initialized: {[tool.name for tool in tools_list]}")
43
 
44
+ # --- Agent Prompt (Reverting to version that EXPLICITLY includes {tools} and {tool_names} in the system message string) ---
45
+ OPENAI_SYSTEM_PROMPT_TEXT_WITH_TOOLS_EXPLICIT = (
46
+ "You are 'Quantum Health Navigator', an advanced AI assistant for healthcare professionals. "
 
47
  "Your primary goal is to assist with medical information lookup, treatment optimization queries, and general medical Q&A. "
48
+ "You have access to a set of specialized tools (their names are: {tool_names}). Their detailed descriptions are available to you: {tools}. Use them when a user's query can be best answered by one of them.\n" # Explicit {tools} and {tool_names}
49
  "Disclaimers: Always state that you are for informational support and not a substitute for clinical judgment. Do not provide direct medical advice for specific patient cases without using the 'quantum_treatment_optimizer' tool if relevant.\n"
50
+ "Patient Context for this session (if provided by the user earlier): {patient_context}\n"
51
 
52
  "Tool Usage Guidelines:\n"
53
  "1. When using the 'quantum_treatment_optimizer' tool, its 'action_input' argument requires three main keys: 'patient_data', 'current_treatments', and 'conditions'.\n"
54
  " - The 'patient_data' key MUST be a dictionary. Populate this dictionary by extracting relevant details from the {patient_context}. "
55
  " For example, if {patient_context} is 'Age: 50; Gender: Male; Key Medical History: Hypertension; Chief Complaint: headache', "
56
+ " then 'patient_data' could be {{\"age\": 50, \"gender\": \"Male\", \"relevant_history\": [\"Hypertension\"], \"symptoms\": [\"headache\"]}}. "
57
  " Include details like age, gender, chief complaint, key medical history, and current medications from {patient_context} within this 'patient_data' dictionary. If a value is not present in context, omit the key or use null/None if appropriate for the tool, but prioritize providing what is available.\n"
58
  " - 'current_treatments' should be a list of strings derived from the 'Current Medications' part of {patient_context}.\n"
59
  " - 'conditions' should be a list of strings, including primary conditions from the 'Key Medical History' or 'Chief Complaint' parts of {patient_context}, and any conditions explicitly mentioned or implied by the current user query.\n"
 
65
  )
66
 
67
  prompt = ChatPromptTemplate.from_messages([
68
+ ("system", OPENAI_SYSTEM_PROMPT_TEXT_WITH_TOOLS_EXPLICIT), # Using the version with explicit {tools} and {tool_names}
69
  MessagesPlaceholder(variable_name="chat_history"),
70
  ("human", "{input}"),
71
  MessagesPlaceholder(variable_name="agent_scratchpad")
72
  ])
73
+ app_logger.info("Agent prompt template (with explicit tools/tool_names in system message) created.")
74
 
 
75
  if llm is None:
76
+ app_logger.critical("LLM object is None at agent creation (OpenAI). Cannot proceed.")
77
  raise SystemExit("Agent LLM failed to initialize.")
 
78
  try:
79
  agent = create_openai_functions_agent(llm=llm, tools=tools_list, prompt=prompt)
80
  app_logger.info("OpenAI Functions agent created successfully.")
 
82
  app_logger.error(f"Failed to create OpenAI Functions agent: {e}", exc_info=True)
83
  raise ValueError(f"OpenAI agent creation failed: {e}")
84
 
 
 
85
  agent_executor = AgentExecutor(
86
  agent=agent,
87
  tools=tools_list,
88
  verbose=True,
89
+ handle_parsing_errors=True,
90
+ max_iterations=7,
 
91
  )
92
  app_logger.info("AgentExecutor with OpenAI agent created successfully.")
93
 
 
 
94
  _agent_executor_instance = agent_executor
 
95
  def get_agent_executor():
96
  global _agent_executor_instance
97
  if _agent_executor_instance is None:
98
+ app_logger.critical("CRITICAL: Agent executor is None when get_agent_executor is called (OpenAI).")
99
+ raise RuntimeError("Agent executor (OpenAI) was not properly initialized.")
100
+ if not settings.OPENAI_API_KEY:
101
  app_logger.error("OpenAI API Key is missing at get_agent_executor call. Agent will fail.")
102
  raise ValueError("OpenAI API Key not configured.")
103
  return _agent_executor_instance
104
 
 
105
  if __name__ == "__main__":
106
  if not settings.OPENAI_API_KEY:
107
+ print("🚨 Please set your OPENAI_API_KEY in .env or environment.")
108
  else:
109
  print("\nπŸš€ Quantum Health Navigator (OpenAI Agent Test Console) πŸš€")
110
+ try: test_executor = get_agent_executor()
111
+ except ValueError as e_init: print(f"⚠️ Agent init failed: {e_init}"); exit()
112
+ history = []
113
+ context = ("Age: 60; Gender: Male; Chief Complaint: general fatigue and occasional dizziness; "
114
+ "Key Medical History: Type 2 Diabetes, Hypertension; "
115
+ "Current Medications: Metformin 1000mg daily, Lisinopril 20mg daily; Allergies: None.")
116
+ print(f"ℹ️ Simulated Context: {context}\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  while True:
118
+ usr_in = input("πŸ‘€ You: ").strip()
119
+ if usr_in.lower() in ["exit", "quit"]: print("πŸ‘‹ Exiting."); break
120
+ if not usr_in: continue
 
 
 
 
121
  try:
122
+ res = test_executor.invoke({
123
+ "input": usr_in,
124
+ "chat_history": history,
125
+ "patient_context": context,
126
+ # DO NOT PASS "tools" or "tool_names" here; the agent constructor does that
127
  })
128
+ ai_out = res.get('output', "No output.")
129
+ print(f"πŸ€– Agent: {ai_out}")
130
+ history.extend([HumanMessage(content=usr_in), AIMessage(content=ai_out)])
131
+ if len(history) > 8: history = history[-8:]
132
+ except Exception as e_invoke: print(f"⚠️ Invoke Error: {type(e_invoke).__name__} - {e_invoke}")