890 Views
July 30, 23
スライド概要
Kansai WordPress Meetup@大阪 2023/07
Developer
OpenAIを利用して サイト運用効率化を試している話 Kansai WordPress Meetup@大阪 2023/07
今日伝えたいこと • LLM(大規模言語モデル)は、 「この文章の続きはなにか?」を予測するモデル • 記事作成時の「苦手な作業」をLLMに任せよう • モデルの性質と、 効率化したいタスクのマッチングを意識してツールを選ぼう
Agenda • ChatGPTを利用した、コンテンツ作成の効率化した話 • OpenAI APIで、「記事作成作業」を効率化した話 • LLMを利用する際の注意点
HELLO! ✋ 岡本 秀高 (Hide) • Stripe Developer Advocate • WordCamp Kyoto 2017 • @hidetaka_dev • https://hidetaka.dev
Agenda • ChatGPTを利用した、コンテンツ作成の効率化した話 • OpenAI APIで、「記事作成作業」を効率化した話 • LLMを利用する際の注意点
技術記事 ワークショップ資料を 実行コマンドから生成
コードと指示から 記事を作る
コードと指示から 記事を作る
記事作成作業あるある: エラーが出たので、記事が書けません
PHPやJSの エラーログから 問題箇所を見つける
修正するコードの 相談・提案を受ける
こんな使い方もしています • 箇条書きのメモ(イベントレポート・製品フィードバック)を 社内共有のレポート形式に整形する • 英語の記事や新しいOSSのReadmeをコピペして、 「どんなことが書いてあるか」をざっくり教えてもらう • 記事タイトルやペルソナなどのブレーンストーミング
Stripeに関する記事を RSSなどで収集し、 LLMで紹介文生成
使ってみて感じたこと • 「与えた文章・情報」の処理はとても上手 • 例: この文章の要約文 / SNSシェア文 / タイトル考えて • 「自分が渡していない情報・話題」については、 つねに「知らんけど」を付け加えてくる雑談として扱う • 「このコードで実装できますよ。知らんけど」
よくやる対話方法1: ワンショットの作業依頼 • 「どんな情報」を「なぜ」「どんな形式で欲しいか」を 明示的に指示する • 今から英文記事を貼り付けます • この記事を日本語で要約してください • X (Twitter)で共有するので、文章は100文字以内にしてください
よくやる対話方法2: 居酒屋・喫煙室の雑談 • 「自分の考えを整理するため」に、ChatGPTと対話する • いわゆる「壁打ち」 • 「WordPressってどんなユーザーがターゲット?」 • 「日本だとそのユースケースは少なくない?」 • 「〜だと思うけど、開発者としてはどう思う?」
https://speakerdeck.com/yoshidashingo/20230524?slide=14
https://speakerdeck.com/yoshidashingo/20230524?slide=17
うまくいかない時は・・・ • 「聞きたいこと・やってほしいこと」を分割する • 例: 「同期パターンの作り方を教えて」 1. 「WordPress 同期パターン」やリリースノートを検索 2. 記事内容をコピペして、 「この記事から同期パターンについて教えて」 3. 「もっと調べたい場合の検索キーワードを提案して」 • 「これさえわかれば、自分でできる or 社内で質問できる」のラインを見極めよう
Chat GPTを使う際に意識すること • 「意図しない回答」が来た時は、「100%質問が悪い」 • 質問は具体的か?別の解釈ができないか? • 「なにを生成して欲しいか?」を明確に伝えたか? • モデルが知らないことを聞いていないか? • 自分が持っている情報を追加で渡せば解決しないか?
Agenda • ChatGPTを利用した、コンテンツ作成の効率化した話 • OpenAI APIで、「記事作成作業」を効率化した話 • LLMを利用する際の注意点
自動化できるものは、 自動化したい
利用しているSaaSの 更新履歴を要約
const completion = await this.client.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [{
role: 'system',
content: `
あなたはStripeのAPI開発者です。
与えられたフィードの情報を、以下の制約条件をもとに要約を出力してください。
制約条件:
・文章は簡潔にわかりやすく。
・箇条書きのMarkdown形式で出力。
・要約した文章は日本語へ翻訳。
・最終的な結論を含めること。
出力する文章の例:
** 要約 **
StripeのAPIに新しい値「link」が追加され、支払いリンクを作成/更新する際に使用でき
るようになりました。
** 詳細 **
- PaymentLinkを作成/更新する際に、新しい値「link」を使用できるようになりました。
- この新機能は、PaymentLink#create.payment_method_types[]、
PaymentLink#update.payment_method_types[]、および
PaymentLink.payment_method_types[]で使用できます。
- 「link」値は、支払いに使用される課金情報が保存されたURLを表します。
- これにより、支払いリンクをより使いやすくすることができます。
- この機能は、API開発者にとって非常に便利であり、StripeのAPIの改善につながると
期待されています。
`
})
}, {
role: "user",
content: content
}],
Role: systemで指示
Role: userで要約したい文章
$response = wp_remote_post(
'https://api.openai.com/v1/chat/completions',
array(
'body' => json_encode($data),
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
),
'timeout' => 100
)
);
if ( is_wp_error( $response ) ) {
$error_message = $response->get_error_message();
error_log( print_r( $error_message, true ) );
return '';
}
$json = json_decode(
wp_remote_retrieve_body( $response ),
true
);
PHPでは、
公式SDKが未提供
(2023/07時点)
add_action(
‘transition_post_status',
function( $new_status, $old_status, $post ) {
if ( 'publish' !== $new_status ) {
return;
}
$OpenaiWP = new OpenAIWOrdPress();
$OpenaiWP->generate_excerpt_by_post( $post );
}, 10, 3 );
記事公開時に「だけ」
処理を走らせる
フックの例
<?php
function generate_excerpt_by_post( $post ) {
if ( $post->post_excerpt ) {
return;
}
$content = get_post_field( 'post_content', $post->ID );
$generated_excerpt = $this->generate_excerpt( $content);
if ( ! $generated_excerpt ) {
return;
}
}
wp_update_post( array(
'ID' => $post->ID,
'post_excerpt' => $generated_excerpt,
) );
概要(excerpt)がない時、
OpenAI APIで要約を生成
生成した要約の例
「記事公開時」にできそうなこと • 文章から「要約」や「SNSシェア文章」を生成 • 記事のカテゴリ設定やタグ付け • 英語の記事slugを生成
組み込み時の注意点 • OpenAI APIを「不必要に呼び出さない」 • 再生成は明示的な操作にする • データがあるならデフォルトでは生成スキップ • プロンプトをハードコードしない • 指示内容を調整するなら、Setting APIで設定画面を
ちょっとPHPやWordPressから 離れた使い方
LangChain https://www.langchain.com/
LangChain x WordPress • 記事データをモデルの推論対象に追加する(Embedding) • 記事の検索を自然言語ベースで実装 • 関連記事のレコメンドや検索 • Etc..
const updateIndex = async () => {
const embeddings = new OpenAIEmbeddings({
openAIApiKey: process.env.OPENAI_API_KEY
})
const model = new OpenAI({
temperature: 0,
openAIApiKey: process.env.OPENAI_API_KEY,
});
const response = await fetch('https://<site URL>/wp-json/wp/v2/posts')
const jsonResponse = await response.json()
const indexData = jsonResponse.map((data: any) => data.content.rendered)
const jsonString = JSON.stringify(indexData)
const bytes = new TextEncoder().encode(jsonString)
const jsonBlobData = new Blob([bytes], {
type: 'application/json:charset=utf-8'
})
const jsonLoader = new JSONLoader(jsonBlobData)
const docs = await jsonLoader.loadAndSplit()
const vectorStoreData = await MemoryVectorStore.fromDocuments(docs, embeddings)
writeFileSync('./dummy-data.json', JSON.stringify(vectorStoreData))
}
VectorStoreに
ベクトル化した
記事データを保存
const runAnswer = async () => {
const model = new ChatOpenAI({
temperature: 0,
openAIApiKey: process.env.OPENAI_API_KEY,
});
const embeddings = new OpenAIEmbeddings({
openAIApiKey: process.env.OPENAI_API_KEY
})
const jsonLoader = new JSONLoader('./dummy-data3.json')
const d = await jsonLoader.load()
const vectorStoreData = await HNSWLib.fromDocuments(d, embeddings)
const chain = RetrievalQAChain.fromLLM(model,
vectorStoreData.asRetriever())
return chain.call({
query: "AstroをCloudflare Pagesにデプロイする方法を教えて"
})
VectorStoreのデータから
自然言語で記事検索
const POST_TITLE = 'ReactコンポーネントをAstroコンポーネントに書き換え
る際の、クラス名の取り扱いについて'
export const run = async () => {
const result = await fetch(
`https://wp-api.example/wp-json/wp/v2/posts?per_page=50`
)
const resposne = await result.json()
const vectorStore = await HNSWLib.fromTexts(
resposne.map((post) => post.title.rendered),
resposne.map((post) => ({id: post.id})),
new OpenAIEmbeddings()
);
const search = await vectorStore.similaritySearch(POST_TITLE,
4);
};
return search.map(item => {
const post = resposne.find(post => {
return post.id === item.metadata.id)
});
return post
}).filter(post => post.title.rendered !== POST_TITLE)
近似値検索だけで、
関連記事検索(node.js)
コードの詳細はZennで https://zenn.dev/hideokamoto/scraps/744cfdd408d5bc
LangChain x WordPress • OpenAIなどへの連携をよしなにしてくれる • ToolsやAgentなどで、ユースケースに応じた最適な処理 • ツールごとに利用できる言語が限られる点に注意 • 処理をnode.jsやPythonで実施 -> 結果だけWP / PHPで取得など
Agenda • ChatGPTを利用した、コンテンツ作成の効率化した話 • OpenAI APIで、「記事作成作業」を効率化した話 • LLMを利用する際の注意点
LLMの注意点 • 予測結果に「再現性」を期待しない • そのモデルが「いつ学習したか」を忘れない • 「最終的な決断」は「あなたの仕事」です
予測結果に「再現性」を期待しない • 「さっきと言ってること違うやん・・・」 • プログラムは「書かれた通りに動く」が、 LLMは「都度都度予測する」だけ • 出力データをレビュー・訂正する仕組みを用意しよう
そのモデルの知識は「いつ」のもの? • 利用する「モデル」は、事前に学習を済ませている • 「学習していないこと」には、正確な回答ができない • 「その情報は、利用するモデルが知っている情報か?」 • 可能なら、Pythonなどで追加情報を埋め込む(Embedding)
「決めるのは、あなた」 • LLMは本質的には「文章の続きを予想」するもの • 「何をやるべきか」を決めてくれるものではない • 「自分が判断するための壁打ち」には頼もしいが、 「LLMに他者に対する選考や評価」をやらせない
https://www.docswell.com/s/yoshidashingo/ZLLVJ7-llm-app-on-aws#p15
まとめ • LLMは「この文章の続きはなにか?」を予測するモデル • 「苦手な作業」をLLMに任せよう • 「予測と処理は別物」なのを忘れない • LLMをうまくつかって、「自分のやりたいこと」に集中しよう