LangGraphの使い方(超基本編)

# LangGraphとは
エージェントワークフローを作成するために使用されるLLMアプリ構築するためのライブラリです。

https://www.langchain.com/langgraph

AIエージェントが今後の流行になるとのことでしたので、LangGraphの基本的な使用方法を試してみました。

# インストール
```bash
pip install -U langgraph
```

# LangGraphの概念
Graphは基本的に「Node」と「Edge」という要素で構成されている。
- Node
    - 処理部分
- Edge
    - Node同士の接続部分

```mermaid
graph LR
    Node1 -- edge1 --> Node2
    Node2 -- edge2 --> Node3
```

Stateというアプリのスナップショットを表す共有データ構造もある。

NodeとEdgeを組み合わせることで、時間経過と共にStateが変化するワークフローを構成することができる。

https://langchain-ai.github.io/langgraph/concepts/low_level/

# シンプルなグラフ
## Stateの定義
`TypedDict`で`State`クラスを定義する。
```python
from typing_extensions import TypedDict

class State(TypedDict):
    value: str
```

## Graphの作成
`StateGraph`に定義した`State`クラスを引数にインスタンスを作成する。
```python
from langgraph.graph import StateGraph

graph = StateGraph(State)
```

## Nodeの作成
`node`は`State`を受け取って、更新したい情報を返す関数として定義する。
今回はNodeを2つ作成し、受け取った文字列に`_node1`や`_node2`を付け加える処理にしている。
```python
def node1(state: State):
    value = state["value"] + "_node1"
    return {"value": value}

def node2(state: State):
    value = state["value"] + "_node2"
    return {"value": value}
```

## GraphにNodeの追加
`graph`の`add_node`メソッドを使用して、NodeをGraphに追加する。
```python
graph.add_node("node1", node1)
graph.add_node("node2", node2)
```

## Edgeの追加
`node1`と`node2`を`add_edge`でEdgeとして接続する。
```python
graph.add_edge("node1", "node2")
```

## 始点と終点を定義
`set_entry_point`で始点を、`set_finish_point`で終点を定義する。
```python
graph.set_entry_point("node")

graph.set_finish_point("node2")
```

## Graphのコンパイル
NodeとEdgeで構成したGraphをコンパイルする。
```python
graph = graph.compile()
```

コンパイルしたGraphからmermaidで可視化したグラフを出力することができる。
```python
from IPython.display import Image, display

display(Image(graph.get_graph().draw_mermaid_png()))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3968617/292c6f88-5001-5db2-b493-93ff2edef8c5.png)

<details><summary>mermaid出力方法</summary>

```python
print(graph.get_graph().draw_mermaid())
```

```mermaid
%%{init: {'flowchart': {'curve': 'linear'}}}%%
graph TD;
	__start__([<p>__start__</p>]):::first
	node1(node1)
	node2(node2)
	__end__([<p>__end__</p>]):::last
	__start__ --> node1;
	node1 --> node2;
	node2 --> __end__;
	classDef default fill:#f2f0ff,line-height:1.2
	classDef first fill-opacity:0
	classDef last fill:#bfb6fc
```

</details>

## 実行
`invoke`で`State`の初期値を与える。
```python
graph.invoke({"value": "hoge"})
```

出力
```
{'value': 'hoge_node1_node2'}
```

初期値の`hoge`の入力に対して、node1で実行されて`hoge_node1`になり、node2で実行されて`hoge_node1_node2`になっていて、期待した動作になっている。

### デバッグ
`invoke`の引数で、`debug`を`True`にすることで実行時の情報を可視化できる。
```python
graph.invoke({"value": "hoge"}, debug=True)
```

出力
```bash
[-1:checkpoint] State at the end of step -1:
{}
[0:tasks] Starting 1 task for step 0:
- __start__ -> {'value': 'hoge'}
[0:writes] Finished step 0 with writes to 1 channel:
- value -> 'hoge'
[0:checkpoint] State at the end of step 0:
{'value': 'hoge'}
[1:tasks] Starting 1 task for step 1:
- node1 -> {'value': 'hoge'}
[1:writes] Finished step 1 with writes to 1 channel:
- value -> 'hoge_node1'
[1:checkpoint] State at the end of step 1:
{'value': 'hoge_node1'}
[2:tasks] Starting 1 task for step 2:
- node2 -> {'value': 'hoge_node1'}
[2:writes] Finished step 2 with writes to 1 channel:
- value -> 'hoge_node1_node2'
[2:checkpoint] State at the end of step 2:
{'value': 'hoge_node1_node2'}
```

Graphの流れを追うことができる。

# まとめ
LangGraphの超基本的な使用方法について試してみました。
AIエージェントは、さらに複雑なGraph構造になると思われるので、とりあえず基本的な使用方法を知れてよかったと思います。
今後は条件分岐やLLMを使用した本格的なAIエージェントの作成を試してみたいと思います。