【AIエージェント入門】LangChain・LangGraphによるエージェント開発　その①複数のモデルを使ってみる

どうも。@TM_AIbuchoことおっさんです。
SES企業の社長が開発経験ゼロからAIを学習しています。
是非とも暖かく、時には厳しく見守っていただけると嬉しいです。

# はじめに AIエージェントとは

AIエージェントの定義は明確ではないですが、**一般的には特定の目的に応じて自律的に目標を設定し、タスクを実行していくシステム**をAIエージェントといわれています。

LangChainによるAIエージェント開発を目指していきます。
以下書籍を参考にしています。
[LangChainとLangGraphによるRAG・AIエージェント［実践］入門 (エンジニア選書) 単行本（ソフトカバー） – 2024/11/9   西見 公宏 (著), 吉田 真吾 (著), 大嶋 勇樹 (著)](https://amzn.asia/d/4zaK7Ls)

---

# LangChain

LangChainは、大規模言語モデル（LLM）に基づいてアプリケーションを構築するためのオープンソースフレームワークです。

プロンプト作成、メモリ、RAG、ワークフローなど複雑な処理を繋いでLLMアプリケーションを開発できるFWです。比較的簡単に複数のモデルを組み合わせることも可能。
PythonとJavascriptに対応しています。

# それでは実装していく！　まずは基本機能から

GoogleColab上で実装していきます。
まずはLangChain-coreとLangChain-openaiをインストール

``` Python
!pip install langchain-core==0.3.0 langchain-openai==0.2.0
```

OpenAIのAPIキーをGoogleColabのシークレットに登録。読み込みます。

``` Python:入力
import os
from google.colab import userdata

os.environ["OPENAI_API_KEY"] = userdata.get("OPENAI_API_KEY")
```

``` Python:入力
model = OpenAI(model="gpt-4o-mini",temperature=0)
output = model.invoke("こんにちは。あなたは誰ですか？")
print(output)
```
``` Python:結果
---------------------------------------------------------------------------
NotFoundError                             Traceback (most recent call last)
<ipython-input-9-ebced5ade7ce> in <cell line: 4>()
      2 
      3 model = OpenAI(model="gpt-4o-mini",temperature=0)
----> 4 output = model.invoke("こんにちは。あなたは誰ですか？")
      5 print(output)

10 frames
/usr/local/lib/python3.10/dist-packages/openai/_base_client.py in _request(self, cast_to, options, retries_taken, stream, stream_cls)
   1057 
   1058             log.debug("Re-raising status error")
-> 1059             raise self._make_status_error_from_response(err.response) from None
   1060 
   1061         return self._process_response(

NotFoundError: Error code: 404 - {'error': {'message': 'This is a chat model and not supported in the v1/completions endpoint. Did you mean to use v1/chat/completions?', 'type': 'invalid_request_error', 'param': 'model', 'code': None}}
```

エラーが出ました。gpt-4o-miniのモデルはCompletionsAPIで使えないらしいのでgpt-3.5-turboに変更してみます。

``` Python:入力
from langchain_openai import OpenAI

model = OpenAI(model="gpt-3.5-turbo-instruct",temperature=0)
output = model.invoke("こんにちは。あなたは誰ですか？")
print(output)
```

``` Python:結果

私はAIのチャットボットです。あなたのお話し相手としてプログラムされています。どのようにお手伝いしましょうか？
```

4oや4o-miniを使う場合は、ChatCompletionsAPIを使います。

``` Python:入力
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4o-mini",temperature=0)

messages = [
    SystemMessage("あなたは優秀なアシスタントです。"),
    HumanMessage("こんにちは！わたしは承太郎です。"),
    AIMessage(content="こんにちは、承太郎さん！あなたのお役にたてるように頑張ります。なにか困ってることはありますか？"),
    HumanMessage("わたしの名前は？"),
]
```
``` Python:結果
あなたの名前は承太郎さんですね！何か他にお話ししたいことがありますか？
```

LangChainではChatCompletionsAPIでのroleを、SystemMessage、HumanMessage、AIMessageとしている。
これでプロンプトを作っていきます。

``` Python:入力
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4o-mini",temperature=0)

messages = [
    SystemMessage("あなたは優秀なアシスタントです。"),
    HumanMessage("きみに名前を授けよう。そうだな、猫型ロボットのドラ男とでもしようか。"),
    AIMessage(content="ありがとうございます！猫型ロボットのドラ男です。あなたのお役にたてるように頑張ります。なにか困ってることはありますか？"),
    HumanMessage("君の名は。"),
]
```
``` Python:結果
私の名前はドラ男です！猫型ロボットとして、あなたのお手伝いをするためにここにいます。何か質問やリクエストがあれば教えてくださいね！
```

OpenAIではなくGeminiを使ってみます。（もちろんClaude先生に聞きながら） geminiだとroleとpartsが必要で、convert_messages_to_gemini_formatを作成する必要があるとのこと。違ってたら教えて下さい・・・！

``` Python:入力
import os
from google.colab import userdata
import google.generativeai as genai
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage

api_key = userdata.get("GEMINI_API_KEY")
genai.configure(api_key=api_key)

model = genai.GenerativeModel('gemini-1.5-pro')
chat = model.start_chat()

def convert_messages_to_gemini_format(messages):
   gemini_messages = []
   for msg in messages:
       if isinstance(msg, SystemMessage):
           role = "user"
           content = f"システム: {msg.content}"
       elif isinstance(msg, HumanMessage):
           role = "user"
           content = msg.content
       elif isinstance(msg, AIMessage):
           role = "model"
           content = msg.content
       gemini_messages.append({"role": role, "parts": [content]})
   return gemini_messages

messages = [
   SystemMessage("あなたは優秀なアシスタントです。"),
   HumanMessage("来週は熱海に、来月は沖縄に、来年は北海道にいきます。"),
   AIMessage(content="そうなんですね！なにか聞きたいことがあれば何でも質問してください。"),
   HumanMessage("来年はどこにいく？"),
]

chat = model.start_chat(history=convert_messages_to_gemini_format(messages[:-1]))
response = chat.send_message(messages[-1].content)
print(response.text)
```
``` Python:回答：Gemini
来年は北海道に行くとおっしゃっていましたね。
```

LangChainのCallback機能を使うことで、生成される回答をストリーミングで出力させることも簡単にできる。
これだとわからないですが、ストリーミングで出力されてます。
Gif動画にしたいところですが、~~面倒なので~~いつかアップデートすることにします。


``` Python:入力
from langchain_core.callbacks import StreamingStdOutCallbackHandler

model = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0,
    streaming=True,
    callbacks=[StreamingStdOutCallbackHandler()]
)

messages = [
    SystemMessage("あなたは優秀なアシスタントです。"),
    HumanMessage("坂本龍馬が作った会社は？"),
]

ai_message = model.invoke(messages)
```
``` Python:結果
坂本龍馬が作った会社は「亀山社中」です。亀山社中は1865年に設立され、貿易や海運を行う商社として活動しました。坂本龍馬はこの会社を通じて、幕末の日本における商業の発展や、明治維新に向けた動きに寄与しました。後に亀山社中は「海援隊」と改称され、政治的な活動にも関与するようになりました。
```

続いて、個人的に大好きなAnthoropicのClaudeも使ってみます。
Langchain-anthropicをインストールします。

``` Python:入力
!pip install langchain-core==0.3.0 langchain-anthropic
```

Claueのモデルnameと料金情報はここに記載がありました。
https://docs.anthropic.com/en/docs/about-claude/models

ケチって一番安いモデルにします。

``` Python:結果
import os
from google.colab import userdata
from langchain_anthropic import ChatAnthropic
from langchain_core.callbacks import StreamingStdOutCallbackHandler

os.environ["CLAUDE_API_KEY"] = userdata.get("CLAUDE_API_KEY")

model = ChatAnthropic(
    model="claude-3-haiku-20240307",  
    streaming=True,
    anthropic_api_key=os.environ["CLAUDE_API_KEY"],
    callbacks=[StreamingStdOutCallbackHandler()]
)

messages = [
    SystemMessage("あなたは優秀なアシスタントです。"),
    HumanMessage("竜馬がゆくの作者は？"),
]

ai_message = model.invoke(messages)
```

``` Python:結果
「竜馬がゆく」の作者は、司馬遼太郎です。

司馬遼太郎は、日本の歴史小説家として有名な作家です。「竜馬がゆく」は、彼の代表作の1つで、明治維新期の志士、坂本竜馬を主人公にした歴史小説です。1961年に上梓され、以後多くの読者に愛されてきた作品です。

司馬遼太郎は、日本の近代史を専門に研究し、数多くの歴史小説を生み出した作家として知られています。「坂本竜馬伝」「幕末維新史」などの代表作を通じて、明治維新の時代を生き抜いた英雄的人物像を描き出すことで高い評価を得ています。
```

LangChainをつかってLLMをAPI経由で使う最も基本的な方法をやってみました。
次回からはLangChainの主要な機能、PromptTemplate、Output parser、Chain - LangChaiin Expression Language(LCEL)、RAG実装などやっていきます！

開発ド素人なので、認識間違っていたりおかしなところあったらアドバイスいただけると嬉しいです～

# まとめ

今回はLangChainの基本的な機能として、OpenAI、Google、Anthropicの各種LLM APIを利用した実装を行いました。

- OpenAIのAPIでは、Completions APIとChat Completions APIで使えるモデルが異なります
- LangChainでは、メッセージの種類をSystemMessage、HumanMessage、AIMessageとして区別します
- Geminiではroleとpartsの指定が必要で、メッセージの変換処理が必要です
- ストリーミング出力はCallBack機能を使うことで簡単に実装できます

次回は、LangChainのより発展的な機能として以下の実装に取り組んでいきます：

- PromptTemplate
- Output parser
- Chain - LangChain Expression Language (LCEL)
- RAG実装