Commit ·
32bf280
1
Parent(s): 57e2365
fixing build issues
Browse files- reactlanggraphagent.py +29 -69
- requirements.txt +1 -0
reactlanggraphagent.py
CHANGED
|
@@ -9,10 +9,9 @@ logging.getLogger('tensorflow').setLevel(logging.ERROR)
|
|
| 9 |
warnings.filterwarnings('ignore', module='tensorflow')
|
| 10 |
warnings.filterwarnings('ignore', module='tf_keras')
|
| 11 |
|
| 12 |
-
from
|
| 13 |
-
from langchain.agents import create_react_agent, AgentExecutor
|
| 14 |
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 15 |
-
from langchain_core.
|
| 16 |
|
| 17 |
from custom_tools import get_custom_tools_list
|
| 18 |
from system_prompt import SYSTEM_PROMPT
|
|
@@ -29,10 +28,11 @@ except ImportError:
|
|
| 29 |
|
| 30 |
class ReActLangGraphAgent:
|
| 31 |
"""
|
| 32 |
-
ReAct agent implementation using
|
| 33 |
|
| 34 |
This agent uses the ReAct (Reasoning + Acting) pattern where the agent
|
| 35 |
reasons about what to do and then acts by calling tools iteratively.
|
|
|
|
| 36 |
"""
|
| 37 |
|
| 38 |
def __init__(self):
|
|
@@ -42,7 +42,7 @@ class ReActLangGraphAgent:
|
|
| 42 |
|
| 43 |
self.tools = get_custom_tools_list()
|
| 44 |
self.llm = self._create_llm_client()
|
| 45 |
-
self.
|
| 46 |
|
| 47 |
def _create_llm_client(self):
|
| 48 |
"""Create and return the LLM client."""
|
|
@@ -55,71 +55,18 @@ class ReActLangGraphAgent:
|
|
| 55 |
timeout=60
|
| 56 |
)
|
| 57 |
|
| 58 |
-
def
|
| 59 |
-
"""
|
| 60 |
-
Create a custom ReAct prompt template that incorporates the system prompt.
|
| 61 |
-
|
| 62 |
-
Returns:
|
| 63 |
-
PromptTemplate: A prompt template for the ReAct agent
|
| 64 |
-
"""
|
| 65 |
-
# Create a ReAct-style prompt that includes our system prompt
|
| 66 |
-
template = """
|
| 67 |
-
{system_prompt}
|
| 68 |
-
|
| 69 |
-
You have access to the following tools:
|
| 70 |
-
|
| 71 |
-
{tools}
|
| 72 |
-
|
| 73 |
-
Use the following format:
|
| 74 |
-
|
| 75 |
-
Question: the input question you must answer
|
| 76 |
-
Thought: you should always think about what to do
|
| 77 |
-
Action: the action to take, should be one of [{tool_names}]
|
| 78 |
-
Action Input: the input to the action
|
| 79 |
-
Observation: the result of the action
|
| 80 |
-
... (this Thought/Action/Action Input/Observation can repeat N times)
|
| 81 |
-
Thought: I now know the final answer
|
| 82 |
-
Final Answer: the final answer to the original input question (PLAIN TEXT ONLY, NO EXTRA TEXT)
|
| 83 |
-
|
| 84 |
-
CRITICAL: Your Final Answer must be PLAIN TEXT ONLY - just the answer itself with no additional text, markdown, or formatting.
|
| 85 |
-
|
| 86 |
-
Begin!
|
| 87 |
-
|
| 88 |
-
Question: {input}
|
| 89 |
-
Thought: {agent_scratchpad}
|
| 90 |
-
"""
|
| 91 |
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
)
|
| 97 |
-
|
| 98 |
-
def _build_agent(self) -> AgentExecutor:
|
| 99 |
-
"""Build and return the ReAct agent executor."""
|
| 100 |
-
|
| 101 |
-
# Create custom prompt
|
| 102 |
-
prompt = self._create_react_prompt()
|
| 103 |
-
|
| 104 |
-
# Create the ReAct agent using create_react_agent
|
| 105 |
-
agent = create_react_agent(
|
| 106 |
-
llm=self.llm,
|
| 107 |
-
tools=self.tools,
|
| 108 |
-
prompt=prompt
|
| 109 |
-
)
|
| 110 |
-
|
| 111 |
-
# Create agent executor with configuration
|
| 112 |
-
agent_executor = AgentExecutor(
|
| 113 |
-
agent=agent,
|
| 114 |
tools=self.tools,
|
| 115 |
-
|
| 116 |
-
max_iterations=40, # Match the step limit from LangGraphAgent
|
| 117 |
-
max_execution_time=None,
|
| 118 |
-
handle_parsing_errors=True,
|
| 119 |
-
return_intermediate_steps=False
|
| 120 |
)
|
| 121 |
|
| 122 |
-
return
|
| 123 |
|
| 124 |
def __call__(self, question: str, file_name: str = None) -> str:
|
| 125 |
"""
|
|
@@ -146,13 +93,17 @@ Thought: {agent_scratchpad}
|
|
| 146 |
if file_name:
|
| 147 |
question_content += f'\n\nNote: This question references a file: {file_name}'
|
| 148 |
|
| 149 |
-
# Invoke the agent
|
| 150 |
max_retries = config.MAX_RETRIES
|
| 151 |
delay = config.INITIAL_RETRY_DELAY
|
| 152 |
|
| 153 |
for attempt in range(max_retries + 1):
|
| 154 |
try:
|
| 155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
# Success - break out of retry loop
|
| 157 |
break
|
| 158 |
except Exception as e:
|
|
@@ -180,7 +131,16 @@ Thought: {agent_scratchpad}
|
|
| 180 |
print(f"{'='*60}\n")
|
| 181 |
|
| 182 |
# Extract the answer from the response
|
| 183 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
|
| 185 |
if answer is None:
|
| 186 |
print("[WARNING] Agent completed but returned None as answer")
|
|
|
|
| 9 |
warnings.filterwarnings('ignore', module='tensorflow')
|
| 10 |
warnings.filterwarnings('ignore', module='tf_keras')
|
| 11 |
|
| 12 |
+
from langgraph.prebuilt import create_react_agent
|
|
|
|
| 13 |
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 14 |
+
from langchain_core.messages import HumanMessage
|
| 15 |
|
| 16 |
from custom_tools import get_custom_tools_list
|
| 17 |
from system_prompt import SYSTEM_PROMPT
|
|
|
|
| 28 |
|
| 29 |
class ReActLangGraphAgent:
|
| 30 |
"""
|
| 31 |
+
ReAct agent implementation using LangGraph's create_react_agent function.
|
| 32 |
|
| 33 |
This agent uses the ReAct (Reasoning + Acting) pattern where the agent
|
| 34 |
reasons about what to do and then acts by calling tools iteratively.
|
| 35 |
+
Built on top of LangGraph's prebuilt ReAct agent.
|
| 36 |
"""
|
| 37 |
|
| 38 |
def __init__(self):
|
|
|
|
| 42 |
|
| 43 |
self.tools = get_custom_tools_list()
|
| 44 |
self.llm = self._create_llm_client()
|
| 45 |
+
self.agent_graph = self._build_agent()
|
| 46 |
|
| 47 |
def _create_llm_client(self):
|
| 48 |
"""Create and return the LLM client."""
|
|
|
|
| 55 |
timeout=60
|
| 56 |
)
|
| 57 |
|
| 58 |
+
def _build_agent(self):
|
| 59 |
+
"""Build and return the ReAct agent graph using LangGraph's create_react_agent."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
|
| 61 |
+
# LangGraph's create_react_agent returns a compiled graph
|
| 62 |
+
# It automatically handles the ReAct loop with tools
|
| 63 |
+
agent_graph = create_react_agent(
|
| 64 |
+
model=self.llm,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
tools=self.tools,
|
| 66 |
+
state_modifier=SYSTEM_PROMPT # System prompt is added as state modifier
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
)
|
| 68 |
|
| 69 |
+
return agent_graph
|
| 70 |
|
| 71 |
def __call__(self, question: str, file_name: str = None) -> str:
|
| 72 |
"""
|
|
|
|
| 93 |
if file_name:
|
| 94 |
question_content += f'\n\nNote: This question references a file: {file_name}'
|
| 95 |
|
| 96 |
+
# Invoke the agent graph with retry logic for 504 errors
|
| 97 |
max_retries = config.MAX_RETRIES
|
| 98 |
delay = config.INITIAL_RETRY_DELAY
|
| 99 |
|
| 100 |
for attempt in range(max_retries + 1):
|
| 101 |
try:
|
| 102 |
+
# LangGraph's create_react_agent expects messages as input
|
| 103 |
+
response = self.agent_graph.invoke(
|
| 104 |
+
{"messages": [HumanMessage(content=question_content)]},
|
| 105 |
+
config={"recursion_limit": 80} # Match the recursion limit from LangGraphAgent
|
| 106 |
+
)
|
| 107 |
# Success - break out of retry loop
|
| 108 |
break
|
| 109 |
except Exception as e:
|
|
|
|
| 131 |
print(f"{'='*60}\n")
|
| 132 |
|
| 133 |
# Extract the answer from the response
|
| 134 |
+
# LangGraph's create_react_agent returns the last message in the messages list
|
| 135 |
+
messages = response.get("messages", [])
|
| 136 |
+
|
| 137 |
+
if not messages:
|
| 138 |
+
print("[WARNING] Agent completed but returned no messages")
|
| 139 |
+
return "Error: No answer generated"
|
| 140 |
+
|
| 141 |
+
# Get the last message (the agent's final response)
|
| 142 |
+
last_message = messages[-1]
|
| 143 |
+
answer = last_message.content if hasattr(last_message, 'content') else str(last_message)
|
| 144 |
|
| 145 |
if answer is None:
|
| 146 |
print("[WARNING] Agent completed but returned None as answer")
|
requirements.txt
CHANGED
|
@@ -6,6 +6,7 @@ ddgs
|
|
| 6 |
pytz
|
| 7 |
wikipedia
|
| 8 |
arxiv
|
|
|
|
| 9 |
langgraph
|
| 10 |
langchain-core
|
| 11 |
langchain-google-genai
|
|
|
|
| 6 |
pytz
|
| 7 |
wikipedia
|
| 8 |
arxiv
|
| 9 |
+
langchain
|
| 10 |
langgraph
|
| 11 |
langchain-core
|
| 12 |
langchain-google-genai
|