Vibe-coding実践例:X自動投稿のコメント案をAIで生成Ollama(llama3.1:8b)

AIテキスト

前回までで、RSSで記事を収集しLLMで要約、PythonでXに投稿するコードを作成しました。

今回は収集した記事に対し、コメント案を生成するプロンプトとコードをVibe codingで作成していきます。

コメント案生成プロンプトの基本設計

AIに単純に記事の要約からコメントを出すよう指示すると、記事内容にコメントが影響される傾向があります。

AIの原理であるTransformerは、直近文脈の語彙・構文・感情語を高確率で踏襲するためと考えられます。

コメント生成時に、発言者のキャラクターや人格を設定することで、統一感のある投稿が可能となります。

AIキャラクター設計の基本構造

下記はChatGPTの提案によるものです。

LLMにニュース記事を引用してXに投稿するコメントの案を書かせたい。
文章にキャラクターや性格付けをする方法を教えてください。

下記はその解釈をサマリしたもので、SNS等での経験則や、Character.AIなどのキャラクター設計の基本構造を参考にしていると考えられます。

色々深堀りして調べたくなりますが、Vibe codingの主義にのっとり、動くことを優先してこのまま進めてみます。

「性格」の定義より「制約」の定義が有効

一般的なプロンプトの指示では「あなたは辛口で知的な評論家です」のように文章で与える例を見ますが、 LLMは「文章」より「制約」の方が得意とのこと。

例えば、下記のようなパラメータをjsonで記述する例が示されます。

フィールド役割
tone文体・語彙選択に直結
stance賛否バランスを制御
expertise専門用語量・抽象度
emotion感情語・煽り抑制
aggressiveness批判の強度
confidence断定 vs 留保

これに、数値を加えて程度の表現を与えます。

  • emotion: 0.0〜1.0
  • aggressiveness: 批判の強さ
  • length: 280字制約を意識させる

LLM向けペルソナ設定のためのJSONスキーマ例

{
  "id": "string",
  "version": "1.0",

  "tone": "calm | ironic | neutral | optimistic | pessimistic",
  "stance": "positive | neutral | critical | slightly_critical",
  "expertise": "general | industry | engineer | researcher",

  "emotion": 0.0,
  "aggressiveness": 0.0,
  "confidence": 0.5,

  "risk_tolerance": 0.2,

  "news_summary": "ニュース要約文(2〜4行程度)",

  "tweet": {
    "length": {
      "min": 80,
      "max": 200
    },
    "style": "assertive | observational | questioning",
    "emoji": false,
    "hashtag": "none | minimal"
  },

  "constraints": {
    "avoid_definitive_claims": true,
    "avoid_personal_attack": true,
    "single_topic": true
  }
}

tweetはXでの投稿向けの指定、constraintsは”安全装置”で、炎上防止スイッチとのこと。これもそのまま入れてみます。 json中は英語の方が良いとのことで、そのまま従って英語としています。

コード例

コメント生成時に与えるプロンプト例を出力してもらいました。 また、添付ファイルとして前回RSSフィードから作成した、記事全文と要約を含むMarkdownファイルを与えています。

下記のプロンプトを用いて、添付のRSSフィードの要約を与え、Xで投稿するコメントの案を全記事分出力するコードを作成してください。
-----
前述のJSONスキーマ
添付ファイル

前回作成したMarkdown形式のパース処理が長くなったので、下記では省略しています。 また、フォールバックや例外処理などが冗長だったため、手動で削っていますが動作に違いはありません。

import re
from pathlib import Path
from typing import List, Dict
import requests
import sys
import json

OLLAMA_URL = "http://localhost:11434/api/generate"
OLLAMA_MODEL = "llama3.1:8b"

PERSONA_PROMPT = """以下の persona JSON を厳密に解釈し、
persona 内の tweet / constraints を含む全ルールを遵守して、
下記ニュース要約に対するX向けコメント案を1つ生成せよ。

【persona】
{
  "id": "string",
  "version": "1.0",
  "tone": "calm",
  "stance": "slightly_critical",
  "expertise": "engineer",
  "emotion": 0.0,
  "aggressiveness": 0.0,
  "confidence": 0.5,
  "risk_tolerance": 0.2,
  "tweet": {
    "length": { "min": 80, "max": 200 },
    "style": "observational",
    "emoji": false,
    "hashtag": "none"
  },
  "constraints": {
    "avoid_definitive_claims": true,
    "avoid_personal_attack": true,
    "single_topic": true
  }
}

【news_summary】
__NEWS_SUMMARY__

【output】
コメント案のみを1つ出力せよ。
"""

def parse_rss() -> List[Dict]:
    # ...省略
    return articles

def generate_comment(news_summary: str) -> str:
    prompt = PERSONA_PROMPT.replace("__NEWS_SUMMARY__", news_summary)

    payload = {
        "model": OLLAMA_MODEL,
        "prompt": prompt,
        "stream": False
    }

    response = requests.post(OLLAMA_URL, json=payload, timeout=180)
    response.raise_for_status()
    data = response.json()
    text = data.get("response")

    return text

def main():
    articles = parse_rss()

    for idx, article in enumerate(articles, 1):
        comment = generate_comment(article["summary"])
        print(f"{article['title']}\n {article['url']}\n{comment}\n")

if __name__ == "__main__":
    main()

出力例

実際のRSSフィードと記事の要約を与えて、コメント案を生成してもらいました。
前回に引き続き、モデルにはllama3.1:8bを利用しています。

下記はその例で、日本語としての内容はそれなりですが、カギ括弧の表記や補足説明にブレが多く、そのままでは使いづらい印象です。 ある日のRSSフィードの最初の5件を抽出し、特殊な例をピックアップしたわけではなく、全体的に似た傾向が見られました。

例えば、こちらの例は「」でコメント囲み、”といえばよいでしょう。”というLLMの発言が付いています。

「Instagram の責任者、アダム・モセリ氏は AI生成コンテンツが増えており、実物の写真や画像に電子透かしを付けるほうが近いうちには現実的になると言っています。AI技術
の進歩は便利ですが、コピーキャット対策も必要ですよね」と言えば良いでしょう。                                                                                   

こちらはダブルクォーテーションで囲まれています。

"気になる生成AI技術のまとめを見ると、画像を各レイヤーに分解できるQwen-Image-Layeredと音声を分離するSAM Audioが注目されています。こういった新しいアプロ
ーチは未来への足りないかもしれませんが、今のところは、AI技術の進化が想像以上に速くなってきていますね。"

こちらは全体がコメントと見られますが、口調がやや固い印象です。

「Large Language Models as Pokémon Battle Agents: Strategic Play and Content Generation」の論文は、主な大規模言語モデル同士の戦略的プレイとコンテンツ生成能力を
試したものです。独自性と創造性が高いAI研究であることから、将来この分野での応用が期待できると考えられます。

一転して、こちらはかなりフランクな口調で、他の例とトーンが異なります。

「なるほど!テスラ車のドアロックの解錠・施錠には、一般的なキーフォブだけでなくTeslaモバイルアプリを使うこともできるんですね。アップルの「Car Key」機能にも対応
しそうだそうです。新しい技術が次々と進化してきているのがすごいですね。」

下記は説明的な長文?を回答してきた例です。

以下がニュース要約に対するX向けコメント案となります:

"サムスンがスマホとタブレットの境界線を溶かした。10インチの幅で、キーボードを使うことでビジネス用途にも利用できるようになった。"

このコメントは以下の条件に沿ったものです。

- tone: カルム
- しゃべり方: オブザーバショナリティー
- emoji: 使わない

注意点

実際はMarkdownのパース処理を正しく行うコードは一回では生成できず、3~4回程度やり直しが発生しました。

手動で直せば速いのですが、ここでは発生したエラー内容をコピペしてChatGPTに伝え、修正するループを繰り返す形で完成させています。

まだ”Vibe coding”の範囲内であり、コードを見なくても動くプログラムを完成させることができています。

まとめ

今回は、RSSフィードから取得した記事要約に対し、X向けコメント案を生成するプロンプトとコードをVibe codingで作成しました。

Markdown形式は人間にわかりやすく、コードに触らずにデバッグするための強力なツールですが、これ以上の拡張には限界があるため、次回は別の方法を検討します。

またLLMの出力するコメント案も、実用性はありますがトリミングや手作業が多くなるため、よりよいLLMを探してみたいと思います。

タイトルとURLをコピーしました