You are an expert at programming. I want you thouroughly understand the below concept for LangGraph for building agents so that you apply it for my need. 
Code - 
Creating agents
Let’s start by creating an agents.py file to define our three agents:

The "analysis" agent for initial prompt classification
The "code" agent for code-related queries
The "general" agent for global topics
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI

# Creating the first analysis agent to check the prompt structure
# This print part helps you to trace the graph decisions
def analyze_question(state):
    llm = ChatOpenAI()
    prompt = PromptTemplate.from_template("""
    You are an agent that needs to define if a question is a technical code one or a general one.

    Question : {input}

    Analyse the question. Only answer with "code" if the question is about technical development. If not just answer "general".

    Your answer (code/general) :
    """)
    chain = prompt | llm
    response = chain.invoke({"input": state["input"]})
    decision = response.content.strip().lower()
    return {"decision": decision, "input": state["input"]}

# Creating the code agent that could be way more technical
def answer_code_question(state):
    llm = ChatOpenAI()
    prompt = PromptTemplate.from_template(
        "You are a software engineer. Answer this question with step by steps details : {input}"
    )
    chain = prompt | llm
    response = chain.invoke({"input": state["input"]})
    return {"output": response}

# Creating the generic agent
def answer_generic_question(state):
    llm = ChatOpenAI()
    prompt = PromptTemplate.from_template(
        "Give a general and concise answer to the question: {input}"
    )
    chain = prompt | llm
    response = chain.invoke({"input": state["input"]})
    return {"output": response}
In this example, all three agents use OpenAI’s model. However, LangGraph’s allows for the integration of various models, parameters, and tasks within each agent. You can setup these agents with more complex prompts and even implement Retrieval-Augmented Generation (RAG) techniques to improve their capabilities.

Now that we have the agents, lets create the Graph.

Building the Graph
With our agents defined, we’ll create a graph.py file to orchestrate their interactions. The basic graph structure in LangGraph is really simple, here we are going to use three steps:

Associate “nodes” to our agents to find them in the Graph
Define “activation conditions” of the agents
Establish a “workflow” for our graph with the entry point and stops

from langgraph.graph import StateGraph, END
from typing import Annotated, TypedDict
from agents import analyze_question, answer_code_question, answer_generic_question

#You can precise the format here which could be helpfull for multimodal graphs
class AgentState(TypedDict):
    input: str
    output: str
    decision: str

#Here is a simple 3 steps graph that is going to be working in the bellow "decision" condition
def create_graph():
    workflow = StateGraph(AgentState)

    workflow.add_node("analyze", analyze_question)
    workflow.add_node("code_agent", answer_code_question)
    workflow.add_node("generic_agent", answer_generic_question)

    workflow.add_conditional_edges(
        "analyze",
        lambda x: x["decision"],
        {
            "code": "code_agent",
            "general": "generic_agent"
        }
    )

    workflow.set_entry_point("analyze")
    workflow.add_edge("code_agent", END)
    workflow.add_edge("generic_agent", END)

    return workflow.compile()
As you can see, the structure is simple and easily adaptative. You can add new agent, change the conditions, modify the workflow and create way more complex structure to handle specifics GenAI uses cases.

Finally we are going to try this first application!

Launching the Program
Finally, we’ll create a main.py file to bring our LangGraph project to life. This file initializes the graph and provides an interface for our first interaction!

import os

#Embedding API keys directly in your code is definilty not secure or recommended for production environments.
#Always use proper key management practices.
os.environ["OPENAI_API_KEY"] = "your-openai-key"

from graph import create_graph
from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, END

class UserInput(TypedDict):
    input: str
    continue_conversation: bool

def get_user_input(state: UserInput) -> UserInput:
    user_input = input("\nEnter your question (ou 'q' to quit) : ")
    return {
        "input": user_input,
        "continue_conversation": user_input.lower() != 'q'
    }

def process_question(state: UserInput):
    graph = create_graph()
    result = graph.invoke({"input": state["input"]})
    print("\n--- Final answer ---")
    print(result["output"])
    return state

def create_conversation_graph():
    workflow = StateGraph(UserInput)

    workflow.add_node("get_input", get_user_input)
    workflow.add_node("process_question", process_question)

    workflow.set_entry_point("get_input")

    workflow.add_conditional_edges(
        "get_input",
        lambda x: "continue" if x["continue_conversation"] else "end",
        {
            "continue": "process_question",
            "end": END
        }
    )

    workflow.add_edge("process_question", "get_input")

    return workflow.compile()

def main():
    conversation_graph = create_conversation_graph()
    conversation_graph.invoke({"input": "", "continue_conversation": True})

if __name__ == "__main__":
    main()