Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save KrishnanSriram/a9d55b50201df1ae6e74cfe3d2663629 to your computer and use it in GitHub Desktop.

Select an option

Save KrishnanSriram/a9d55b50201df1ae6e74cfe3d2663629 to your computer and use it in GitHub Desktop.
A simple implementation of langgraph with tools and agents - Aligned more with agentic approach
#!/usr/bin/env python3
"""
LangGraph Web Content Agent using ToolNode and Agent approach
Proper implementation with agent decision-making and tool execution
"""
import requests
from datetime import datetime
from typing import TypedDict, List, Annotated
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import ToolNode
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage, ToolMessage
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from bs4 import BeautifulSoup
import os
import uuid
os.environ["OPENAI_API_KEY"] = "XXXXXsdkjbfaksjdgfkDJ-fkjsadbfasdjbfk"
# Define the agent state with messages
class State(TypedDict):
messages: Annotated[List[BaseMessage], add_messages]
# Define tools using @tool decorator
@tool
def fetch_web_content(url: str) -> str:
"""Fetch content from a web URL and return cleaned text"""
try:
response = requests.get(url, timeout=10, verify=False)
response.raise_for_status()
# Use BeautifulSoup to parse the HTML and extract text
soup = BeautifulSoup(response.text, 'html.parser')
text = soup.get_text(separator=' ', strip=True)
print("Content fetched and parsed successfully.")
return text
except requests.exceptions.RequestException as e:
return f"Error fetching content: {e}"
except Exception as e:
return f"Error parsing HTML: {e}"
@tool
def summarize_text(content: str) -> str:
"""Summarize the given content in simple English using Ollama"""
try:
llm = ChatOpenAI(model="gpt-4", temperature=0.3)
# llm = ChatOllama(model="llama3.2", temperature=0.3)
prompt = f"""Please summarize the following content in simple English.
Use short sentences and common words. Keep it under 200 words.
Content:
{content}
Summary:"""
summary = llm.invoke(prompt)
return summary.content
except Exception as e:
return f"Error summarizing content: {str(e)}"
@tool
def save_content_to_file(content: str, filename: str = None) -> str:
"""Save content to a local file with timestamp"""
try:
if not filename:
# timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"summary_{str(uuid.uuid4())}.txt"
with open(filename, 'w', encoding='utf-8') as f:
f.write(f"Content Summary - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write("=" * 50 + "\n\n")
f.write(content)
return f"Content successfully saved to {filename}"
except Exception as e:
return f"Error saving file: {str(e)}"
# Create the tools list
tools = [fetch_web_content, summarize_text, save_content_to_file]
# Create tool node
tool_node = ToolNode(tools)
def create_agent():
"""Create the agent with tool calling capabilities"""
llm = ChatOpenAI(model="gpt-4", temperature=0.5)
# llm = ChatOllama(model="mistral:7b", temperature=0.1)
# Bind tools to the LLM
llm_with_tools = llm.bind_tools(tools)
return llm_with_tools
def agent_node(state: State):
"""Agent node that decides what tools to call"""
# Get the last message to understand current context
messages = state["messages"]
last_message = messages[-1]
# Create the agent
agent = create_agent()
# Create system message for the agent
system_prompt = """You are a helpful agent that can fetch web content, summarize it, and save it to files.
Your workflow should be:
1. First, use fetch_web_content to get content from the provided URL
2. Then, use summarize_text to create a simple English summary
3. Finally, use save_content_to_file to save the summary
Always follow this sequence and use the tools in order. Be methodical and complete each step before moving to the next.
Every step is mandatory and should not be skipped"""
# If this is the first message, add system context
if len(messages) == 1 and isinstance(last_message, HumanMessage):
enhanced_messages = [
HumanMessage(content=system_prompt),
last_message
]
else:
enhanced_messages = messages
# Get response from agent
response = agent.invoke(enhanced_messages)
return {"messages": [response]}
def should_continue(state: State) -> str:
"""Decide whether to continue with tools or end"""
messages = state["messages"]
last_message = messages[-1]
# If the last message has tool calls, go to tools
if hasattr(last_message, 'tool_calls') and last_message.tool_calls:
return "tools"
# Otherwise, we're done
return "end"
def create_workflow():
"""Create the LangGraph workflow with agent and tools"""
# Create the state graph
workflow = StateGraph(State)
# Add nodes
workflow.add_node("agent", agent_node)
workflow.add_node("tools", tool_node)
# Set entry point
workflow.set_entry_point("agent")
# Add conditional edges
workflow.add_conditional_edges(
"agent",
should_continue,
{
"tools": "tools",
"end": END
}
)
# After tools, always go back to agent
workflow.add_edge("tools", "agent")
# Compile the workflow
return workflow.compile()
def run_agent_workflow(url: str):
"""Run the agent workflow for the given URL"""
print("=" * 60)
print("LangGraph Agent with ToolNode")
print("=" * 60)
print(f"Processing URL: {url}")
print("-" * 60)
# Create initial state with human message
initial_message = HumanMessage(
content=f"Please fetch, summarize, and save the content from this URL: {url}"
)
initial_state = State(messages=[initial_message])
# Create and run workflow
app = create_workflow()
try:
print("Running workflow...")
# Simply invoke the workflow and get final result
final_result = app.invoke(initial_state)
print("Workflow completed!")
print()
print("=" * 60)
print("RESULTS:")
print("=" * 60)
# Show results from the final state
final_messages = final_result["messages"]
# Count and show tool results
for msg in final_messages:
if isinstance(msg, ToolMessage):
if msg.name == "fetch_web_content":
print(f"✓ Content fetched: {len(msg.content)} characters")
elif msg.name == "summarize_text":
print(f"✓ Content summarized: {len(msg.content)} characters")
print(f" Preview: {msg.content[:150]}...")
elif msg.name == "save_content_to_file":
print(f"✓ {msg.content}")
except Exception as e:
print(f"Error running workflow: {str(e)}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
print("LangGraph Agent with ToolNode")
print("Fetch, Summarize, and Save Web Content")
print()
# Get URL from user
url = "https://www.usbank.com/credit-cards/bank-smartly-visa-signature-credit-card.html"
print()
# Run the agent workflow
run_agent_workflow(url)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment