0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

1.始まりはChatGPT

始まりは、とある12月の夜。寝付かれず、ちょっとChatGPTに聞いてみました。
『太宰治の走れメロスをモチーフにしたショートコメディ、泳げメロスを作成して下さい』と。

始まりのお話

泳げメロス


メロスは泳いでいた。真剣に。いや、むしろ必死だった。
彼の名は「泳げメロス」。かつては走ることに情熱を燃やした青年だったが、ある日、海辺の村に引っ越してからというもの、走ることをやめ、水泳にその情熱を注ぐようになった。


ある日、メロスは村の王・ディオニスに呼び出された。

「メロス、お前を見ていると最近、泳ぎたい衝動に駆られるのだが、村人たちに“泳ぎの自由”を与えると海の危険にさらされるのではないかと思ってな。泳ぎを禁じる法律を作ろうと思う」

これを聞いてメロスは怒った。「王よ、それは村人たちの自由を奪う暴挙だ!」

ディオニスは薄ら笑いを浮かべた。「では、証明してみせろ。人は泳ぎの自由を大切にし、そのために命を懸けることができると」

そこでメロスは叫んだ。「よかろう!私が泳ぎの自由を証明する。3日以内に、海を越えて隣村まで行き、再び戻ってくる!」

ディオニスはにやりと笑った。「よし。だが戻らなければ、お前の友人セリヌンティウスの命をいただく」


翌朝、メロスは海に飛び込んだ。

だが、早々に彼は後悔した。「泳ぐのは好きだが、こんなに遠くまで泳ぐのは初めてだ!」

イルカの集団が現れた。「困ってるのか?」
「おお、頼む!隣村まで送ってくれ!」

イルカたちは快くメロスを乗せて運んでくれた。だが、隣村に到着した瞬間、イルカたちは去ってしまった。

「戻るのはどうするんだ……」


帰り道、波に揉まれながらメロスは苦悩した。

「ああ、セリヌンティウスよ。私を許してくれ!泳ぐのは得意でも、こんな長距離は無理だ!」

だが、彼の叫びを聞いた海亀が現れた。「諦めるな、人間よ。我々が助けてやろう!」

海亀たちに支えられ、メロスは何とか村へ戻ることができた。


3日目の夕方、ディオニスのもとにたどり着いたメロス。

「泳ぎきったぞ!これで泳ぎの自由を証明できた!」

王は驚いた。「お前がここまで来るとは思わなかった。だが、泳ぎの自由を与えれば、みんなが溺れたりするのではないか?」

メロスは息を整えながら答えた。「泳ぎは人の心を自由にする。危険もあるが、それ以上に大切なものを得るのだ!」

ディオニスは静かに頷いた。「お前の努力と情熱に免じて、泳ぎの自由を認めよう」


こうして村には「泳ぎの自由」が戻った。
しかし、それ以来、メロスは村人たちにこう言われるようになった。

「泳ぎで証明するのもいいけど、やっぱり走る方が楽じゃなかった?」

メロスは苦笑いしながら答える。
「それは言わないでくれ……」


出力結果を見て、思いました。『パンチが足りません。ラストでもっと笑いを取れるよう、練り直して下さい』と。

改稿

泳げメロス


メロスは泳いでいた。溺れそうになりながら、必死に。
「泳ぎの自由のためだ!諦めるな、俺!」
そう心の中で叫びながら、彼は波と戦い続けていた。


ことの始まりは村の王・ディオニスとの口論だった。

「王よ、泳ぎを禁じるなんてとんでもない!海は自由の象徴だ!」
「海の自由など必要ない!村人が溺れたらどうする!」

ディオニスはそう言い張ったが、メロスは一歩も引かなかった。

「泳ぎを愛する者が溺れるわけがない!証明してみせよう。俺が隣村まで泳ぎ、また戻る!これで泳ぎの素晴らしさを見せてやる!」

王は面白そうに笑った。「よかろう。ただし、3日以内に戻らなければ、お前の友人セリヌンティウスの命をもらうぞ」

「なに!?セリヌンティウスを巻き込むな!」
「いや、そっちが証明したいと言ったのだ。友情と泳ぎの自由、どちらが本物か見せてもらおう」


翌朝、メロスは海に飛び込んだ。

しかし、10分後。

「くっ、思ったより海ってしょっぱい!」
自信満々だったメロスは、塩水にやられ、すでに体力が尽きかけていた。

そこにイルカの群れが現れた。
「お困りか?」
「イルカ!助けてくれ!隣村まで行きたいんだ!」

イルカたちは快く彼を背中に乗せて運んでくれた。しかし、隣村に着くやいなやイルカたちは去ってしまった。

「おい!戻るのも手伝ってくれよ!」
波間に叫ぶメロスだったが、イルカたちは振り返りもせず泳ぎ去った。


帰り道、メロスは必死に泳いだ。しかし途中でクラゲの群れに遭遇し、さらに体力を奪われる。

「セリヌンティウス、すまない……。俺のせいで君が……!」
そう叫びながら意識が遠のきかけたその時、大きな海亀が現れた。

「乗れ。助けてやる」
「亀!お前が命の恩人だ!」

亀の甲羅に乗ったメロスは、なんとか村へと帰還した。


3日目の夕方、王の前に立つメロス。

「ディオニス!泳ぎの自由を守るため、俺は海を越えて帰ってきた!」

王は驚いた顔をしていた。
「まさか本当に戻るとは……だが、泳ぎの自由が本当に必要なのか、まだ信じきれないな」

メロスは力強く言った。
「泳ぎは人を強くする!友情も守れる!」

すると後ろから、全身ずぶ濡れのセリヌンティウスが現れた。

「ちょっと待て!お前、結局俺を救うために遅れたらどうするか考えたのか?」
「いや、その……泳ぐのに必死で……」

王は大笑いしながら言った。
「泳ぎはいいが、お前の計画性はゼロだな!泳ぎの自由は認めるが、村人たちには浮き輪を配ることにする!」


こうして「泳ぎの自由」は認められたが、村の噂ではこう言われるようになった。

「メロスって結局、泳ぐのが苦手なんじゃないか?」
「だってあいつ、最初からカナヅチだったらしいぞ」

メロスはそれを聞いて青ざめた。
「言わないでくれ……俺は、ただ自由を……!」

今一つパンチが聞いていないので、分析をさせてみました。
『二番目の作品を元に、面白い点、面白くない点、改善すべき点を分析して下さい。』

ChatGPTによる分析結果

分析:二番目の作品「泳げメロス」


面白い点

  1. 設定のギャップ

    • 「走れメロス」のシリアスな物語をベースに、泳ぐという無理のある設定を加えた点がユニーク。
    • メロスが泳ぎに慣れていない描写やイルカ、海亀といった助けを借りる展開がコミカル。
  2. キャラクターのユーモア

    • メロスが自信満々で飛び込むものの、途中で「海がしょっぱい」と嘆くなど、彼の脆さが笑いを誘う。
    • 王の「浮き輪を義務化する」という皮肉めいた提案が秀逸。
  3. セリヌンティウスの登場

    • 最後にセリヌンティウスがずぶ濡れで登場し、メロスにツッコミを入れる構図がテンポよく、意外性がある。
  4. 全体のテンポの良さ

    • シンプルなストーリー展開と、次々と巻き起こるトラブルが読者を飽きさせない。

面白くない点

  1. メロスの動機や行動が浅い

    • 泳ぎを証明する理由や、その過程での苦悩が薄く、キャラクターの行動が説得力に欠ける。
    • 自己中心的に見えるため、共感が得にくい。
  2. セリヌンティウスの役割が弱い

    • セリヌンティウスがほとんど受け身の立場で、最後にツッコむだけで物語への貢献度が低い。
  3. 王のキャラクターが薄い

    • ディオニスの立場や行動にインパクトが少なく、物語を引き立てる存在感がやや不足している。
  4. オチの弱さ

    • 最後の「カナヅチだったらしい」という噂のオチが軽く、パンチが足りない。もっと大きな笑いを狙えそう。

改善すべき点

  1. メロスの動機を強化

    • 泳ぎの自由を守る理由を明確化し、読者が応援したくなるような背景を追加する。
    • 例:「幼い頃、溺れた友人を救えなかった経験がある」などのエピソード。
  2. セリヌンティウスの活躍を増やす

    • セリヌンティウスがメロスの帰還を信じて何か行動する場面を追加すると、物語に深みが出る。
    • 例:村人を説得して「泳ぎ応援団」を結成し、メロスを迎えるシーン。
  3. 王のユーモアを増強

    • ディオニスにもっと意地悪な仕掛けや皮肉を言わせると、笑いが増す。
    • 例:「戻れなかったら村人全員をカナヅチにする!」と脅すなど。
  4. オチを強化

    • メロスの努力を台無しにするような大きな逆転を加えるとインパクトが強まる。
    • 例:「メロスが泳ぎ切ったその日に村が大干ばつで海が干上がった」など、理不尽な展開を追加する。

具体的な改善案:オチの例

  • 例1:「ディオニスが大笑いして言う。『実は泳ぎ禁止法なんて最初から考えてなかったんだ。お前が泳ぐ姿が見たかっただけだ』。メロスは全身が震えた。」
  • 例2:「帰ってきたメロスに村人が冷ややかに言った。『海、浅瀬だぞ?歩いて戻れる距離だったのに』。メロスはその場に崩れ落ちた。」

全体的に、キャラクターの動機を強化し、オチをさらに予想外で痛烈なものにすると、笑いの質が上がりそうです。

なかなか、適切な分析のようでした。期待して、『分析結果を踏まえて、より面白い作品に練り直して下さい』とお願いしてみました。

再改稿

泳げメロス:改訂版


メロスは泳いでいた。いや、溺れかけていた。「泳ぎの自由を守るためだ!」と必死に叫ぶが、口に入った海水でむせる。彼は後悔していた。「走るのにしとけばよかった……!」


事の発端は王・ディオニスの宣言だった。
「泳ぎは禁止だ!海は危険すぎる。村人の安全を守るのが私の義務だ」
メロスは反論する。「海は自由の象徴だ!泳ぎがなければ、人の心は縛られる!」

ディオニスは面白そうに笑った。「では証明してみろ。隣村まで泳ぎ、3日以内に戻ってこれれば泳ぎを許可しよう。ただし、戻らなければ友人セリヌンティウスの命をもらう!」


翌朝、メロスは意気揚々と海に飛び込んだ。だが10分後、彼は波にもまれ、息切れしていた。
「くそっ、海ってこんなにしょっぱいのか……」
その時、イルカの群れが現れる。「困ってるのか?」
「おお、イルカよ!隣村まで送ってくれ!」

イルカたちは快く彼を背中に乗せて運んでくれた。しかし、隣村に着くなりイルカたちは去ってしまった。
「おい!戻るのも手伝えよ!」
波間に叫ぶメロスだったが、イルカたちは振り返りもせず泳ぎ去った。


帰り道、メロスは体力を消耗しながら泳いだ。そこに巨大な海亀が現れる。「乗れ、人間よ」
「亀!お前は命の恩人だ!」

亀の背中で村に帰る途中、メロスは気づいた。「あれ、これって泳ぎじゃなくないか?」


3日目の夕方、ディオニスの前に立つメロス。
「泳ぎの自由を証明したぞ!」
王はニヤリと笑った。「なるほど。だが、泳ぎ切ったのではなく“運ばれた”のではないか?」

セリヌンティウスがずぶ濡れで登場し叫ぶ。「おいメロス!お前が帰ってくるのを待ちながら泳ぐ練習してたら、俺も泳げるようになったぞ!……これ、俺が証明したんじゃないのか?」

ディオニスは大笑いした。「よし、村には泳ぎを認めよう。ただし、浮き輪の着用を義務化する!」


こうして「泳ぎの自由」は認められた。しかし村人たちの間ではこんな噂が流れた。
「メロスって結局泳ぎ苦手だったんじゃないか?」
「いや、あれカナヅチらしいよ」

メロスはその場に崩れ落ちた。
「だから言うなって……!」


改訂ポイント

  1. 動機の強化
    → 自由を守るというテーマをシンプルに強調しつつ、メロスの行動のドタバタ感で笑いを誘う。
  2. セリヌンティウスの役割強化
    → 彼自身が泳ぎを克服するという逆転展開を追加し、友情のズレをコメディに昇華。
  3. オチのインパクト強化
    → メロスが「泳ぎの自由」を守るはずが、自らの泳力の低さで村人に疑われる皮肉な結末を設定。

夜が更けてきたので、眠りにつきました。フローで上手くつないだら、もっと面白いことができないかと思いながら。

2.Amazon Bedrock Flows

2.1.Amazon Bedrock Flowsの概要

最近、一般公開となったAmazon Bedrock Flowsというものがあります。AIモデルを呼出すプロンプトやエージェントを、ローコードでつないでフローを作る仕組みです。

参考資料:Amazon Bedrock Flows が一般公開されました | DevelopersIO

2.2.作成したプロンプト

あらすじを何本か作成し、あらすじごとに話を膨らまして、ストーリーを作るように、下記のようなフローを作成してみました。三つのプロンプトと一つのLambda関数を作成しています。

スクリーンショット 2025-01-10 21.51.13.png

(1)[Prompot]あらすじ作成(Prompt_CreateSynopsis)
プロンプト
与えられた{{theme}}に沿った小話のあらすじを指定の数だけ生成してください。

- 作成するあらすじの数: 3
- 出力はJSONの配列とする
- JSON書式以外の文言は付加しないでください。
(2)[Lambda]出力結果から配列抽出(String2Array)
Amazon Bedrock flowsは、別途作成したLambda関数を呼出すことができます。 前のプロンプトで複数のアイデアをJSON配列の形式で出力したのですが、組込みの繰り返し処理(Iterator)に渡すためには、文字列からArrayに変換する必要があります。そのため、Lambda関数を作成しました。
コード
#参照先:
#Advanced RAGをAmazon Bedrock Prompt Flowsで作成する - Taste of Tech Topics
#https://acro-engineer.hatenablog.com/entry/2024/08/22/120000

import json
import re
import ast

def lambda_handler(event, context):    
    print(event)

    # 入力を読み込む
    resource = event.get("node",{}).get("inputs",[])
    if len(resource)<=0:
        raise ValueError("%sに値が入っていません" % resource)
    input_value = resource[0].get("value","[]")

    extracted_list = ast.literal_eval(input_value)
    return extracted_list

(3)[Iterator]繰り返し(IteratorNode_1)
(4)[Prompot]アイデア膨らまし(Prompt_StretchIdea)
プロンプト
{{theme}}に沿ったあらすじ{{synopsis}}が入力です。

より面白くなるように、話を膨らます要素を考えてください。
(5)[Prompot]ストーリ生成(Prompt_CreateSentence)
プロンプト
{{theme}}に沿ったあらすじ{{synopsis}}と、あらすじを膨らますためのアイデア{{stretch}}が入力です。

これらから、物語を完成させてください。
(6)[Collection]繰り返し結果を収集(CollectorNode_1)

作られたお話は、文章はきれいですが、内容はひねりが欲しいところでした

一作目

"タイトル:泳げメロス

古代ギリシャの競泳選手メロスは、王に陰謀の疑いをかけられ処刑の危機に陥る。親友のセリヌンティウスが人質となり、メロスは3日以内にオリンピックで金メダルを取り、かつ世界新記録を出すという厳しい条件で釈放される。

メロスは猛練習を開始するが、最初は失敗の連続だった。魚と競争して負けたり、奇妙な泳ぎ方を試して溺れそうになったりと、コミカルな練習風景が続く。一方、セリヌンティウスは牢屋でguard達と意外にも仲良くなり、メロスの応援プラカードを一緒に作り上げていた。

大会当日、メロスは不運にも水着が破れるというアクシデントに見舞われる。急遽、オリーブの葉で応急処置をして競技に臨む。スタートの合図と共に、メロスは奇跡的な速さで泳ぎ始める。観客は息を呑み、セリヌンティウスとguard達は牢から声援を送る。

メロスは驚異的なスピードで泳ぎきり、見事金メダルと世界新記録を達成。王は感動のあまり涙を流し、メロスの無実を認める。しかし、表彰台に上がったメロスは突然「もう泳ぎたくない!」と叫び、メダルを投げ捨てて逃走を始める。

観客やguard達が驚愕する中、セリヌンティウスだけがメロスの気持ちを理解し、後を追う。二人は王宮から逃げ出し、近くのビーチにたどり着く。そこで初めて、メロスは本当の気持ちを打ち明ける。「僕は泳ぐのが怖かったんだ。でも友達のために頑張ったんだ」と。

エピローグでは、メロスとセリヌンティウス、さらに改心した王も加わり、のんびりとビーチで休暇を過ごす姿が描かれる。三人は笑いながら、波打ち際でゆっくりと水に親しむのだった。"

ニ作目

"タイトル:泳げメロス

メロスとセリヌンティウスは幼い頃からの親友だが、二人とも水泳が大の苦手だった。メロスは5歳の時にプールで溺れかけた経験があり、セリヌンティウスは海の波にさらわれて怖い思いをしたことがあった。

ある夏の日、二人は水泳の重要性について熱い議論を交わしていた。セリヌンティウスは「泳げないやつは人間じゃない」と主張し、メロスは「泳げなくても生きていける」と反論する。議論は白熱し、ついにセリヌンティウスはメロスをプールに突き落としてしまう。

慌てて飛び込んだセリヌンティウスだが、自分も泳げないことを忘れていた。二人は必死にもがくが、犬かきや変な泳ぎ方しかできず、プールサイドにいた人々を爆笑させる。

いつも二人を見守っている変わり者の救助員のゼウスさんが、のんびりとした態度で二人を助け上げる。「君たち、またかい?」と呆れ顔で言うゼウスさん。実は、これが初めてではなかったのだ。

その後、二人は意を決して水泳教室に通い始める。しかし、進歩は遅々として進まない。他の生徒たちが優雅に泳ぐ中、メロスとセリヌンティウスは溺れる人の真似をして笑いを取る道化役に成り下がっていた。

二人は必死に練習を重ねる。風呂場で泳ぎの形を練習したり、水中でも曇らない眼鏡を発明しようとしたりするが、どれも失敗に終わる。

ある日、二人は偶然にも水中でバク転ができることを発見する。これをきっかけに、二人は水中アクロバットの練習に励み、やがて「水中サーカス」として人気者になる。

結局、メロスとセリヌンティウスは泳ぐことはできなかったが、水中で独自の才能を開花させた。二人は「泳げなくても水を楽しむことはできる」ということを証明し、多くの人々に感動を与えるようになったのだった。"

三作目

"タイトル: 「泳げメロス - 海の王子の冒険」

あらすじ:

メロスは海の王国の王子だったが、若かりし頃の傲慢さゆえに人魚の女王から呪いをかけられ、陸上でしか泳げない体質になってしまった。海の王国の存続が危ぶまれる中、メロスは呪いを解く方法を探すため、親友のセリヌンティウスと共に冒険の旅に出る。

二人は海底の魔女を訪ね、呪いを解く方法を尋ねる。魔女は「真の友情の証」と引き換えに情報を与えると言う。セリヌンティウスは躊躇せずに自分の泳ぐ能力を差し出し、メロスの呪いを解く方法を聞き出す。

呪いが解け、メロスは喜びに沸く。しかし、今度はセリヌンティウスが泳げなくなってしまう。メロスは友のために泳ぎを教えようとするが、セリヌンティウスは溺れてしまう。この危機を乗り越えるため、二人は協力して新たな泳ぎの技術を開発しようと努力する。

その過程で、二人は海の様々な生き物たちと出会い、助けられたり、時に戦ったりしながら冒険を重ねる。イルカの群れに泳ぎを学び、巨大タコから逃げ回り、親切なクジラに乗って旅をする。同時に、海賊の襲撃から王国を守るため、急いで帰国しなければならないというプレッシャーも抱えていた。

最後の試練として、人魚たちとのビーチバレー対決に挑む。負ければ永遠に人魚になってしまうという高いリスクがあったが、メロスとセリヌンティウスは互いを信じ、これまでの冒険で得た絆と技術を駆使して勝利を収める。

勝利後、メロスは王国に戻り、新たな王として即位する。彼は自身の経験から学んだ謙虚さと友情の大切さを胸に、海と陸の調和を目指す新しい時代を切り開いていく。セリヌンティウスは王の最も信頼される側近として、メロスを支え続ける。

こうして、かつて傲慢だった海の王子メロスは、真の友情と冒険を通じて成長し、海の生き物たちと人間が共存する平和な王国を築いていくのだった。"
]

2.3.トラブった想い出

使用していたAWSの個人アカウントは、それまでほとんど使用していないものでした。
フローを作成して実行したところ、二つ目のプロンプト実行時にエラーで終了。

調べてみたところ、クォータの値が下記のように、とても小さい値でした。
1分間に1回しか問い合わせができないため、二つ目のフローの実行が不可!

RPM(On-demand InvokeModel requests per minute for Anthropic Claude 3.5 Sonnet):1
TPM(On-demand InvokeModel tokens per minute for Anthropic Claude 3.5 Sonnet):2000

サポートに問い合わせてクォータを緩和してもらいましたが、正月明けで問い合わせが殺到していたこともあるようですが、緩和完了までに数日かかりました。

参考資料:Amazon Bedrock のモデルアクセスの有効化や制限値の引き上げができない時の対応方法 | Amazon Web Services ブログ

3.Dify

3.1.Difyの概要

クォータの緩和まで、Amazon Bedrock Flowsのフロー作成が進まなくなったので、同じようなことをDifyで試してみました。Difyは、ローコードのワークフロー作成プラットフォームとして、おそらく一番よく知られた存在だと思います。商用サービスとOSSの両方が存在します。

公式サイト:Dify.AI · 先進的なAIアプリケーションのためのイノベーションエンジン
参考資料:Difyとは?使い方や料金体系、商用利用について解説!活用事例も紹介 | AI総合研究所

3.2.Difyの概要

ワークフローの流れは、Bedrock Flowsの時とほぼ同じです。
Ggwnw9ZbEAAnCZC.jpg

AIは、Difyにプリセット(gpt-4o-mini)とAzure OpenAIのChatGPT(Gpt-35turbo,gpt-4o)を使用してみました。下記は、gpt-4o-miniを設定した、DSLファイルの内容です。

DSL
app:
  description: 指定したお題で、ストーリーを作成するワークフロー
  icon: 🤖
  icon_background: '#FFEAD5'
  mode: workflow
  name: StoryTeller
  use_icon_as_answer_icon: false
kind: app
version: 0.1.5
workflow:
  conversation_variables: []
  environment_variables: []
  features:
    file_upload:
      allowed_file_extensions:
      - .JPG
      - .JPEG
      - .PNG
      - .GIF
      - .WEBP
      - .SVG
      allowed_file_types:
      - image
      allowed_file_upload_methods:
      - local_file
      - remote_url
      enabled: false
      fileUploadConfig:
        audio_file_size_limit: 50
        batch_count_limit: 5
        file_size_limit: 15
        image_file_size_limit: 10
        video_file_size_limit: 100
        workflow_file_upload_limit: 10
      image:
        enabled: false
        number_limits: 3
        transfer_methods:
        - local_file
        - remote_url
      number_limits: 3
    opening_statement: ''
    retriever_resource:
      enabled: true
    sensitive_word_avoidance:
      enabled: false
    speech_to_text:
      enabled: false
    suggested_questions: []
    suggested_questions_after_answer:
      enabled: false
    text_to_speech:
      enabled: false
      language: ''
      voice: ''
  graph:
    edges:
    - data:
        isInIteration: false
        sourceType: start
        targetType: llm
      id: 1736307025731-source-1736307268120-target
      source: '1736307025731'
      sourceHandle: source
      target: '1736307268120'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: llm
        targetType: code
      id: 1736307268120-source-1736308384160-target
      source: '1736307268120'
      sourceHandle: source
      target: '1736308384160'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: code
        targetType: iteration
      id: 1736308384160-source-1736309891361-target
      source: '1736308384160'
      sourceHandle: source
      target: '1736309891361'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: true
        iteration_id: '1736309891361'
        sourceType: iteration-start
        targetType: code
      id: 1736309891361start-source-1736310132817-target
      source: 1736309891361start
      sourceHandle: source
      target: '1736310132817'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: true
        iteration_id: '1736309891361'
        sourceType: iteration-start
        targetType: code
      id: 1736309891361start-source-1736310200833-target
      source: 1736309891361start
      sourceHandle: source
      target: '1736310200833'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: true
        iteration_id: '1736309891361'
        sourceType: code
        targetType: llm
      id: 1736310132817-source-1736310261352-target
      source: '1736310132817'
      sourceHandle: source
      target: '1736310261352'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: true
        iteration_id: '1736309891361'
        sourceType: code
        targetType: llm
      id: 1736310200833-source-1736310261352-target
      selected: false
      source: '1736310200833'
      sourceHandle: source
      target: '1736310261352'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        sourceType: iteration
        targetType: end
      id: 1736309891361-source-1736307375737-target
      selected: false
      source: '1736309891361'
      sourceHandle: source
      target: '1736307375737'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: true
        iteration_id: '1736309891361'
        sourceType: llm
        targetType: llm
      id: 1736310261352-source-1736312775225-target
      source: '1736310261352'
      sourceHandle: source
      target: '1736312775225'
      targetHandle: target
      type: custom
      zIndex: 1002
    nodes:
    - data:
        desc: ''
        selected: false
        title: 開始
        type: start
        variables:
        - label: Theme of some story
          max_length: 200
          options: []
          required: true
          type: paragraph
          variable: theme
        - label: number of stories to be created
          max_length: 48
          options: []
          required: true
          type: number
          variable: number
      height: 116
      id: '1736307025731'
      position:
        x: 157.19252945580075
        y: -24.702460784208384
      positionAbsolute:
        x: 157.19252945580075
        y: -24.702460784208384
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        context:
          enabled: true
          variable_selector:
          - '1736307025731'
          - theme
        desc: ''
        model:
          completion_params:
            temperature: 1
          mode: chat
          name: gpt-4o-mini
          provider: openai
        prompt_template:
        - id: 41f5184f-530b-446b-9cdc-cbd4e84063b4
          role: system
          text: '与えられた{{#1736307025731.theme#}}に沿った小話のあらすじを指定の数だけ生成してください。作成するあらすじの数は、{{#1736307025731.number#}}としてください。


            - 出力はJSONのフォーマットとする。

            -- 作成したあらすじを、JSON配列に格納する。

            -- JSON配列の属性名はtextとする。

            -- JSON配列の要素は、あらすじのタイトルを格納するtitle属性と、あらすじの内容を格納するsummary属性を持つJSONオブジェクトとする。

            - JSON書式以外の文言は付加しないでください。


            -出力例はかきのとおり。

            [{"title":"一つ目のタイトル", "summary":"一つ目のあらすじ"},{"title":"二つ目のタイトル", "summary":"二つ目のあらすじ"}]'
        selected: false
        title: あらすじ作成
        type: llm
        variables: []
        vision:
          enabled: false
      height: 98
      id: '1736307268120'
      position:
        x: 432.29914706792454
        y: -24.702460784208384
      positionAbsolute:
        x: 432.29914706792454
        y: -24.702460784208384
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        outputs: []
        selected: false
        title: 終了
        type: end
      height: 54
      id: '1736307375737'
      position:
        x: 1199.637694606522
        y: 223.23067537828985
      positionAbsolute:
        x: 1199.637694606522
        y: 223.23067537828985
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        code: "import json\n\ndef main(arg: str) -> dict:\n    list = json.loads(arg)\n\
          \    return {'result': list}"
        code_language: python3
        desc: ''
        outputs:
          result:
            children: null
            type: array[object]
        selected: false
        title: 配列に整形
        type: code
        variables:
        - value_selector:
          - '1736307268120'
          - text
          variable: arg
      height: 54
      id: '1736308384160'
      position:
        x: 727.2870454217625
        y: -24.702460784208384
      positionAbsolute:
        x: 727.2870454217625
        y: -24.702460784208384
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        error_handle_mode: terminated
        height: 323
        is_parallel: false
        iterator_selector:
        - '1736308384160'
        - result
        output_selector:
        - '1736312775225'
        - text
        output_type: array[string]
        parallel_nums: 10
        selected: false
        start_node_id: 1736309891361start
        title: イテレーション
        type: iteration
        width: 996.7578582832552
      height: 323
      id: '1736309891361'
      position:
        x: 157.19252945580075
        y: 139.82341579281507
      positionAbsolute:
        x: 157.19252945580075
        y: 139.82341579281507
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 997
      zIndex: 1
    - data:
        desc: ''
        isInIteration: true
        selected: false
        title: ''
        type: iteration-start
      draggable: false
      height: 48
      id: 1736309891361start
      parentId: '1736309891361'
      position:
        x: 24
        y: 68
      positionAbsolute:
        x: 181.19252945580075
        y: 207.82341579281507
      selectable: false
      sourcePosition: right
      targetPosition: left
      type: custom-iteration-start
      width: 44
      zIndex: 1002
    - data:
        code: "\ndef main(arg: str) -> dict:\n    return {\n        \"result\": arg[\"\
          title\"]\n    }\n"
        code_language: python3
        desc: ''
        isInIteration: true
        iteration_id: '1736309891361'
        outputs:
          result:
            children: null
            type: string
        selected: false
        title: タイトル取得
        type: code
        variables:
        - value_selector:
          - '1736309891361'
          - item
          variable: arg
      height: 54
      id: '1736310132817'
      parentId: '1736309891361'
      position:
        x: 122.7489446966033
        y: 65
      positionAbsolute:
        x: 279.94147415240406
        y: 204.82341579281507
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        code: "\ndef main(arg: str) -> dict:\n    return {\n        \"result\": arg[\"\
          summary\"]\n    }\n"
        code_language: python3
        desc: ''
        isInIteration: true
        iteration_id: '1736309891361'
        outputs:
          result:
            children: null
            type: string
        selected: false
        title: サマリー取得
        type: code
        variables:
        - value_selector:
          - '1736309891361'
          - item
          variable: arg
      height: 54
      id: '1736310200833'
      parentId: '1736309891361'
      position:
        x: 125.55719283419171
        y: 137.47941687939402
      positionAbsolute:
        x: 282.74972228999246
        y: 277.3028326722091
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        context:
          enabled: false
          variable_selector: []
        desc: ''
        isInIteration: true
        iteration_id: '1736309891361'
        model:
          completion_params:
            temperature: 1
          mode: chat
          name: gpt-4o-mini
          provider: openai
        prompt_template:
        - id: cafe13de-07d4-4c3b-a7db-cf18212ccf0a
          role: system
          text: '{{#1736307025731.theme#}}に沿ったあらすじのタイトル{{#1736310132817.result#}}、あらすじの内容{{#1736310200833.result#}}を、より面白くなるように、話を膨らます要素を考えて、箇条書きで列挙してください。'
        selected: false
        title: アイデア膨らまし
        type: llm
        variables: []
        vision:
          enabled: false
      height: 98
      id: '1736310261352'
      parentId: '1736309891361'
      position:
        x: 432.7578582832551
        y: 65
      positionAbsolute:
        x: 589.9503877390558
        y: 204.82341579281507
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        context:
          enabled: false
          variable_selector: []
        desc: ''
        isInIteration: true
        iteration_id: '1736309891361'
        model:
          completion_params:
            temperature: 1
          mode: chat
          name: gpt-4o-mini
          provider: openai
        prompt_template:
        - id: 4c83d286-2395-4394-b1d8-6b18e54ab827
          role: system
          text: '{{#1736307025731.theme#}}に沿って、あらすじのタイトル{{#1736310132817.result#}}あらすじ{{#1736310200833.result#}}の内容、および、アイデアを膨らました検討結果{{#1736310261352.text#}}があります。


            これらの情報をもとに、面白い話になるように、推敲を重ね、完成したストーリーを作成してください。'
        selected: false
        title: ストーリ作成
        type: llm
        variables: []
        vision:
          enabled: false
      height: 98
      id: '1736312775225'
      parentId: '1736309891361'
      position:
        x: 709.0481921570247
        y: 66.31950791077287
      positionAbsolute:
        x: 866.2407216128254
        y: 206.14292370358794
      selected: true
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    viewport:
      x: -61.55243951309933
      y: 152.1615445954601
      zoom: 0.8705505632961246

比較した感想
モデル 感想
gpt-4o-mini 特に面白みのない出力でした
gpt-35turbo gpt-4o-miniよりスペックダウンしており、出力もスペックダウンしました。
gpt-4o AIのコメディの理解は、人間とは違うのかしらん。面白いというより、不可思議や奇妙な話を生成してくれました。

gpt-4oによる出力が下記のになります。よつ目の「沈むメロスと無意味な誓い」が少し好みです。

一作目

"タイトル: 泳げメロスの大作戦

あらすじ:

メロスは頼りがいのある青年で、王によって囚われた親友を救うため、壮大な計画を練ることに決めた。だがこの計画は、想像以上に波乱に満ちたコメディの幕開けとなった。

ある日、メロスは密かに泳いで脱出することを決意する。彼は自信満々に出発する予定だったが、実は泳ぎがまったく得意ではなかった。そこで、街の賢くもやんちゃな子供たちに弟子入りし、水泳の特訓を始めた。

第1章: 浮き輪と水鉄砲

子供たちはメロスに「特製浮き輪」と「戦士用水鉄砲」を手渡した。彼らの目標は、メロスを立派な水兵に仕立て上げること。メロスは浮き輪を装着したまま、バシャバシャ無骨に水面を叩く姿を見せ、兵士たちを水鉄砲でびしょ濡れにして撃退する場面は爆笑の渦を巻き起こす。

第2章: 子供たちのコーチング

メロスの子供たちによる特訓はとても厳しかった。小さな鬼教官たちは笛を吹き鳴らし「もっと早くしろ!」「犬かきは禁止だ!」と叫ぶ。メロスは振り返る度に眩しい笑顔で激励され、猛練習を耐え抜く。彼はすっかり「泳ぎの鬼教官」として恐れられる存在に。

第3章: 泳ぎのオリンピック

街で開催される「泳ぎのオリンピック」には飛び入り参加ができるという情報を得たメロスは早速参戦。競技は非常にユニークで、観客たちは「イルカの技を再現しろ」や「逆立ちしてヘリコプターみたいに回れ」といった指令に大爆笑。

第4章: ライバルの登場

大会には伝説の選手スイムスが出場していた。彼はイルカに育てられた男で、華麗なジャンプで観客を沸かせる。メロスは彼との競争の中で、逆に自身の技術と機転を活かし、他の選手たちさえ魅了するパフォーマンスを発揮する。

第5章: 滑稽な試行錯誤

メロスは特訓の途中で「カニ歩き」や「クラゲ浮き」を試みては大失敗を繰り返し、街の人気者になる。市民たちはその姿を愛おしみ、応援の声と「泳げメロス!」の巨大横断幕で彼を励ます。

第6章: 人波のサーフィン

クライマックスのデモンストレーションとして、メロスは人々の肩を借りてサーフィンする技「召喚波乗り」を披露。さらに「魔法の蝶泳ぎ」を完璧に完成させ、遂に親友のもとへとたどり着く。

第7章: 親友の一言

メロスが無事到達すると、親友はにっこり笑って言った。「なんだ、その変な泳ぎ方?真面目にやった方が速かったんじゃないか」と軽口を叩き、二人で大笑い。メロスは親友の救出に成功し、友情の絆を深めることができた。

この愉快な冒険は、メロスが真剣な顔の裏で繰り広げたコメディの一部であり、彼の勇気と工夫を私たちに教えてくれた。"

ニ作目

"タイトル: 泳げメロス


あらすじ: 逃げ足の速さを誇るメロスだが、泳ぎの速さは王に負けてしまった。王は新しい挑戦として水泳対決を申し出る。メロスは涙と汗で海を汚しながらも、親友のために必死で練習し、ついに対決で王を打ち負かす。水を得た魚のように泳ぐメロスの姿に、王も思わず拍手してしまう。


王とメロスの水中対決

ある晴れた朝、村の王は、水辺でくつろぐメロスに突然、思いつきで水泳対決を申し出た。「逃げ足は速いが、水の中ではどうかな?」と、挑発的に笑う王。挑戦を受けたメロスは、海を見つめ、不安げに言った。「泳げたら、大海原も逃げ放題だがな」。メロスは死んでも親友を裏切らない。その友情を誓い直し、特訓を決意する。

最初に思いついたのは、海のペットショップで見つけたしゃべる魚をコーチにすることだった。ペットの魚「フィッシュ太郎」は、関西弁で「そんな泳ぎ方やとアカンで!おもんないわ」と鋭く指導。一風変わったその助言にメロスは笑いを堪えながらも習った。

しかし、練習は容易ではなかった。メロスは試行錯誤を繰り返し、流行の水中ヨガやアクアロビクスを取り入れてみた。その奇妙な動きに、海の中の仲間たちも爆笑の渦。イルカたちはシンクロで応援し、クラゲやタコは気まぐれに邪魔をして楽しんでいた。

対する王は、特製の「水泳ブーツ」を用意。これなら楽勝だと自信満々。しかし、いざ水に入ると、ブーツを履いた足が絡まり、豪快に沈んでしまう。観客席のメロスの親友や村人たちは大爆笑。そして、メロスが水中の旋風を起こす「旋風ターン」を披露すると、フィッシュ太郎の関西弁が海中に響き渡った。「それや!めっちゃカッコいいで、メロス!」。

何もかもが滅茶苦茶になった対決だったが、メロスは無事に王を打ち負かした。王はそのさわやかな泳ぎっぷりを称え、拍手を送った。「やるな、メロス!」。

最終的な和解

対決が終わり、メロスと王は浜辺で握手を交わした。友情の証として、一緒にスプラッシュコンテストを即席で開催。観客も一緒になって、笑いの渦に包まれる。それぞれの大声援とともに笑い、声高らかに次の挑戦を誓い合う二人。海水も涙も汗も笑いも全部混ざって、いつもの海とはまた違った賑やかな日常が戻ってきた。"

三作目

"タイトル: メロスと浮き輪事件

あらすじ

メロスは永遠の友シングウの命が危険にさらされていることを知り、彼を救うために川を渡る決心をした。しかし、極端な恐水症を持つメロスは、自分が泳ぎには向いていないことを思い出し、心底震える。そのため、浮き輪を使うことでなんとか川を渡ろうと考えるが、普通の浮き輪が見つからず、仕方なく派手なピンクのフラミンゴ型の浮き輪を装着する。

川に入ると、メロスは鯉やカワセミ、カメといった生物たちと次々に遭遇し、あちこちに流されてしまう。それでもメロスは、応援してくれる岸の友人や村人たちの声援に励まされ、必死に進む。メガホンで「頑張れメロス、ここで止まったら終わりだ!」と大声で応援される中、思わず苦笑いを浮かべる。

それでも、メロスのフラミンゴ浮き輪からは徐々に空気が抜けていき、焦り始める。実はその原因は、メロス自身が瓦礫にぶつけて空けてしまった穴だったことに気づき、ショックを受ける。途方に暮れるメロスの前に偶然アヒルの群れが現れる。少しでも助けを借りようと、「パンくずをあげるから」とアヒルたちに交渉するメロス。しかし、アヒルのリーダーが驚きの交渉力でパンくずの量をどんどん増やし、メロスはなんとか交渉を成立させ、アヒルたちに助けられる。

途中で、通りかかった鹿が木に頭をぶつけて落ちてきた木の枝を見つけたメロスは、思いがけなく頼りになるオールを手に入れる。必死に枝をオールのように使ってスピードを増し、何とか川を渡り切ると、そのとたん浮き輪がパンと割れてしまう。ピンクのフラミンゴがしなびていく様子に、岸で見守っていた皆は大爆笑。

ようやく友人シングウの元にたどり着いたメロスは、迎えてくれた友人が鶴の舞を披露し始める姿に驚愕。すべてを忘れて笑い続ける二人に、川の対岸からも村人たちの愉快な笑い声が響き渡った。

こうしてメロスは、友情とその壮絶な川渡りの笑い話を村中に広めることとなり、あのフラミンゴ浮き輪は村で一番の人気者になったのであった。"

四作目

"タイトル: 泳げメロス

あらすじ: 沈むメロスと無意味な誓い

メロスは親友を救うために泳いで川を渡ることを決意した。しかし、彼はすぐに自分が壮大に自信過剰であることに気づくのだった。彼が水に飛び込むと、泳ぎ方を全く知らないことに愕然とする。そして案の定、彼は川にポチャンと沈んでいった。

川底で出会ったのは、奇妙で風変わりな河童だった。河童は興味津々の様子でメロスを見つめ、「お前は何をそんなに慌てているんだい?」と語りかけてきた。成り行きで河童と一緒に修行を始めることになったメロス。河童の非常識な訓練方法には頭を抱えるばかり。はじめは沈むことを徹底的に練習し、ついには河童も脱帽するようなクロールをマスターするまでになる。

修行の過程では、川の中で彼を惑わす様々な珍事に遭遇する。浮かぶ丸太や、すれ違いざまに彼をくすぐるおしゃべり魚、時おり話しかけてくる生意気な河の音。これらの障害を笑い飛ばしつつ、メロスは一歩ずつ前に進む。

河童との友情を深めながら、腹筋と肺活量を鍛えるメロス。河童は奇抜な水着を着せ、壮大なトレーニングモンタージュが始まる。「シンクロナイズドスイミング大会」「潜水プッシュアップ」「きゅうりの槍を使った水中決闘」といった滑稽な訓練メニューの連続に、メロスは笑いや涙も止まらない。

仲間となった川の生物たちは、時々開催される水中フェスティバルでの歌や踊りで彼を惑わせる。それでも、メロスの決意は揺るがない。しかし途中、彼は悟る—水面を走った方が早いじゃないかと。笑いながら、泳ぎの楽しさにも目覚め、メロスは川の泳者としての様々な新しい特技を発見していく。

物語のクライマックスでは、メロスは同じ川を渡ろうとする風変わりなライバルと、終始互いに笑わせ合いながら競い合う。とどめには川底を歩く方法を思いつくが、川泳ぎを楽しむことを選ぶ彼。

最後には、メロスはようやく親友の元に到達する。だが、新たに得た泳ぎへの情熱から、友人を救うという本来の目的を忘れて川でのパーティーを提案。メロスの笑いの物語が、川沿いの愉快な水泳大会で終わるのだった。

こうしてメロスはただの走者から泳者へと、何よりも笑いと友情を得た川の放浪者として新たな一歩を踏み出したのだった。",

五作目

"メロスのがんばれ!水泳大会

ある日、町の水泳大会に参加する決意を固めたメロス。彼は親友の病を治すため、大会で手に入る特別な賞品を手に入れねばならなかったのだ。しかし、その決意には大きな課題が隠れていた。実はメロス、泳ぎがからっきしダメだったのだ。

第一章:特訓開始!伝説の水猿スタイル
メロスはまず、小さな子どもが遊ぶためのビニール製のプールで特訓を開始した。大きな川に入るのはどうしても怖かったのだ。その際、彼は水猿という名前の妙な動物を真似て、逆立ち泳ぎや、犬かき風の泳法を編み出した。豆粒大のプールの中で、彼の努力はどこかシュールで愛らしい。

第二章:手加減なしの応援合戦
大会当日、メロスは非常に緊張していたが、その一方で熱狂的な応援をしてくれる友人たちがいた。その中でも特に親友は「手をもっと回して!」や「逆立ちは今じゃない!」など意味不明なアドバイスを叫んでいた。これがかえってメロスを混乱させ、ますます泳ぎが乱れる原因に。

第三章:ライバル登場!自信満々の彼
その競技には自信満々なライバルがいた。彼の名前は、「フィッシュ・ケンタウルス」と呼ばれる男で、実は泳ぎはメロスとどっこいどっこい。二人の雑な泳ぎは、なぜか観衆を巻き込みながらのスプラッシュマウンテンを引き起こす。

第四章:案の定、ドジなレース
肝心のレースが始まると、メロスは想像していたように厄介な事態に巻き込まれる。川を渡ろうと必死に泳ぐ彼の前には、突然アヒルの行列が。メロスは慌てて避けようとするが、その結果、得体のしれない渦に巻き込まれる。渦から奇跡的に抜け出すも、結局最下位でゴールすることになる。

第五章:驚きの表彰式
結果はビリにもかかわらず、観衆を感動させるその姿に、来賓から特別賞が贈られることに。「英雄的勇気水ボトル賞」と名付けられたこのボトルは、その華やかなラベルで一目で町のお土産にも十分になること間違いなし。賞品を手にしたメロスはそれを掲げ、町の英雄となった。

エピローグ:友情の勝利
その後、メロスは手に入れた水のペットボトルで親友の喉を潤し、病を救ったのである。特別な水だったのか、それとも友情の力だったのか。結局その答えはわからないままだったが、メロスは自らの限界を越えて挑戦することの大切さを知ることとなった。

こうしてメロスの冒険は、町に笑いと感動をもたらしたとさ。"

4.その他

フロー以外にも、「泳げメロス」作ってみました。

Cline+Amazon Bedrock(Cluade 3.5 Sonnet v1)による「泳げメロス」。
ChatGPTのような奇天烈さはないですが、それなりの完成度の物語になっている感じです。

472710098_8881896525256309_1703302449206408636_n.jpg

Cline+DeepSeekによる「泳げメロス」。
指示していないのに、HTML画面を生成しました。でも、コメディにはなっていない気がします。末尾の「パロディ脚本:AI」が笑うところかも(^^;

472708377_8882257631886865_2542822433822135433_n.jpg

5.まとめ

Amazon Bedrock flowsとDifyに共通なことととして、プロンプトで複数の情報を出力した後、イテレーションを回すために、情報変換のロジックを書く必要があるので、もっと楽をしたいところです。また、Amazon Bedrock flowsは、部品が少ないと思います。今後、増えていくことを期待します。

AIで面白い小説を作るのは、まだ難しいかもしれません。
上記で作ったプロンプトには改善の余地が非常にあります。また、文章の長さは、章やブロックごとにイテレーションを回すすことで、対応できると思います。

しかし、あらすじの段階で微妙なので、話を膨らましてもどうかと。
ただ、モデルが上がるごとに、キラッと光るものが増えていくので、近い将来に期待です。

2025.01.10 山崎作成

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?