はじめに

(本記事はclaude codeによる投稿です)

情報収集の自動化って、結局のところ「自分が何に興味を持つか」をシステムに教え込むことなんですよね。 これまで私は、FeedlyとInstapaperで日々記事をRead LaterやLikeで手動キュレーションしていました。でも、「この蓄積された行動データこそが、最高の学習素材なのでは?」と思い立って、機械学習ベースの記事ピックアップシステムを作ってみました。

従来システムの限界

第1段階:固定ルールベース

最初は「AWS」「AI」「マツダ」みたいなキーワードをハードコーディングして記事を分類していました。
keywords = ["AWS", "Lambda", "マツダ", "CX-5", "ChatGPT"]
if any(keyword in title for keyword in keywords):
    return True

でも、これだと:

  • 新しい関心領域に対応できない
  • 文脈を理解できない(「AWSの障害」も「AWS新機能」も同じ扱い)
  • 関心の変化に追従できない

第2段階:AI判定ベース

そこでClaude 3.5 Sonnetに記事の関心度をスコア化してもらうようにしました。
def judge_article_relevance(article):
    prompt = f"""
    以下の記事がmasakaさんの関心領域に該当するかを0-1で判定してください。
    関心領域:AWS、生成AI、Amazon Connect、マツダ、ポルシェ、声優...
    記事:{article['title']}
    """
    return anthropic_client.complete(prompt)
これで文脈理解は向上しましたが、まだ「人間が定義した関心領域」の枠内でした。

第3段階:学習ベースシステムの誕生

発想の転換

「そもそも私の興味って、Read LaterやLikeした記事の集合体じゃない?」 これが今回のシステムの出発点です。手動キュレーションの履歴を「正解データ」として扱い、そこから特徴量を抽出して新しい記事の関連度を判定する仕組みを作りました。

システム構成

class LearningBasedPicker:
    def collect_learning_data(self):
        # Feedly Read Later記事を取得(200件)
        readlater_articles = self.get_feedly_readlater()
        
        # Instapaper Like記事を取得(25件)  
        instapaper_articles = self.get_instapaper_likes()
        
        return readlater_articles + instapaper_articles
    
    def extract_features(self, learning_data):
        # 日本語形態素解析(SudachiPy)
        tokenized_texts = [self.tokenize_japanese(article) for article in learning_data]
        
        # TF-IDFベクトル化
        vectorizer = TfidfVectorizer(max_features=1000)
        tfidf_matrix = vectorizer.fit_transform(tokenized_texts)
        
        # 重要語を抽出(上位50語)
        return extract_top_features(tfidf_matrix, vectorizer)

学習結果

225件の学習データから抽出された重要特徴語(上位10個):

1. aws (0.046) - AWS関連 2. ai (0.040) - AI関連 3. amazon (0.035) - Amazon関連 4. mcp (0.033) - Model Context Protocol 5. agent (0.032) - エージェント関連 6. claude (0.031) - Claude関連 7. 2025 (0.030) - 最新情報への関心

面白いことに、手動で定義していたキーワードがちゃんと上位に来ていて、さらに「mcp」「agent」など、最近の関心事も自動的に検出されています。

推論フェーズ

新着記事に対して、学習した特徴語との類似度を計算:
def calculate_similarity_score(self, article, features_data):
    # 記事をトークン化
    tokens = self.tokenize_japanese(article['title'] + article['summary'])
    
    # 特徴語との一致度を計算  
    similarity_score = 0.0
    for token in tokens:
        if token in features_data['top_features']:
            similarity_score += features_data['top_features'][token]
    
    # 正規化してスコア化
    return similarity_score / len(tokens) if tokens else 0.0

実運用での成果

ピックアップ精度の向上

従来のルールベースでは見逃していた記事が適切にピックアップされるようになりました。

例えば:

  • 「NotebookLMの新機能」→ 私がAIツールをよく使うことを学習済み
  • 「ランボルギーニ・テメラリオ」→ 車関連の記事への関心を検出
  • 「IIJリングノート」→ 技術系企業への関心を反映

自動進化する仕組み

新しくRead LaterやLikeした記事は自動的に学習データに蓄積され、月1回程度の特徴量再抽出で システムが進化していきます。

学習データ更新

python3 learning_based_ai_picker.py --collect

特徴量再抽出

python3 learning_based_ai_picker.py --features

運用コスト削減

  • チェック記事数:100件 → 5件(95%削減)
  • 精度:関心度の高い記事のみに絞り込み
  • メンテナンス:キーワード更新作業が不要

技術的なポイント

日本語処理の工夫

SudachiPyで形態素解析し、名詞・動詞・形容詞のみを特徴語として採用:
def tokenize_japanese(self, text):
    tokens = []
    for token in self.tokenizer.tokenize(text, self.mode):
        pos = token.part_of_speech()[0]
        if pos in ['名詞', '動詞', '形容詞']:
            tokens.append(token.dictionary_form())
    return ' '.join(tokens)

スケーラビリティの考慮

  • 特徴語数を1000語に制限(計算コスト削減)
  • TF-IDFで重要語のみ抽出(ノイズ除去)
  • JSON形式での特徴量永続化(高速読み込み)

今後の展望

フィードバック学習の実装

ピックアップした記事への反応(クリック、共有、スキップ)も学習データに加えて、より精度の高いシステムに。

マルチモーダル対応

記事の画像や動画コンテンツも分析対象に加えて、より豊富な特徴量を抽出。

コミュニティ学習

他のユーザーの行動データも参考にして、新しい関心領域の発見につなげる。

まとめ

手動キュレーションの蓄積を機械学習で活用することで:

1. 個人化:自分だけの関心パターンを学習 2. 自動進化:新しい行動データで継続的に改善 3. 効率化:情報過多の中から本当に価値のある記事のみを抽出

結果として、「人間が行う質の高い判断」と「機械の高速処理能力」を組み合わせた、理想的な情報収集システムができました。 重要なのは、AIに丸投げするのではなく、人間の行動データを上手く活用してAIを「育てる」アプローチです。あなたも普段の情報収集行動を振り返って、そこから学習できることがあるかもしれませんね。 --- このシステムのソースコードや詳細な実装については、また別の記事で紹介したいと思います。