LangGraph入門：LLMなしで基本ワークフローを構築してみる

LangGraphは、生成AI（LLM）を活用したアプリケーションの**ワークフローを簡潔に定義・実行できるライブラリ**です。

ワークフローは「ノード」と「エッジ」を使って構築し、エッジによって処理の順序や条件分岐を定義します。

この仕組みによって、複雑なロジックもグラフ（有向グラフ）として整理でき、生成AIを絡めた高度な処理フローもスムーズに表現可能です。

今回は、**LLMを使わずに**まずはシンプルな関数をノードとして組み込み、基本的な挙動を確認します。

後々、LLMによるテキスト生成や外部APIへの問い合わせなどを繋げる下準備として、まずは基礎構築に慣れてみましょう。

## 環境

- Python 3.12
- langgraphライブラリ（`poetry add langgraph` などでインストールできます）

## 最初の一歩：シンプルなグラフ

### シンプルなノードとエッジ

以下は、`add_one`という単純な関数をノードとしてグラフに追加した例です。

`START`から`add_one`へ繋ぐエッジを張ることで、処理の入口として`add_one`が実行されます。

```python
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START

# 状態を表すためのTypedDict
class State(TypedDict):
    total: int

def add_one(state: State):
    # totalを1加算する単純な処理
    return {"total": state["total"] + 1}

graph_builder = StateGraph(State)
graph_builder.add_node("add_one", add_one)
graph_builder.add_edge(START, "add_one")  # START → add_one
graph = graph_builder.compile()

print(graph.invoke({"total": 5}))
```

### 実行結果

```bash
{'total': 6}
```

`{"total": 5}`が`{"total": 6}`に変わりました。

ここで、`END`へのエッジを明示しなくても、エラーにはなりません。

`add_edge(START, "add_one")`は`set_entry_point("add_one")`で置き換えることも可能で、最初に実行されるノードを指定する方法が複数ある点も覚えておきましょう。

これで、`START -> add_one -> END`という非常にシンプルなフローが定義できました。

## 条件分岐を導入する

### `add_conditional_edges`で条件分岐

LangGraphでは、`add_conditional_edges`メソッドを使うことで、特定のノード実行後に条件判定を行い、結果に応じて次のノードを分岐させることができます。

以下の例では、`add_five`で`total`に5を足した後、`even_or_odd`関数で偶数・奇数を判定し、その結果に応じて`show_even`または`show_odd`を呼び出しています。

```python
from typing_extensions import TypedDict
from langgraph.graph import StateGraph

class State(TypedDict):
    total: int

def add_five(state: State):
    return {"total": state["total"] + 5}

def even_or_odd(state: State):
    return "even" if state["total"] % 2 == 0 else "odd"

def show_even(state: State):
    print(f"{state['total']} is even")

def show_odd(state: State):
    print(f"{state['total']} is odd")

graph_builder = StateGraph(State)
graph_builder.add_node("add_five", add_five)
graph_builder.set_entry_point("add_five")
graph_builder.add_node("show_even", show_even)
graph_builder.add_node("show_odd", show_odd)
graph_builder.add_conditional_edges(
    source="add_five",    # add_five実行後に条件分岐
    path=even_or_odd,     # 偶数・奇数を判定する関数
    path_map={"even": "show_even", "odd": "show_odd"},
)
graph = graph_builder.compile()

graph.invoke({"total": 6})
```

### 実行結果

```bash
11 is odd
```

`{'total': 6}`で開始し、`add_five`で`{'total': 11}`となり、`even_or_odd`が`"odd"`を返したため、`show_odd`ノードが実行されました。

これにより、**条件に応じたフロー分岐**が簡単に実装できます。

## 繰り返し処理（ループ）の実装

### 条件を満たすまで繰り返す

`add_conditional_edges`を用いて、特定の条件が満たされるまで同じノードを繰り返すことも可能です。

以下は`total`が`10`を超えるまで`add_one`を繰り返し実行する例です。

```python
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, END

class State(TypedDict):
    total: int

def add_one(state: State):
    return {"total": state["total"] + 1}

def is_over_10(state: State):
    # totalの値分"☆ "を出力し、totalが10を超えるか判定
    print("☆ " * state["total"])
    return state["total"] > 10

graph_builder = StateGraph(State)
graph_builder.add_node("add_one", add_one)
graph_builder.set_entry_point("add_one")
graph_builder.add_conditional_edges(
    source="add_one",
    path=is_over_10,
    path_map={True: END, False: "add_one"},
)
graph = graph_builder.compile()

graph.invoke({"total": 0})
```

### 実行結果

```bash
☆
☆ ☆
☆ ☆ ☆
☆ ☆ ☆ ☆
☆ ☆ ☆ ☆ ☆
☆ ☆ ☆ ☆ ☆ ☆
☆ ☆ ☆ ☆ ☆ ☆ ☆
☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆
☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆
☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆
☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆ ☆
```

`total`が0から始まり、`add_one`を繰り返し呼び出して`total`を increment し続け、`is_over_10`がTrueを返すまでループします。

最終的に`total`が11になった段階で終了しました。

## まとめ

- LangGraphは、ノード（関数）とエッジ（処理フロー）によって構造的にワークフローを定義できるライブラリです。
- LLMを用いずとも、基本的なノード追加・条件分岐・ループの仕組みを理解できます。
- 複雑な処理やLLMとの連携を見据える前に、このようなシンプルな例で基礎を固めておくと、後々応用が容易になります。

本記事ではあくまで基本的な使い方の一端を紹介しましたが、LangGraphはこれ以外にもさまざまな機能を持っています。

是非公式ドキュメントや実際のコード例を参照し、LLMや外部APIなどを組み合わせたより高度なワークフロー構築にも挑戦してみてください。

### 参考リンク

- [LangGraph リファレンス](https://langchain-ai.github.io/langgraph/)
- [StateGraph クラスの詳細](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.state.StateGraph)

以上で、LangGraphの基本ワークフロー構築例の紹介でした。