【基礎確認】pythonのlangchain_core.output_parsersモジュールStrOutputParser関数

# はじめに
[LangChainとLangGraphによるRAG・AIエージェント［実践］入門](https://www.amazon.co.jp/dp/B0DK4YGYBL?tag=xpg-22&linkCode=ogi&th=1&psc=1)
を読んでいて、10章で躓いたので、初心に戻って、一つずつ紐解いて学習することにしました。
今回のテーマは「langchain_core.output_parsers」モジュール「StrOutputParser」関数

# 前回までの投稿
1. 必要なライブラリとモジュールをインポートする
[【基礎確認】pythonのoperatorモジュール](https://qiita.com/o_chan_t/items/4ad3cd5fc832f9be9d86)
[【基礎確認】pythonのtypingモジュール](https://qiita.com/o_chan_t/items/1f54806ad90c79904af2)
[【基礎確認】pythonのdotenvモジュール](https://qiita.com/o_chan_t/items/641eada727fa5a27aaf3)

# pip-list
```
langchain                                0.3.13
langchain-community                      0.3.12
langchain-core                           0.3.27
```


# サンプルコード

```sample.py
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.llms import FakeListLLM

responses = [
    "Pythonは読みやすく簡潔な構文が特徴です。",
    "Pythonは豊富なライブラリとフレームワークを持っています。",
    "Pythonは多目的で、様々な分野で使用されています。"
]

llm = FakeListLLM(responses=responses)
prompt = ChatPromptTemplate.from_messages([
    ("human", "以下の質問に1文で答えてください: {question}")
])

chain = prompt | llm | StrOutputParser()

result = chain.invoke({"question": "Pythonの特徴は何ですか？"})
print(result)
```

## 解説
1. StrOutputParserは、LangChainライブラリの一部で、LLMの出力を文字列として解析するために使用する。
2. サンプルコードでは、FakeListLLMモデルとChatPromptTemplateを使用してチェーンを作成し、StrOutputParserを適用している。
3. FakeListLLMは、テストやデモンストレーション用に事前に定義された応答を返すモックLLM。
4. チェーンは、プロンプト、LLM、StrOutputParserの順に連結されている。
5. プロンプトの出力がLLMに渡され、その結果がStrOutputParserによって処理される。
6. invoke()メソッドを使用してチェーンを実行し、結果を文字列として取得する。
7. FakeListLLMは、定義された応答リストから順番に返答を提供する。
8. 実際のLLM APIを呼び出すことなく、LangChainのワークフローをテストしたり、デモンストレーションを行う。

# StrOutputParser()を使う効果が分かる例
```sample.py
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.llms import FakeListLLM
import json

responses = [
    "Pythonの特徴: 読みやすさ, 豊富なライブラリ, 多目的性",
    json.dumps({"features": ["読みやすさ", "豊富なライブラリ", "多目的性"]}, ensure_ascii=False),
    "特徴:\n1. 読みやすさ\n2. 豊富なライブラリ\n3. 多目的性"
]

llm = FakeListLLM(responses=responses)
prompt = ChatPromptTemplate.from_messages([
    ("human", "以下の質問に答えてください: {question}")
])

chain_with_parser = prompt | llm | StrOutputParser()
chain_without_parser = prompt | llm

for i in range(3):
    result_with_parser = chain_with_parser.invoke({"question": "Pythonの特徴は何ですか？"})
    result_without_parser = chain_without_parser.invoke({"question": "Pythonの特徴は何ですか？"})
    
    print(f"回答 {i+1}:")
    print("【StrOutputParserあり】\n", type(result_with_parser), "\n", result_with_parser)
    print()
    print("【StrOutputParserなし】\n", type(result_without_parser), "\n", result_without_parser)
    print()

```

```
回答 1:
【StrOutputParserあり】
 <class 'str'>
 Pythonの特徴: 読みやすさ, 豊富なライブラリ, 多目的性

【StrOutputParserなし】
 <class 'str'>
 {"features": ["読みやすさ", "豊富なライブラリ", "多目的性"]}

回答 2:
【StrOutputParserあり】
 <class 'str'>
 特徴:
1. 読みやすさ
2. 豊富なライブラリ
3. 多目的性

【StrOutputParserなし】
 <class 'str'>
 Pythonの特徴: 読みやすさ, 豊富なライブラリ, 多目的性

回答 3:
【StrOutputParserあり】
 <class 'str'>
 {"features": ["読みやすさ", "豊富なライブラリ", "多目的性"]}

【StrOutputParserなし】
 <class 'str'>
 特徴:
1. 読みやすさ
2. 豊富なライブラリ
3. 多目的性
```