Skip to main content
Glama

Agentic Job Intelligence Pipeline (MCP + LLM)

エージェント駆動型パイプライン。Model Context Protocol を使用して外部ツールを調整し、構造化データを取得します。LLMスコアリング層が、非構造化ジョブ説明を候補者プロフィールに対してランク付けします。コンテキストウィンドウの圧力は、段階的なメタデータ優先の取得戦略(pipeline.py)で処理され、同じツールは、独自のプランニングループを持つ本格的なツール呼び出しエージェント(agent.py)や、REST + WebSocket API(api.py)にも公開されています。詳細は docs/ を参照してください。

実行する

pip install -r requirements.txt

python pipeline.py --benchmark     # token comparison, zero API calls
python pipeline.py --dry-run       # real MCP subprocess handshake, no LLM
export OPENAI_API_KEY=sk-...
python pipeline.py --top 8         # fixed 3-stage pipeline
python agent.py --dry-run          # agent tool discovery, no LLM calls
export OPENAI_API_KEY=sk-...
python agent.py --top 8            # tool-calling agent with a planning loop
python eval.py --prefilter-only    # stage-1 recall, deterministic half, no key needed
pytest -q                          # in-process MCP server, no key needed

uvicorn api:app --reload           # REST + WebSocket layer, http://localhost:8000
curl localhost:8000/health
curl -X POST localhost:8000/rank -H 'content-type: application/json' -d '{"use_llm": false}'

Related MCP server: trackly-cli

測定結果

150件のジョブコーパス、ショートリスト8件。prefilter() は、タグ/タイトル、シニア度(候補者の年数が4年未満の場合は senior を除外)、および勤務地(候補者の希望都市、エイリアス正規化済み、またはリモート)のゲートを適用し、生存件数を150件から31件に削減します:

戦略

プロンプトトークン

ナイーブ法との比較

A — 全150件の完全な説明文を送信

67,360

—

B — メタデータ優先、その後8件取得

13,802

4.9× 安い

C — プリフィルタ → メタデータ → 8件取得

6,258

10.8× 安い

以下のコマンドで再現できます: python pipeline.py --benchmark。実際の数値は、このリポジトリの data/jobs.json の現在のデータに基づいており、プレースホルダではありません。トークン数は tiktoken の o200k_base エンコーダー(gpt-4o / gpt-4o-mini が実際に使用するもの)を使用しています。正確であり、推定ではありません。従来の chars ÷ 4 ヒューリスティックは、このコーパスでナイーブ戦略のコストを 17.4% 過大評価していました。benchmark() の heuristic_vs_real_tokens フィールドがその比較を再現します。

アーキテクチャ

   MCP SERVER (stdio subprocess)              MCP CLIENT / pipeline.py
   ---------------------------------          ------------------------------------
   tool  list_jobs        -> metadata  <----  Stage 0  prefilter()   [0 tokens]
   tool  get_job_details  -> full text        Stage 1  shortlist     [~5k tokens]
   tool  get_candidate_profile                Stage 2  score         [~4k tokens]
   tool  corpus_stats
   resource  jobs://schema                    Meter tracks tokens per stage
   prompt    rank_jobs

段階的取得の根拠

ナイーブな方法: すべての完全な説明文をモデルに渡し、ランク付けを依頼する。これには3つの問題があります。

  1. コスト — 1回の実行あたり79kのプロンプトトークンが必要で、コーパスに比例して増加します。

  2. 限界 — 数百件を超えると、コンテキストウィンドウを完全に超えます。遅いのではなく、不可能です。

  3. 品質 — 長いコンテキストの想起は、大きなプロンプトの途中で低下するため、候補を追加するほどランキングは悪化します。

段階的取得、最も安いフィルタから:

段階

仕組み

コスト

この段階の理由

0

Pythonによる決定論的なタグ/タイトル/勤務地フィルタ

無料

if で除外できるものをモデルに読ませない。150 → 91。

1

LLMは各ジョブの約~55トークンのメタデータを参照し、上位8件を選択

~5k

高い再現率のスクリーニング。ステージ2で拒否できるため、過剰に含めるよう指示。

2

生存した8件のみの完全な説明文

~4k

完全な忠実度。回答に影響する場合にのみ、一度だけコストを支払う。

一般化可能な原則 — そして面接で声に出して言うべきこと — は コストによるカスケード です。フィルタを安い順に並べ、各段階のしきい値は精度ではなく再現率に設定します。後の段階で拒否できる一方、早期の段階で落としたものを取り戻すことはできないからです。

エージェント層(agent.py)

pipeline.py は固定されたスクリプトです。プリフィルタ、その後常にショートリスト、常にスコアリングを行います。agent.py は、OpenAI関数呼び出しを介して同じMCPツールをモデルに提供し、モデル自身がパスを計画できるようにします。これはハードコードされたシーケンスではなく、本物のツール呼び出しエージェントです。

  • ツール呼び出しとしての構造化された最終回答。 エージェントは「JSONで答えて祈る」のではありません。完了するということは、パラメータスキーマがまさに schemas.RankingResult である合成ツール submit_rankings を呼び出すことを意味します。無効な引数は検証エラーとして返され、モデルはそれを読み取って修正できます。再試行回数に上限があります。

  • ツールの失敗は劣化であって、クラッシュではありません。 すべてのMCPツール例外は、通常の {"error": ...} ツール結果になりモデルにフィードバックされるため、実行全体を停止させる代わりに、悪い呼び出しを回避できます。

  • 収束しないモデルでも何かは返されます。 有効な出力なしにステップ/再試行の予算を使い果たした場合、エージェントは pipeline.py と同じ決定論的な prefilter → shortlist → score ロジックにフォールバックし、fallback_used: true を報告します。

  • 一時的なAPIエラーには独自の再試行があります。 tenacity を使用して、上記のスキーマ再試行ループとは別に処理されます。接続不良と不正な回答は異なる障害モードです。

ステップバイステップのループについては、docs/CODE_WALKTHROUGH.md を参照してください。

REST + WebSocket層(api.py)

FastAPIサービスがMCPツール、pipeline.py、agent.py をラップし、CLIスクリプトとしてだけでなく、HTTP経由でアクセスできるようにします。

エンドポイント

機能

GET /health

死活確認

GET /jobs, GET /jobs/{id}

メタデータ一覧 / 完全な詳細。MCPツールと同じ「説明文を含まない」不変条件

GET /stats

コーパス統計

POST /rank

ランキングパイプラインを実行(デフォルトでは agentic プランニングループ、または固定の段階的パイプライン)。use_llm: false の場合は無料の決定論的部分のみ実行

WS /ws/rank

POST /rank と同じですが、最後に単一のレスポンスを返す代わりに、エージェントの各ステップごとに1つのイベントをリアルタイムでストリーミングします。

1つのMCP stdioセッションが起動時に一度だけ開かれ、ロックの背後で共有されます(api.MCPSession)。リクエストごとにサブプロセスを生成するのではなく、実際のコネクションプールに対する意図的な簡素化であり、api.py のモジュールdocstringにその旨が記載されています。実際の分散システムとして過大評価されていません。各リクエストには相関ID(request_id)が割り当てられ、ログとすべてのストリーミングイベントにスレッド化されるため、非同期ホップをまたいで実行を追跡できます。

確実に覚えておくべきMCPのポイント

  • 存在理由: Nモデル × M統合が N + M になります。1つのプロトコル、stdioまたはStreamable HTTP上のJSON-RPC 2.0。

  • ツール vs リソース vs プロンプト: モデル制御 / アプリケーション制御 / ユーザー制御。この3つを正しく理解することは、面接での差別化ポイントになることがよくあります。

  • CallToolResult の構造: content(ブロック)、structured_content(型付けされており、オブジェクト以外の戻り値は {"result": ...} としてラップされる)、is_error。pipeline.call() を参照。

  • ツール設計は人間以外の呼び出し元に対するAPI設計です。 list_jobs と get_job_details が分割されているのは、その分割によって段階的取得が可能になるからです。docstringはモデルが読むツールの説明文です。曖昧なdocstringは誤ったツール選択につながります。

  • スカラー引数よりもバッチ引数: get_job_details(job_ids: list[str]) は1往復で済みますが、get_job_detail(job_id: str) は8往復かかります。

既知の制限

  • ショートリストの再現率(ステージ1がプリフィルタを生き残ったラベル付き関連ジョブを保持するかどうか)を測定するには、実際の OPENAI_API_KEY が必要です。python eval.py --top 8 で実行できますが、コストの理由でここでは実行していません。

  • コーパスは合成データです。実際の求人情報はより複雑です — HTML、重複、古いリストなど。

  • 実行間のキャッシュがないため、繰り返し呼び出すとステージ1のコストが再度発生します。

ステージ1の再現率 — 推定ではなく測定

data/relevance_labels.json には、人間が候補者に関連すると判断する20件のジョブIDが含まれており、文書化された再現可能なルーブリックに基づいて選ばれています(ファイルを参照)。eval.py は次の2つを別々にチェックします。

  • prefilter_recall — ラベル付き関連ジョブ20件のうち、決定論的プリフィルタを生き残るのは何件か。無料、APIキー不要: python eval.py --prefilter-only → 20/20、再現率1.0。ラベルのルーブリックはプリフィルタ自身のゲートの厳密なサブセットであるため、これはプリフィルタが標的の役割を静かに落としていないことを確認するものであり、そう思い込むのではありません。

  • shortlist_recall — そのうち、実際に実行する top でLLMショートリストも生き残るのは何件か。python eval.py --top 8 — OPENAI_API_KEY が必要で、実際のモデル呼び出しを伴うため、このリポジトリでは実行されていません。キーがあるときに自分で実行してください。

あなたのTODO

  1. prefilter() — シニア度と勤務地のゲートを追加。--benchmark を再実行し、数値を記録。 完了: 150 → 31件の生存、ナイーブ法と比較して10.8倍の削減。

  2. approx_tokens を実際の tiktoken カウントに置き換え、÷4ヒューリスティックの誤差を記録。 完了: ヒューリスティックは17.4%過大評価。

  3. 20件のラベル付き関連性セットを構築し、ステージ1の再現率を測定。 無料の部分(prefilter_recall = 1.0)は完了。有料の部分(shortlist_recall)は eval.py --top 8 に配線済み。自分のキーで実行してください。

  4. サーバーをClaude DesktopのMCP設定に組み込み、手動で呼び出す。 設定スニペットと再起動手順は docs/OVERVIEW.md にあります。実際の登録はあなた自身のClaude Desktopアプリで行うものであり、このリポジトリが代わりにできることではありません。

ドキュメント

  • docs/OVERVIEW.md — このプロジェクトが何であるか、どのような問題をなぜ解決するか、アーキテクチャ、Claude Desktopの配線、ローカルでのテスト可能性、既知の制限。

  • docs/CODE_WALKTHROUGH.md — すべてのモジュールを関数ごとに解説。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    MCP server that exposes job search data from multiple boards, enabling clients to query and manage job listings via natural language.
    7
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    MCP server for job search and application tracking, enabling AI agents to search jobs, get details, manage applications, and find contacts across 128K+ jobs and 1,900+ companies.
    781 npm
    3
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A custom MCP server that exposes a jobs database to any MCP-compatible LLM client, allowing users to ask in plain English to search, filter, and match job openings.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server that aggregates and deduplicates job listings from multiple public sources, ranks them against a user's resume, and exposes tools for searching, viewing details, explaining fit, and tracking applications.
    MIT