Closed11

LCEL(Langchain Expression Language)の練習ノート

もぶもぶもぶもぶ

Prompt + LLM
https://python.langchain.com/docs/expression_language/cookbook/prompt_llm_parser

from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from dotenv import load_dotenv

load_dotenv()

prompt = ChatPromptTemplate.from_template("{topic}に関するポエムを書いてください")
model = ChatOpenAI()
chain = prompt | model
print(chain.invoke({"topic": "ゲームキューブ"}))
content='青い空に輝く\n蒼き箱、ゲームキューブ\n青春の日々を彩る\n夢中で遊ぶ、その姿\n\nメモリーカードに\n宿る数々の冒険\nマリオやゼルダ、ポケモン\n時を超えて続く物語\n\n友と共に戦い、競い合い\n手に汗握 る瞬間\nコントローラーを握りしめて\n次々とクリアを目指す\n\n四方八方から響く\nゲームキューブの音楽\n リズムに乗って心躍り\n現実を忘れるひととき\n\nあの頃の思い出は\n今も心に刻まれている\nゲームキューブ 、永遠の存在\n愛され続ける名機\n\n青い箱、ゲームキューブ\n遊び尽くした日々も\n今でも輝き続ける\n永遠 のゲーム機、ゲームキューブ'
もぶもぶもぶもぶ

プログラム

from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from dotenv import load_dotenv

load_dotenv()

prompt = ChatPromptTemplate.from_template("{topic}に関する大喜利をしてください")
model = ChatOpenAI(temperature=1.0, model="gpt-4")
functions = [
    {
        "name": "ogiri",
        "description": "A ogiri",
        "parameters": {
            "type": "object",
            "properties": {
                "setup": {"type": "string", "description": "大喜利のお題"},
                "punchline": {
                    "type": "string",
                    "description": "大喜利の回答",
                },
            },
            "required": ["setup", "punchline"],
        },
    }
]

chain = prompt | model.bind(function_call={"name": "ogiri"}, functions=functions)

print(chain.invoke({"topic": "ゲームキューブ"}))

functionsだけじゃなくfunction_callも別で渡さないといけない理由がまだわからない

実行結果

content='' additional_kwargs={'function_call': {'name': 'ogiri', 'arguments': '{\n"setup": "ゲームキューブが突然、難解な数学の問題を出してきたら何を
言い出すか?",\n"punchline": "「スクエア(四角)じゃなくて、キューブ(立方体)だから当然、立方数の計算を覚えてるよね?」"\n}'}}

🤔

Langsmithでのトレース


もぶもぶもぶもぶ

入力と出力の整形を入れて使いやすくしてみる

from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from dotenv import load_dotenv
from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser
from langchain.schema.runnable import RunnableMap, RunnablePassthrough

load_dotenv()

prompt = ChatPromptTemplate.from_template("{topic}に関する大喜利をしてください")
model = ChatOpenAI(temperature=1.0, model="gpt-4")
functions = [
    {
        "name": "ogiri",
        "description": "A ogiri",
        "parameters": {
            "type": "object",
            "properties": {
                "setup": {"type": "string", "description": "大喜利のお題"},
                "punchline": {
                    "type": "string",
                    "description": "大喜利の回答",
                },
            },
            "required": ["setup", "punchline"],
        },
    }
]

map_ = RunnableMap({"topic": RunnablePassthrough()})
chain = (
    map_
    | prompt
    | model.bind(function_call={"name": "ogiri"}, functions=functions)
    | JsonOutputFunctionsParser()
)

result = chain.invoke("ゲームキューブ")
print(result)

{'setup': 'ゲームキューブが突然しゃべりだしたらどうしますか?', 'punchline': '突然の事態に驚きつつも、まずは「スマブラ勝負、お願いします」とお願いしてみます。'}
もぶもぶもぶもぶ

https://python.langchain.com/docs/expression_language/cookbook/retrieval

RAGもきれいにかけるなー
ぱっと見とっつきにくかったけど、LCELいいですね

from operator import itemgetter

from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.schema.output_parser import StrOutputParser
from langchain.vectorstores import FAISS
from dotenv import load_dotenv

load_dotenv()

vectorstore = FAISS.from_texts(
    ["harrison worked at kensho"], embedding=OpenAIEmbeddings()
)
retriever = vectorstore.as_retriever()

model = ChatOpenAI()
template = """Answer the question based only on the following context:
{context}

Question: {question}

Answer in the following language: {language}
"""
prompt = ChatPromptTemplate.from_template(template)

chain = (
    {
        "context": itemgetter("question") | retriever,
        "question": itemgetter("question"),
        "language": itemgetter("language"),
    }
    | prompt
    | model
    | StrOutputParser()
)

result = chain.invoke({"question": "where did harrison work", "language": "japanese"})
print(result)
ハリソンはケンショで働きました。
もぶもぶもぶもぶ

うーーーん、記憶管理周りは、宣言的なスタイルだと難しいか......
ライブラリとしてもまだ未整備の領域っぽいし一旦スキップ

もぶもぶもぶもぶ

https://python.langchain.com/docs/expression_language/cookbook/sql_db

SQLのスキーマ定義に応じて質問に答えるためのSQLを生成するところまで

from langchain.prompts import ChatPromptTemplate
from langchain.utilities import SQLDatabase
from dotenv import load_dotenv
from operator import itemgetter
from langchain.chat_models import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnableLambda, RunnableMap


load_dotenv()

template = """Based on the table schema below, write a SQL query that would answer the user's question:
{schema}

Question: {question}
SQL Query:"""
prompt = ChatPromptTemplate.from_template(template)

db = SQLDatabase.from_uri("sqlite:///./chinook.db")


def get_schema(_):
    return db.get_table_info()


model = ChatOpenAI()


inputs = {"schema": RunnableLambda(get_schema), "question": itemgetter("question")}
sql_response = (
    RunnableMap(inputs) | prompt | model.bind(stop=["\nSQLResult:"]) | StrOutputParser()
)

result = sql_response.invoke({"question": "How many employees are there?"})
print(result)
SELECT COUNT(*) FROM employees;
もぶもぶもぶもぶ
from langchain.prompts import ChatPromptTemplate
from langchain.utilities import SQLDatabase
from dotenv import load_dotenv
from operator import itemgetter
from langchain.chat_models import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnableLambda, RunnableMap


load_dotenv()

template = """Based on the table schema below, write a SQL query that would answer the user's question:
{schema}

Question: {question}
SQL Query:"""
prompt = ChatPromptTemplate.from_template(template)

db = SQLDatabase.from_uri("sqlite:///./chinook.db")


def get_schema(_):
    return db.get_table_info()


model = ChatOpenAI()


inputs = {"schema": RunnableLambda(get_schema), "question": itemgetter("question")}
sql_response = (
    RunnableMap(inputs) | prompt | model.bind(stop=["\nSQLResult:"]) | StrOutputParser()
)


res_template = """Based on the table schema below, question, sql query, and sql response, write a natural language response:
{schema}

Question: {question}
SQL Query: {query}
SQL Response: {response}"""
prompt_response = ChatPromptTemplate.from_template(res_template)

full_chain = (
    RunnableMap(
        {
            "question": itemgetter("question"),
            "query": sql_response,
        }
    )
    | {
        "schema": RunnableLambda(get_schema),
        "question": itemgetter("question"),
        "query": itemgetter("query"),
        "response": lambda x: db.run(x["query"]),
    }
    | prompt_response
    | model
)

result = full_chain.invoke({"question": "How many employees are there?"})
print(result)
content='There are 8 employees.'
もぶもぶもぶもぶ

https://python.langchain.com/docs/expression_language/cookbook/multiple_chains

複数のChainを連結する方法
※ HaskellのArrowのプログラミングみたいになってきた

from operator import itemgetter

from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser

from dotenv import load_dotenv

load_dotenv()

prompt1 = ChatPromptTemplate.from_template("{person}の出身国はどこですか?国名だけを答えてください")
prompt2 = ChatPromptTemplate.from_template("{country}の有名な観光地はどこですか? {language}で答えてください")

model = ChatOpenAI()

chain1 = prompt1 | model | StrOutputParser()
chain2 = (
    {"country": chain1, "language": itemgetter("language")}
    | prompt2
    | model
    | StrOutputParser()
)

result = chain2.invoke({"person": "シェイクスピア", "language": "日本語"})
print(result)

もぶもぶもぶもぶ

split and merge

from operator import itemgetter

from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough

from dotenv import load_dotenv

load_dotenv()

planner = (
    ChatPromptTemplate.from_template("ディベートの参加者として、このテーマに関する主張を一つ生成してください: {topic}")
    | ChatOpenAI()
    | StrOutputParser()
    | {"base_response": RunnablePassthrough()}
)

arguments_pros = (
    ChatPromptTemplate.from_template("この主張に対する賛成意見を列挙してください: {base_response}")
    | ChatOpenAI()
    | StrOutputParser()
)

arguments_cons = (
    ChatPromptTemplate.from_template("この主張に対する反対意見を列挙してください: {base_response}")
    | ChatOpenAI()
    | StrOutputParser()
)

final_responder = (
    ChatPromptTemplate.from_messages(
        [
            ("ai", "{original_response}"),
            ("human", "Pros:\n{pros}\n\nCons:\n{cons}"),
            ("system", "以上の議論をまとめてください"),
        ]
    )
    | ChatOpenAI()
    | StrOutputParser()
)

chain = (
    planner
    | {
        "pros": arguments_pros,
        "cons": arguments_cons,
        "original_response": itemgetter("base_response"),
    }
    | final_responder
)

result = chain.invoke({"topic": "人工知能は人間を超えるか"})
print(result)
まとめると、人工知能は人間を超える可能性があるという主張には以下のような理由があります。

1. 人工知能は計算能力や情報処理能力において人間を凌駕する可能性があるため、複雑な問題の解決や予測が正確に行える可能性がある。
2. 人工知能は疲れずに連続的な作業を行えるため、効率的な作業の実現が期待できる。
3. 人工知能は客観的な結果を導くことができるため、感情やバイアスによる影響を受けず、より公平な意思決定が可能となる。
4. 人工知能は人間の制約を受けないため、危険な環境や過酷な条件下での作業や探索が可能となる。
5. 人工知能の発展により、新たな産業やビジネスの創造が可能となり、経済成長や社会的な発展を促進することができる。    

一方で、人工知能が人間を超えるという主張には以下のような反論も存在します。

1. 人工知能は人間の創造性や直感的な思考を理解することはできないため、人間の能力を超えることはあり得ない。
2. 人工知能は倫理的な判断や道徳的な価値観を持つことができないため、人間が行うような重要な意思決定や問題解決には適さない。
3. 人工知能が人間の仕事を代替することで失業問題が生じる可能性がある。
4. 人工知能の結果は情報の信頼性に欠ける場合があり、人間の経験や直感に基づく判断が重要である。
5. 人工知能の発展が進むと、人間の成長や発展が制限される可能性がある。

したがって、人工知能が人間を超える可能性がある一方で、人間と人工知能の相補的な関係を築くことが重要であり、倫理的な 視点や社会的な配慮を持って人工知能の活用を進めるべきです。

途中経過も出力できないとつらいな。やり方あるんだっけ

このスクラップは2023/10/08にクローズされました