Skip to content

bsorrentino/langgraph4j

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

90 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LangGraph for Java

🦜🕸️LangGraph for Java. A library for building stateful, multi-agents applications with LLMs, built for work with langchain4j

It is a porting of original LangGraph from LangChain AI project in Java fashion

News

Date Release info
May 20, 2024 1.0-SNAPSHOT Add "Image To PlantUML Diagram" sample
May 18, 2024 1.0-SNAPSHOT Add getGraph() method to CompiledGraph to return a PlantUML representation of your Graph

Quick Start

Adding LangGraph dependency

👉 Currently are available only the developer SNAPSHOTs

Maven

JDK8 compliant

<dependency>
    <groupId>org.bsc.langgraph4j</groupId>
    <artifactId>langgraph4j-jdk8</artifactId>
    <version>1.0-SNAPSHOT</version>
<dependency>

JDK17 compliant

work in progress

Define the agent state

The main type of graph in langgraph is the StatefulGraph. This graph is parameterized by a state object that it passes around to each node. Each node then returns operations to update that state. These operations can either SET specific attributes on the state (e.g. overwrite the existing values) or ADD to the existing attribute. Whether to set or add is denoted by initialize the property with a AppendableValue. The State must inherit from AgentState base class (that essentially is a Map wrapper).

public class AgentState {

   public AgentState( Map<String,Object> initData ) { ... };
   
   public final java.util.Map<String,Object> data() { ... };

   public final <T> Optional<T> value(String key) { ... };

   public final <T> AppendableValue<T> appendableValue(String key ) { ... };

}

Define the nodes

We now need to define a few different nodes in our graph. In langgraph, a node is a function that accept an AgentState as argument. There are two main nodes we need for this:

  1. The agent: responsible for deciding what (if any) actions to take.
  2. A function to invoke tools: if the agent decides to take an action, this node will then execute that action.

Define Edges

We will also need to define some edges. Some of these edges may be conditional. The reason they are conditional is that based on the output of a node, one of several paths may be taken. The path that is taken is not known until that node is run (the LLM decides).

  1. Conditional Edge: after the agent is called, we should either:
    • If the agent said to take an action, then the function to invoke tools should be called
    • If the agent said that it was finished, then it should finish
  2. Normal Edge: after the tools are invoked, it should always go back to the agent to decide what to do next

Define the graph

We can now put it all together and define the graph! (see example below)

Integrate with LangChain4j

Like default use case proposed in LangGraph blog, We have ported AgentExecutor implementation from langchain using LangGraph4j. In the agents project's module, you can the complete working code with tests. Feel free to checkout and use it as a reference. Below you can find a piece of code of the AgentExecutor to give you an idea of how is has built in langgraph style.

public static class State implements AgentState {

   public State(Map<String, Object> initData) {
      super(initData);
   }

   Optional<String> input() {
      return value("input");
   }
   Optional<AgentOutcome> agentOutcome() {
      return value("agent_outcome");
   }
   AppendableValue<IntermediateStep> intermediateSteps() {
      return appendableValue("intermediate_steps");
   }
   
}

var toolInfoList = ToolInfo.fromList( objectsWithTools );

final List<ToolSpecification> toolSpecifications = toolInfoList.stream()
        .map(ToolInfo::specification)
        .toList();

var agentRunnable = Agent.builder()
                        .chatLanguageModel(chatLanguageModel)
                        .tools( toolSpecifications )
                        .build();

var workflow = new StateGraph<>(State::new);

workflow.setEntryPoint("agent");

workflow.addNode( "agent", node_async( state ->
    runAgent(agentRunnable, state)) // see implementation in the repo code
);

workflow.addNode( "action", node_async( state ->
    executeTools(toolInfoList, state)) // see implementation in the repo code
);

workflow.addConditionalEdge(
        "agent",
        edge_async( state -> {
            if (state.agentOutcome().map(AgentOutcome::finish).isPresent()) {
                return "end";
            }
            return "continue";
        }),
        Map.of("continue", "action", "end", END)
);

workflow.addEdge("action", "agent");

var app = workflow.compile();

return  app.stream( inputs );

Samples

References

About

🚀 LangGraph for Java. A library for building stateful, multi-actor applications with LLMs, built for work jointly with langchain4j

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published