「いまのスキルで将来食べていけるか不安」
「転職する / しないをどう判断したらいいか迷う」
そんなモヤモヤを抱えるエンジニア向けに、PC だけで動く「Career & Skill Advisor」を紹介します。

1. アプリの概要

このアプリは、職務経歴書と興味分野を入力すると、3つのローカルLLMがキャリア戦略・市場性評価・転職判断プランを自動生成し、Markdownで統合レポートを出力します。レポートは、市場規模データと、あなたの強み弱みを分析したSWOT分析結果が添えられるため、単なる感覚ではなくファクトを踏まえて方向性を検討できます。

ローカルLLMの管理は、Ollamaを利用します。Ollamaとは、ローカルLLMを動作・管理するソフトウェアです。無料のOSSでMITライセンスです。データは外部送信されないので、個人情報である職務経歴書を入力しても安心です。

ローカルLLMは、Gemma3を利用します。Gemma3は軽量なローカルLLMですが、Chatbot Arenaでo1-previewモデルより上位の評価です。人間の目視評価で、最新のクラウド型モデルと遜色ない会話ができます。また、短いトークン数での文章理解や知識蒸留で工夫されており、メモリ効率が極めて高いことが特徴です。ライセンスは、Gemma Terms of Useです。

2. 環境構築手順

1. Ollamaのインストール

以下の公式のURL にアクセスし、Ollamaのインストーラーをダウンロードします。


ダウンロードしたOllamaSetup.exeをクリックし、インストールしてください。

インストールが完了したら、「すべてのアプリ」をクリックしてOllamaを起動しましょう。Ollamaは画面を持たないコマンドラインツールです。右下のシステムトレイにollamaが常駐するので、それで起動しているかどうかを確認できます。

※Ollamaの詳細なインストール手順と利用方法は、以下記事の[2. Ollamaのインストールと利用方法]をご参考ください。
OllamaをPythonから操作:WindowsでローカルLLM入門

2. Pythonのインストール

ダウンロードサイトからpythonをインストールする。

3. 必要なライブラリのインストール

pip install streamlit==1.37.1 ollama requests

4. Gemma3モデルを Ollama に pull

Gemma3のパラメータは、1b、4b、12b、27bから選べます。
お持ちのパソコンのメモリが32GB程度ある場合、gemma3:12bをpullしてください。もし、メモリが8GB程度で少な目の場合、gemma3:1bもしくはgemma3:4bモデルをpullしてください。
ollama pull gemma3:12b

5. アプリコードの配置

この記事末尾の Appendix にあるコードをコピーして、carrer_advidor.pyのファイル名で保存する。

6. アプリを起動

streamlit run career_advisor.py
上記を実行すると、ブラウザが自動で開き、タイトル「🎯 Career & Skill Advisor – Tri-LLM」が見えれば準備完了です。
自動で開かない場合は、ブラウザに http://localhost:8501 と打ち込んでアクセスしてください。

3. アプリの使い方

1. 職務経歴書をアップロード

PDF / DOCX / TXT いずれかをドラッグ&ドロップ。
ファイルはローカルでのみ解析。

2. 興味分野を入力

例: 生成AI × プロジェクトマネジメント
「技術キーワード + 役割/領域」で具体的に書くと精度アップ。

3. 🔍 分析を開始 をクリック

10〜40 秒で 4 つのタブが表示されます。

4. 結果タブの読み方

🏆 Strategy Coach: キャリア案 3 件
📊 Market Analyst: 求人数・年収・成長率の SWOT
📚 Learning Planner: 学習ロードマップ+転職の要否
📝 統合レポート: 上記 3 つを一本化

5. Markdown でダウンロード

統合レポートタブ下部の「📥 レポートを Markdown で保存」をクリック。
キャリア分析結果を、markdownファイルで保存することができます。

6. まとめ

ローカルLLMは、最初のモデルのダウンロード以外、インターネットに接続しないので、安心して個人情報をLLMに入力できます。
なお、本ツールの出力結果はあくまで参考情報です。最終判断は自己責任でお願いいたします。

Appendix — career_advisor.py

# -*- coding: utf-8 -*-
"""
Streamlit アプリ: Career & Skill Advisor
三つのローカル LLM (gemma3:12b, ollama 経由) が職務経歴書と興味分野を入力として
それぞれの視点でアドバイスを生成し、最終的に統合レポートを表示する。
"""

import textwrap
from concurrent.futures import ThreadPoolExecutor
import ollama
import streamlit as st

# --------------------------------------------------
# Streamlit 設定
# --------------------------------------------------
st.set_page_config(page_title="Career & Skill Advisor", page_icon="🎯", layout="centered")
st.title("🎯 Career & Skill Advisor – Tri‑LLM")

# --------------------------------------------------
# LLM 設定
# --------------------------------------------------
SUMMARIZER_MODEL = "gemma3:12b"

# --------------------------------------------------
# System Prompts
# --------------------------------------------------
SYSTEM_PROMPT_A = textwrap.dedent(
    """
    あなたは Executive Career Coach です。ユーザーの職務経歴書と興味分野を踏まえ、
    3〜5 年で達成可能なキャリアオプションを3件提案してください。
    それぞれ (タイトル 15字以内 + 概要 40字以内) で出力してください。
    """
)

SYSTEM_PROMPT_B = textwrap.dedent(
    """
    あなたは Tech Job Market Analyst です。ユーザーの目標分野について、日本国内の
    求人数・給与中央値・成長率を推定し、SWOT 形式で分析してください。数字が不明な場合は
    推定レンジを示し、出典無しを明記してください。
    """
)

SYSTEM_PROMPT_C = textwrap.dedent(
    """
    あなたは Learning Planner です。ユーザーの目標分野を達成するために、
    転職すべきかどうかを評価てください。
    なお、転職にはリスクが伴うため、現職で達成できる場合は、転職を進めないでください。
    """
)

SYSTEM_PROMPT_SUM = textwrap.dedent(
    """
    あなたは Report Writer です。以下に3人の専門家 (Coach, Analyst, Planner)
    が提示したコンテンツがあります。コンテンツを理解し総合レポート作成してください。
    """
)

# --------------------------------------------------
# ユーティリティ: LLM 呼び出し
# --------------------------------------------------
@st.cache_data(show_spinner=False)
def run_llm(system_prompt: str, user_payload: str, temperature: float = 0.5) -> str:
    """gemma3:12b を使って 1 回推論するヘルパー"""
    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": user_payload},
    ]
    response = ollama.chat(
        model=SUMMARIZER_MODEL,
        messages=messages,
        options={"temperature": temperature},
    )
    return response["message"]["content"].strip()

# --------------------------------------------------
# UI: 入力フォーム
# --------------------------------------------------
resume_file = st.file_uploader(
    "職務経歴書 (PDF/DOCX/TXT)",
    type=["pdf", "docx", "txt"],
    help="ファイルはローカル PC 内でのみ処理されます。外部へ送信されません。",
)
interest_text = st.text_area("興味分野 (例: 生成AI × PM)", max_chars=300)

analyze_btn = st.button("🔍 分析を開始", disabled=not (resume_file and interest_text))

# --------------------------------------------------
# メイン処理
# --------------------------------------------------
if analyze_btn:
    with st.spinner("LLM がキャリアプランを生成中…"):
        # 1) 職務経歴書テキスト抽出
        resume_bytes = resume_file.read()
        resume_text = resume_bytes.decode("utf-8", errors="ignore")

        # 2) ユーザーペイロード作成
        user_payload = f"""### 職務経歴書\n{resume_text}\n\n### 興味分野\n{interest_text}"""

        # 3) LLM 並列実行
        with ThreadPoolExecutor(max_workers=3) as ex:
            futures = [
                ex.submit(run_llm, SYSTEM_PROMPT_A, user_payload, 0.5),
                ex.submit(run_llm, SYSTEM_PROMPT_B, user_payload, 0.3),
                ex.submit(run_llm, SYSTEM_PROMPT_C, user_payload, 0.7),
            ]
            result_A, result_B, result_C = [f.result() for f in futures]

        # 4) 統合レポート生成
        combined_payload = (
            "## Coach Advice\n" + result_A +
            "\n\n## Market Analysis\n" + result_B +
            "\n\n## Learning Plan\n" + result_C
        )
        summary = run_llm(SYSTEM_PROMPT_SUM, combined_payload, 0.3)

        # 5) 4 つの Markdown を丸ごと結合(ダウンロード用)
        full_markdown = (
            "# Strategy Coach\n" + result_A +
            "\n\n# Market Analyst\n" + result_B +
            "\n\n# Learning Planner\n" + result_C +
            "\n\n# Integrated Report\n" + summary
        )

    # --------------------------------------------------
    # 6) 結果表示
    # --------------------------------------------------
    tab1, tab2, tab3, tab4 = st.tabs([
        "🏆 Strategy Coach", "📊 Market Analyst", "📚 Learning Planner", "📝 統合レポート"
    ])

    with tab1:
        st.markdown(result_A)

    with tab2:
        st.markdown(result_B)

    with tab3:
        st.markdown(result_C)

    with tab4:
        st.markdown(summary)  # 統合レポート表示

        # --- 🎯 ここだけにダウンロードボタンを配置 ---
        st.download_button(
            "📥 レポートを Markdown で保存",
            data=full_markdown,
            file_name="career_report.md",
            mime="text/markdown",
        )

    st.success("完了しました!")

# --------------------------------------------------
# フッター
# --------------------------------------------------
st.markdown(
    "<sub>Powered by gemma3:12b (ollama) – Local Inference Only</sub>",
    unsafe_allow_html=True,
)
関連記事: