Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Graph Display not working for over 3 levels nested graph and when more than one node #2607

Open
5 tasks done
kmprasad4u opened this issue Dec 3, 2024 · 5 comments
Open
5 tasks done

Comments

@kmprasad4u
Copy link

kmprasad4u commented Dec 3, 2024

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangGraph/LangChain documentation with the integrated search.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangGraph/LangChain rather than my code.
  • I am sure this is better as an issue rather than a GitHub discussion, since this is a LangGraph bug and not a design question.

Example Code

from langchain_core.messages import AIMessage
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import MessagesState

# ********************************************************************************************************************

def get_weather(state: MessagesState):
    return None

def will_it_rain(state: MessagesState):
    return None

workflow = StateGraph(MessagesState)
workflow.add_node("will_it_rain", will_it_rain)
workflow.add_node("get_weather", get_weather) # Just adding this additional node throws error

workflow.add_edge(START, "will_it_rain")
workflow.add_edge("will_it_rain", "get_weather")
workflow.add_edge("get_weather", END)
executor_agent = workflow.compile()

# ********************************************************************************************************************

def testingSubSubGraphNode1(state: MessagesState):
    return {
        "messages": [AIMessage(content="Testing Sub Sub Node 1")]
    }

workflow = StateGraph(MessagesState)
workflow.add_node("testingSubSubGraphNode1", testingSubSubGraphNode1)
workflow.add_node("executor_agent", executor_agent)

workflow.add_edge(START, "testingSubSubGraphNode1")
workflow.add_edge("testingSubSubGraphNode1", "executor_agent")
workflow.add_edge("executor_agent", END)
subSubGraph = workflow.compile()


# ********************************************************************************************************************

def testingSubGraphNode(state: MessagesState):
    return {
        "messages": [AIMessage(content="Testing Sub Node 1")]
    }

workflow = StateGraph(MessagesState)
workflow.add_node("testingSubGraphNode1", testingSubGraphNode)
workflow.add_node("testingSubGraphNode2", subSubGraph)
workflow.add_edge(START, "testingSubGraphNode1")
workflow.add_edge("testingSubGraphNode1", "testingSubGraphNode2")
workflow.add_edge("testingSubGraphNode2", END)
subGraph = workflow.compile()


# ********************************************************************************************************************


def testingParentNode(state: MessagesState):
    return {
        "messages": [AIMessage(content="Testing Parent Node")]
    }

workflow = StateGraph(MessagesState)
workflow.add_node("testingParentNode1", testingParentNode)
workflow.add_node("testingParentNode2", subGraph)
workflow.add_edge(START, "testingParentNode1")
workflow.add_edge("testingParentNode1", "testingParentNode2")
workflow.add_edge("testingParentNode2", END)
parentGraph = workflow.compile()

if __name__ == "__main__": 


    subSubGraphImage = subSubGraph.get_graph(xray=True).draw_mermaid_png() # This works
    
    #print(subSubGraph.get_graph(xray=True).draw_ascii())
    #with open("SubSubGraph.png", "wb") as f:
    #    f.write(subSubGraphImage)
    print("created sub sub graph image") 
    print("***********************************************************************************")



    subGraphImage = subGraph.get_graph(xray=True).draw_mermaid_png() # This works
    
    #print(subGraph.get_graph(xray=True).draw_ascii())
    #with open("SubGraph.png", "wb") as f:
    #    f.write(subGraphImage)
    print("created sub graph image")
    print("***********************************************************************************")



    #graphJson = parentGraph.get_graph(xray=True).to_json()
    #print(str(graphJson))
    
    # This doesn't work when there are more than 1 node in the executor_agent
    parentImage = parentGraph.get_graph(xray=True).draw_mermaid_png() 
    
    #print(parentGraph.get_graph(xray=True).draw_ascii())
    #with open("parentImage.png", "wb") as f:
    #    f.write(parentImage)
    print("created parent graph image")

Error Message and Stack Trace (if applicable)

ValueError: Found duplicate subgraph 'executor_agent' -- this likely means that you're reusing a subgraph node with the same name. Please adjust your graph to have subgraph nodes with unique names.

Description

I am trying to create nested graphs and using 2 nodes in the fourth level. But when displaying the graph, i get error message. I have tried to simplify the code as much as possible to illustrate the problem.

This was started as an issue with create_react_agent, but later observed to be different issue altogether and the example code is updated with more simplified version without using create_react_agent.

System Info

langchain==0.3.7
langchain-core==0.3.18
langchain-community==0.3.7
langgraph==0.2.48

@gbaian10
Copy link
Contributor

gbaian10 commented Dec 3, 2024

parentImage = parentGraph.get_graph(xray=2).draw_mermaid_png() 

True is actually 1, since bool is a subclass of int.
You can directly input the number representing the sublayer depth you want to expand.

@kmprasad4u
Copy link
Author

Yes I did try it, Less than 3 it doesn't throw error. But that doesn't give the full depth in the image if there are over 3 levels and the create_react_agent is used in the 3rd level.

Since the default is False, I assumed True is to display all levels and I would expect an option to display all levels instead of hardcoding a number like that.

@vbarda
Copy link
Collaborator

vbarda commented Dec 7, 2024

True is actually 1, since bool is a subclass of int.

^ This is actually incorrect for get_graph -- True actually means get full depth.

The ValueError you're running into does seem strange, will investigate

@gbaian10
Copy link
Contributor

gbaian10 commented Dec 8, 2024

Hi, @kmprasad4u . Sorry for the trouble. @vbarda is right.
When xray is set to True, it does indeed default to expanding all the subgraphs.

When I looked at your example, I didn't pay attention to what was written above.
I only looked at the content below if __name__ == "__main__":, modified it to 2, got the correct result, and didn't delve further.


I later noticed the content of your testingSubSubGraphNode2.

In this situation, it can work.

def testingSubSubGraphNode2(state):
    return {"messages": []}

In this situation, it will throw an error.

executor_agent = create_react_agent(llm, [get_weather])

def testingSubSubGraphNode2(state):
    executor_agent.invoke({"messages": "Hi, how are you?"})
    return {"messages": []}

Even if you directly assign the global variable of create_react_agent to a new local variable, it still results in an error.

executor_agent = create_react_agent(llm, [get_weather])

def testingSubSubGraphNode2(state):
    a = executor_agent
    return {"messages": []}

However, if I create it within the function instead of get it directly from the global variable, it works properly.

def testingSubSubGraphNode2(state):
    a = create_react_agent(llm, [get_weather])
    return {"messages": []}

I later determined that the issue is likely with self.get_subgraphs (in Pregel).
In some cases (like the example above), it retrieves the graph from the node's action function.
And these retrieved graphs can result in Mermaid not rendering correctly.

image

I'm not sure if a graph that isn't explicitly declared as a Node, but is just executed within a node's action function, should appear in Mermaid.
From my perspective, it probably shouldn't be displayed.

@kmprasad4u kmprasad4u changed the title Graph Display not working for over 2 levels nested graph and when using create_react_agent Graph Display not working for over 2 levels nested graph and when using react agents Dec 9, 2024
@kmprasad4u
Copy link
Author

kmprasad4u commented Dec 9, 2024

Even, I assumed that agent.invoke shouldn't have been displayed in the image when it was implicitly called inside the node function. I also noted that If I have a function call to get the agent and then use it, it just worked as I had expected without the react agent in the image and didn't throw error. But since it was working fine with smaller graphs, I thought it should be working for higher depths as well.

Anyways, I initially thought the error was due to create_react_agent. I was also in need of interrupting one tool call alone which i believe create_react_agent didn't support. Hence I created my own simple version of the react agent, and the same error is present in that as well.

Based on your comment, I tried to not use invoke from within the node and instead used the react agent as the node itself, and still the same issue is present.

Then I went ahead and simplified it by removing all LLM calls and Tools. Just having two simple nodes in 4th level is causing error. Having just one node alone is not throwing error. I have updated the simplified code in my first post.

@kmprasad4u kmprasad4u changed the title Graph Display not working for over 2 levels nested graph and when using react agents Graph Display not working for over 3 levels nested graph and when more than one node Dec 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants