Files
langgraph/langgraph-java/CHANNEL_INITIALIZATION.md
T
2025-03-02 13:09:22 -08:00

107 lines
4.0 KiB
Markdown

# Channel Initialization in Java LangGraph
This document explains how channel initialization is handled in the Java implementation of LangGraph, matching Python's behavior.
## Current Implementation
### Java Implementation (Python-Compatible)
In the Java implementation:
1. **First Superstep Behavior**:
- Only nodes that have the input channel as one of their triggers run in the first superstep
- This matches Python's behavior for graph execution
2. **Channel Reading**:
- Channels that haven't been initialized return `null` values (instead of throwing exceptions)
- Nodes are expected to handle potentially `null` values from uninitialized channels
3. **Graph Execution**:
- Subsequent supersteps only execute nodes that:
- Subscribe to a channel that was updated
- OR have a trigger matching a channel that was updated
## Key Distinctions
There's an important distinction between:
1. **Input channels** - Channels from which the node reads values when it executes
2. **Trigger channels** - Channels that determine when this node should execute
In our Java implementation:
- `channels` property defines which channels the node reads from
- `triggerChannels` property defines which channels can cause the node to execute
This naming is more intuitive and aligns better with the conceptual distinction between reading from a channel and being triggered by a channel.
## Implementation Details
The Python-compatible implementation in Java LangGraph makes the following changes:
1. Modified `TaskPlanner.plan()` to only execute nodes with input channel triggers in the first superstep
2. Updated tests to:
- Add triggers for nodes that should execute on first superstep (e.g., `trigger("input")`)
- Remove unnecessary manual channel initialization that was previously used to avoid EmptyChannelException
- Use input maps to provide initial values instead of `channel.update()`
- Only keep manual initialization in specific test cases that need it (like the mix of initialized/uninitialized channels test)
3. Clarified the distinction between "subscribe to read" and "trigger to execute" semantics
## Recommended Practices
When building graphs with the Java implementation, follow these practices to ensure Python compatibility:
### 1. Add trigger channels to nodes
Always add appropriate trigger channels to nodes that should execute in the first superstep:
```java
PregelNode node = new PregelNode.Builder("node", executable)
.channel("input") // Channel to read from
.triggerChannel("input") // Channel that triggers execution
.writer("output")
.build();
```
You can also add multiple trigger channels if needed:
```java
PregelNode node = new PregelNode.Builder("node", executable)
.channel("input1")
.channel("input2")
.triggerChannel("input1") // Will trigger on this channel
.triggerChannel("input2") // And also on this channel
.writer("output")
.build();
```
### 2. Handle uninitialized channels gracefully
Inside node execution logic, handle potentially uninitialized channels using default values:
```java
// Handle uninitialized channels with a default value
Integer input = 0; // Default value for uninitialized channel
if (inputs.containsKey("inputChannel") && inputs.get("inputChannel") != null) {
input = (Integer) inputs.get("inputChannel");
}
```
### 3. Provide initial values through input map
Instead of manually initializing channels, provide initial values through the input map:
```java
// DO NOT do this:
// channel.update(Collections.singletonList(initialValue));
// Instead, provide values in the input map:
Map<String, Object> input = new HashMap<>();
input.put("inputChannel", initialValue);
Object result = pregel.invoke(input, null);
```
### 4. Remember execution rules
- Only nodes with input channel as a trigger run in the first superstep
- In subsequent supersteps, nodes run if they subscribe to or have a trigger matching an updated channel
- Uninitialized channels return `null` or empty collections rather than throwing exceptions