File size: 4,250 Bytes
c337d6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
from dotenv import load_dotenv
from tavily import TavilyClient
from langchain_openai import ChatOpenAI
from typing import Dict, TypedDict, List
from langgraph.graph import StateGraph, END
from langchain_core.prompts import ChatPromptTemplate

# Load environment variables
load_dotenv()

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")

# Check if API keys are set
try:
    if not OPENAI_API_KEY or not TAVILY_API_KEY:
        raise ValueError("API keys for OpenAI and Tavily must be set in environment variables.")
except ValueError as e:
    print(f"Error: {e}")
    raise

# Initialize the LLM and Tavily client
try:
    # Initialize the LLM (using OpenAI as an example, replace with your preferred model)
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
    # Initialize Tavily client for web search
    tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
except Exception as e:
    print(f"Error initializing LLM or Tavily client: {e}")
    raise

# Define the shared state for the agents
class ResearchState(TypedDict):
    query: str
    research_data: List[Dict]
    final_answer: str

# Research Agent: Crawls the web and gathers information
def research_agent(state: ResearchState) -> ResearchState:
    query = state["query"]
    print(f"Research Agent: Searching for '{query}'...")

    # Use Tavily to search the web
    search_results = tavily_client.search(query, max_results=5)

    # Extract relevant information from search results
    research_data = []
    for result in search_results["results"]:
        research_data.append({
            "title": result["title"],
            "url": result["url"],
            "content": result["content"][:500]  # Limit content length for brevity
        })

    print(f"Research Agent: Found {len(research_data)} relevant sources.")
    return {"research_data": research_data}

# Answer Drafter Agent: Processes research data and drafts a response
def answer_drafter_agent(state: ResearchState) -> ResearchState:
    research_data = state["research_data"]
    query = state["query"]

    # Create a prompt for the answer drafter
    prompt = ChatPromptTemplate.from_template(
        """

        You are an expert at drafting concise and accurate answers. Based on the following research data, provide a clear and informative response to the query: "{query}".



        Research Data:

        {research_data}



        Provide a well-structured answer in 3-5 sentences, citing the sources where relevant.

        """
    )

    # Format the research data for the prompt
    research_text = "\n".join([f"- {item['title']}: {item['content']} (Source: {item['url']})" for item in research_data])
    chain = prompt | llm

    # Generate the final answer
    response = chain.invoke({"query": query, "research_data": research_text})
    final_answer = response.content

    print("Answer Drafter Agent: Drafted the final answer.")
    return {"final_answer": final_answer}

# Define the LangGraph workflow
def create_workflow():
    workflow = StateGraph(ResearchState)

    # Add nodes for each agent
    workflow.add_node("research_agent", research_agent)
    workflow.add_node("answer_drafter_agent", answer_drafter_agent)

    # Define the flow: Research Agent -> Answer Drafter Agent -> End
    workflow.add_edge("research_agent", "answer_drafter_agent")
    workflow.add_edge("answer_drafter_agent", END)

    # Set the entry point
    workflow.set_entry_point("research_agent")

    return workflow.compile()

# Main function to run the system
def run_deep_research_system(query: str) -> str:
    # Initialize the workflow
    app = create_workflow()

    # Initial state
    initial_state = {
        "query": query,
        "research_data": [],
        "final_answer": ""
    }

    # Run the workflow
    final_state = app.invoke(initial_state)

    return final_state["final_answer"]

# Example usage
if __name__ == "__main__":
    query = "What are the latest advancements in quantum computing?"
    answer = run_deep_research_system(query)
    print("\nFinal Answer:")
    print(answer)