mgbam commited on
Commit
e11982a
ยท
verified ยท
1 Parent(s): 52c7695

Update agent.py

Browse files
Files changed (1) hide show
  1. agent.py +55 -56
agent.py CHANGED
@@ -8,34 +8,26 @@ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
8
  from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
9
 
10
  # --- Import your defined tools FROM THE 'tools' PACKAGE ---
11
- # This relies on tools/__init__.py correctly exporting these names.
12
  from tools import (
13
  BioPortalLookupTool,
14
  UMLSLookupTool,
15
  QuantumTreatmentOptimizerTool,
16
- # QuantumOptimizerInput, # Only if needed for type hints directly in this file for some reason
17
- # GeminiTool, # Assuming not used for now as main LLM is Gemini
18
  )
19
 
20
- from config.settings import settings # This loads your HF secrets into the settings object
21
  from services.logger import app_logger
22
 
23
  # --- Initialize LLM (Gemini) ---
24
- llm = None # Initialize to None in case of failure
25
  try:
26
  gemini_api_key_from_settings = settings.GEMINI_API_KEY
27
  api_key_to_use = gemini_api_key_from_settings or os.getenv("GOOGLE_API_KEY")
28
 
29
  if not api_key_to_use:
30
- app_logger.error(
31
- "CRITICAL: Gemini API Key not found. "
32
- "Ensure GEMINI_API_KEY is set in Hugging Face Space secrets and loaded into settings, "
33
- "or GOOGLE_API_KEY is set as an environment variable."
34
- )
35
- raise ValueError(
36
- "Gemini API Key not configured. Please set it in Hugging Face Space secrets "
37
- "as GEMINI_API_KEY or ensure GOOGLE_API_KEY environment variable is available."
38
- )
39
 
40
  llm = ChatGoogleGenerativeAI(
41
  model="gemini-1.5-pro-latest",
@@ -43,18 +35,13 @@ try:
43
  google_api_key=api_key_to_use,
44
  convert_system_message_to_human=True,
45
  )
46
- app_logger.info(f"ChatGoogleGenerativeAI ({llm.model}) initialized successfully using provided API key.")
47
-
48
  except Exception as e:
49
  detailed_error_message = str(e)
50
- user_facing_error = f"Gemini LLM initialization failed: {detailed_error_message}. " \
51
- "Check API key validity, model name, and configurations in Hugging Face Secrets."
52
- if "default credentials were not found" in detailed_error_message.lower() or \
53
- "could not find default credentials" in detailed_error_message.lower() or \
54
- "api_key" in detailed_error_message.lower():
55
- user_facing_error = "Gemini LLM initialization failed: API key issue or missing credentials. " \
56
- "Ensure GEMINI_API_KEY is correctly set in Hugging Face Secrets and is valid."
57
- app_logger.error(user_facing_error + f" Original error details: {detailed_error_message}", exc_info=False)
58
  else:
59
  app_logger.error(user_facing_error, exc_info=True)
60
  raise ValueError(user_facing_error)
@@ -69,8 +56,10 @@ tools_list = [
69
  app_logger.info(f"Agent tools initialized: {[tool.name for tool in tools_list]}")
70
 
71
 
72
- # --- Agent Prompt (for Structured Chat with Gemini and your tools) ---
73
- SYSTEM_PROMPT_TEMPLATE = (
 
 
74
  "You are 'Quantum Health Navigator', an advanced AI assistant for healthcare professionals. "
75
  "Your primary goal is to provide accurate information and insights based on user queries and available tools. "
76
  "You must adhere to the following guidelines:\n"
@@ -79,7 +68,7 @@ SYSTEM_PROMPT_TEMPLATE = (
79
  "unless it's the direct output of a specialized tool like 'quantum_treatment_optimizer'.\n"
80
  "2. Patient Context: The user may provide patient context at the start of the session. This context is available as: {patient_context}. "
81
  "You MUST consider this context when it's relevant to the query, especially for the 'quantum_treatment_optimizer' tool.\n"
82
- "3. Tool Usage: You have access to the following tools (names: {tool_names}):\n{tools}\n" # <--- {tool_names} ADDED HERE
83
  " To use a tool, respond *only* with a JSON markdown code block with 'action' and 'action_input' keys. "
84
  " The 'action_input' must match the schema for the specified tool. Examples:\n"
85
  " For `umls_lookup`: ```json\n{{\"action\": \"umls_lookup\", \"action_input\": \"myocardial infarction\"}}\n```\n"
@@ -90,45 +79,55 @@ SYSTEM_PROMPT_TEMPLATE = (
90
  "5. Specific Tool Guidance:\n"
91
  " - If asked about treatment optimization for a specific patient (especially if patient context is provided), you MUST use the `quantum_treatment_optimizer` tool.\n"
92
  " - For definitions, codes, or general medical concepts, `umls_lookup` or `bioportal_lookup` are appropriate.\n"
93
- "6. Conversation Flow: Refer to the `Previous conversation history` to maintain context.\n\n"
94
- "Begin!\n\n"
95
- "Previous conversation history:\n"
96
- "{chat_history}\n\n"
97
- "New human question: {input}\n"
98
- "{agent_scratchpad}"
99
  )
100
 
 
 
 
 
 
 
 
 
101
  prompt = ChatPromptTemplate.from_messages([
102
- ("system", SYSTEM_PROMPT_TEMPLATE),
103
- MessagesPlaceholder(variable_name="agent_scratchpad"),
 
 
104
  ])
105
  app_logger.info("Agent prompt template created for Gemini structured chat agent.")
106
 
107
  # --- Create Agent ---
108
- if llm is None:
109
- app_logger.critical("LLM object is None at agent creation stage. Cannot proceed.")
110
  raise SystemExit("Agent LLM failed to initialize. Application cannot start.")
111
 
112
  try:
113
  agent = create_structured_chat_agent(llm=llm, tools=tools_list, prompt=prompt)
114
  app_logger.info("Structured chat agent created successfully with Gemini LLM and tools.")
115
  except Exception as e:
116
- # The error "Prompt missing required variables: {'tool_names'}" would be caught here
117
- # if the placeholder wasn't correctly handled or if others are missing.
118
  app_logger.error(f"Failed to create structured chat agent: {e}", exc_info=True)
119
- raise ValueError(f"Gemini agent creation failed: {e}") # This is what you saw in the UI
 
 
 
120
 
121
  # --- Create Agent Executor ---
122
  agent_executor = AgentExecutor(
123
  agent=agent,
124
  tools=tools_list,
125
  verbose=True,
126
- handle_parsing_errors=True,
127
  max_iterations=10,
128
  early_stopping_method="generate",
129
  )
130
  app_logger.info("AgentExecutor with Gemini agent created successfully.")
131
 
 
132
  # --- Getter Function for Streamlit App ---
133
  _agent_executor_instance = agent_executor
134
 
@@ -143,46 +142,46 @@ def get_agent_executor():
143
  if __name__ == "__main__":
144
  main_test_api_key = settings.GEMINI_API_KEY or os.getenv("GOOGLE_API_KEY")
145
  if not main_test_api_key:
146
- print("๐Ÿšจ Please set your GOOGLE_API_KEY (for Gemini) in .env file or as an environment variable to run the test.")
147
  else:
148
  print("\n๐Ÿš€ Quantum Health Navigator (Gemini Agent Test Console) ๐Ÿš€")
149
- print("-----------------------------------------------------------")
150
- # ... (rest of __main__ block from previous full agent.py) ...
151
  try:
152
  test_executor = get_agent_executor()
153
  except ValueError as e_init:
154
- print(f"โš ๏ธ Agent initialization failed during test startup: {e_init}")
155
- print("Ensure your API key is correctly configured.")
156
  exit()
157
 
158
  current_chat_history_for_test_run = []
159
  test_patient_context_summary_str = (
160
- "Age: 62; Gender: Female; Chief Complaint: Recent onset of blurry vision and fatigue; "
161
  "Key Medical History: Prediabetes, Mild dyslipidemia; "
162
  "Current Medications: None reported; Allergies: Sulfa drugs."
163
  )
164
- print(f"โ„น๏ธ Simulated Patient Context for this test run: {test_patient_context_summary_str}\n")
165
 
166
  while True:
167
  user_input_str = input("๐Ÿ‘ค You: ").strip()
168
  if user_input_str.lower() in ["exit", "quit"]:
169
- print("๐Ÿ‘‹ Exiting test console.")
170
  break
171
  if not user_input_str:
172
  continue
173
  try:
174
- app_logger.info(f"__main__ test: Invoking agent with input: '{user_input_str}'")
 
175
  response_dict = test_executor.invoke({
176
  "input": user_input_str,
177
- "chat_history": current_chat_history_for_test_run,
178
- "patient_context": test_patient_context_summary_str
 
179
  })
180
- ai_output_str = response_dict.get('output', "Agent did not produce an 'output' key.")
181
  print(f"๐Ÿค– Agent: {ai_output_str}")
182
  current_chat_history_for_test_run.append(HumanMessage(content=user_input_str))
183
  current_chat_history_for_test_run.append(AIMessage(content=ai_output_str))
184
- if len(current_chat_history_for_test_run) > 10:
185
  current_chat_history_for_test_run = current_chat_history_for_test_run[-10:]
186
  except Exception as e:
187
- print(f"โš ๏ธ Error during agent invocation: {e}")
188
- app_logger.error(f"Error in __main__ agent test invocation: {e}", exc_info=True)
 
8
  from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
9
 
10
  # --- Import your defined tools FROM THE 'tools' PACKAGE ---
 
11
  from tools import (
12
  BioPortalLookupTool,
13
  UMLSLookupTool,
14
  QuantumTreatmentOptimizerTool,
15
+ # QuantumOptimizerInput, # Import if needed for type hints directly in this file
16
+ # GeminiTool, # Uncomment if using
17
  )
18
 
19
+ from config.settings import settings
20
  from services.logger import app_logger
21
 
22
  # --- Initialize LLM (Gemini) ---
23
+ llm = None
24
  try:
25
  gemini_api_key_from_settings = settings.GEMINI_API_KEY
26
  api_key_to_use = gemini_api_key_from_settings or os.getenv("GOOGLE_API_KEY")
27
 
28
  if not api_key_to_use:
29
+ app_logger.error("CRITICAL: Gemini API Key not found in settings or environment.")
30
+ raise ValueError("Gemini API Key not configured.")
 
 
 
 
 
 
 
31
 
32
  llm = ChatGoogleGenerativeAI(
33
  model="gemini-1.5-pro-latest",
 
35
  google_api_key=api_key_to_use,
36
  convert_system_message_to_human=True,
37
  )
38
+ app_logger.info(f"ChatGoogleGenerativeAI ({llm.model}) initialized successfully for agent.")
 
39
  except Exception as e:
40
  detailed_error_message = str(e)
41
+ user_facing_error = f"Gemini LLM initialization failed: {detailed_error_message}."
42
+ if "credential" in detailed_error_message.lower() or "api_key" in detailed_error_message.lower():
43
+ user_facing_error = "Gemini LLM initialization failed: API key/credential issue. Check HF Secrets."
44
+ app_logger.error(user_facing_error + f" Original: {detailed_error_message}", exc_info=False)
 
 
 
 
45
  else:
46
  app_logger.error(user_facing_error, exc_info=True)
47
  raise ValueError(user_facing_error)
 
56
  app_logger.info(f"Agent tools initialized: {[tool.name for tool in tools_list]}")
57
 
58
 
59
+ # --- Agent Prompt (Revised Structure) ---
60
+ # System prompt contains general instructions and placeholders for context/tools.
61
+ # Chat history, current input, and agent scratchpad are handled as separate message sequence parts.
62
+ REVISED_SYSTEM_PROMPT_TEXT = (
63
  "You are 'Quantum Health Navigator', an advanced AI assistant for healthcare professionals. "
64
  "Your primary goal is to provide accurate information and insights based on user queries and available tools. "
65
  "You must adhere to the following guidelines:\n"
 
68
  "unless it's the direct output of a specialized tool like 'quantum_treatment_optimizer'.\n"
69
  "2. Patient Context: The user may provide patient context at the start of the session. This context is available as: {patient_context}. "
70
  "You MUST consider this context when it's relevant to the query, especially for the 'quantum_treatment_optimizer' tool.\n"
71
+ "3. Tool Usage: You have access to the following tools (names: {tool_names}):\n{tools}\n"
72
  " To use a tool, respond *only* with a JSON markdown code block with 'action' and 'action_input' keys. "
73
  " The 'action_input' must match the schema for the specified tool. Examples:\n"
74
  " For `umls_lookup`: ```json\n{{\"action\": \"umls_lookup\", \"action_input\": \"myocardial infarction\"}}\n```\n"
 
79
  "5. Specific Tool Guidance:\n"
80
  " - If asked about treatment optimization for a specific patient (especially if patient context is provided), you MUST use the `quantum_treatment_optimizer` tool.\n"
81
  " - For definitions, codes, or general medical concepts, `umls_lookup` or `bioportal_lookup` are appropriate.\n"
82
+ "6. Conversation Flow: Maintain context from the chat history.\n\n"
83
+ "Begin!"
84
+ # Note: {chat_history}, {input}, and {agent_scratchpad} are NOT in this string anymore.
85
+ # They are handled by the ChatPromptTemplate.from_messages structure.
 
 
86
  )
87
 
88
+ # Create the prompt template
89
+ # Input variables for this prompt will be:
90
+ # - patient_context (from invoke call)
91
+ # - tool_names (provided by create_structured_chat_agent)
92
+ # - tools (provided by create_structured_chat_agent)
93
+ # - chat_history (from invoke call, via MessagesPlaceholder)
94
+ # - input (from invoke call, via ("human", "{input}"))
95
+ # - agent_scratchpad (managed by agent, via MessagesPlaceholder)
96
  prompt = ChatPromptTemplate.from_messages([
97
+ ("system", REVISED_SYSTEM_PROMPT_TEXT),
98
+ MessagesPlaceholder(variable_name="chat_history"),
99
+ ("human", "{input}"), # The current human input
100
+ MessagesPlaceholder(variable_name="agent_scratchpad") # For agent's intermediate work (must be list of BaseMessages)
101
  ])
102
  app_logger.info("Agent prompt template created for Gemini structured chat agent.")
103
 
104
  # --- Create Agent ---
105
+ if llm is None: # Should have been caught by now, but defensive check
106
+ app_logger.critical("LLM object is None at agent creation stage. Application cannot proceed.")
107
  raise SystemExit("Agent LLM failed to initialize. Application cannot start.")
108
 
109
  try:
110
  agent = create_structured_chat_agent(llm=llm, tools=tools_list, prompt=prompt)
111
  app_logger.info("Structured chat agent created successfully with Gemini LLM and tools.")
112
  except Exception as e:
 
 
113
  app_logger.error(f"Failed to create structured chat agent: {e}", exc_info=True)
114
+ # This is where "Prompt missing required variables: {'tool_names'}" was caught previously.
115
+ # Or "variable agent_scratchpad should be a list of base messages" if structure is wrong.
116
+ raise ValueError(f"Gemini agent creation failed: {e}")
117
+
118
 
119
  # --- Create Agent Executor ---
120
  agent_executor = AgentExecutor(
121
  agent=agent,
122
  tools=tools_list,
123
  verbose=True,
124
+ handle_parsing_errors=True, # Important for structured output parsing
125
  max_iterations=10,
126
  early_stopping_method="generate",
127
  )
128
  app_logger.info("AgentExecutor with Gemini agent created successfully.")
129
 
130
+
131
  # --- Getter Function for Streamlit App ---
132
  _agent_executor_instance = agent_executor
133
 
 
142
  if __name__ == "__main__":
143
  main_test_api_key = settings.GEMINI_API_KEY or os.getenv("GOOGLE_API_KEY")
144
  if not main_test_api_key:
145
+ print("๐Ÿšจ Please set your GOOGLE_API_KEY (for Gemini) in .env or environment to run test.")
146
  else:
147
  print("\n๐Ÿš€ Quantum Health Navigator (Gemini Agent Test Console) ๐Ÿš€")
148
+ # ... (rest of the __main__ block from the previous full agent.py, it should work with this prompt structure) ...
 
149
  try:
150
  test_executor = get_agent_executor()
151
  except ValueError as e_init:
152
+ print(f"โš ๏ธ Agent initialization failed: {e_init}")
 
153
  exit()
154
 
155
  current_chat_history_for_test_run = []
156
  test_patient_context_summary_str = (
157
+ "Age: 58; Gender: Female; Chief Complaint: Recent onset of blurry vision and fatigue; "
158
  "Key Medical History: Prediabetes, Mild dyslipidemia; "
159
  "Current Medications: None reported; Allergies: Sulfa drugs."
160
  )
161
+ print(f"โ„น๏ธ Simulated Patient Context: {test_patient_context_summary_str}\n")
162
 
163
  while True:
164
  user_input_str = input("๐Ÿ‘ค You: ").strip()
165
  if user_input_str.lower() in ["exit", "quit"]:
166
+ print("๐Ÿ‘‹ Exiting.")
167
  break
168
  if not user_input_str:
169
  continue
170
  try:
171
+ app_logger.info(f"__main__ test: Invoking with: '{user_input_str}'")
172
+ # The keys here must match the input variables expected by the combined prompt and agent
173
  response_dict = test_executor.invoke({
174
  "input": user_input_str,
175
+ "chat_history": current_chat_history_for_test_run, # List of BaseMessage
176
+ "patient_context": test_patient_context_summary_str,
177
+ # `tools`, `tool_names`, `agent_scratchpad` are handled internally by the agent executor
178
  })
179
+ ai_output_str = response_dict.get('output', "No 'output' key in response.")
180
  print(f"๐Ÿค– Agent: {ai_output_str}")
181
  current_chat_history_for_test_run.append(HumanMessage(content=user_input_str))
182
  current_chat_history_for_test_run.append(AIMessage(content=ai_output_str))
183
+ if len(current_chat_history_for_test_run) > 10: # Limit history
184
  current_chat_history_for_test_run = current_chat_history_for_test_run[-10:]
185
  except Exception as e:
186
+ print(f"โš ๏ธ Error: {e}")
187
+ app_logger.error(f"Error in __main__ test invocation: {e}", exc_info=True)