gemini-2.0-flashが賢くてコスパがよすぎる件
この記事はLLMをAPIで使うこと前提の記事です。
AI エージェント開発ハッカソン参加記事:Gemini 2.0 Flash で技術文書分析ツール「Tascario」を作ってみたの、技術的補足記事です。
APIでLLMを使っている皆さん gemini-2.0-flash
を使っていますか?APIで使う限り、かなり性能が高く、コスパも良すぎて、APIならこれ一択で良いのでは?とすら思い始めています。
この記事ではTypeScriptで書いていますが、Pythonなど他の言語でもできるので、お好きな対話型AIに聞いてみるといいでしょう。例えば、次のようなプロンプトです。
添付の記事はTypeScriptでサンプルが書かれているが、サンプル内容を全部Pythonに書き直して。それ以外はそのままで
この記事で得られる知見
- gemini-2.0-flashの力がわかる
- 文章を分析して構造化出力を得られる
- シンプルなプロンプトだと、アホの子になってしまう現象を回避して、gemini-2.0-flashの本領を発揮させる方法
gemini-2.0-flashの衝撃
もちろんタスクによって違うとは思いますが、筆者がLLMをAPIで使う時に重視するのは、与えたコンテキストの範囲で理解力が低下しないこと(100kトークン与えたら、100kトークン全部理解しててほしい)、指示に追従する能力と、日本語の読み書き性能です。
- コンテキストの範囲内で取りこぼさない
- 指示に追従する
- 日本語の読み書き
その点でずっと優秀であり続けたのがClaude 3.5 Sonnetです。コイツはこの3つの能力が尋常ではなく高いです。でも、お値段も高く、レスポンスも遅いです。大量のデータ処理をやらせるには、コスパが悪いです。
お値段が安いモデルにはclaude-3.0-haikuとかgpt-4o-miniとかgemini-1.5-flashとかがありますが、こいつらは割と能力が低いです。
そのため、トレードオフが存在していて、ずっと頭を悩ませ続けていたんですが、gemini-2.0-flashは、能力が高く、値段もすごく安いため、トレードオフしなくてもいいのでは?と希望を持てる状況になりました。
なお、gemini-2.0-flashと3.5-sonnetのどっちが賢いか?は特に検証していません。たぶん後者の方が間違いなく賢いとは思うけどAPIで使う範囲内であれば、sonnetじゃないと難しかったものも、リプレイスできるなという手応えです。
先日VertexAIでも使えるようになった
元々Google AI Studio(Google DeepMind)では gemini-2.0-flash-exp
というモデルを無料で試すことができます。このたび Gemini on VertexAI(Google Cloud)でも gemini-2.0-flash-001
というモデルが正式に使えるようになりました。
2/11現時点では、まだ us-central1
でしか使えないようなので、東京リージョンである asia-northeast1
とかで使うにはもう少し時間がかかるかもしれません。
実際に使いこなしてみる
筆者は構造化出力を活用しています。先日のAI エージェント開発ハッカソン参加記事:Gemini 2.0 Flash で技術文書分析ツール「Tascario」を作ってみたで使っていたテクニックを紹介します。
Zennなどからとってきた技術記事や、適当な記事を手元に用意します。
プロンプト
用意するプロンプトは次の通りです。
const prompt = `Contentは文章である。ただし不完全でノイズを含んでいることがある。これは日本人向けなので、必ず日本語で出力せよ。
1. Contentは必ずその文章の持つ主張があり、主張はこの文章全体で情報量が多いはずである。まずは主張を特定せよ
2. 主張を元にdescriptionを作成せよ
3. descriptionを元に、主張をすべて検証せよ
4. ノイズを取り除いた上で、残りの分析結果を日本語で出力せよ
<Content>
${content}
</Content>
※サイト全体で有効な情報、広告、広いアナウンスなどはノイズである可能性が高い。`;
重要なのはスキーマ定義です。
const schema: ResponseSchema = {
type: SchemaType.OBJECT,
properties: {
...
},
required: [...]
}
このような形式です。
中間分析
最終的に、gemini-2.0-flashの本当の力を発揮させるために、まず中間分析をします。
properties
の中に以下のコードを記述します。
claims: {
type: SchemaType.ARRAY,
description: "主張を出せる限り出し尽くす",
items: {
type: SchemaType.OBJECT,
properties: {
text: { type: SchemaType.STRING, description: "主張" },
source: { type: SchemaType.STRING, description: "情報源" },
evidence: { type: SchemaType.STRING, description: "根拠" },
certainty: {
type: SchemaType.STRING,
description: "確からしさ",
},
},
required: ["text", "evidence", "certainty"],
},
},
description: {
type: SchemaType.STRING,
description: "文書の要約を1000文字程度で",
},
claimValidation: {
type: SchemaType.ARRAY,
description: "descriptionを元に、主張を検証しなおす",
items: {
type: SchemaType.OBJECT,
properties: {
claim: {
type: SchemaType.STRING,
description: "検証する対象の主張",
},
summaryDescription: {
type: SchemaType.STRING,
description: "descriptionとの関連性を説明せよ",
},
reader: {
type: SchemaType.STRING,
description: "それは読者が知りたいことか?",
},
isRelevant: {
type: SchemaType.ARRAY,
description: "この文章の主題にそっているか?",
items: { type: SchemaType.BOOLEAN },
},
},
},
},
noises: {
type: SchemaType.ARRAY,
description: "除去すべきノイズ",
items: { type: SchemaType.STRING },
},
プロンプト指示の1〜3をさせています。
まずは claims
でこの文章における主張を出せる限り、出させます。そのための SchemaType.ARRAY
であり、その主張に関して詳細に考えさせるための SchemaType.OBJECT
です。どういう主張で、情報源はどこで、根拠は何か?確からしさを考えさせています。
この情報源や根拠は、モデルによってはハルシネーションを生じたり、指示の仕方に左右されがちですが、gemini-2.0-flashが賢いため、このシンプルすぎる指示でも十分に従ってくれます。もっと頭の良くないモデルだと、プロンプト全体に「ハルシネーションしないで」とか、指示に「Contentに含まれる文字列のみを使って」などが必要になることがあります。
またこれだけ賢いと、複数の情報源(URLと内容のセット)を与えると、どのURLの内容を参照した、みたいな情報も高い精度で取り出せるでしょう。
次にそれをもとに description
を作らせます。
この二つを元に claimValidation
で、それぞれの claims
が、主題に沿っているか、読者の知りたい情報かをバリデーションします。
最後に noise
として、文章に含まれている余分な要素を出力させます。
これで、中間分析ができます。
中間分析のメリットは gemini-2.0-flash
の、ロングコンテキスト下での指示追従能力低下を抑制できることです。一般的にLLMはコンテキストの先頭と最後の影響を一番受けます。LLMの仕組みを思い出してほしいんですが、LLMは、トークナイズされた文章を受け取って、続きのトークンを1つ出力します。そのため、ある1トークンを出力するときの「最後」というのは、自分が出力した内容そのものの影響を受けます。
つまり対話型アプリで単純な指示を出しているとアホの子になってしまう現象を、中間分析させることで回避しています。中間分析を、CoT(Chain of Thought)の一種と考えることもできるでしょう。
同じようなことは、構造化出力じゃなくて、XML出力とかでも可能で、Clineのプロンプトや、ClaudeのArtifactsのシステムプロンプトではXMLタグを出力させて、思考をさせていますが、筆者的には構造化出力を活用するのが一番楽なので、半ば手癖で書いています。どれを使うと一番効果的かはモデルによっても違うかもしれません。
最終成果物
最終成果物は次の通りです。
keywords: {
type: SchemaType.ARRAY,
description: "文書の重要なキーワード",
items: { type: SchemaType.STRING },
},
knowledge: {
type: SchemaType.ARRAY,
items: { type: SchemaType.STRING },
description: "この文書から得られる知識・知見",
},
readingContexts: {
type: SchemaType.ARRAY,
items: { type: SchemaType.STRING },
description: "この文章が役立つシチュエーション",
},
insights: {
type: SchemaType.ARRAY,
description: "この文章から得られる洞察",
items: { type: SchemaType.STRING },
},
summary: {
type: SchemaType.STRING,
description: "忙しい人向けに3000文字程度で分かりやすく解説せよ",
},
title: {
type: SchemaType.STRING,
description: "文書のタイトル",
},
},
AI Agent Hackathonのために作ったTascarioでは、記事を与えると、その記事をいま読むべきか?をさくっと判断できる材料を出力したいので、「この文章から得られる知識・知見」「この文章が役立つシチュエーション」「この文章から得られる洞察」などが重要になってきます。それらを出力させています。
ここまでのプロンプトとスキーマ定義をVertexAIのgenerateContentに食わせます。
const config = {
projectId: "hoge",
location: "us-central1",
modelId: "gemini-2.0-fash-001"
};
const vertexAI = new VertexAI({
project: config.projectId,
location: config.location,
});
const model = vertexAI.preview.getGenerativeModel({
model: config.modelId,
});
const result = await model.generateContent({
contents: [{ role: "user", parts: [{ text: request.prompt }] }],
generationConfig: {
responseMimeType: "application/json",
responseSchema,
},
});
const response = result.response;
const generatedText = response.candidates[0].content.parts[0].text;
このようなコードです。 generateContent
を呼び出すときに generateConfig
で responseMimeType: "application/json"
が指定されていると、JSONが帰ってくる構造化出力が実現できます。
コード全文
import {
type ResponseSchema,
SchemaType,
VertexAI,
} from "@google-cloud/vertexai";
const main = async (projectId: string, content: string) => {
const prompt = `Contentは文章である。ただし不完全でノイズを含んでいることがある。これは日本人向けなので、必ず日本語で出力せよ。
1. Contentは必ずその文章の持つ主張があり、主張はこの文章全体で情報量が多いはずである。まずは主張を特定せよ
2. 主張を元にdescriptionを作成せよ
3. descriptionを元に、主張をすべて検証せよ
4. ノイズを取り除いた上で、残りの分析結果を日本語で出力せよ
<Content>
${content}
</Content>
※サイト全体で有効な情報、広告、広いアナウンスなどはノイズである可能性が高い。`;
const responseSchema: ResponseSchema = {
type: SchemaType.OBJECT,
properties: {
// 中間分析
claims: {
type: SchemaType.ARRAY,
description: "主張を出せる限り出し尽くす",
items: {
type: SchemaType.OBJECT,
properties: {
text: { type: SchemaType.STRING, description: "主張" },
source: { type: SchemaType.STRING, description: "情報源" },
evidence: { type: SchemaType.STRING, description: "根拠" },
certainty: {
type: SchemaType.STRING,
description: "確からしさ",
},
},
required: ["text", "evidence", "certainty"],
},
},
description: {
type: SchemaType.STRING,
description: "文書の要約を1000文字程度で",
},
claimValidation: {
type: SchemaType.ARRAY,
description: "descriptionを元に、主張を検証しなおす",
items: {
type: SchemaType.OBJECT,
properties: {
claims: {
type: SchemaType.STRING,
description: "検証する対象の主張",
},
summaryDescription: {
type: SchemaType.STRING,
description: "descriptionとの関連性を説明せよ",
},
reader: {
type: SchemaType.STRING,
description: "それは読者が知りたいことか?",
},
isRelevant: {
type: SchemaType.ARRAY,
description: "この文章の主題にそっているか?",
items: { type: SchemaType.BOOLEAN },
},
},
},
},
noises: {
type: SchemaType.ARRAY,
description: "除去すべきノイズ",
items: { type: SchemaType.STRING },
},
// 成果物
keywords: {
type: SchemaType.ARRAY,
description: "文書の重要なキーワード",
items: { type: SchemaType.STRING },
},
knowledge: {
type: SchemaType.ARRAY,
items: { type: SchemaType.STRING },
description: "この文書から得られる知識・知見",
},
readingContexts: {
type: SchemaType.ARRAY,
items: { type: SchemaType.STRING },
description: "この文章が役立つシチュエーション",
},
insights: {
type: SchemaType.ARRAY,
description: "この文章から得られる洞察",
items: { type: SchemaType.STRING },
},
summary: {
type: SchemaType.STRING,
description: "忙しい人向けに3000文字程度で分かりやすく解説せよ",
},
title: {
type: SchemaType.STRING,
description: "文書のタイトル",
},
},
required: [
"claims",
"description",
"claimValidation",
"noises",
"keywords",
"knowledge",
"readingContexts",
"insights",
"summary",
"title",
],
};
const vertexAI = new VertexAI({
project: projectId,
location: "us-central1",
});
const model = vertexAI.preview.getGenerativeModel({
model: "gemini-2.0-flash-001",
});
const result = await model.generateContent({
contents: [{ role: "user", parts: [{ text: prompt }] }],
generationConfig: {
responseMimeType: "application/json",
responseSchema,
},
});
const response = result.response;
const generatedText = response?.candidates?.[0]?.content?.parts?.[0]?.text;
return generatedText;
};
const content = "<分析したい記事>"
const projectId = "<Google CloudのプロジェクトID>"
main(projectId, content).then(console.log).catch(console.error);
結果
せっかくなので AI エージェント開発ハッカソン参加記事:Gemini 2.0 Flash で技術文書分析ツール「Tascario」を作ってみた の記事を食わせてみましょう。
結果のJSON全文
{
"claimValidation": [
{
"claims": "Tascarioは、技術文書やLLMとの会話を分析し、人間の思考負荷を軽減するツールである。",
"isRelevant": [
true
],
"reader": "技術文書やLLMの活用に課題を感じている人",
"summaryDescription": "Tascarioの概要と目的が一致している。"
},
{
"claims": "Tascarioは、記事の分析、検索、ノート機能を通じて、情報過多な状況で必要な情報へのアクセスを支援する。",
"isRelevant": [
true
],
"reader": "情報収集・整理に課題を感じている人",
"summaryDescription": "Tascarioの主要機能と想定されるユースケースが合致している。"
},
{
"claims": "Tascarioは、Google Cloud Platform上で動作し、Vertex AIのLLMとEmbedding機能を活用している。",
"isRelevant": [
true
],
"reader": "クラウド技術に関心のあるエンジニア",
"summaryDescription": "Tascarioのアーキテクチャに関する記述と一致している。"
}
],
"claims": [
{
"certainty": "確実",
"evidence": "記事全体の内容、特に「Tascario概要」のセクション",
"text": "Tascarioは、技術文書やLLMとの会話を分析し、人間の思考負荷を軽減するツールである。",
"source": "Tascario概要"
},
{
"certainty": "確実",
"evidence": "想定ユースケース1, 想定ユースケース2",
"text": "Tascarioは、記事の分析、検索、ノート機能を通じて、情報過多な状況で必要な情報へのアクセスを支援する。",
"source": "想定ユースケース"
},
{
"certainty": "確実",
"evidence": "アーキテクチャ",
"text": "Tascarioは、Google Cloud Platform上で動作し、Vertex AIのLLMとEmbedding機能を活用している。",
"source": "アーキテクチャ"
},
{
"certainty": "高い",
"evidence": "技術的特徴",
"text": "Tascarioは、Gemini 2.0 Flashとtext-multilingual-embedding-002を利用して、文書の分析と検索を行っている。",
"source": "技術的特徴"
},
{
"certainty": "やや低い",
"evidence": "課題, 導入方法",
"text": "Tascarioの導入と設定には、Google Cloud Platformに関する一定の知識が必要である。",
"source": "課題, 導入方法"
}
],
"description": "この記事は、AIエージェント開発ハッカソンで開発された技術文書分析ツール「Tascario」について解説しています。Tascarioは、Gemini 2.0 Flashを活用し、技術文書やLLMとの会話を分析することで、情報過多な状況における思考負荷を軽減し、必要な情報へのアクセスを支援します。記事の分析、検索機能、ノート機能などを搭載し、Google Cloud Platform上で動作します。導入にはGCPに関する知識が求められますが、情報収集・整理の効率化に貢献するツールとして期待されます。",
"insights": [
"LLMを活用した文書分析ツールは、情報過多な現代において、思考負荷の軽減と効率的な情報収集に貢献できる。",
"クラウドベースのアーキテクチャとAPI連携により、柔軟なシステム構築と機能拡張が可能になる。",
"ユーザーインターフェースの改善と機能拡充により、更なる利便性の向上が期待できる。"
],
"keywords": [
"AIエージェント",
"技術文書分析",
"Gemini 2.0 Flash",
"LLM",
"情報検索",
"知識管理",
"Cloud Run",
"Vertex AI",
"Firestore",
"Tascario"
],
"knowledge": [
"Gemini 2.0 Flashを用いた技術文書分析の手法",
"Embeddingによる文書のベクトル化と類似度計算",
"Google Cloud PlatformにおけるAIアプリケーションの構築",
"tRPC APIによるフロントエンドとバックエンドの連携",
"情報過多な状況における課題と、それを解決するためのAI技術の応用"
],
"noises": [
"Zennの告知",
"バッジに関する記述",
"記事の公開・更新日",
"他の記事へのリンク",
"目次",
"投稿・埋め込みに関する記述",
"冗長な技術的詳細(例:具体的なコードの場所)",
"インフラ構築に関する個人的な苦労話",
"ハッカソン参加の感想"
],
"readingContexts": [
"技術文書や記事を効率的に分析・検索したい時",
"大量のLLMの会話ログを整理・分析したい時",
"情報過多な状況で、必要な情報を見つけ出すのに苦労している時",
"AI技術を活用した情報収集・整理ツールに関心がある時",
"Gemini 2.0 FlashやVertex AIの活用事例を知りたい時"
],
"summary": "「Tascario」は、AIエージェント開発ハッカソンで開発された、技術文書分析ツールです。Gemini 2.0 Flashを活用し、大量の技術文書やLLMとの会話を分析することで、情報過多による思考の負担を軽減し、必要な情報へのアクセスを容易にします。主な機能として、記事の分析、自然言語による検索、ノート機能があり、Google Cloud Platform上で動作します。記事を取り込むと、AIが内容を分析し、読むべきタイミングや得られる知見、洞察などを提示します。また、キーワード検索だけでなく、AIが文脈を理解して関連性の高い記事を提案します。アーキテクチャは、T3 Stackをベースとし、Firestoreをデータストアとして利用、Vertex AIのLLMとEmbedding機能を活用しています。導入にはGCPに関する知識が必要ですが、情報収集・整理を効率化する強力なツールとなる可能性を秘めています。今後の課題として、一括インポート機能やノート機能の完成、UIの改善などが挙げられています。",
"title": "AI エージェント開発ハッカソン参加記事:Gemini 2.0 Flash で技術文書分析ツール「Tascario」を作ってみた"
}
中間成果物を削ったときのJSON全文
{
"insights": [
"LLMを活用することで、大量の技術文書やAIとの会話から必要な情報を効率的に抽出できる。",
"個人の知識管理や情報収集をAIによって高度化し、思考の負荷を軽減できる。",
"Gemini 2.0 FlashのようなLLMとembedding技術を組み合わせることで、文書の分析と検索を高度化できる。",
"クラウド環境(GCP)を活用することで、スケーラブルな文書管理・分析システムを構築できる。",
"既存の技術(T3 Stack, tRPCなど)を組み合わせることで、効率的な開発が可能になる。"
],
"keywords": [
"AIエージェント",
"Gemini 2.0 Flash",
"技術文書分析",
"LLM",
"Embedding",
"GCP",
"Cloud Run",
"Firestore",
"T3 Stack",
"tRPC",
"情報過多",
"知識管理",
"情報検索",
"ノート",
"自動サジェスト"
],
"knowledge": [
"Tascarioは、Gemini 2.0 Flashを活用した技術文書分析ツールである。",
"Tascarioは、文書の取り込み、分析、検索、ノート作成機能を備えている。",
"Tascarioは、GCP上で動作し、Cloud Run, Firestore, Vertex AIなどのサービスを利用している。",
"Tascarioのアーキテクチャは、T3 Stackをベースとしており、フロントエンドとバックエンドはtRPCで通信している。",
"Tascarioは、embedding技術を用いて文書の類似度を計算し、関連する情報を検索する。",
"Tascarioは、ノート機能を通じて、思考の整理やAIによるサジェストを支援する。"
],
"readingContexts": [
"大量の技術文書や情報を効率的に処理したいとき",
"AIとの会話内容を整理・分析したいとき",
"必要な情報を迅速に検索したいとき",
"思考を整理し、アイデアを発展させたいとき",
"個人の知識管理システムを構築したいとき",
"AI技術を活用した情報収集・分析ツールに興味があるとき"
],
"summary": "Tascarioは、Gemini 2.0 Flashを活用した技術文書分析ツールです。日々の大量の情報に溺れている人や、思考負荷を下げたい人を対象に、技術文書やAIとの会話を分析し、必要な情報を効率的に抽出・検索することを目的としています。主な機能として、記事の登録・分析、ダッシュボード表示、記事検索、ノート作成があり、GCP上で動作します。アーキテクチャはT3 Stackをベースとし、フロントエンドとバックエンドはtRPCで通信します。Vertex AIのLLMとEmbedding機能を活用し、文書の類似度を計算して関連情報を検索します。ノート機能では、思考の整理やAIによるサジェストを支援します。今後は、一括インポートやRSSフィードの取り込み、Chrome拡張機能などの機能拡張が検討されています。開発者は、個人の知識管理システムを高度化し、「僕の考えた最強で最終のノート」を完成させることを目指しています。",
"title": "AIエージェント開発ハッカソン参加記事:Gemini 2.0 Flash で技術文書分析ツール「Tascario」を作ってみた"
}
サマリーはさほど違いはないんですが、大きく違うのは読むべき時(readingContext
)や得られる知見(knowledge
)です。
ちょうど、Tascarioでは「文章を読むべきかどうかを即座に判断する材料」が重要なのでこの二つがキーとなります。
中間分析なしの「読むべきとき」
- 大量の技術文書や情報を効率的に処理したいとき
- AIとの会話内容を整理・分析したいとき
- 必要な情報を迅速に検索したいとき
- 思考を整理し、アイデアを発展させたいとき
- 個人の知識管理システムを構築したいとき
- AI技術を活用した情報収集・分析ツールに興味があるとき
中間分析ありの「読むべきとき」
- 技術文書や記事を効率的に分析・検索したい時
- 大量のLLMの会話ログを整理・分析したい時
- 情報過多な状況で、必要な情報を見つけ出すのに苦労している時
- AI技術を活用した情報収集・整理ツールに関心がある時
- Gemini 2.0 FlashやVertex AIの活用事例を知りたい時
この通り、中間分析を入れるとより的確になります。「Gemini 2.0 FlashやVertex AIの活用事例を知りたい時」が入っているのは得点が高いですね。
中間分析なしの「読んで得られる知見」
- Tascarioは、Gemini 2.0 Flashを活用した技術文書分析ツールである
- Tascarioは、文書の取り込み、分析、検索、ノート作成機能を備えている
- Tascarioは、GCP上で動作し、Cloud Run, Firestore, Vertex AIなどのサービスを利用している
- Tascarioのアーキテクチャは、T3 Stackをベースとしており、フロントエンドとバックエンドはtRPCで通信している
- Tascarioは、embedding技術を用いて文書の類似度を計算し、関連する情報を検索する
- Tascarioは、ノート機能を通じて、思考の整理やAIによるサジェストを支援する
中間分析ありの「読んで得られる知見」
- Gemini 2.0 Flashを用いた技術文書分析の手法
- Embeddingによる文書のベクトル化と類似度計算
- Google Cloud PlatformにおけるAIアプリケーションの構築
- tRPC APIによるフロントエンドとバックエンドの連携
- 情報過多な状況における課題と、それを解決するためのAI技術の応用
この通り雲泥の差になっています。中間分析なしだとTascarioそのものの機能説明に終始していて、読者にとって読んで得られる知見ではありませんが、中間分析ありだと、ちゃんと読者にとって意味のある情報になっています。
また、ノイズが多い記事の分析をさせたとき、中間分析がないとノイズだらけの結果になります。
たとえば https://dic.pixiv.net/a/ジト目マチュ は、内容がかなりシンプルすぎて、他の情報が多い記事です。
これを分析させたとき、中間分析をしてノイズ除去をした方が的確になります。
中間分析ありの、「読んで得られる知見」と「読むべきとき」が次の通りです。ちゃんと、「ジト目マチュ」という極めてニッチな文章を正しく表現できていると思います。
{
"knowledge": [
"ジト目マチュは、『機動戦士Gundam GQuuuuuuX』の主人公アマテ・ユズリハの萌え要素である。",
"ジト目マチュは、pixivでイラストや小説が投稿されている。",
"ジト目マチュは、専用タグが作られるほど特徴的なキャラクターである。"
],
"readingContexts": [
"『機動戦士Gundam GQuuuuuuX』のファン",
"ジト目属性のキャラクターに興味がある人",
"pixivなどのイラスト投稿サイトで二次創作を楽しむ人",
"アニメや漫画のキャラクターの属性について知りたい人",
"特定のキャラクター属性に特化したタグの利用状況を知りたい人"
],
}
中間分析ありJSON全文
{
"claimValidation": [
{
"claims": "ジト目マチュは『機動戦士Gundam GQuuuuuuX』の主人公、アマテ・ユズリハの萌え要素である。",
"isRelevant": [
true
],
"reader": "アニメファン、ガンダムファン、萌え要素に興味がある人",
"summaryDescription": "記事の冒頭で「ジト目マチュ」がアマテ・ユズリハの萌え要素であると明記されているため、関連性が高い。"
},
{
"claims": "ジト目マチュは専用タグ化されるほど特徴的なキャラクターである。",
"isRelevant": [
true
],
"reader": "イラストレーター、アニメーター、キャラクターデザイナー",
"summaryDescription": "記事本文で、専用タグ化されるほど特徴的なキャラクターであると述べられているため、関連性が高い。"
}
],
"claims": [
{
"certainty": "高",
"evidence": "記事タイトルおよび冒頭の説明文",
"text": "ジト目マチュは、『機動戦士Gundam GQuuuuuuX』の主人公アマテ・ユズリハの、ジト目属性を強調した萌え要素を指す。",
"source": "ピクシブ百科事典"
},
{
"certainty": "中",
"evidence": "記事本文",
"text": "ジト目マチュは、専用タグが作られるほど特徴的なキャラクターである。",
"source": "ピクシブ百科事典"
},
{
"certainty": "低",
"evidence": "pixivのイラスト投稿数",
"text": "ジト目マチュは、pixivを中心に一定の人気がある。",
"source": "ピクシブ百科事典"
}
],
"description": "この記事は、ピクシブ百科事典における『機動戦士Gundam GQuuuuuuX』の主人公アマテ・ユズリハの萌え要素「ジト目マチュ」に関する解説記事です。ジト目マチュが専用タグ化されるほど特徴的なキャラクターであることを説明し、pixivにおけるイラストの投稿状況や関連情報をまとめています。",
"insights": [
"特定のキャラクターの属性が、独立した萌え要素として認識され、タグ付けされる現象。",
"pixivのようなプラットフォームが、特定のキャラクター属性に注目した二次創作を促進する役割を果たしている。",
"アニメキャラクターの属性が、ファンコミュニティによって多様な解釈や表現を生み出す。",
"ジト目という属性が、特定のキャラクターの魅力を高める要素として機能している。"
],
"keywords": [
"ジト目マチュ",
"アマテ・ユズリハ",
"機動戦士Gundam GQuuuuuuX",
"ジト目",
"萌え要素",
"ピクシブ百科事典"
],
"knowledge": [
"ジト目マチュは、『機動戦士Gundam GQuuuuuuX』の主人公アマテ・ユズリハの萌え要素である。",
"ジト目マチュは、pixivでイラストや小説が投稿されている。",
"ジト目マチュは、専用タグが作られるほど特徴的なキャラクターである。"
],
"noises": [
"ピクシブ百科事典のプライバシーポリシー改定に関する告知",
"サイトのヘッダー、フッター情報(ログイン、新規登録、記事投稿など)",
"注目記事、ニュース",
"記事のカテゴリ分類",
"サイト内のナビゲーションリンク",
"広告",
"pixivisionの記事一覧",
"人気の記事ランキング",
"更新された記事、新しく作成された記事の一覧",
"著作権情報",
"フィードバック",
"編集機能へのリンク",
"問題報告機能"
],
"readingContexts": [
"『機動戦士Gundam GQuuuuuuX』のファン",
"ジト目属性のキャラクターに興味がある人",
"pixivなどのイラスト投稿サイトで二次創作を楽しむ人",
"アニメや漫画のキャラクターの属性について知りたい人",
"特定のキャラクター属性に特化したタグの利用状況を知りたい人"
],
"summary": "この記事は、ピクシブ百科事典における「ジト目マチュ」というキーワードに関する解説です。ジト目マチュとは、『機動戦士Gundam GQuuuuuuX』の主人公アマテ・ユズリハの、ジト目属性を強調した萌え要素を指します。記事では、ジト目マチュがpixivを中心にイラストや小説などの二次創作の対象となっていること、専用のタグが作られるほど特徴的なキャラクターとして認識されていることが述べられています。関連情報として、アマテ・ユズリハの親記事や、その他の関連キーワードへのリンクが提供されています。また、pixivに投稿されたジト目マチュのイラストが多数紹介されており、ファンコミュニティにおける活動の一端を垣間見ることができます。総じて、この記事は、特定のキャラクター属性が独立した萌え要素として認識され、二次創作を通じて多様な表現を生み出している事例を示すものと言えるでしょう。",
"title": "ジト目マチュ (じとめまちゅ)とは【ピクシブ百科事典】"
}
中間分析なしだと、次のように、大分ボヤけてしまいます。「ジト目マチュ」というコアテーマから外れたものになります。
{
"knowledge": [
"「ジト目」は、キャラクターの表情の一種であり、アニメやマンガなどの文脈で特定の感情や性格を表すために使用される。",
"pixivは、イラストや小説などの創作物を共有・公開するためのオンラインプラットフォームである。",
"機動戦士Gundam GQuuuuuuXは、ガンダムシリーズの一作品であり、特定のアニメシリーズまたは関連作品を指す。",
"萌え要素とは、キャラクターの魅力的な特徴であり、ファンがそのキャラクターに愛着を持つ理由となる。",
"タグは、オンラインコンテンツを分類し、検索を容易にするために使用されるキーワードまたはフレーズである。"
],
"readingContexts": [
"アニメやマンガのキャラクターデザインに関心がある人",
"pixivなどのオンラインアートコミュニティの動向を知りたい人",
"特定のキャラクターのファンアートや二次創作を楽しみたい人",
"ガンダムシリーズの新しい作品やキャラクターについて情報を探している人",
"「ジト目」のような特定の視覚的特徴が、キャラクターの魅力にどのように貢献するかを理解したい人"
],
}
中間分析なしJSON全文
{
"insights": [
"「ジト目マチュ」は、『機動戦士Gundam GQuuuuuuX』の主人公アマテ・ユズリハの萌え要素の一つとして認識されている。",
"pixivにおいて、「ジト目マチュ」のイラストや小説が投稿されており、一定のファンコミュニティが存在する。",
"「ジト目マチュ」タグは、特定のキャラクターの視覚的特徴を強調し、ファンアートや創作活動を促進する役割を果たしている。",
"記事は、関連するキャラクターや作品へのリンクを提供し、読者がさらに情報を探索できるように設計されている。",
"pixiv百科事典の記事は、ユーザーがコンテンツを投稿・共有し、特定のテーマに関する情報を集約するプラットフォームとして機能している。"
],
"keywords": [
"ジト目マチュ",
"機動戦士Gundam GQuuuuuuX",
"アマテ・ユズリハ",
"pixiv",
"萌え要素",
"キャラクター",
"イラスト",
"小説",
"ファンアート",
"タグ"
],
"knowledge": [
"「ジト目」は、キャラクターの表情の一種であり、アニメやマンガなどの文脈で特定の感情や性格を表すために使用される。",
"pixivは、イラストや小説などの創作物を共有・公開するためのオンラインプラットフォームである。",
"機動戦士Gundam GQuuuuuuXは、ガンダムシリーズの一作品であり、特定のアニメシリーズまたは関連作品を指す。",
"萌え要素とは、キャラクターの魅力的な特徴であり、ファンがそのキャラクターに愛着を持つ理由となる。",
"タグは、オンラインコンテンツを分類し、検索を容易にするために使用されるキーワードまたはフレーズである。"
],
"readingContexts": [
"アニメやマンガのキャラクターデザインに関心がある人",
"pixivなどのオンラインアートコミュニティの動向を知りたい人",
"特定のキャラクターのファンアートや二次創作を楽しみたい人",
"ガンダムシリーズの新しい作品やキャラクターについて情報を探している人",
"「ジト目」のような特定の視覚的特徴が、キャラクターの魅力にどのように貢献するかを理解したい人"
],
"summary": "この文章は、ピクシブ百科事典における「ジト目マチュ」というキャラクターに関する記事です。ジト目マチュは、アニメ『機動戦士Gundam GQuuuuuuX』の主人公アマテ・ユズリハの萌え要素の一つであり、その特徴的なジト目が専用タグ化されるほど人気があります。記事では、pixivにおけるイラストや小説の投稿状況、関連キャラクター、関連記事などが紹介されています。また、記事にはpixivisionのおすすめ記事や、pixiv百科事典の人気記事、更新された記事、新しく作成された記事へのリンクも含まれています。記事の閲覧数やコメント数、pixivでのタグ投稿数などの情報も提供されており、ジト目マチュに関心のある読者にとって有益な情報源となっています。記事は、キャラクターの視覚的特徴がどのようにファンコミュニティで共有され、楽しまれているかを示す一例です。",
"title": "ジト目マチュ (じとめまちゅ)とは【ピクシブ百科事典】"
}
ノイズの方が多い記事から、正しく「ジト目マチュ」を取り出させているすごさがわかるでしょうか?最初から人間が「ジト目マチュ」を出してくれといえば従ってくれますが、それでは汎用的なプロンプトではありません。かといって、「タイトル」から取り出してくれ」という絞った指示だとそこに的確に書かれていないものは取り出せないでしょう。
中間分析があることによって、LLMの持つ柔軟な知性が的確に発揮されたことがわかるでしょう。
出力形式
ちゃんとJSONで出力が保証されているようでその点は楽でした。実験途中では古いモデルだったり、オプション指定ミスとかで、JSON以外の文字列が混じって苦労しました。なお、その名残がHackathonのコードである https://github.com/erukiti/tascario-public に残っていますが、そのコードは不要だったはずです。
発展
本当はTypeScriptとの相性の良いzodスキーマを使いたかったです。zodスキーマをJsonSchemaに変換するライブラリはあるので、食わせてみたんですが、JsonSchmeaそのものではないようでダメでした。
まとめ
-
gemini-2.0-flash
はAPIで使うこと前提で十分な性能を発揮し、値段が安いため、コスパのよい優秀なモデル - ただし、プロンプトの与え方次第で性能が大きく変わる
- 中間分析をさせることで、最終成果物の精度が大きく変わる(構造化出力を駆使したCoT)
- 構造化出力は指示がしやすく、かつ情報が取り出しやすい
Discussion
すでにご存知かもしれないですが、Firebase GenKitは内部的にラップされたzodを利用して、GeminiモデルでJSONスキーマに準拠した構造化出力をさせることができます。
参考: https://firebase.google.com/docs/genkit/models?hl=ja#structured-output