Skip to content

Commit 1645e1c

Browse files
authored
Feat/ext langgraph checkpoint (#868)
* feat: align put, put_writes and get_tuple to redis checkpoint saver for consistincy Signed-off-by: Casper Nielsen <[email protected]> * chore: include new import of python-ulid for langgraph checkpoint support Signed-off-by: Casper Nielsen <[email protected]> * chore: ruff formatting Signed-off-by: Casper Nielsen <[email protected]> * fix: include missing import of msgpack Signed-off-by: Casper Nielsen <[email protected]> * fix: ensure handing of empty checkpoint_id passed in config to put_writes Signed-off-by: Casper Nielsen <[email protected]> * chore: align extract of config between put and put_writes Signed-off-by: Casper Nielsen <[email protected]> * fix: handle str retrieval for get_tuple with extra type checking Signed-off-by: Casper Nielsen <[email protected]> * chore: add example for ext-langgraph Signed-off-by: Casper Nielsen <[email protected]> * fix: rename to redis-memory Signed-off-by: Casper Nielsen <[email protected]> * feat: add sqlite component Signed-off-by: Casper Nielsen <[email protected]> * fix: remove refs to redis Signed-off-by: Casper Nielsen <[email protected]> * chore: update readme with details on dual state component setup Signed-off-by: Casper Nielsen <[email protected]> * fix: add guard for None metadata Signed-off-by: Casper Nielsen <[email protected]> * test: update test case to handle new output format Signed-off-by: Casper Nielsen <[email protected]> * chore: remove redundant graph .compile() call Signed-off-by: Casper Nielsen <[email protected]> * fix: remove statestores and rely on existing metadata created Signed-off-by: Casper Nielsen <[email protected]> * fix: delete files not needed to align with ci testing Signed-off-by: Casper Nielsen <[email protected]> * fix: rename to agent.py & simplify Signed-off-by: Casper Nielsen <[email protected]> * chore: align deps Signed-off-by: Casper Nielsen <[email protected]> * fix: correct readme to align with other examples Signed-off-by: Casper Nielsen <[email protected]> * chore: add extra validation lines Signed-off-by: Casper Nielsen <[email protected]> * feat: add langgraph-checkpointer to test Signed-off-by: Casper Nielsen <[email protected]> * chore: ruff formatting Signed-off-by: Casper Nielsen <[email protected]> * fix: add instruction for the OPENAI_API_KEY export Signed-off-by: Casper Nielsen <[email protected]> * feat: attempt using smaller llama model for examples testing Signed-off-by: Casper Nielsen <[email protected]> * fix: correct deps for ci install Signed-off-by: Casper Nielsen <[email protected]> * feat: ensure ci installs required dependencies Signed-off-by: Casper Nielsen <[email protected]> * chore: formatting Signed-off-by: Casper Nielsen <[email protected]> * fix: ensure ollama runs as a bg process Signed-off-by: Casper Nielsen <[email protected]> * fix: be more concise in the multiply ask Signed-off-by: Casper Nielsen <[email protected]> * fix: the small model isn't consistent enough for CI to depend on it. Add sleep to ensure ollama us serving before pulling model Signed-off-by: Casper Nielsen <[email protected]> * fix: simplify verification strings to handle non determinism in response Signed-off-by: Casper Nielsen <[email protected]> --------- Signed-off-by: Casper Nielsen <[email protected]>
1 parent 126825d commit 1645e1c

File tree

9 files changed

+499
-71
lines changed

9 files changed

+499
-71
lines changed

.github/workflows/validate_examples.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ jobs:
8888
uses: actions/setup-go@v5
8989
with:
9090
go-version: ${{ env.GOVER }}
91+
- name: Set up Llama
92+
run: |
93+
curl -fsSL https://ollama.com/install.sh | sh
94+
nohup ollama serve &
95+
sleep 10
96+
ollama pull llama3.2:latest
9197
- name: Checkout Dapr CLI repo to override dapr command.
9298
uses: actions/checkout@v6
9399
if: env.DAPR_CLI_REF != ''
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Dapr For Agents - LangGraph Checkpointer
2+
3+
Supporting Dapr backed Checkpointer for LangGraph based Agents.
4+
5+
## Pre-requisites
6+
7+
- [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started)
8+
- [Install Python 3.10+](https://www.python.org/downloads/)
9+
10+
## Install Dapr python-SDK
11+
12+
<!-- Our CI/CD pipeline automatically installs the correct version, so we can skip this step in the automation -->
13+
14+
<!-- STEP
15+
name: Install deps
16+
-->
17+
18+
```sh
19+
pip3 install -r requirements.txt
20+
```
21+
22+
<!-- END_STEP -->
23+
24+
## Run the example
25+
26+
Export your `OPENAI_API_KEY`:
27+
28+
```bash
29+
export OPENAI_API_KEY="SK-..."
30+
```
31+
32+
Run the following command in a terminal/command prompt:
33+
34+
<!-- STEP
35+
name: Run subscriber
36+
expected_stdout_lines:
37+
- '== APP == Add 3 and 4.'
38+
- '== APP == a: 3'
39+
- '== APP == b: 4'
40+
- '== APP == 7'
41+
- '== APP == Args:'
42+
- '== APP == a: 7'
43+
- '== APP == b: 2'
44+
- '== APP == 14'
45+
46+
output_match_mode: substring
47+
background: true
48+
match_order: none
49+
sleep: 15
50+
-->
51+
52+
```bash
53+
# 1. Run the LangGraph agent
54+
dapr run --app-id langgraph-checkpointer --app-port 5001 --resources-path ./components -- python3 agent.py
55+
```
56+
57+
<!-- END_STEP -->
58+
59+
## Cleanup
60+
61+
Either press CTRL + C to quit the app or run the following command in a new terminal to stop the app:
62+
63+
```bash
64+
dapr stop --app-id langgraph-checkpointer
65+
```
66+
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from dapr.ext.langgraph import DaprCheckpointer
2+
from langchain_core.messages import HumanMessage, SystemMessage
3+
from langchain_ollama import ChatOllama
4+
from langgraph.graph import START, MessagesState, StateGraph
5+
from langgraph.prebuilt import ToolNode, tools_condition
6+
7+
8+
def add(a: int, b: int) -> int:
9+
"""Adds a and b.
10+
11+
Args:
12+
a: first int
13+
b: second int
14+
"""
15+
return a + b
16+
17+
18+
def multiply(a: int, b: int) -> int:
19+
"""Multiply a and b.
20+
21+
Args:
22+
a: first int
23+
b: second int
24+
"""
25+
return a * b
26+
27+
28+
tools = [add, multiply]
29+
llm = ChatOllama(model='llama3.2:latest')
30+
llm_with_tools = llm.bind_tools(tools)
31+
32+
sys_msg = SystemMessage(
33+
content='You are a helpful assistant tasked with performing arithmetic on a set of inputs.'
34+
)
35+
36+
37+
def assistant(state: MessagesState):
38+
return {'messages': [llm_with_tools.invoke([sys_msg] + state['messages'])]}
39+
40+
41+
builder = StateGraph(MessagesState)
42+
43+
builder.add_node('assistant', assistant)
44+
builder.add_node('tools', ToolNode(tools))
45+
46+
builder.add_edge(START, 'assistant')
47+
builder.add_conditional_edges(
48+
'assistant',
49+
tools_condition,
50+
)
51+
builder.add_edge('tools', 'assistant')
52+
53+
memory = DaprCheckpointer(store_name='statestore', key_prefix='dapr')
54+
react_graph_memory = builder.compile(checkpointer=memory)
55+
56+
config = {'configurable': {'thread_id': '1'}}
57+
58+
messages = [HumanMessage(content='Add 3 and 4.')]
59+
messages = react_graph_memory.invoke({'messages': messages}, config)
60+
for m in messages['messages']:
61+
m.pretty_print()
62+
63+
messages = [HumanMessage(content='Multiply the result by 2.')]
64+
messages = react_graph_memory.invoke({'messages': messages}, config)
65+
for m in messages['messages']:
66+
m.pretty_print()
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
apiVersion: dapr.io/v1alpha1
2+
kind: Component
3+
metadata:
4+
name: statestore
5+
spec:
6+
type: state.redis
7+
version: v1
8+
metadata:
9+
- name: redisHost
10+
value: localhost:6379
11+
- name: redisPassword
12+
value: ""
13+
- name: actorStateStore
14+
value: "true"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
langchain-core>=1.0.7
2+
langgraph>=1.0.3
3+
langchain-ollama>=1.0.0

0 commit comments

Comments
 (0)