File size: 8,798 Bytes
93406ed be49f6d 93406ed 4a3a03e f194991 93406ed 29659ac 93406ed 4a3a03e 93406ed 4a3a03e 93406ed 216ab9a f194991 93406ed f194991 93406ed 216ab9a 93406ed |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# /home/user/app/agent.py
import os
from langchain_openai import ChatOpenAI # For OpenAI models
from langchain.agents import AgentExecutor, create_openai_functions_agent # Agent optimized for OpenAI function calling
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import AIMessage, HumanMessage # SystemMessage not always explicitly needed in prompt list for this agent
# --- Import your defined tools FROM THE 'tools' PACKAGE ---
from tools import (
BioPortalLookupTool,
UMLSLookupTool,
QuantumTreatmentOptimizerTool,
# QuantumOptimizerInput, # Import if needed for type hints directly in this file
# GeminiTool, # Not needed if primary LLM is OpenAI
)
from config.settings import settings # This loads your HF secrets into the settings object
from services.logger import app_logger
# --- Initialize LLM (OpenAI) ---
llm = None
try:
if not settings.OPENAI_API_KEY:
app_logger.error("CRITICAL: OPENAI_API_KEY not found in settings. Agent cannot initialize.")
raise ValueError("OpenAI API Key not configured. Please set it in Hugging Face Space secrets as OPENAI_API_KEY.")
# Choose your preferred OpenAI model
# "gpt-3.5-turbo-0125" is a good balance of cost and capability for function calling.
# "gpt-4-turbo-preview" or "gpt-4" is more capable but more expensive.
llm = ChatOpenAI(
model_name="gpt-3.5-turbo-0125", # Or "gpt-4-turbo-preview"
temperature=0.2, # Lower for more predictable tool use
openai_api_key=settings.OPENAI_API_KEY
)
app_logger.info(f"ChatOpenAI ({llm.model_name}) initialized successfully for agent.")
except Exception as e:
detailed_error_message = str(e)
user_facing_error = f"OpenAI LLM initialization failed: {detailed_error_message}. Check API key and model name."
if "api_key" in detailed_error_message.lower() or "authenticate" in detailed_error_message.lower():
user_facing_error = "OpenAI LLM initialization failed: API key issue. Ensure OPENAI_API_KEY is correctly set in Hugging Face Secrets and is valid."
app_logger.error(user_facing_error + f" Original: {detailed_error_message}", exc_info=False)
else:
app_logger.error(user_facing_error, exc_info=True)
raise ValueError(user_facing_error)
# --- Initialize Tools List ---
tools_list = [
UMLSLookupTool(),
BioPortalLookupTool(),
QuantumTreatmentOptimizerTool(),
]
app_logger.info(f"Agent tools initialized: {[tool.name for tool in tools_list]}")
# --- Agent Prompt (for OpenAI Functions Agent) ---
# This prompt is simpler because much of the tool-calling logic is handled by
# OpenAI's function-calling mechanism, which create_openai_functions_agent leverages.
# The agent will be able to see the tool descriptions.
# We still provide system instructions and placeholders for history and input.
# The {agent_scratchpad} is crucial for OpenAI Functions agent to work correctly.
# The {patient_context} variable needs to be passed in the invoke call.
OPENAI_SYSTEM_PROMPT_TEXT = (
"You are 'Quantum Health Navigator', an AI assistant for healthcare professionals. "
"Your goal is to assist with medical information lookup, treatment optimization queries, and general medical Q&A. "
"You have access to a set of tools to help you. Use them when appropriate.\n"
"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"
"Patient Context for this session (if provided by the user earlier): {patient_context}\n"
"When using the 'quantum_treatment_optimizer' tool, ensure you populate its 'patient_data' argument using the available {patient_context}.\n"
"Always be clear and concise. Cite tools if their output forms a key part of your answer."
)
# `create_openai_functions_agent` typically works well with a system message,
# chat history placeholder, human input placeholder, and agent_scratchpad placeholder.
prompt = ChatPromptTemplate.from_messages([
("system", OPENAI_SYSTEM_PROMPT_TEXT),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad") # Essential for OpenAI Functions agent
])
app_logger.info("Agent prompt template created for OpenAI Functions agent.")
# --- Create Agent ---
if llm is None:
app_logger.critical("LLM object is None at agent creation stage (OpenAI). Application cannot proceed.")
raise SystemExit("Agent LLM failed to initialize. Application cannot start.")
try:
agent = create_openai_functions_agent(llm=llm, tools=tools_list, prompt=prompt)
app_logger.info("OpenAI Functions agent created successfully.")
except Exception as e:
app_logger.error(f"Failed to create OpenAI Functions agent: {e}", exc_info=True)
raise ValueError(f"OpenAI agent creation failed: {e}")
# --- Create Agent Executor ---
agent_executor = AgentExecutor(
agent=agent,
tools=tools_list,
verbose=True,
handle_parsing_errors=True, # Handles cases where LLM output for function call is malformed
max_iterations=10,
# return_intermediate_steps=True, # Useful for debugging
)
app_logger.info("AgentExecutor with OpenAI agent created successfully.")
# --- Getter Function for Streamlit App ---
_agent_executor_instance = agent_executor
def get_agent_executor():
"""
Returns the configured agent executor for OpenAI.
The executor is initialized when this module is first imported.
"""
global _agent_executor_instance
if _agent_executor_instance is None:
app_logger.critical("CRITICAL: Agent executor is None when get_agent_executor is called (OpenAI).")
raise RuntimeError("Agent executor (OpenAI) was not properly initialized. Check startup logs.")
# You can add a check for settings.OPENAI_API_KEY here too if desired,
# but the LLM init should have caught it.
return _agent_executor_instance
# --- Example Usage (for local testing) ---
if __name__ == "__main__":
if not settings.OPENAI_API_KEY:
print("π¨ Please set your OPENAI_API_KEY in .env file or as an environment variable to run the test.")
else:
print("\nπ Quantum Health Navigator (OpenAI Agent Test Console) π")
print("-----------------------------------------------------------")
# ... (rest of the __main__ block from the previous agent.py, it should work.
# The invoke payload will still need "input", "chat_history", and "patient_context") ...
try:
test_executor = get_agent_executor()
except ValueError as e_init:
print(f"β οΈ Agent initialization failed: {e_init}")
exit()
current_chat_history_for_test_run = []
test_patient_context_summary_str = (
"Age: 70; Gender: Male; Chief Complaint: Shortness of breath on exertion; "
"Key Medical History: COPD, Atrial Fibrillation; "
"Current Medications: Tiotropium inhaler, Apixaban 5mg BID; Allergies: Penicillin."
)
print(f"βΉοΈ Simulated Patient Context for this test run: {test_patient_context_summary_str}\n")
while True:
user_input_str = input("π€ You: ").strip()
if user_input_str.lower() in ["exit", "quit"]:
print("π Exiting.")
break
if not user_input_str:
continue
try:
app_logger.info(f"__main__ test (OpenAI): Invoking with: '{user_input_str}'")
# Keys for invoke: "input", "chat_history", and any other variables in your prompt (like "patient_context")
response_dict = test_executor.invoke({
"input": user_input_str,
"chat_history": current_chat_history_for_test_run, # List of BaseMessage
"patient_context": test_patient_context_summary_str
})
ai_output_str = response_dict.get('output', "Agent did not produce an 'output' key.")
print(f"π€ Agent: {ai_output_str}")
current_chat_history_for_test_run.append(HumanMessage(content=user_input_str))
current_chat_history_for_test_run.append(AIMessage(content=ai_output_str))
if len(current_chat_history_for_test_run) > 10:
current_chat_history_for_test_run = current_chat_history_for_test_run[-10:]
except Exception as e:
print(f"β οΈ Error during agent invocation: {e}")
app_logger.error(f"Error in __main__ OpenAI agent test invocation: {e}", exc_info=True) |