LLM本文抽出パイプライン再設計(HTTP化以降)

ozy's labo.


LLM をフィルタとして使用する場合の覚え書きです.
同じ事をされる方の参考になれば幸いです.

1 LLM本文抽出パイプライン再設計(HTTP化以降)

1.1 背景

llama-cli を直接パイプで叩く方式では,以下の問題が発生しました.

  • 対話モードへのフォールバック
  • 停止条件不明確による無限生成(">" が延々出力)
  • stdin / TTY 判定問題
  • chat template 自動適用による挙動不安定

これらにより,CLI直叩き方式は廃止しました.

1.2 llama-server 方式への移行

llama.cpp の server モードへ移行しました.

/path/to/llama.cpp/build-cuda/bin/llama-server \
  -m model.gguf \
  -c 4096 \
  -ngl 32 \
  --host 127.0.0.1 \
  --port 8080

この方式により,

  • 1リクエスト=1生成
  • max_tokens 明示制御可能
  • stop指定可能
  • JSONレスポンス取得可能

となり,CLI由来の不安定要素が解消されました.

1.3 curl + jq による問い合わせ方式

OpenAI互換API(/v1/chat/completions)を利用します.

curl -s \
  -H "Content-Type: application/json" \
  -d @request.json \
  http://127.0.0.1:8080/v1/chat/completions

応答抽出:

jq -r '.choices[0].message.content'

1.4 pandoc廃止

当初構成:

HTML → pandoc → Markdown → LLM

しかし,tableレイアウト中心HTMLでは pandoc が本文を 0バイト出力する問題が発生しました.

確認結果:

DEBUG SIZE: 0

よって pandoc は今回の用途に不適切と判断しました.

1.5 HTML直渡し方式へ変更

現在の構成:

HTML
→ nkf で UTF-8 正規化
→ そのまま LLM へ渡す
→ LLM が本文抽出

CONTENT="$(nkf -w -Lu "$src")"

LLMは構造理解が可能なため,

  • ナビゲーション削除
  • フッタ除去
  • tableレイアウト解釈

が可能です.

1.6 文字コード処理方針

重要確認事項:

  • LLMは charset を解釈しない
  • metaタグの charset は無意味
  • UTF-8文字列としてのみ処理される

よって,

  • nkf による UTF-8 正規化は必須
  • meta charset は削除可能

という設計に確定しました.

1.7 現在の問題点

動作は確認済みですが,

  • ローカルLLMが小規模
  • max_tokens制限
  • context制限

により,

  • 本文途中で切断
  • 抽出精度不安定

が発生しています.

これは設計問題ではなく,モデル能力の限界と判断しています.

1.8 現在のパイプライン構造

mirror/siteX
→ nkf(UTF-8統一)
→ HTML直渡し
→ llama-server(HTTP)
→ YAML + Markdown出力
→ normalized/siteX

というレイヤ分離構造になっています.

1.9 設計到達点まとめ

  • CLI版は不安定
  • server方式が安定
  • pandocは不適切
  • HTML直渡しが最適
  • UTF-8正規化は必須
  • meta charsetは無視可能

1.10 現在の状況

現在,このフィルタは,コンソールから使うパイプラインとして稼働しています.

  • 標準入力を読み込み,
  • コマンド内に記されたプロンプトなどを jq で JSON に整形,
  • curl でローカルサーバーに投げる.
  • 受け取って出力

という手順です.
llama-cli への直接アクセスでは不十分で,サーバー方式に移行する必要がありました.

2 派生物 readability

また,派生物として,mozilla/readability を使用する,不要行削除フィルタも生まれました.

インストール.

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
npm init -y
npm install jsdom @mozilla/readability

スクリプト本体.

#!/usr/bin/env node

// mozilla readability をフィルタとして使う

const { JSDOM } = require("jsdom");
const { Readability } = require("@mozilla/readability");

// stdinを全部読む
let html = "";

process.stdin.setEncoding("utf8");

process.stdin.on("data", chunk => {
  html += chunk;
});

process.stdin.on("end", () => {
  try {
    const dom = new JSDOM(html, {
      url: "https://example.com"
    });

    const reader = new Readability(dom.window.document, {
      charThreshold: 200,
      keepClasses: false
    });

    const article = reader.parse();

    if (!article || !article.textContent) {
      console.error("No article detected.");
      process.exit(0);
    }

    // テキスト整形(LLM向け)
    const cleaned = article.textContent
      .replace(/\r/g, "")
      .replace(/\n{3,}/g, "\n\n")
      .replace(/[ \t]+/g, " ")
      .trim();

    console.log(cleaned);

  } catch (err) {
    console.error("Error:", err.message);
    process.exit(1);
  }
});


Date: 2026-03-06

Author: ozyukiwo

Created: 2026-03-11 水 08:08

Emacs 26.3 (Org mode 9.1.9)

Validate