Ollamaを使用したオンプレミスLLMによる構造化データ抽出
このブログでは、Ollamaを使用して構造化データを抽出する方法を紹介します。これはローカルで実行でき、独自のクラウドやサーバーにデプロイすることができます。
完全なコードはこちらで見ることができます。わずか約100行のPythonコードです。ぜひチェックしてみてください🤗!
前提条件
Postgresのインストール
Postgresがインストールされていない場合は、インストールガイドを参照してください。
ollamaのインストール
Ollamaを使用すると、LLMモデルを簡単にローカルマシンで実行できます。始めるには:
Ollamaをダウンロードしてインストールします。
ollama pullコマンドでお好みのLLMモデルを取得します。例えば:
ollama pull llama3.2
マークダウンファイルから構造化データを抽出する
1. 出力を定義する
Pythonマニュアルから以下の情報を構造化データとして抽出します。
そこで、以下のように出力データクラスを定義します。目標はModuleInfo
を抽出して入力することです。
@dataclasses.dataclass
class ArgInfo:
"""Information about an argument of a method."""
name: str
description: str
@dataclasses.dataclass
class MethodInfo:
"""Information about a method."""
name: str
args: cocoindex.typing.List[ArgInfo]
description: str
@dataclasses.dataclass
class ClassInfo:
"""Information about a class."""
name: str
description: str
methods: cocoindex.typing.List[MethodInfo]
@dataclasses.dataclass
class ModuleInfo:
"""Information about a Python module."""
title: str
description: str
classes: cocoindex.typing.List[ClassInfo]
methods: cocoindex.typing.List[MethodInfo]
2. cocoIndex フローを定義する
マークダウンから構造化データを抽出するためのcocoIndexフローを定義しましょう。これは非常にシンプルです。
まず、ソースとしてマークダウン形式のPythonドキュメントを追加します。PDFの読み込み方法については、後のセクションで説明します。
@cocoindex.flow_def(name="ManualExtraction")
def manual_extraction_flow(flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.DataScope):
data_scope["documents"] = flow_builder.add_source(
cocoindex.sources.LocalFile(path="markdown_files"))
modules_index = data_scope.add_collector()
flow_builder.add_source
は以下のサブフィールドを持つテーブルを作成します。詳細はドキュメントをご覧ください。
-
filename
(キー, 型:str
): ファイルの名前、例:dir1/file1.md
-
content
(型:str
(binary
がFalse
の場合)、それ以外はbytes
): ファイルの内容
次に、マークダウンファイルから構造化データを抽出しましょう。これは非常に簡単で、LLM仕様を提供し、定義された出力タイプを渡すだけです。
CocoIndexはLLMを使用してデータを処理する組み込み関数(例:ExtractByLlm)を提供しています。Ollamaの組み込みサポートがあり、ローカルマシンで簡単にLLMモデルを実行できます。モデルの完全なリストはこちらで確認できます。また、OpenAI APIもサポートしています。完全なドキュメントと手順はこちらで確認できます。
# ...
with data_scope["documents"].row() as doc:
doc["module_info"] = doc["content"].transform(
cocoindex.functions.ExtractByLlm(
llm_spec=cocoindex.LlmSpec(
api_type=cocoindex.LlmApiType.OLLAMA,
# See the full list of models: https://ollama.com/library
model="llama3.2"
),
output_type=ModuleInfo,
instruction="Please extract Python module information from the manual."))
抽出後、上記で定義したデータスコープのコレクターからcollect
関数を使用して、出力から好きなものを選んで取得するだけです。
modules_index.collect(
filename=doc["filename"],
module_info=doc["module_info"],
)
最後に、抽出したデータをテーブルにエクスポートします。
modules_index.export(
"modules",
cocoindex.storages.Postgres(table_name="modules_info"),
primary_key_fields=["filename"],
)
3. インデックスのクエリとテスト
🎉 これで準備完了です!
以下のコマンドを実行してインデックスをセットアップし、更新します。
python main.py cocoindex setup
python main.py cocoindex update
インデックスの更新状態はターミナルに表示されます。
インデックスが構築されると、modules_info
という名前のテーブルが作成されます。いつでもクエリを実行できます。例えば、Postgresシェルを開始します。
psql postgres://cocoindex:cocoindex@localhost/cocoindex
そして、SQLクエリを実行します。
SELECT filename, module_info->'title' AS title, module_summary FROM modules_info;
ドキュメントから抽出された構造化データを確認できます。以下は抽出されたモジュール情報のスクリーンショットです。
CocoInsight
CocoInsightは、データパイプラインとデータインデックスを理解するためのツールです。
CocoInsightは現在早期アクセス中(無料)です😊。CocoInsightのクイック3分チュートリアルはYouTubeで見る。
1. CocoIndexサーバーを実行する
python main.py cocoindex server -c https://cocoindex.io
CocoInsightダッシュボードを見るにはhttps://cocoindex.io/cocoinsightにアクセスしてください。ローカルのCocoIndexサーバーにゼロデータ保存で接続します。
CocoInsightダッシュボードには2つの部分があります。
- Flows: 定義したフローを確認でき、そのデータを収集できます。
- Data: データインデックスのデータを確認できます。
データ側では、任意のデータをクリックして下にスクロールすると詳細を確認できます。このデータ抽出の例では、マークダウンファイルから抽出されたデータと表形式で表示された構造化データを確認できます。
例えば、arrayモジュールでは、データをクリックするとデータをプレビューできます。
また、多くの素晴らしい更新が近日公開されます。ぜひご期待ください!
データにサマリーを追加する
cocoindexをフレームワークとして使用すると、データに対する任意の変換(LLMサマリーを含む)を簡単に追加でき、そのデータをデータインデックスの一部として収集できます。
例えば、各モジュールに簡単なサマリーを追加してみましょう。
後ほどLLMの例を追加します。
1. 出力を定義する
まず、出力定義の一部として作成したい構造を定義しましょう。
@dataclasses.dataclass
class ModuleSummary:
"""Summary info about a Python module."""
num_classes: int
num_methods: int
2. cocoIndex フローを定義する
次に、データをサマリーするためのカスタム関数を定義しましょう。詳細はこちらをご覧ください。
@cocoindex.op.function()
def summarize_module(module_info: ModuleInfo) -> ModuleSummary:
"""Summarize a Python module."""
return ModuleSummary(
num_classes=len(module_info.classes),
num_methods=len(module_info.methods),
)
3. フローに関数をプラグインする
# ...
with data_scope["documents"].row() as doc:
# ... after the extraction
doc["module_summary"] = doc["module_info"].transform(summarize_module)
🎉 これで準備完了です!
以下のコマンドを実行してインデックスをセットアップし、更新します。
python main.py cocoindex setup
python main.py cocoindex update
PDFファイルから構造化データを抽出する
Ollamaは直接PDFファイルを入力としてサポートしていないため、まずはmarkdownに変換する必要があります。
これを行うには、PDFをmarkdownに変換するカスタム関数をプラグインします。詳細はこちらをご覧ください。
1. 関数の仕様を定義する
関数の仕様は関数の特定のインスタンスの動作を構成します。
class PdfToMarkdown(cocoindex.op.FunctionSpec):
"""Convert a PDF to markdown."""
2. エグゼキュータークラスを定義する
エグゼキュータークラスは、関数仕様を実装するクラスです。これは関数の実際の実行を担当します。
このクラスはPDFコンテンツをバイトとして受け取り、一時ファイルに保存し、PdfConverterを使用してテキストコンテンツを抽出します。抽出されたテキストは文字列として返され、PDFをマークダウン形式に変換します。
これはspec: PdfToMarkdown
によって関数仕様と関連付けられています。
@cocoindex.op.executor_class(gpu=True, cache=True, behavior_version=1)
class PdfToMarkdownExecutor:
"""Executor for PdfToMarkdown."""
spec: PdfToMarkdown
_converter: PdfConverter
def prepare(self):
config_parser = ConfigParser({})
self._converter = PdfConverter(create_model_dict(), config=config_parser.generate_config_dict())
def __call__(self, content: bytes) -> str:
with tempfile.NamedTemporaryFile(delete=True, suffix=".pdf") as temp_file:
temp_file.write(content)
temp_file.flush()
text, _, _ = text_from_rendered(self._converter(temp_file.name))
return text
なぜここで単独の関数ではなく、仕様とエグゼキュータを定義したいのか疑問に思うかもしれません。主な理由は、実際のデータを処理する準備ができる前に、(パーサーの初期化など)いくつかの重い準備作業を行う必要があるからです。
3. フローに関数をプラグインする
# Note the binary = True for PDF
data_scope["documents"] = flow_builder.add_source(cocoindex.sources.LocalFile(path="manuals", binary=True))
modules_index = data_scope.add_collector()
with data_scope["documents"].row() as doc:
# plug in your custom function here
doc["markdown"] = doc["content"].transform(PdfToMarkdown())
🎉 これで準備完了です!
以下のコマンドを実行してインデックスをセットアップし、更新します。
python main.py cocoindex setup
python main.py cocoindex update
Community
コミュニティからのご意見をお待ちしています!GithubとDiscordで私たちを見つけてください。
この投稿や私たちの活動が気に入ったら、ぜひGithub上のCocoindexに⭐スターをつけて応援してください❤️。温かいココナッツハグとともに、心から感謝します🥥🤗。
Discussion