Dify RAG でヒットしないとき:埋め込み品質・分割・検索パラメータの診断術
Dify で RAG(Retrieval-Augmented Generation)を構築したものの、「期待した文書がヒットしない」「検索精度が低い」という経験はありませんか。せっかくナレッジベースを整備しても、適切な情報が取得できなければ AI の回答品質は大きく低下してしまいます。
RAG の検索精度を左右する要因は多岐にわたりますが、特に重要なのが 埋め込み品質・文書分割(チャンク分割)・検索パラメータ の 3 つです。本記事では、これらの要素を体系的に診断し、ヒット率を改善する実践的な手法を解説いたします。初めて RAG のチューニングに取り組む方でも、段階的に問題を特定できるよう、図解と具体例を交えてご紹介しますね。
背景
RAG の基本的な仕組み
RAG は、大規模言語モデル(LLM)に外部知識を組み合わせることで、より正確で最新の情報に基づいた回答を生成する技術です。Dify では、ユーザーがアップロードした文書をナレッジベースとして管理し、質問に応じて関連する文書を検索して LLM に渡します。
以下の図は、Dify における RAG の基本的なデータフローを示しています。
mermaidflowchart LR
user["ユーザー"] -->|質問| dify["Dify アプリ"]
dify -->|埋め込みベクトル化| embed["Embedding モデル"]
embed -->|検索クエリベクトル| vdb[("ベクトルDB")]
vdb -->|類似文書取得| dify
dify -->|プロンプト生成| llm["LLM"]
llm -->|回答| user
図で理解できる要点:
- ユーザーの質問は埋め込みベクトルに変換される
- ベクトル DB から類似度の高い文書が取得される
- 取得した文書を元に LLM が回答を生成する
埋め込みベクトルと類似度検索
埋め込み(Embedding)とは、テキストを数百〜数千次元のベクトル(数値の配列)に変換する技術です。意味的に近いテキストは、ベクトル空間上でも近い位置に配置されます。
Dify では、文書を事前に埋め込みベクトルに変換してベクトル DB に保存し、質問が来ると同様にベクトル化して類似度検索を行います。この仕組みにより、キーワード検索では見つけられない意味的に関連する文書も取得できるのです。
しかし、この仕組みが適切に機能するには、いくつかの条件が揃っている必要があります。
課題
RAG でヒットしない主な原因は、以下の 3 つの領域に分類できます。
1. 埋め込み品質の問題
埋め込みモデルが質問と文書の意味的関連性を正しく捉えられていない場合、類似度スコアが低くなり、関連文書が取得できません。
主な原因:
- 埋め込みモデルの言語や分野が合っていない
- 質問と文書の表現が大きく異なる
- モデルの次元数や性能が不足している
2. 文書分割(チャンク分割)の問題
文書を適切なサイズに分割できていないと、必要な情報が複数のチャンクに分散したり、逆に大きすぎて検索精度が低下したりします。
主な原因:
- チャンクサイズが大きすぎる(情報密度が低い)
- チャンクサイズが小さすぎる(文脈が失われる)
- オーバーラップが不適切(重複が少なすぎる)
3. 検索パラメータの問題
適切な文書が埋め込まれていても、検索時のパラメータ設定が不適切だと、必要な文書が取得されません。
主な原因:
- Top K の値が小さすぎる(候補が少ない)
- スコア閾値が高すぎる(フィルタリングされすぎ)
- リランキングの設定が不適切
以下の図は、これらの課題がどのように検索失敗につながるかを示しています。
mermaidflowchart TD
query["質問文"] --> embed_issue{"埋め込み品質<br/>は適切か?"}
embed_issue -->|No| fail1["類似度スコア低下<br/>→ヒットしない"]
embed_issue -->|Yes| chunk_issue{"チャンク分割<br/>は適切か?"}
chunk_issue -->|No| fail2["情報の分散・欠落<br/>→ヒットしない"]
chunk_issue -->|Yes| param_issue{"検索パラメータ<br/>は適切か?"}
param_issue -->|No| fail3["フィルタリング過多<br/>→ヒットしない"]
param_issue -->|Yes| success["適切な文書取得<br/>→回答生成"]
図で理解できる要点:
- 問題は段階的に発生する
- 各段階で適切な対処が必要
- 最終的な成功には 3 つすべての要素が重要
解決策
ここでは、各課題に対する診断方法と具体的な対処法を解説します。
1. 埋め込み品質の診断と改善
診断方法
まず、埋め込みモデルが質問と文書を適切にベクトル化できているかを確認します。Dify のナレッジベース設定で、現在使用している埋め込みモデルを確認しましょう。
診断チェックリスト:
| # | 項目 | 確認内容 | 推奨設定 |
|---|---|---|---|
| 1 | モデルの言語対応 | 日本語文書に対応しているか | multilingual または ja モデル |
| 2 | モデルの次元数 | ベクトルの次元数は十分か | 768 次元以上 |
| 3 | モデルの分野適合性 | 文書の専門分野に適しているか | 汎用モデルまたは分野特化モデル |
| 4 | 類似度スコア | 実際の検索でスコアはどの程度か | 0.7 以上が理想 |
改善方法
埋め込みモデルの変更は、Dify のナレッジベース設定から行えます。以下は推奨されるモデルの選択基準です。
日本語文書の場合:
text-embedding-ada-002(OpenAI): 多言語対応で高品質text-multilingual-embedding-002(Google): 多言語に強いintfloat/multilingual-e5-large(オープンソース): コスト重視
モデルを変更した後は、必ずナレッジベースの 再埋め込み を実行してください。既存の埋め込みベクトルは自動的には更新されません。
typescript// Dify API を使った埋め込みベクトルの確認例
interface EmbeddingConfig {
provider: string;
model: string;
dimensions: number;
}
// 現在の埋め込み設定を確認
const checkEmbeddingConfig = async (
datasetId: string
): Promise<EmbeddingConfig> => {
const response = await fetch(
`https://api.dify.ai/v1/datasets/${datasetId}`,
{
headers: {
Authorization: `Bearer ${process.env.DIFY_API_KEY}`,
},
}
);
const data = await response.json();
return data.embedding_model;
};
上記のコードは、Dify API を使って現在のナレッジベースの埋め込み設定を確認する例です。provider と model の情報を取得することで、どのモデルが使われているかを確認できます。
2. 文書分割(チャンク分割)の診断と改善
診断方法
チャンク分割の適切性を判断するには、実際に分割された文書を確認するのが最も確実です。
診断チェックリスト:
| # | 項目 | 確認内容 | 推奨設定 |
|---|---|---|---|
| 1 | チャンクサイズ | 1 チャンクの文字数は適切か | 500-1000 文字 |
| 2 | オーバーラップ | 隣接チャンク間の重複は適切か | チャンクサイズの 10-20% |
| 3 | 文脈の保持 | 意味の切れ目で分割されているか | 段落・セクション単位 |
| 4 | 情報の完結性 | 1 チャンク内で意味が完結するか | 質問に答えられる単位 |
チャンクサイズの最適化
チャンクサイズは、文書の性質によって調整が必要です。以下は、文書タイプ別の推奨設定です。
文書タイプ別の推奨設定:
| # | 文書タイプ | チャンクサイズ | オーバーラップ | 理由 |
|---|---|---|---|---|
| 1 | 技術ドキュメント | 800-1000 文字 | 100-200 文字 | 詳細な説明が多い |
| 2 | FAQ・Q&A | 300-500 文字 | 50-100 文字 | 1 問 1 答で完結 |
| 3 | 長文記事・論文 | 1000-1500 文字 | 200-300 文字 | 文脈の連続性が重要 |
| 4 | マニュアル | 500-800 文字 | 100-150 文字 | 手順の一貫性が必要 |
Dify では、ナレッジベースの「分割設定」からこれらのパラメータを調整できます。設定変更後は、文書を再度アップロードして分割を反映させましょう。
typescript// チャンク分割設定の例
interface ChunkConfig {
mode: 'automatic' | 'custom';
max_tokens: number;
chunk_overlap: number;
separator: string;
}
// 技術ドキュメント向けの設定例
const technicalDocConfig: ChunkConfig = {
mode: 'custom',
max_tokens: 800, // 約 800-1000 文字相当
chunk_overlap: 150, // 約 150-200 文字の重複
separator: '\n\n', // 段落区切り
};
このコードは、Dify の API または設定ファイルでチャンク分割を定義する際の構造例です。max_tokens はトークン数(日本語では約 1 文字 = 1-2 トークン)、chunk_overlap は重複部分のトークン数を指定します。
オーバーラップの重要性
オーバーラップ(重複)を設定すると、文書の境界をまたぐ情報も確実に取得できます。以下の図で、オーバーラップの効果を視覚的に理解しましょう。
mermaidflowchart TD
doc["元文書: ABCDEFGHIJKLMNOP"]
subgraph no_overlap["オーバーラップなし"]
chunk1["チャンク1: ABCDE"]
chunk2["チャンク2: FGHIJ"]
chunk3["チャンク3: KLMNO"]
end
subgraph with_overlap["オーバーラップあり"]
chunk4["チャンク1: ABCDE"]
chunk5["チャンク2: DEFGH"]
chunk6["チャンク3: GHIJK"]
end
doc --> no_overlap
doc --> with_overlap
no_overlap --> issue["境界情報DEが<br/>取得できない"]
with_overlap --> good["境界情報DEも<br/>確実に取得"]
図で理解できる要点:
- オーバーラップなしでは境界の情報が失われる可能性がある
- オーバーラップありでは境界情報も確実にカバーできる
- 適切な重複率でバランスを取ることが重要
3. 検索パラメータの診断と改善
診断方法
検索パラメータは、取得する文書の量と品質を制御します。Dify のアプリ設定で確認できますので、まずは現在の設定を把握しましょう。
診断チェックリスト:
| # | パラメータ | 確認内容 | 推奨設定 | 影響 |
|---|---|---|---|---|
| 1 | Top K | 取得する文書数は適切か | 3-5 件 | 少ないと取りこぼし |
| 2 | Score Threshold | スコア閾値は厳しすぎないか | 0.7 以下 | 高いとフィルタ過多 |
| 3 | Rerank | リランキングを有効化しているか | 有効推奨 | 精度向上 |
| 4 | Rerank Top N | リランキング後の件数は適切か | 2-3 件 | LLM への入力を最適化 |
Top K の最適化
Top K は、ベクトル検索で取得する候補文書の数です。この値が小さすぎると、必要な情報が取得されない可能性があります。
typescript// 検索パラメータの設定例
interface RetrievalConfig {
topK: number;
scoreThreshold: number;
rerankEnabled: boolean;
rerankTopN: number;
}
// 標準的な設定例
const standardConfig: RetrievalConfig = {
topK: 5, // 5 件の候補を取得
scoreThreshold: 0.7, // 類似度 0.7 以上のみ
rerankEnabled: true, // リランキング有効化
rerankTopN: 3, // 最終的に 3 件を LLM に渡す
};
このコードは、Dify のアプリ設定における検索パラメータの構造です。topK で候補数を、scoreThreshold で品質基準を制御します。
スコア閾値の調整
スコア閾値(Score Threshold)は、類似度がこの値以上の文書のみを取得するフィルタです。厳しすぎると有用な文書まで除外されてしまいます。
推奨調整ステップ:
- 初期設定: スコア閾値を
0.0(無効)に設定して、すべての候補のスコアを確認 - スコア分布の把握: 実際の検索で、関連文書のスコアがどの範囲にあるかを確認
- 閾値の設定: 関連文書の最低スコアより少し低めに設定(例: 最低スコアが 0.75 なら、閾値は 0.70)
- 検証と調整: 実際の検索結果を見ながら微調整
typescript// スコア閾値の段階的調整を支援する関数
const analyzeScoreDistribution = (
results: Array<{ content: string; score: number }>
) => {
// スコアの統計情報を計算
const scores = results.map((r) => r.score);
const max = Math.max(...scores);
const min = Math.min(...scores);
const avg =
scores.reduce((a, b) => a + b, 0) / scores.length;
console.log(`スコア分布:`);
console.log(` 最大: ${max.toFixed(3)}`);
console.log(` 最小: ${min.toFixed(3)}`);
console.log(` 平均: ${avg.toFixed(3)}`);
// 推奨閾値を提案
const recommendedThreshold = min - 0.05;
console.log(
`推奨閾値: ${recommendedThreshold.toFixed(3)}`
);
};
上記の関数は、検索結果のスコア分布を分析し、適切な閾値を提案します。最小スコアより少し低めの値を推奨することで、取りこぼしを防ぎます。
リランキングの活用
リランキング(Rerank)は、ベクトル検索で取得した候補を、より高度なモデルで再評価する機能です。これにより、検索精度を大幅に向上できます。
typescript// リランキングの動作イメージ
interface RerankResult {
originalRank: number;
rerankScore: number;
content: string;
}
// ベクトル検索 → リランキングのフロー
const searchWithRerank = async (
query: string,
config: RetrievalConfig
): Promise<RerankResult[]> => {
// 1. ベクトル検索で Top K 件を取得
const vectorResults = await vectorSearch(
query,
config.topK
);
// 2. リランキングモデルで再評価
const rerankResults = await rerankModel(
query,
vectorResults
);
// 3. Top N 件を最終結果として返す
return rerankResults.slice(0, config.rerankTopN);
};
このコードは、ベクトル検索とリランキングを組み合わせた検索フローを示しています。最初に多めの候補を取得し、高精度なモデルで絞り込むことで、精度とコストのバランスを取ります。
以下の図は、検索パラメータの最適化プロセスを示しています。
mermaidflowchart TD
start["検索開始"] --> vector["ベクトル検索<br/>Top K=5"]
vector --> threshold{"スコア閾値<br/>≥0.7?"}
threshold -->|Yes| pass["候補に残す"]
threshold -->|No| filter["除外"]
pass --> rerank["リランキング<br/>精度向上"]
rerank --> final["Top N=3を<br/>LLMに渡す"]
final --> generate["回答生成"]
style filter fill:#ffcccc
style final fill:#ccffcc
図で理解できる要点:
- Top K で広く候補を取得
- スコア閾値で品質をフィルタリング
- リランキングで精度を向上
- Top N で LLM への入力を最適化
具体例
ここでは、実際に Dify RAG でヒットしない問題を診断し、解決する具体的な手順を示します。
シナリオ: 技術ドキュメントの検索失敗
状況:
- 社内の技術ドキュメントをナレッジベースに登録
- 「Next.js のデプロイ手順」という質問に対して関連文書がヒットしない
- ドキュメントには確実に該当内容が含まれている
ステップ 1: 埋め込み品質の診断
まず、現在の埋め込みモデルと検索結果のスコアを確認します。
typescript// Dify API で検索結果とスコアを取得
const diagnosisStep1 = async (query: string) => {
const response = await fetch(
'https://api.dify.ai/v1/datasets/{dataset_id}/retrieve',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.DIFY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: query,
retrieval_model: {
top_k: 10,
score_threshold: 0.0, // 診断のため閾値を無効化
},
}),
}
);
const data = await response.json();
return data.records;
};
このコードは、診断のためにスコア閾値を無効化し、Top K を多めに設定して検索を実行します。すべての候補とそのスコアを確認できます。
実行結果の分析:
typescript// 取得した結果を分析
const analyzeResults = (
records: any[],
expectedKeyword: string
) => {
console.log('=== 検索結果分析 ===');
records.forEach((record, index) => {
const hasKeyword =
record.content.includes(expectedKeyword);
console.log(
`${index + 1}. スコア: ${record.score.toFixed(3)}`
);
console.log(
` キーワード "${expectedKeyword}" 含む: ${
hasKeyword ? 'Yes' : 'No'
}`
);
console.log(
` 内容抜粋: ${record.content.substring(0, 50)}...`
);
console.log('');
});
};
// 使用例
const records = await diagnosisStep1(
'Next.jsのデプロイ手順'
);
analyzeResults(records, 'デプロイ');
この分析により、「デプロイ」というキーワードを含む文書のスコアを確認できます。期待する文書が低スコアの場合、埋め込みモデルが適切でない可能性があります。
ステップ 2: チャンク分割の確認
次に、ナレッジベースの文書がどのように分割されているかを確認します。
typescript// ナレッジベースの文書セグメント(チャンク)を取得
const diagnosisStep2 = async (documentId: string) => {
const response = await fetch(
`https://api.dify.ai/v1/datasets/{dataset_id}/documents/${documentId}/segments`,
{
headers: {
Authorization: `Bearer ${process.env.DIFY_API_KEY}`,
},
}
);
const data = await response.json();
return data.data;
};
このコードは、特定の文書がどのようにチャンクに分割されているかを取得します。各チャンクの内容と文字数を確認しましょう。
チャンク分析:
typescript// チャンクの品質を分析
const analyzeChunks = (segments: any[]) => {
console.log('=== チャンク分析 ===');
segments.forEach((segment, index) => {
const length = segment.content.length;
const hasContext =
segment.content.split('\n').length > 1;
console.log(`チャンク ${index + 1}:`);
console.log(` 文字数: ${length}`);
console.log(` 複数段落: ${hasContext ? 'Yes' : 'No'}`);
console.log(
` 内容: ${segment.content.substring(0, 100)}...`
);
console.log('');
});
// 統計情報
const avgLength =
segments.reduce((sum, s) => sum + s.content.length, 0) /
segments.length;
console.log(`平均文字数: ${avgLength.toFixed(0)} 文字`);
};
この分析により、チャンクサイズが適切か、情報が分散していないかを確認できます。例えば、「デプロイ手順」が複数のチャンクに分かれている場合、チャンクサイズを大きくする必要があります。
ステップ 3: 検索パラメータの最適化
診断結果に基づいて、検索パラメータを調整します。
typescript// 最適化された検索設定
interface OptimizedConfig {
embedding: {
model: string;
provider: string;
};
chunking: {
max_tokens: number;
chunk_overlap: number;
};
retrieval: {
topK: number;
scoreThreshold: number;
rerankEnabled: boolean;
rerankTopN: number;
};
}
// 技術ドキュメント向けの最適化設定例
const optimizedConfig: OptimizedConfig = {
embedding: {
model: 'text-embedding-ada-002',
provider: 'openai',
},
chunking: {
max_tokens: 1000, // 技術文書は大きめ
chunk_overlap: 150, // 15% のオーバーラップ
},
retrieval: {
topK: 5,
scoreThreshold: 0.65, // 診断結果から調整
rerankEnabled: true,
rerankTopN: 3,
},
};
このコードは、診断結果に基づいて最適化された設定を定義しています。埋め込みモデル、チャンク分割、検索パラメータをすべて考慮した総合的な設定です。
ステップ 4: 改善の検証
設定変更後、実際に検索精度が改善したかを検証します。
typescript// 改善前後の比較
const compareResults = async (
query: string,
before: any[],
after: any[]
) => {
console.log('=== 改善前後の比較 ===');
console.log(`質問: ${query}`);
console.log('');
console.log('【改善前】');
before.slice(0, 3).forEach((record, index) => {
console.log(
` ${index + 1}. スコア: ${record.score.toFixed(3)}`
);
console.log(
` ${record.content.substring(0, 60)}...`
);
});
console.log('');
console.log('【改善後】');
after.slice(0, 3).forEach((record, index) => {
console.log(
` ${index + 1}. スコア: ${record.score.toFixed(3)}`
);
console.log(
` ${record.content.substring(0, 60)}...`
);
});
// スコア向上率を計算
const beforeAvg =
before
.slice(0, 3)
.reduce((sum, r) => sum + r.score, 0) / 3;
const afterAvg =
after.slice(0, 3).reduce((sum, r) => sum + r.score, 0) /
3;
const improvement =
((afterAvg - beforeAvg) / beforeAvg) * 100;
console.log('');
console.log(`スコア向上率: ${improvement.toFixed(1)}%`);
};
この比較により、改善の効果を定量的に測定できます。スコアの向上だけでなく、実際に期待する文書が上位にランクインしているかも確認しましょう。
完全な診断フロー
以下は、上記のステップを統合した完全な診断フローです。
typescript// 包括的な RAG 診断ツール
class RAGDiagnostics {
private apiKey: string;
private datasetId: string;
constructor(apiKey: string, datasetId: string) {
this.apiKey = apiKey;
this.datasetId = datasetId;
}
// 完全な診断を実行
async runFullDiagnosis(
query: string,
expectedDocId?: string
) {
console.log('=== Dify RAG 診断開始 ===\n');
// 1. 埋め込み品質診断
console.log('ステップ 1: 埋め込み品質診断');
const searchResults = await this.searchWithFullDetails(
query
);
this.analyzeEmbeddingQuality(searchResults);
// 2. チャンク分割診断
if (expectedDocId) {
console.log('\nステップ 2: チャンク分割診断');
const chunks = await this.getDocumentChunks(
expectedDocId
);
this.analyzeChunkQuality(chunks);
}
// 3. 検索パラメータ診断
console.log('\nステップ 3: 検索パラメータ診断');
this.analyzeSearchParameters(searchResults);
// 4. 改善提案
console.log('\n=== 改善提案 ===');
this.generateRecommendations(searchResults);
}
// その他のメソッドは省略...
}
このクラスは、すべての診断ステップを統合し、包括的な分析と改善提案を提供します。実際のプロジェクトでは、このようなツールを作成しておくことで、効率的に問題を特定できますね。
まとめ
Dify RAG でヒットしない問題は、埋め込み品質・チャンク分割・検索パラメータ の 3 つの要素を体系的に診断することで解決できます。
本記事でご紹介した診断手法をまとめると、以下のようになります。
診断の基本ステップ:
- 埋め込み品質の確認: スコア閾値を無効化して全候補を取得し、期待する文書のスコアを確認する
- チャンク分割の検証: 文書がどのように分割されているかを確認し、情報の分散や欠落がないかチェックする
- 検索パラメータの最適化: Top K、スコア閾値、リランキングを段階的に調整し、最適なバランスを見つける
- 改善の検証: 設定変更前後で検索結果を比較し、定量的に効果を測定する
重要なポイント:
- 埋め込みモデルは文書の言語と分野に合ったものを選択しましょう
- チャンクサイズは文書タイプに応じて調整し、オーバーラップを適切に設定することで境界情報の取りこぼしを防げます
- 検索パラメータは一度に変更せず、段階的に調整して効果を確認しながら最適化していきましょう
- リランキングを活用することで、検索精度を大幅に向上できます
RAG の検索精度向上は試行錯誤が必要ですが、体系的なアプローチを取ることで、確実に改善できるはずです。本記事の診断手法を活用して、ぜひ高品質な RAG システムを構築してくださいね。
関連リンク
articleDify RAG でヒットしないとき:埋め込み品質・分割・検索パラメータの診断術
articleDify の評価基盤を俯瞰:観測・指標・人手評価の設計ポイント
articleDify フィードバック学習運用:人手評価・プロンプト AB テスト・継続改善
articleDify マルチテナント設計:データ分離・キー管理・レート制限の深掘り
articleDify ワークフロー定型 30:分岐・並列・リトライ・サーキットブレーカの型
articleDify を Kubernetes にデプロイ:Helm とスケーリング設計の実践
articleCodex が誤ったコードを出すときの対処:再現最小化・拘束条件・テスト駆動の適用
articleDify RAG でヒットしないとき:埋め込み品質・分割・検索パラメータの診断術
articleAstro の大規模ナビゲーション設計:メガメニュー/パンくず/サイト内検索
articleDeno のインストール完全ガイド:macOS/Linux/Windows とバージョン固定術
article【最新比較】Gemini 3 Pro vs GPT-5.1 Codex-Max: 開発者が本当に使うべきAIはどっち?
articleHeadless UI と Radix UI を徹底比較:アクセシビリティ・拡張性・学習コスト
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来