10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LangGraphを試した① ~グラフ編~

Last updated at Posted at 2024-08-23

はじめに

最近 LangGraph を触って見たので、概念やコードの書き方について備忘録的に書いていきたいと思います。
今回はグラフの作成方法についてです。

ステートグラフ

LangGraph は状態を保持してグラフ上を移動しながら各ノードで処理を行うことでタスクを行います。Wikipediaにあるようにグラフとは

数学のグラフ理論におけるグラフ(英: graph)とは数学的構造の一つ。対象の集合で、対象の一部が相互に何らかの脈絡で「関係している」ようなものをいう。ここで対象とは頂点(節点やノードとも)と呼ばれる抽象物であり、互いに関係のある頂点の対は辺(枝やエッジとも)と呼ばれる[1]。

であり、ノード(頂点)をエッジ(辺)で結んだものになります。

まずはグラフを定義しましょう。グラフを作るにはStateを定義する必要があります。StateTypedDictで、以下のコードのように定義されます。

from typing_extensions import Annotated, TypedDict
from langgraph.graph import StateGraph

def reducer(a: list, b: int | None) -> list:
    if b is not None:
        return a + [b]
    return a

class State(TypedDict):
    x: Annotated[list, reducer]
    message: str

graph = StateGraph(State)

Stateは各ノードで更新されます。ノードの戻り値に含まれたキーのみ上書きされますが、xのようにAnnotatedで reducer 関数を設定することにより、リストを加算する形で更新されます。
チャットボットを作成する場合、人間の入力や LLM の応答をリストとして保存したいので、そのための reducer 関数が用意されているのでそれを使うことが多いでしょう。

from typing_extensions import Annotated, TypedDict
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages

class State(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]

graph = StateGraph(State)

ノード

ノードではなんらかの処理を行い、Stateを更新します。
ノードはStateを受け取り、Stateの更新情報のdictを戻り値とした関数として定義されます。
add_nodeでグラフに追加します。

def add_1_node(state: State) -> dict:
    next_x = state['x'][-1] + 1
    return {"x": next_x}

graph.add_node("add_one", add_1_node)

def div_by_2_node(state: State) -> dict:
    next_x = state['x'][-1] / 2
    return {
        "x": next_x,
        "message": "div2!"
    }

graph.add_node("div_by_two", div_by_2_node)

開始・終了用のノードが用意されています。

from langgraph.graph import START ,END

エッジ

単純にノードからノードへ結ぶ場合はadd_edgeで設定できます。

graph.add_edge(START, "add_one")

1つの始点ノードから複数の終点ノードへとエッジを結びたい場合はadd_conditional_edgesを用います。

def is_even(state: State):
    return state['x'][-1] % 2 == 0

graph.add_conditional_edges("add_one", is_even, {True: "div_by_two", False: END})

グラフのコンパイル

残りのエッジを追加します。

graph.add_edge("div_by_two", END)

グラフへのノードとエッジの追加が終わったら最後にグラフをコンパイルします。

app = graph.compile()

数字に1を足し、偶数だったら2で割り、奇数だったらそのままという処理をするグラフが作成されました。
qiita_test_graph.png

実行

Stateの初期値を与えてinvokeすれば実行されます。

result1 = app.invoke({"x": 3})
result2 = app.invoke({"x": 4})

print(result1)
# {'x': [3, 4, 2], 'message': 'div2!'}
print(result2)
# {'x': [4, 5]}

期待通りの処理が行われました。

おわりに

今回は LangGraph でグラフを作り、簡単な計算を行いました。次回はノードでLLMを利用する話を扱いたいと思います。

その②を書きました。

参考文献

LangGraph公式

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?