mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-29 11:19:54 +02:00
107 lines
4.0 KiB
Markdown
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 |