Skip to content

Commit 5c7e005

Browse files
feat: add checkpoint and workflow doc for eino (#1393)
1 parent b54d089 commit 5c7e005

33 files changed

Lines changed: 1918 additions & 10 deletions

content/en/docs/eino/core_modules/chain_and_graph_orchestration/_index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Description: ""
33
date: "2025-02-11"
44
lastmod: ""
55
tags: []
6-
title: 'Eino: Chain & Graph Orchestration'
6+
title: 'Eino: Chain & Graph & Workflow Orchestration'
77
weight: 0
88
---
99

content/en/docs/eino/core_modules/chain_and_graph_orchestration/call_option_capabilities.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ date: "2025-02-11"
44
lastmod: ""
55
tags: []
66
title: 'Eino: CallOption capabilities and specification'
7-
weight: 0
7+
weight: 5
88
---
99

1010
**CallOption**: A channel for directly passing data to a specific set of nodes (Component, Implementation, Node) when invoking Graph compilation products.

content/en/docs/eino/core_modules/chain_and_graph_orchestration/callback_manual.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ date: "2025-03-18"
44
lastmod: ""
55
tags: []
66
title: 'Eino: Callback Manual'
7-
weight: 0
7+
weight: 4
88
---
99

1010
## **Problem Solved**

content/en/docs/eino/core_modules/chain_and_graph_orchestration/chain_graph_introduction.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ date: "2025-03-28"
44
lastmod: ""
55
tags: []
66
title: 'Eino: Chain/Graph Orchestration Introduction'
7-
weight: 0
7+
weight: 1
88
---
99

1010
> All code examples in this document can be found at: [https://github.com/cloudwego/eino-examples/tree/main/compose](https://github.com/cloudwego/eino-examples/tree/main/compose)
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
---
2+
Description: ""
3+
date: "2025-08-07"
4+
lastmod: ""
5+
tags: []
6+
title: 'Eino: Interrupt & CheckPoint User Manual'
7+
weight: 6
8+
---
9+
10+
# Introduction
11+
12+
Using the Interrupt & CheckPoint feature, it is possible to pause the execution of the Graph at a specified location and resume it from the breakpoint later, and if it is a StateGraph, the State can also be modified before resuming from the breakpoint.
13+
14+
> 💡
15+
> Resume from breakpoint can only restore the data generated by each node during input and runtime,and it is necessary to ensure that the Graph orchestration andCallOptionsare exactly the same.
16+
17+
# Use Interrupt
18+
19+
Interrupt supports pausing the Graph before or after the execution of a specified Node. During Compile, pass in the WithInterruptAfterNodes and WithInterruptBeforeNodes Options to set Interrupt:
20+
21+
```go
22+
import (
23+
"github.com/cloudwego/eino/compose"
24+
)
25+
26+
func main() {
27+
g := NewGraph[string, string]()
28+
err := g.AddLambdaNode("node1", compose.InvokableLambda(func(ctx **context**._Context_, input string) (output string, err error) {/*invokable func*/})
29+
if err != nil {/* error handle */}
30+
err = g.AddLambdaNode("node2", compose.InvokableLambda(func(ctx **context**._Context_, input string) (output string, err error) {/*invokable func*/})
31+
if err != nil {/* error handle */}
32+
33+
/** other graph composed code
34+
xxx
35+
*/
36+
37+
err = g.Compile(ctx, compose.WithInterruptAfterNodes([]string{"node1"}), compose.WithInterruptBeforeNodes([]string{"node2"}))
38+
if err != nil {/* error handle */}
39+
}
40+
```
41+
42+
> 💡
43+
> Currently, setting breakpoints is only supported during Compile. If you need to set them during requests, feel free to submit your suggestions~
44+
45+
Whether the current run is interrupted and the interrupt information can be obtained from the error returned by the run:
46+
47+
```go
48+
// compose/checkpoint.go
49+
50+
type InterruptInfo struct {
51+
State any
52+
BeforeNodes []string
53+
AfterNodes []string
54+
SubGraph map[string]InterruptInfo
55+
}
56+
57+
func ExtractInterruptInfo(err error) (info *InterruptInfo, existed bool) {}
58+
```
59+
60+
For example:
61+
62+
```go
63+
import "github.com/cloudwego/eino/compse"
64+
65+
/***graph compose code
66+
* g := NewGraph
67+
* xxx
68+
* runner := g.Compile
69+
*/
70+
71+
result, err := runner.Invoke(ctx, input)
72+
if info, ok := ExtractInterruptInfo(err); ok {
73+
// handler info
74+
}
75+
if err != nil {
76+
// handle error
77+
}
78+
```
79+
80+
> 💡
81+
> When Interrupt occurs, the output is null, which is meaningless.
82+
83+
# Using CheckPoint
84+
85+
CheckPoint records the running state of the Graph, and using CheckPoint allows resuming the operation after an Interrupt.
86+
87+
## Implement CheckPointerStore
88+
89+
CheckPointStore is a KV storage interface where the key type is string and the value type is []byte. We do not provide encapsulation or default implementation, so users need to implement it themselves to store checkpoints.
90+
91+
```go
92+
// coompose/checkpoint.go
93+
94+
type CheckpointStore interface {
95+
Get(ctx **context**._Context_, key string) (value []byte, existed bool,err error)
96+
Set(ctx **context**._Context_, key string, value []byte) (err error)
97+
}
98+
```
99+
100+
## Register serialization method
101+
102+
The saving and loading of CheckPoint involve the serialization and deserialization of the input and output of Graph nodes as well as State. When only simple types or Eino built-in types (such as Message or Document) are used, users do not need to perform additional operations; when custom structs are introduced, types need to be registered in advance, and Eino provides a registration method RegisterSerializableType:
103+
104+
```go
105+
import "github.com/cloudwego/eino/compose"
106+
107+
type MyStruct struct {
108+
// struct body
109+
}
110+
111+
// func RegisterSerializableType[T any](name string) error
112+
err = compose.RegisterSerializableType[MyStruct]("MyStruct")
113+
```
114+
115+
The registered type will have additional type information recorded during serialization. Therefore, during deserialization, even if the type is not specified (such as deserializing to interface{}), Eino can still deserialize the correct type. The key in the registration method uniquely identifies this type, and once the key is determined, it must be ensured that it cannot be changed; otherwise, the persisted checkpoint cannot be correctly restored.
116+
117+
> 💡
118+
> The unexported fields of Struct cannot be accessed, so they will not be stored/restored
119+
120+
If the registered type implements json Marshaler and Unmarshaler, the serialization and deserialization of this type will use custom methods.
121+
122+
```
123+
// encoding/json
124+
125+
type Marshaler interface {
126+
MarshalJSON() ([]byte, error)
127+
}
128+
129+
type Unmarshaler interface {
130+
UnmarshalJSON([]byte) error
131+
}
132+
```
133+
134+
## Turn on CheckPoint
135+
136+
After creating the CheckPointStore, pass it as an option during Compile Graph and bind the CheckPointer to the Graph:
137+
138+
```go
139+
import (
140+
"github.com/cloudwego/eino/compose"
141+
)
142+
143+
func main() {
144+
/** graph composed code
145+
xxx
146+
*/
147+
148+
err = g.Compile(ctx, compose.WithCheckPointStore(store), compose.WithInterruptBeforeNodes([]string{"node2"}))
149+
if err != nil {/* error handle */}
150+
}
151+
```
152+
153+
After that, CheckPoint can be introduced via CallOption when making a request:
154+
155+
```
156+
// compose/checkpoint.go
157+
158+
func WithCheckPointID(checkPointID string, sm StateModifier) Option
159+
type StateModifier func(ctx context.Context, path NodePath, state any) error
160+
func WithStateModifier(sm StateModifier) GraphCompileOption
161+
```
162+
163+
The Checkpoint id will be used as the key for the CheckPointStore. When the graph runs, it will check if this id exists in the CheckPointStore. If it exists, the graph will resume execution from the checkpoint; interrupt will save the graph state to this id.
164+
165+
StateModifier takes effect when the Graph resumes running, can modify the State before running, and the path takes effect in nested graphs, being an empty array when not nested.
166+
167+
```go
168+
/* graph compose and compile
169+
xxx
170+
*/
171+
172+
// first run interrupt
173+
id := GenUUID()
174+
_, err := runner.Invoke(ctx, input, WithCheckPointID(id))
175+
176+
// resume from id
177+
_, err = runner.Invoke(ctx, input/*unused*/,
178+
WithCheckPointID(id),
179+
WithStateModifier(func(ctx context.Context, path NodePath, state any) error{
180+
state.(*testState).Field1 = "hello"
181+
return nil
182+
}),
183+
)
184+
```
185+
186+
> 💡
187+
> When resuming, the input will not be read, so just pass an empty input at this time.
188+
189+
## Dynamic Interrupt
190+
191+
A node returning a special error can dynamically trigger an Interrupt:
192+
193+
```
194+
// eion/compose/checkpoint.go
195+
var InterruptAndRerun = errors.New("interrupt and rerun")
196+
```
197+
198+
After receiving this error returned by the node, Eino Graph will interrupt. When resuming operation, it will run this node again, and before running again, it will call StateModifier to modify the state (if configured).
199+
200+
In this case, when the node is run again, the input will be replaced with a null value instead of the original input. If the original input is still needed when running again, it needs to be saved to the State in advance.
201+
202+
# CheckPoint in Streaming
203+
204+
Streaming requires splicing data streams when saving CheckPoint, so a splicing method needs to be registered:
205+
206+
```go
207+
// compose/stream_concat.go
208+
func RegisterStreamChunkConcatFunc[T any](fn func([]T) (T, error))
209+
210+
// example
211+
type TestStruct struct {
212+
Body string
213+
}
214+
215+
// RegisterStreamChunkConcatFunc非线程安全,需要在初始化阶段使用
216+
RegisterStreamChunkConcatFunc(func(ss []TestStruct)(TestStruct, error){
217+
ret := TestStruct{Body:""}
218+
for i := range ss {
219+
ret.Body += ss[i].Body
220+
}
221+
return ret, nil
222+
})
223+
```
224+
225+
eino provides concat methods for *schema.Message, []*schema.Message, and string by default.
226+
227+
# Interrupt&CheckPoint in the nested graph
228+
229+
When the parent graph passes a CheckPointer, passing InterruptNodes via WithGraphCompileOptions when calling AddAnyGraph can enable Interrupt&CheckPoint for the child graph. If the parent graph does not set a CheckPointer, an error will be reported during Compile.
230+
231+
```go
232+
/* graph compose code
233+
xxx
234+
*/
235+
g.AddAnyGraph("node1", subGraph, WithGraphCompileOptions(
236+
WithInterruptAfterNodes([]string{"node2"}),
237+
))
238+
239+
g.Compile(ctx, WithCheckPointer(cp))
240+
```
241+
242+
If interrupted in the subgraph, the state modified upon resume should be the subgraph state. TODO, explain the use of Path in StateModifier
243+
244+
# Example
245+
246+
[https://github.com/cloudwego/eino-examples/tree/main/compose/graph/react_with_interrupt](https://github.com/cloudwego/eino-examples/tree/main/compose/graph/react_with_interrupt)

content/en/docs/eino/core_modules/chain_and_graph_orchestration/orchestration_design_principles.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ date: "2025-03-18"
44
lastmod: ""
55
tags: []
66
title: 'Eino: The design concept of orchestration'
7-
weight: 0
7+
weight: 2
88
---
99

1010
In the LLM application orchestration solutions, the most popular ones are langchain and langgraph, which officially provide SDKs for Python and TypeScript. These two languages are known for their flexibility, which brings great convenience to SDK development but also causes significant confusion and cognitive burden for SDK users.

content/en/docs/eino/core_modules/chain_and_graph_orchestration/stream_programming_essentials.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ date: "2025-02-11"
44
lastmod: ""
55
tags: []
66
title: Eino Points of Streaming Orchestration
7-
weight: 0
7+
weight: 3
88
---
99

1010
> 💡

0 commit comments

Comments
 (0)