TECH PLAY

サイオステクノロジー(Tech.Lab)

サイオステクノロジー(Tech.Lab) の技術ブログ

628

GitHub Actions の失敗ログ、まだ手動で読んでいませんか? ども!龍ちゃんです。 CI が落ちたときの対応、毎回こうなっていませんか? GitHub Actions の UI を開く 失敗した Run を探す 失敗したジョブを開く ログをスクロールしてエラー行を目視で探す エラーメッセージをコピーしてググる 地味に面倒なんですよね、これ。特にジョブが複数あるワークフローだと、どのジョブのどのステップで落ちたのかを探すだけで時間を食う。 これ、Agent Skills に任せたら1行で終わります。 Before After 操作 GitHub UI → ログ目視 → 手動分析 「CI失敗してるから原因を調べて」 所要時間 5〜10分 30秒 得られるもの エラー行のコピペ 原因分析 + 修正方針のレポート 本記事では、gh CLI を使った CI ログ自動分析スキルを GitHub Copilot の Agent Skills として実装する手順を解説します。Claude Code で同じスキルを作った「 gh CLI × Claude Code で GitHub Actions 失敗ログをチャットで即解決 」の Copilot 移植版です。 190行あった Claude Code 版の SKILL.md を、Copilot の 500 トークン制限に合わせて 58 行に圧縮する設計がメインの話題になります。 対象読者 Agent Skills で実用的なスキルを作りたい人 Claude Code のスキルを Copilot に移植したい人 CI/CD のデバッグを自動化したい人 Agent Skills の基本(ディレクトリ構造、SKILL.md の書き方)は「 【2026年版】Agent Skills 入門 」を参照してください。 GitHub Actions の失敗を Agent Skills で自動分析する 作り方の前に、まず完成形を見てください。こういうやりとりになります。 龍ちゃん CI失敗してるから原因を調べて GitHub Copilot 失敗した Run を特定します。 → gh run list –status failure –limit 5 → gh run view 22573804432 –json jobs → gh run view 22573804432 –log –job 65388009712 ## Failure Analysis Root Cause: integration test が HTTP 503 で失敗 Suggested Fix: サービスのヘルスチェックをテスト前に実行 1行のプロンプトで、失敗 Run の特定からログ取得、原因分析まで全自動。この動きを実現するスキルの作り方を、このあと順を追って解説します。 前提条件 VS Code + GitHub Copilot(Agent Mode が使える状態) gh CLI がインストール・認証済み( gh auth status で確認) .github/skills/gh-workflow/ にスキルが配置済み(本記事で作ります) テスト用の失敗ワークフロー(demo-failure.yml) 検証用に、意図的に失敗するワークフローを用意しました。 name: Demo - Failure Workflow on: workflow_dispatch: jobs: setup: name: Setup runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Verify environment run: | echo "Environment check..." echo "OS: $(uname -s)" echo "Setup completed." test: name: Test runs-on: ubuntu-latest needs: setup steps: - name: Checkout repository uses: actions/checkout@v4 - name: Run unit tests run: | echo "Running unit tests..." echo "test_fetch_article ... PASSED" echo "test_parse_html ... PASSED" echo "Unit tests passed." - name: Run integration tests run: | echo "Running integration tests..." echo "" echo "FAILED: test_pipeline.py::test_full_pipeline" echo " AssertionError: Expected status code 200, got 503" echo " File: tests/test_pipeline.py, line 42" echo " assert response.status_code == 200" echo "" echo "1 passed, 1 failed in 3.42s" exit 1 deploy: name: Deploy runs-on: ubuntu-latest needs: test steps: - name: Deploy application run: echo "Deploying..." Setup → Test → Deploy の3ジョブ構成で、Test ジョブの integration tests が 503 エラーで exit 1 します。CI/CD でよくあるパターンを再現しています。 手動実行して失敗させておきます。 gh workflow run "Demo - Failure Workflow" # 30秒ほど待ってから確認 gh run list --workflow "demo-failure.yml" --limit 1 デモ 1:gh run list でクイックステータス確認 VS Code の Agent Mode で「CI確認して」と入力します。 スキルが発火すると、Copilot は SKILL.md の Mode 1(クイックステータス)に従い、 gh run list で最新の実行状況を一覧取得します。 実行されたコマンド: git branch --show-current gh run list --branch main --limit 10 --json databaseId,status,conclusion,name,headBranch,event,createdAt,displayTitle 出力(Copilot のレポート): 日時 ワークフロー名 ステータス Run ID 3/2 11:23 Demo – Failure Workflow failure 22573804432 2/26 06:20 Demo – Failure Workflow failure 22430458939 2/26 06:20 Demo – CI Pipeline success 22430440934 2/26 06:19 Demo – CI Pipeline success 22430416062 「最新の CI が失敗しています」と報告したうえで、「失敗ログを分析しますか?」と次のアクションを提案してくれます。ブランチ取得から一覧表示まで自動で、自分が打つのはプロンプト1行だけです。 デモ 2:gh run view –log で失敗ログを自動分析 ここがメインのデモです。「3/2に失敗したものを取得してほしい」と入力すると、スキルの Mode 4(ログ分析)が起動します。 Copilot は SKILL.md に書かれた Progressive Filtering (段階的絞り込み)の手順に従って、4ステップで自動分析します。 Step 1: 失敗 Run の特定 gh run view 22573804432 --json jobs,status,conclusion,createdAt,updatedAt,headBranch,event,workflowName Run 全体の情報を取得。3ジョブの中から Test ジョブが failure であることを特定。 Step 2: 失敗ジョブの絞り込み JSON レスポンスから失敗ジョブの ID(65388009712)を抽出。Step 4 の「Run integration tests」が failure であることを確認。 Step 3: ログ取得 gh run view 22573804432 --log --job 65388009712 --log は必ず --job と併用します。これは SKILL.md の Token Efficiency Rules で定義したルールです。 --job なしだと全ジョブのログが出力されてトークンを大量消費するので、失敗ジョブに絞って取得します。 Step 4: エラー分析とレポート出力 ## Failure Analysis **Run:** #22573804432 - Demo - Failure Workflow **Branch:** main | Job | Error Summary | |-----|--------------| | Test | AssertionError: Expected status code 200, got 503 | **Root Cause:** Integration test `test_pipeline.py::test_full_pipeline` が失敗。 外部サービスへの接続で HTTP 503 (Service Unavailable) を受信。 **Suggested Fix:** 1. サービスのヘルスチェックをテスト前に実行 2. テストエンドポイントへのネットワーク接続を確認 3. テストデータ・環境設定を見直し Run 全体 → 失敗ジョブ → 失敗ステップ → エラー行と、段階的に絞り込んで 503 エラーを特定し、原因と修正方針をレポートにまとめてくれました。これが Progressive Filtering の実際の動きです。 デモ 3:英語プロンプトでの発火確認 description に英語キーワードも埋め込んであるので、英語でも発火します。 「Analyze the GitHub Actions error logs」と入力すると、同じく Progressive Filtering が走り、英語で Failure Analysis Report が出力されました。日本語チームと英語チームが混在する環境でも使えます。 Copilot 用 SKILL.md の作り方:190行→58行に圧縮する設計 やっと本題です。ここが一番悩んだところで、Claude Code 版の SKILL.md(190行)を Copilot の制約に合わせて58行に圧縮する設計を解説します。 ディレクトリ構成と配置ルール .github/ ├── copilot-instructions.md ← ルーティング追記 ├── skills/ │ └── gh-workflow/ │ ├── SKILL.md ← 本体(58行・219語) │ └── references/ │ └── commands.md ← 詳細情報(79行・266語) └── workflows/ ├── demo-failure.yml ← テスト用(意図的に失敗) └── demo-success.yml ポイント: ファイル名は SKILL.md (大文字必須) ディレクトリ名は kebab-case で name フィールドと一致させる Claude Code 版( .claude/skills/gh-workflow/ )とは別ディレクトリなので、両方共存できる SKILL.md と references/ の分離基準 GitHub Copilot には SKILL.md に対する 500 トークン制限 (約60行・300語以内)があります。Claude Code にはこの制限がないので、190行の SKILL.md がそのまま動いていましたが、Copilot ではそうはいきません。 圧縮の方針は「SKILL.md はルーター、詳細は references/ に分離」です。 分類 SKILL.md に残す references/commands.md に分離 モード判定 4モードのテーブル(4行) – Token Efficiency Rules 必須ルール4項目 – 各モードの手順 概要(主なコマンド1行ずつ) JSON 出力パターン全文 レポートテンプレート – ステータス一覧 + 失敗分析テンプレート Status/Conclusion 一覧 – 12行の値テーブル Important Notes – 4項目の注意事項 残す基準 : Copilot がスキルを実行するときに「最初に読む必要がある情報」だけ残す。モード判定(何をすべきか)とトークン効率ルール(やってはいけないこと)。この2つがないと、Copilot は最初の一歩を踏み出せません。 分離する基準 : 必要になったタイミングで参照すればいい情報。JSON の出力パターンやレポートテンプレートは、実行が進んだ段階で references/ から読み込めば十分です。「あとで見ればいいもの」は全部 references/ に押し出す。割り切りが大事でした。 Copilot の Progressive Disclosure(関連度に基づいて必要なファイルだけ読み込む仕組み)がこの分離設計と噛み合います。SKILL.md を読んでモードを判定し、実行に必要な詳細情報を references/ から追加で読む、という流れになるわけです。 圧縮結果: Claude Code 版 Copilot 版 SKILL.md 190行 58行(219語) 参照ファイル なし(全部入り) references/commands.md(79行・266語) 合計 190行 137行(2ファイル) 行数の合計はあまり変わりませんが、SKILL.md 単体が 500 トークン予算の 73% に収まっているのがポイントです。 description の書き方:単一行で書く鉄則 description は Copilot がスキルを選ぶかどうかを判定する 最重要フィールド です。ここの設計が発火率を左右します。 鉄則:description は単一行で書く。 description: | の複数行記法は使わない。 # NG: 複数行記法 → Copilot が "|" だけ読み込んでしまう description: | GitHub Actions の Workflow 状態確認とログ分析を行うスキル。 Use when: CIが失敗した原因を調べたい。 # OK: 単一行 → Copilot が全文を正しく読み込む description: GitHub Actionsのワークフロー状態確認と失敗ログ分析を行うスキル。gh CLIでCI/CDのログ取得から原因分析まで実行する。Use when: CIが失敗した原因を調べたい、ワークフローの状態を確認したい、PRのチェック結果を見たい。Triggers on: CI確認, Workflow確認, CI失敗, ログ分析, GitHub Actions debug,CI status check, workflow failure, PRチェック, エラーログ, pipeline debug. GitHub Copilot のスキルローダーは YAML の複数行記法( description: | )を正しくパースできません。 | という文字列だけが description として読み込まれ、発火判定に使われる情報がほぼゼロになります。Claude Code ではこの問題は起きないので、移植時に見落としがちな落とし穴です。 description に含める3要素: 機能説明 — 何をするスキルか Use when — どういう場面で使うか(ユーザーの意図) Triggers on — 発火キーワード(日本語 + 英語) Copilot は description の文字列とユーザーの発話の 類似度 でスキルを選ぶので、「ユーザーが実際に言いそうな言葉」を入れておくのがコツです。 description の設計思想や、なぜ発火しないのかの原因分析は「 Claude CodeからGitHub Copilotへ移植したらAgent Skillsが動かない?原因と解決策 」で詳しく解説しています。本記事では実装だけ押さえて先に進みます。 copilot-instructions.md でスキル発火を安定させる description だけでは発火が不安定な場合の補強策として、 copilot-instructions.md にルーティングテーブルを追加します。copilot-instructions.md は Agent Mode で常に読み込まれるファイルなので、ここにスキルへの道しるべを書いておくと発火が安定します。 ## Agent Skills Routing | キーワード | スキル | パス | |-----------|--------|------| | CI確認, Workflow, GitHub Actions, ログ分析, CI失敗, pipeline debug | gh-workflow | `.github/skills/gh-workflow/SKILL.md` | 既存の copilot-instructions.md の末尾に追記するだけです。中身は触らない。 注意点として、ルーティングに登録するスキルは 重要なもの3〜5個に絞る べきです。copilot-instructions.md に書いた内容は毎回のコンテキストに含まれるので、スキル全部を登録するとトークンを無駄遣いします。 この手法の効果と限界は「 Agent Skillsが動かない? 」の「解決策③:Instructions ルーティング」セクションで検証データ付きで解説しています。 allowed-tools の検証:agentskills.io 仕様と実装のギャップ SKILL.md のフロントマターには allowed-tools というフィールドがあります。スキルが使ってよいツールを制限する仕組みです。今回のスキルでは以下のように書きました。 allowed-tools: Bash(gh:*) Bash(git:*) Bash(jq:*) Read 「gh CLI と git と jq のコマンド実行、それとファイル読み取りだけ許可する」という意味です。 agentskills.io Specification での定義 agentskills.io の仕様 では、 allowed-tools は正式なオプションフィールドとして定義されています。ただし Experimental(実験的) ステータスで、”Support for this field may vary between agent implementations” と注記されています。 記法は2パターンあります: # パターン記法(コマンドプレフィックス指定) allowed-tools: Bash(gh:*) Bash(git:*) Read # ツール名列挙(MCP ツール等) allowed-tools: list_workflow_runs summarize_job_log_failures get_job_logs GitHub Copilot での動作検証結果 結論から言うと、 現時点では allowed-tools の enforcement(強制)は実装されていません 。 今回の検証では、 allowed-tools を書いた状態でスキルは正常に発火し、gh CLI のコマンドも問題なく実行されました。一方で、 allowed-tools に列挙していないツールの使用を制限する動作は確認できませんでした。 確認項目 結果 スキルの発火 問題なし(allowed-tools が発火を妨げない) allowed-tools 内のツール使用 問題なし allowed-tools 外のツール制限 未確認(制限が効いている証拠なし) VS Code バリデータの警告 Issue #14131 として報告済み(Open、対応予定なし) allowed-tools はスキル選択時には参照されず、スキル実行時に SKILL.md の本文を読んだ段階で「ガイドライン」として機能している可能性があります。強制力のあるサンドボックスではなく、エージェントへの「お願い」に近い位置づけです。 コミュニティの allowed-tools 実装例 参考までに、 heilcheng/awesome-agent-skills の github-actions-failure-debugging スキルを見ると、 allowed-tools はフロントマターに書かず、本文テキスト内で手順として使用ツールを記述しています。 To debug failing GitHub Actions workflows: 1. Use `list_workflow_runs` to look up recent workflow runs 2. Use `summarize_job_log_failures` to get an AI summary of failed jobs 3. Use `get_job_logs` for full detailed failure logs if needed フロントマターの allowed-tools で制限するか、本文で手順として指示するか。enforcement が実装されていない現時点では、本文に書くほうが確実にエージェントに伝わります。 正直どちらにするか迷ったんですが、自分のスキルでは「両方書いておく」方針にしました。フロントマターは将来の enforcement が来たときの保険、本文は今のエージェントへの確実な指示。二重管理にはなりますが、壊れるリスクよりマシだと判断しています。 Claude Code 版 SKILL.md との違い(比較表) 同じ gh-workflow スキルの Claude Code 版と Copilot 版を比較します。 変わる点:description・トークン予算・ファイル構成 比較項目 Claude Code 版 Copilot 版 ファイルパス .claude/skills/gh-workflow/ .github/skills/gh-workflow/ SKILL.md 行数 190行(1ファイル完結) 58行 + references/commands.md description トリガー文字列列挙 単一行で Use when + Triggers on allowed-tools Bash, Read Bash(gh:*) Bash(git:*) Bash(jq:*) Read 参照ファイル分離 不要(全文コンテキストに読み込み) 必須(500トークン制限) copilot-instructions.md 不要 ルーティング追記推奨 一番大きいのは「トークン予算」です。Claude Code は SKILL.md を丸ごと読み込めるので圧縮の必要がなく、190行でも問題ありません。Copilot は 500 トークン制限があるので、references/ への分離が必須になります。 変わらない点:gh CLI コマンド・Progressive Filtering 比較項目 Claude Code / Copilot 共通 gh CLI コマンド 同一( gh run list , gh run view --log --job 等) Progressive Filtering 同一(一覧→ジョブ特定→ログ取得→分析の4ステップ) Token Efficiency Rules 同一( --log は --job と併用、 watch 禁止等) Report Template 同一(references/commands.md に移植済み) gh CLI のノウハウはそのまま使えます。変えるのはスキルの外側(配置・description・トークン予算)だけで、中身は同じものが動きます。 リポジトリ/ ├── .claude/skills/gh-workflow/SKILL.md ← Claude Code版(190行・1ファイル完結) ├── .github/skills/gh-workflow/ ← Copilot版(58行 + references/) │ ├── SKILL.md │ └── references/commands.md └── (両方共存可能・互いに干渉しない) ちなみに GitHub Copilot は .claude/skills/ 配下のファイルも読み込みます。つまり Claude Code 用に作ったスキルが Copilot 側でも認識される。ただし 190 行の SKILL.md だとトークン予算を超えるし、 description: | の複数行記法は Copilot で壊れるので、そのまま期待どおりに動くかは別問題です。Claude Code ユーザーが Copilot でも使いたいなら、本記事のように .github/skills/ に圧縮版を別途置くのが確実です。 まとめ CI が落ちたら「CI失敗してるから原因を調べて」。それだけで原因分析から修正方針までレポートが出てきます。 やることは .github/skills/gh-workflow/ に SKILL.md と references/commands.md を置くだけ。あとは copilot-instructions.md にルーティングを1行追記すれば完了です。 本記事のポイント: SKILL.md は 500 トークン以内に圧縮 — 190行→58行。モード判定とトークン効率ルールだけ残し、詳細は references/ に分離 description は単一行で書く — description: | の複数行記法は Copilot で読み込まれない。詳細は「 Agent Skillsが動かない? 」 allowed-tools は Experimental — 仕様にはあるが enforcement 未実装。書いておいて損はないが、過信しない gh CLI のノウハウは共通 — Claude Code と Copilot で変えるのは外側だけ ではまた! Claude Code で同じことをやるなら「 gh CLI × Claude Code で GitHub Actions 失敗ログをチャットで即解決 」を参照してください。 検証環境 検証日: 2026年3月2〜3日 環境: VS Code + GitHub Copilot(Agent Mode) モデル: claude-sonnet-4.5(Copilot 経由) 参考: VS Code Docs – Agent Skills , agentskills.io Specification 付録:SKILL.md / references/commands.md 全文コピー用 自分のリポジトリに導入するときは、以下のディレクトリ構成でファイルを配置してください。 .github/ ├── copilot-instructions.md ← 末尾にルーティングを追記 ├── skills/ │ └── gh-workflow/ │ ├── SKILL.md ← 下記「SKILL.md 全文」をコピー │ └── references/ │ └── commands.md ← 下記「commands.md 全文」をコピー └── workflows/ └── demo-failure.yml ← テスト用(本記事「テスト用の失敗ワークフロー」参照) .github/skills/gh-workflow/SKILL.md(58行・219語) --- name: gh-workflow description: GitHub Actionsのワークフロー状態確認と失敗ログ分析を行うスキル。gh CLIでCI/CDのログ取得から原因分析まで実行する。Use when: CIが失敗した原因を調べたい、ワークフローの状態を確認したい、PRのチェック結果を見たい。Triggers on: CI確認, Workflow確認, CI失敗, ログ分析, GitHub Actions debug,CI status check, workflow failure, PRチェック, エラーログ, pipeline debug. allowed-tools: Bash(gh:*) Bash(git:*) Bash(jq:*) Read --- # GitHub Actions Workflow Status & Log Analysis gh CLI を使って GitHub Actions の Workflow ステータス確認・ログ分析を行います。 ## Mode Selection ユーザーの指示から以下の4モードを自動判定して実行する。 | モード | トリガー例 | 主なコマンド | |--------|-----------|-------------| | クイックステータス | 「CI確認して」 | `gh run list` | | Run 詳細 | 「Run #123 の詳細」 | `gh run view <run-id>` | | PR チェック | 「PR #42 のチェック」 | `gh pr checks <pr-number>` | | ログ分析 | 「CI失敗してるから見て」 | `gh run view --log --job` | ## Token Efficiency Rules(必須) - `--log` は必ず `--job <job-id>` と併用(全ジョブログは膨大) - `gh run watch` / `gh pr checks --watch` は使用禁止(トークン大量消費) - JSON 出力 + jq で必要なフィールドのみ取得する - Progressive Filtering: 一覧→絞り込み→詳細の順に段階的に情報取得 ## 各モードの実行概要 ### Mode 1: クイックステータス `gh run list --branch $(git branch --show-current) --limit 10` で一覧取得→テンプレート報告。 ### Mode 2: Run 詳細 `gh run view <run-id> --json status,conclusion,jobs,createdAt,updatedAt,headBranch,event` で詳細取得。 ### Mode 3: PR チェック `gh pr checks <pr-number>` でチェック状況取得。PR番号不明時はブランチから自動検出。 ### Mode 4: ログ分析(メイン) 1. `gh run list --status failure` で失敗 Run 特定 2. `gh run view <run-id> --json jobs` で失敗ジョブ特定 3. `gh run view <run-id> --log --job <job-id>` でログ取得(必ず --job 指定) 4. エラー箇所を分析し原因と修正方針を報告 ## 詳細リファレンス JSON 出力パターン、レポートテンプレート、ステータス一覧は `references/commands.md` を参照。 .github/skills/gh-workflow/references/commands.md(79行・266語) # gh-workflow コマンドリファレンス > SKILL.md から参照される詳細情報。Copilot が必要に応じて読み込む。 ## JSON Output Patterns よく使う構造化データ取得パターン: ```bash # Run 一覧を JSON で取得 gh run list --limit 10 --json databaseId,displayTitle,status,conclusion,headBranch,createdAt,event # Run 内のジョブ詳細 gh run view <run-id> --json jobs --jq '.jobs[] | {id: .databaseId, name, status, conclusion, startedAt, completedAt}' # 失敗ジョブのみ抽出 gh run view <run-id> --json jobs --jq '.jobs[] | select(.conclusion == "failure") | {id: .databaseId, name}' # PR チェックの詳細(JSON) gh pr checks <pr-number> --json name,state,description,detailsUrl ``` ## Report Template 以下のテンプレートを使って結果を報告する。 ### ステータス一覧 ``` ## Workflow Status | # | Workflow | Branch | Status | Conclusion | Triggered | |---|---------|--------|--------|------------|-----------| | 1 | <name> | <branch> | <status> | <conclusion> | <event> | ``` ### 失敗分析 ``` ## Failure Analysis **Run:** #<run-id> - <workflow-name> **Branch:** <branch> **Failed Jobs:** | Job | Error Summary | |-----|--------------| | <job-name> | <error-summary> | **Root Cause:** <分析結果> **Suggested Fix:** <修正方針> ``` ## Status / Conclusion Reference | 値 | 種類 | 意味 | |----|------|------| | `queued` | status | キュー待ち | | `in_progress` | status | 実行中 | | `completed` | status | 完了 | | `waiting` | status | 承認待ち | | `success` | conclusion | 成功 | | `failure` | conclusion | 失敗 | | `cancelled` | conclusion | キャンセル済み | | `skipped` | conclusion | スキップ | | `timed_out` | conclusion | タイムアウト | | `action_required` | conclusion | アクション要求 | | `neutral` | conclusion | 中立(情報のみ) | | `stale` | conclusion | 古い結果 | ## Important Notes - **gh CLI 未認証の場合**: `gh auth status` で認証状態を確認し、未認証ならユーザーに通知 - **リポジトリ外で実行した場合**: エラーをユーザーに通知 - **大量のログ出力**: 必ず `--job` で絞り込み、それでも長い場合は主要なエラー行のみ抽出 - **進行中の Run**: ステータスが `in_progress` の場合、完了を待たずに現在の状態を報告(`watch` は使わない) copilot-instructions.md に追記するルーティング ## Agent Skills Routing | キーワード | スキル | パス | |-----------|--------|------| | CI確認, Workflow, GitHub Actions, ログ分析, CI失敗, pipeline debug | gh-workflow | `.github/skills/gh-workflow/SKILL.md` | 参考リンク 公式ドキュメント VS Code Docs – Agent Skills agentskills.io Specification VS Code Docs – Copilot Customization 関連 Issue microsoft/vscode-copilot-release#14131 — VS Code バリデータが allowed-tools を未認識 関連記事 【2026年版】Agent Skills 入門:SKILL.md の基本から実践まで Claude CodeからGitHub Copilotへ移植したらAgent Skillsが動かない?原因と解決策 gh CLI × Claude Code で GitHub Actions 失敗ログをチャットで即解決 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post GitHub Actions失敗ログ、まだ手動で読む?Copilot Agent Skills で CI デバッグを自動化する実装ガイド first appeared on SIOS Tech Lab .
前回の記事ではSCANOSS GitHub Actionsを使った基本的なコードスキャン自動化の手順 を紹介しました。基本スキャンやポリシーチェック、サブディレクトリスキャンまで確認できたところで、次に気になるのはモノレポ構成への対応です。 scanPath パラメータ は単一の相対パスしか受け付けないため、複数のサブディレクトリを個別にスキャンするにはワークフロー側で工夫が必要です。本記事では、SCANOSS公式の MONOREPO_SETUP.md で推奨されている reusable workflow( workflow_call )パターン を使い、PRで変更されたコンポーネントだけを自動スキャンする構成を実際に構築・検証します。 この記事でわかること : モノレポで scanPath が抱える制約と解決策 reusable workflow( workflow_call )による共通スキャンワークフローの作り方 パスフィルターとの連携で、変更コンポーネントだけスキャンする構成 構築時のハマりポイント( permissions の配置)と解決策 前提条件 前回の記事 の内容を理解していること(基本スキャン、 scanPath の動作) GitHubリポジトリにActions実行権限があること リポジトリのSettings > Secretsに SCANOSS_KEY を登録済みであること scanoss/gha-code-scan@v1.5.0 を使用 検証に使用したリポジトリ構成 本記事の検証には、 application/tools/src/ 配下に複数のPythonパッケージを持つモノレポ構成のリポジトリを使用しました。 application/tools/src/ ├── blog_scraper/ # ブログスクレイピングツール(Pythonファイル9個) ├── svg_to_png/ # SVG→PNG変換ツール(Pythonファイル6個) ├── html_to_png/ # HTMLスクリーンショットツール ├── cleanup_articles/ # 記事クリーンアップツール ├── thumbnail_generator/ # サムネイル生成ツール ├── pv_analyzer/ # PV分析ツール └── notion_sync/ # Notion同期ツール このうち blog_scraper と svg_to_png の2ディレクトリをスキャン対象として検証します。 モノレポでのスキャン課題 前回の記事で紹介した scanPath パラメータ を使えば、スキャン対象をサブディレクトリに限定できます。しかし、 scanPath は 単一の相対パスしか受け付けません 。複数パスのカンマ区切りやワイルドカードには対応していません。 # これはできる scanPath: application/tools/src/blog_scraper # これはできない scanPath: application/tools/src/blog_scraper, application/tools/src/svg_to_png モノレポで複数パッケージを個別にスキャンするには、ワークフロー側で対応が必要です。SCANOSS公式の MONOREPO_SETUP.md では、GitHub Actionsの reusable workflow ( workflow_call )を使ったパターンが推奨されています。 ワークフローの全体構成 作成するファイルは以下の3つです。スキャン対象のコンポーネントが増えるたびにトリガーワークフローを1つ追加します。 .github/workflows/ ├── scanoss-monorepo-base.yml # ベースワークフロー(共通、1つだけ) ├── scanoss-monorepo-blog-scraper.yml # blog_scraper 用トリガー └── scanoss-monorepo-svg-to-png.yml # svg_to_png 用トリガー ファイル 役割 scanoss-monorepo-base.yml workflow_call で呼び出される共通スキャン処理。 scan_path を入力として受け取る scanoss-monorepo-blog-scraper.yml blog_scraper ディレクトリの変更時にベースワークフローを呼び出す scanoss-monorepo-svg-to-png.yml svg_to_png ディレクトリの変更時にベースワークフローを呼び出す ベースワークフローの作成 workflow_call で呼び出される共通のスキャンワークフローです。スキャン対象のパスを inputs.scan_path として受け取ります。 # .github/workflows/scanoss-monorepo-base.yml name: SCANOSS Monorepo Base Scan on: workflow_call: inputs: scan_path: description: 'Directory to scan' required: true type: string jobs: scanoss-scan: name: SCANOSS Scan (${{ inputs.scan_path }}) runs-on: ubuntu-latest permissions: contents: write pull-requests: write checks: write actions: read steps: - name: Checkout code uses: actions/checkout@v4 - name: Run SCANOSS Code Scan id: scanoss-scan uses: scanoss/gha-code-scan@v1.5.0 with: scanPath: ${{ inputs.scan_path }} api.key: ${{ secrets.SCANOSS_KEY }} permissions を ジョブレベル に配置している点が重要です。トップレベルに置くと startup_failure で失敗します。詳細は後述の「ハマりポイント」で説明します。 コンポーネント別トリガーワークフロー 各コンポーネントにつき1つのワークフローファイルを作成し、ベースワークフローを呼び出します。 # .github/workflows/scanoss-monorepo-blog-scraper.yml name: SCANOSS Scan - blog_scraper on: workflow_dispatch: permissions: contents: write pull-requests: write checks: write actions: read jobs: scan: uses: ./.github/workflows/scanoss-monorepo-base.yml with: scan_path: application/tools/src/blog_scraper secrets: inherit # .github/workflows/scanoss-monorepo-svg-to-png.yml name: SCANOSS Scan - svg_to_png on: workflow_dispatch: permissions: contents: write pull-requests: write checks: write actions: read jobs: scan: uses: ./.github/workflows/scanoss-monorepo-base.yml with: scan_path: application/tools/src/svg_to_png secrets: inherit secrets: inherit でリポジトリのSecretsを呼び出し先に渡します。これにより、ベースワークフロー側で ${{ secrets.SCANOSS_KEY }} が使えます。 まずはこの workflow_dispatch (手動実行)の構成で動作確認した後、次のセクションでパスフィルターを追加します。 パスフィルターとの連携 この構成の最大の利点は、 パスフィルター ( on.pull_request.paths )との組み合わせです。トリガーワークフローに paths を追加するだけで、 PRで変更されたコンポーネントだけスキャンを発火 させることができます。 # .github/workflows/scanoss-monorepo-blog-scraper.yml name: SCANOSS Scan - blog_scraper on: pull_request: paths: - 'application/tools/src/blog_scraper/**' workflow_dispatch: permissions: contents: write pull-requests: write checks: write actions: read jobs: scan: uses: ./.github/workflows/scanoss-monorepo-base.yml with: scan_path: application/tools/src/blog_scraper secrets: inherit 変更点は on: セクションに pull_request.paths を追加しただけです。 workflow_dispatch も残しておけば、手動実行も引き続き可能です。 この構成により、以下の動作になります。 PRの変更内容 blog_scraper スキャン svg_to_png スキャン blog_scraper/main.py を修正 実行される 実行されない svg_to_png/converter.py を修正 実行されない 実行される 両方を修正 実行される 実行される docs/ のみ修正 実行されない 実行されない モノレポで7つのパッケージがある場合、全パッケージをフルスキャンすると不要なAPI呼び出しと待ち時間が発生します。パスフィルターを使えば、PRで触ったコンポーネントだけをスキャンできるため、 レビューのフィードバックが速くなり、API利用量も抑えられます 。 ハマりポイント:permissionsの配置 構築時に遭遇したハマりポイントを紹介します。 ベースワークフローのpermissionsをトップレベルに置くとstartup_failure 最初にベースワークフローの permissions を ワークフローのトップレベル に配置したところ、呼び出し元のワークフローが startup_failure で即座に失敗しました。 # NG: トップレベルに配置すると startup_failure になる permissions: contents: write pull-requests: write checks: write actions: read jobs: scanoss-scan: ... startup_failure はログが一切生成されないため、原因の特定に手間取ります。 呼び出し元にpermissionsを書かないとstartup_failure ベースワークフローの permissions をジョブレベルに移動しても、呼び出し元ワークフローに permissions がないと同じく startup_failure で失敗します。 reusable workflow では、 呼び出し元のpermissionsが上限 となります。呼び出し元に permissions を書かない場合はリポジトリのデフォルト権限が適用されますが、SCANOSS Code Scan Actionが必要とする権限( contents: write 、 checks: write 等)が不足する場合に startup_failure が発生します。 解決策 2つの対応を同時に行います。 ベースワークフローの permissions を ジョブレベル に配置する 呼び出し元ワークフローにも permissions を 明示的に記述する 本記事のワークフロー例はすべてこの対応済みの構成です。 実行結果 workflow_dispatch で手動実行した結果です。 ワークフロー ステータス 実行時間 SCANOSS Scan – blog_scraper success 40秒 SCANOSS Scan – svg_to_png success 47秒 各コンポーネントが 独立したワークフローラン として実行されます。GitHub Actions UIでは別々のワークフローとして表示されるため、どのコンポーネントのスキャンが失敗したかが一目でわかります。 コンポーネントの追加方法 新しいパッケージ(例: html_to_png )をスキャン対象に追加する場合、トリガーワークフローを1つ作成するだけです。ベースワークフローの変更は不要です。 # .github/workflows/scanoss-monorepo-html-to-png.yml name: SCANOSS Scan - html_to_png on: pull_request: paths: - 'application/tools/src/html_to_png/**' workflow_dispatch: permissions: contents: write pull-requests: write checks: write actions: read jobs: scan: uses: ./.github/workflows/scanoss-monorepo-base.yml with: scan_path: application/tools/src/html_to_png secrets: inherit コピーして scan_path と paths を書き換えるだけなので、追加コストは低いです。 まとめ SCANOSS GitHub Actionsのreusable workflowパターンを使い、モノレポでコンポーネント別にスキャンを実行する構成を紹介しました。 項目 ポイント scanPathの制約 単一の相対パスのみ。複数パスやワイルドカードは非対応 公式推奨パターン reusable workflow( workflow_call )でベースワークフローを共通化 パスフィルター連携 on.pull_request.paths で変更コンポーネントだけスキャンを発火 permissions ベースワークフローはジョブレベル、呼び出し元にも明示的に記述 コンポーネント追加 トリガーワークフローを1ファイル追加するだけ 参考資料 関連リンク SCANOSS Code Scan Action(GitHub リポジトリ) SCANOSS MONOREPO_SETUP.md(公式モノレポガイド) SCANOSS Code Scan Action(GitHub Marketplace) GitHub Actions: Reusing workflows GitHub Actions: paths フィルター シリーズ記事 SCANOSS CLIでローカルスキャン:インストールからSBOM生成まで SCANOSS GitHub Actionsでコードスキャンを自動化 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post SCANOSS GitHub Actions モノレポ対応:変更コンポーネントだけスキャンする構成 first appeared on SIOS Tech Lab .
ども!最近 GitHub Actions の Workflow を新規で書くことが増えている龍ちゃんです。Bicep のデプロイパイプラインとか、ブログのビルドチェックとか、地味に CI 周りをいじる機会が多いんですよね。 GitHub Actions のログ確認で作業が途切れる問題 CI をいじってると避けられないのが「CI が落ちたときの確認作業」。 VS Code の GitHub Actions 拡張機能 を入れてれば、どのステップが落ちたかはサイドバーのツリーで確認できます。ただ、拡張機能が教えてくれるのは 「どこが落ちたか」 まで。 「なぜ落ちたのか」をテキストレベルで確認する手段 が足りないんですよね。エラーログの中身を確認しようとすると、ブラウザで GitHub Actions の Run ページを開いて、ジョブを展開して、ログをコピーして…というエディタとブラウザの反復横跳びが発生します。コードの修正を Claude Code と進めてる最中だったら、作業の流れもそこで切れてしまう。 僕がほしかったのは、 「なぜ落ちたか」のログを VS Code 内でテキストとして取得できる仕組み でした。テキストさえ手に入れば、「どう直すか」は Claude Code が分析してくれます(人間もやるよ…)。そこで、 Claude Code の Skills (SKILL.md)と GitHub CLI( gh コマンド) を組み合わせて、CI のログ取得から分析までを VS Code 内で完結させるスキルを作りました。この記事ではスキルの使い方と作り方を解説します。SKILL.md やデモ用 Workflow の全文は付録に載せているので、すぐ試したい人はそちらもどうぞ。 gh-workflow スキルで何が変わるか /gh-workflow スキルを入れると、Claude Code のチャットで「CI 失敗してるから見て」と打つだけで、失敗した Run の特定 → ログの取得 → 原因分析 → 修正方針の提示まで一気に進みます。SKILL.md に gh CLI の手順を書いておくだけで、Claude がログ取得から分析まで全部やってくれる仕組みです。 なお、 GitHub Actions 拡張機能 は「どこが落ちたか」のツリー確認や YAML 編集支援が得意で、このスキルは「なぜ落ちたか」のログ取得と分析が得意です。置き換えではなく補完関係なので、両方入れておくのがおすすめです。 なぜ gh CLI + スキルを選んだか CI のログを VS Code 内で取得する方法は他にもあります。 GitHub MCP Server の Actions toolset を使えば、 list_workflow_runs や get_job_logs といったツールで同等のことが実現できます。機能的には十分ですが、MCP はツールの戻り値が大きくなりがちで、トークン消費が膨らみやすいというのはわりとあるあるな話です。また、Claude Code の組み込みツール(WebSearch / WebFetch)で GitHub の情報を取りにいくという手もなくはありません。 その上で gh CLI + SKILL.md を選んだのは、僕の環境に合っていたからです。 CLI があるなら CLI で叩きたい。 これは完全に好みの話ですが、サービスが公式 CLI を出しているなら、僕は CLI を選びがちです。MCP だとツールの戻り値をスキル側でコントロールしにくいけど、CLI なら --json や --jq で出力形式を自在に絞れる。SKILL.md に書く手順も Bash コマンドそのままなので、トークン効率のルールをスキル側で設計しやすいのが大きいです プロジェクトで利用実績があった。 Bicep との統合でシークレット登録に gh CLI を使っていたので、認証周りは設定済みだった 認証が gh auth で済む。 devcontainer の postCreateCommand に入れておけば、環境構築時に自動で認証できる SKILL.md 一枚で完結する。 Markdown ファイルを .claude/skills/gh-workflow/SKILL.md に置くだけで動く。Skills は description だけが常時コンテキストに入り、本文は呼び出し時のみロードされるので、普段の会話を圧迫しない 選択肢が複数ある中で gh CLI を選んだのは優劣の話ではなく、自分の環境と好みに合っていたからです。 gh CLI × Claude Code で CI ログを確認する(デモ) ここからは実際のデモです。前提として、 gh CLI がインストール済みで認証が完了している必要があります。 認証方法について : とりあえず試すなら gh auth login でブラウザ認証するのが一番手軽です。ただし OAuth はスコープが広くなりがちなので、運用するなら PAT(Personal Access Token)で最小限のスコープに絞るのがおすすめです。Fine-grained PAT なら対象リポジトリと Actions の読み取り権限だけに制限できます。 # PAT を使った認証 echo "<your-pat>" | gh auth login --with-token このリポジトリにデモ用の Workflow を2つ用意しました。 demo-success.yml : ファイル構造のチェックと YAML バリデーションを行う2ジョブ構成の CI パイプライン demo-failure.yml : 3ジョブ構成で、Test ジョブが意図的に失敗する Workflow(テスト失敗のログを再現) SKILL.md は4モード対応(クイックステータス / Run 詳細 / PR チェック / ログ分析)ですが、今回はデモ用 PR がないので3モードで見ていきます。 クイックステータス — 「CI 確認して」 一番シンプルなモードです。「CI 確認して」と打つと、スキルが gh run list を実行して直近の Workflow 実行状況を取得します。 completed failure Demo - Failure Workflow main workflow_dispatch 22430458939 22s 2026-02-26T06:20:53Z completed success Demo - CI Pipeline main workflow_dispatch 22430440934 21s 2026-02-26T06:20:13Z completed success Demo - CI Pipeline main workflow_dispatch 22430416062 46s 2026-02-26T06:19:12Z completed failure Demo - CI Pipeline main workflow_dispatch 22430368912 48s 2026-02-26T06:17:20Z この生データを、スキルのレポートテンプレートに従って整形します。 ## Workflow Status | # | Workflow | Branch | Status | Conclusion | Triggered | |---|---------|--------|--------|------------|-----------| | 1 | Demo - Failure Workflow | main | completed | failure | workflow_dispatch | | 2 | Demo - CI Pipeline | main | completed | success | workflow_dispatch | | 3 | Demo - CI Pipeline | main | completed | success | workflow_dispatch | | 4 | Demo - CI Pipeline | main | completed | failure | workflow_dispatch | ブラウザを開かなくても、今の CI の状況がチャット上で確認できます。 Run 詳細 — 「この Run の詳細を見て」 成功した Run の中身を確認したいこともあります。「この Run、ジョブの実行時間どのくらいだった?」みたいなとき、Run ID を指定すると gh run view <run-id> で詳細を取得します。 ✓ main Demo - CI Pipeline · 22430440934 Triggered via workflow_dispatch about 4 minutes ago JOBS ✓ Code Check in 6s (ID 64947983939) ✓ Config Validate in 7s (ID 64947996283) ジョブごとの実行時間とステータスが見えるので、Workflow の構成を変えた後に「ちゃんと速くなったか」を確認するのに使ったりします。 ログ分析 — 「CI 失敗してるから見て」 ここがメインの見せ場です。「CI 失敗してるから見て」と打つと、スキルが以下のステップを自動で実行します。 Step 1: 失敗した Run を特定する gh run list --branch main --status failure --limit 5 completed failure Demo - Failure Workflow main workflow_dispatch 22430458939 Step 2: 失敗したジョブを特定する gh run view 22430458939 --json jobs --jq '.jobs[] | select(.conclusion == "failure") | {id: .databaseId, name}' {"id": 64948053027, "name": "Test"} --json と jq を使って、失敗したジョブだけを抽出しています。全ジョブの情報を取得する必要はなく、失敗したものだけに絞ることでトークンを節約しています。このあたりの工夫は SKILL.md の解説セクションで詳しく説明します。 Step 3: 失敗したジョブのログを取得する gh run view 22430458939 --log --job 64948053027 Test Run integration tests Running integration tests... Test Run integration tests Test Run integration tests FAILED: test_pipeline.py::test_full_pipeline Test Run integration tests AssertionError: Expected status code 200, got 503 Test Run integration tests File: tests/test_pipeline.py, line 42 Test Run integration tests assert response.status_code == 200 Test Run integration tests Test Run integration tests 1 passed, 1 failed in 3.42s Test Run integration tests ##[error]Process completed with exit code 1. --log には必ず --job を付けています。これがないと全ジョブのログが流れてきてトークンを大量に消費するので、失敗したジョブだけに絞るのが鉄則です。 Step 4: Claude が分析してレポートを出す ログを取得したら、Claude がエラー内容を読み取って原因分析と修正方針をまとめます。 ## Failure Analysis **Run:** #22430458939 - Demo - Failure Workflow **Branch:** main **Failed Jobs:** | Job | Error Summary | |-----|--------------| | Test | integration test で AssertionError(期待 200、実際 503) | **Root Cause:** test_pipeline.py の test_full_pipeline テストで、API レスポンスのステータスコードが 期待値 200 に対して 503 (Service Unavailable) を返している。 **Suggested Fix:** - テスト対象の API サーバーが起動しているか確認 - urllib3 のバージョン互換性を確認(requests 2.31.0 は urllib3<3 を要求) 「CI 失敗してるから見て」の一言で、ここまで出てきます。手作業だと Run を探して、ジョブを開いて、ログを読んで…とやっていた調査が全部自動で走り、Claude がそのまま分析に入ります。コードの修正をしていた会話の流れのまま「じゃあこう直しましょう」と続けられるのがポイントです。 このデモではテスト失敗を再現するために作った Workflow を使っています。 demo-failure.yml は echo で pytest 風のエラー出力を再現して exit 1 する構成で、実際のプロジェクトではここに本物のテスト結果が出ます。 SKILL.md の設計 — トークン効率とログ分析の工夫 ここからは「どうやって作ったか」の話です。スキルの実体は .claude/skills/gh-workflow/SKILL.md という Markdown ファイル1枚(全文は付録参照)。自分のプロジェクトでも同じような仕組みを作りたい人向けに、中身をパートごとに見ていきます。 メタデータ( --- で囲まれたヘッダー部分) --- name: gh-workflow description: | This skill should be used when the user asks to "CI確認して", "Workflow確認", "CIの状態を見て", "ワークフローのログを見て", "CI失敗してるから直して", "PRのチェック状況は", "/gh-workflow", or needs to check GitHub Actions workflow status or analyze CI logs. allowed-tools: Bash, Read --- description にスキルの起動条件を書いておくと、Claude がユーザーの発言を見て自動的にこのスキルを呼び出します。「CI確認して」のような日本語のトリガーも列挙できます。 allowed-tools: Bash, Read で、このスキルが使えるツールを制限しています。 Skills は description だけが常時コンテキストに入っていて、本文はスキルが呼び出されたときにだけロードされるので、普段の会話には影響しません。 モード判定 | モード | トリガー例 | 主なコマンド | |--------|-----------|-------------| | クイックステータス | 「CI確認して」 | `gh run list` | | Run 詳細 | 「Run #123 を見て」 | `gh run view <run-id>` | | PR チェック | 「PR #42 のチェック状況」 | `gh pr checks <pr-number>` | | ログ分析 | 「CI失敗してるから見て」 | `gh run view --log --job` | ユーザーの一言からどのモードを実行するかを、このテーブルで Claude に判断させています。 トークン効率のルール ここが SKILL.md で一番重要なパートです。ただ手順を書くだけなら誰でもできますが、 トークンを無駄遣いしないルール を入れることでスキルの実用性が大きく変わります。 **必ず守ること:** - `--log` は必ず `--job <job-id>` と併用する(全ジョブログは膨大でトークンを大量消費する) - `gh run watch` は使用禁止(リアルタイム出力でトークンを大量消費する) - `gh pr checks --watch` は使用禁止(同上) - JSON 出力 + jq で必要なフィールドのみ取得する --log を --job なしで実行すると、全ジョブのログが一気に流れてきます。CI のログは長くなりがちなので、これをそのままコンテキストに入れるとトークンがあっという間になくなります。 --job で失敗したジョブだけに絞るのが鉄則です。 gh run watch を禁止しているのも同じ理由です。リアルタイム出力がずっと流れ続けるとトークンを食い尽くします。進行中の Run は「今の状態を確認する」だけにして、完了を待ちません。 JSON + jq のルールは、 gh run view --json jobs --jq '.jobs[] | select(.conclusion == "failure")' のように必要なフィールドだけ抽出するためのものです。構造化データで取れるものは構造化データで取ります。 ログ分析モードの設計意図 デモセクションで「何が起きるか」を見ましたが、ここでは「なぜこの設計にしたか」を補足します。SKILL.md に以下の手順を書いておくと、Claude はこの順番で gh CLI を実行します。 ### Step 1: 失敗した Run の特定 gh run list --branch $(git branch --show-current) --status failure --limit 5 ### Step 2: 失敗したジョブの特定 gh run view <run-id> --json jobs --jq '.jobs[] | select(.conclusion == "failure") | {id: .databaseId, name}' ### Step 3: 失敗ジョブのログ取得 gh run view <run-id> --log --job <job-id> ### Step 4: エラー分析と報告 Run 全体 → 失敗ジョブ → 失敗ジョブのログ、と段階的に絞り込んでいく設計です。最初から全部のログを取るのではなく、必要なものだけに辿り着くようにステップを分けています。この段階的な絞り込みがトークン効率のルールと連動していて、各ステップで情報量を削ることで Claude に渡すデータを最小限にしています。 レポートテンプレート ## Failure Analysis **Run:** #<run-id> - <workflow-name> **Branch:** <branch> **Failed Jobs:** | Job | Error Summary | |-----|--------------| | <job-name> | <error-summary> | **Root Cause:** <分析結果> **Suggested Fix:** <修正方針> 出力フォーマットを統一しておくと、毎回同じ形式で結果が出るので読み方が一定になります。「Root Cause を見て、Suggested Fix を見る」というパターンに慣れれば、確認作業がさらに速くなります。 改善の余地 gh CLI には --log-failed という失敗ステップのみ取得するオプションもあります。SKILL.md にはまだ組み込んでいませんが、 --log --job と組み合わせればさらにログを絞り込めるので、今後の改善候補です。 もう一つ気になっているのが、ログが大量になるケースです。 --job で絞っても、ジョブ自体のログが長いとトークンを圧迫する可能性があります。たとえばログを取得してファイルに保存だけしておくとか、失敗したログをテキストファイルとして書き出す CLI ツールを作るとか、いろいろ模索できそうだなと思っています。まだやってないですけどね。 まとめ ざっくり振り返ると、Before / After はこうなりました。 Before : CI が落ちたら、ブラウザで Run を探して、ジョブを開いて、ログをコピーして、Claude に貼って、文脈を説明する。コードの修正中だったら作業の流れが切れる。 After : 「CI 失敗してるから見て」と打つ。スキルが gh CLI でログを集めて、Claude が分析して修正方針を出す。コードの修正中でも会話の流れはそのまま。 これを実現しているのは、 .claude/skills/gh-workflow/SKILL.md という Markdown ファイル1枚です。特別なインフラもサーバーも不要で、プロジェクトにファイルを1つ追加するだけで動きます。 GitHub Actions 拡張機能 とは補完関係で使うのがおすすめです。YAML の編集支援や「どこが落ちたか」の確認は拡張機能が得意で、「なぜ落ちたか」のログ取得と分析はスキル + Claude が得意です。 SKILL.md は他のプロジェクトでもそのまま使えます。 gh CLI のコマンドを自分のプロジェクトに合わせて書き換えるだけで、同じ仕組みが動きます。トークン効率のルール( --log には --job 必須、 watch 禁止、JSON + jq で絞り込み)はどのプロジェクトでも共通なので、テンプレートとして参考にしてもらえると思います。 ほなまた〜 シリーズ記事 記事 内容 概要編 — ブラウザなし GitHub 操作を実現する 問題提起と解決策の全体像 この記事(CI 編) 失敗ログの取得から原因分析まで Gist 編 — Gist 操作をチャット1行で完結させる Gist の検索・保存・更新 付録 SKILL.md 全文 .claude/skills/gh-workflow/SKILL.md の内容です。 --- name: gh-workflow description: | This skill should be used when the user asks to "CI確認して", "Workflow確認", "CIの状態を見て", "ワークフローのログを見て", "CI失敗してるから直して", "PRのチェック状況は", "/gh-workflow", or needs to check GitHub Actions workflow status or analyze CI logs. allowed-tools: Bash, Read --- # GitHub Actions Workflow Status & Log Analysis gh CLI を使って GitHub Actions の Workflow ステータス確認・ログ分析を行います。 ## Mode Selection ユーザーの指示から以下の4モードを自動判定して実行する。 | モード | トリガー例 | 主なコマンド | |--------|-----------|-------------| | クイックステータス | 「CI確認して」「Workflowの状態を見て」 | `gh run list` | | Run 詳細 | 「Run #123 を見て」「この Run の詳細」 | `gh run view <run-id>` | | PR チェック | 「PR #42 のチェック状況」「PRのCI」 | `gh pr checks <pr-number>` | | ログ分析 | 「CI失敗してるから見て」「エラーログ確認」 | `gh run view --log --job` | ## Token Efficiency Rules **必ず守ること:** - `--log` は必ず `--job <job-id>` と併用する(全ジョブログは膨大でトークンを大量消費する) - `gh run watch` は使用禁止(リアルタイム出力でトークンを大量消費する) - `gh pr checks --watch` は使用禁止(同上) - JSON 出力 + jq で必要なフィールドのみ取得する --- ## Mode 1: クイックステータス 現在のブランチまたはリポジトリの Workflow 実行状況を一覧表示する。 ### Step 1: Run 一覧の取得 ```bash # 現在のブランチの最新10件 gh run list --branch $(git branch --show-current) --limit 10 # 全ブランチの最新10件(ブランチ指定なし) gh run list --limit 10 ``` ### Step 2: 結果を報告テンプレートで表示 ## Mode 2: Run 詳細 特定の Run ID の詳細情報を取得する。 ### Step 1: Run の詳細取得 ```bash # Run の詳細表示 gh run view <run-id> # JSON で構造化データを取得 gh run view <run-id> --json status,conclusion,jobs,createdAt,updatedAt,headBranch,event ``` ### Step 2: ジョブごとのステータスを整理して報告 ## Mode 3: PR チェック PR に紐づくチェック状況を確認する。 ### Step 1: PR チェックの取得 ```bash # PR のチェック状況 gh pr checks <pr-number> # 現在のブランチの PR チェック(PR 番号不明時) gh pr checks ``` ### Step 2: チェック結果を報告テンプレートで表示 ## Mode 4: ログ分析 失敗した Workflow のログを取得・分析する。 ### Step 1: 失敗した Run の特定 ```bash # 現在のブランチで失敗した Run を検索 gh run list --branch $(git branch --show-current) --status failure --limit 5 ``` ### Step 2: 失敗したジョブの特定 ```bash # Run 内のジョブ一覧を JSON で取得 gh run view <run-id> --json jobs --jq '.jobs[] | {name, status, conclusion}' ``` ### Step 3: 失敗ジョブのログ取得 ```bash # 特定ジョブのログのみ取得(必ず --job を指定) gh run view <run-id> --log --job <job-id> ``` **重要:** `--log` は必ず `--job <job-id>` と併用する。`--job` なしだと全ジョブのログが出力されトークンを大量消費する。 ### Step 4: エラー分析と報告 ログからエラー箇所を特定し、原因と修正方針を報告する。 ## Status / Conclusion Reference | 値 | 種類 | 意味 | |----|------|------| | `queued` | status | キュー待ち | | `in_progress` | status | 実行中 | | `completed` | status | 完了 | | `waiting` | status | 承認待ち | | `success` | conclusion | 成功 | | `failure` | conclusion | 失敗 | | `cancelled` | conclusion | キャンセル済み | | `skipped` | conclusion | スキップ | | `timed_out` | conclusion | タイムアウト | | `action_required` | conclusion | アクション要求 | | `neutral` | conclusion | 中立(情報のみ) | | `stale` | conclusion | 古い結果 | ## JSON Output Patterns よく使う構造化データ取得パターン: ```bash # Run 一覧を JSON で取得 gh run list --limit 10 --json databaseId,displayTitle,status,conclusion,headBranch,createdAt,event # Run 内のジョブ詳細 gh run view <run-id> --json jobs --jq '.jobs[] | {id: .databaseId, name, status, conclusion, startedAt, completedAt}' # 失敗ジョブのみ抽出 gh run view <run-id> --json jobs --jq '.jobs[] | select(.conclusion == "failure") | {id: .databaseId, name}' # PR チェックの詳細(JSON) gh pr checks <pr-number> --json name,state,description,detailsUrl ``` ## Report Template 以下のテンプレートを使って結果を報告する。 ### ステータス一覧 ``` ## Workflow Status | # | Workflow | Branch | Status | Conclusion | Triggered | |---|---------|--------|--------|------------|-----------| | 1 | <name> | <branch> | <status> | <conclusion> | <event> | ``` ### 失敗分析 ``` ## Failure Analysis **Run:** #<run-id> - <workflow-name> **Branch:** <branch> **Failed Jobs:** | Job | Error Summary | |-----|--------------| | <job-name> | <error-summary> | **Root Cause:** <分析結果> **Suggested Fix:** <修正方針> ``` ## Important Notes - **gh CLI 未認証の場合**: `gh auth status` で認証状態を確認し、未認証ならユーザーに通知 - **リポジトリ外で実行した場合**: エラーをユーザーに通知 - **大量のログ出力**: 必ず `--job` で絞り込み、それでも長い場合は主要なエラー行のみ抽出 - **進行中の Run**: ステータスが `in_progress` の場合、完了を待たずに現在の状態を報告(`watch` は使わない) デモ用 Workflow demo-success.yml 2ジョブ構成の CI パイプライン。ファイル構造のチェックと YAML バリデーションを行います。 name: Demo - CI Pipeline on: workflow_dispatch: jobs: check: name: Code Check runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Check file structure run: | echo "Checking project files..." test -f pyproject.toml && echo "OK: pyproject.toml" test -f CLAUDE.md && echo "OK: CLAUDE.md" echo "All checks passed." validate: name: Config Validate runs-on: ubuntu-latest needs: check steps: - name: Checkout repository uses: actions/checkout@v4 - name: Validate YAML configs run: | echo "Validating workflow files..." ls .github/workflows/*.yml | wc -l | xargs -I{} echo "Found {} workflow files" echo "Validation complete." demo-failure.yml 3ジョブ構成で、Test ジョブが意図的に失敗する Workflow。echo で pytest 風のエラー出力を再現しています。 name: Demo - Failure Workflow on: workflow_dispatch: jobs: setup: name: Setup runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Verify environment run: | echo "Environment check..." echo "OS: $(uname -s)" echo "Setup completed." test: name: Test runs-on: ubuntu-latest needs: setup steps: - name: Checkout repository uses: actions/checkout@v4 - name: Run unit tests run: | echo "Running unit tests..." echo "test_fetch_article ... PASSED" echo "test_parse_html ... PASSED" echo "Unit tests passed." - name: Run integration tests run: | echo "Running integration tests..." echo "" echo "FAILED: test_pipeline.py::test_full_pipeline" echo " AssertionError: Expected status code 200, got 503" echo " File: tests/test_pipeline.py, line 42" echo " assert response.status_code == 200" echo "" echo "1 passed, 1 failed in 3.42s" exit 1 deploy: name: Deploy runs-on: ubuntu-latest needs: test steps: - name: Deploy application run: echo "Deploying..." ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post gh CLI × Claude Code で GitHub Actions 失敗ログをチャットで即解決 first appeared on SIOS Tech Lab .
ども!最近は VS Code のターミナルとチャット欄だけで一日が終わる龍ちゃんです。 生成 AI を使った開発、爆速ですよね。コード書いて、テストして、コミットして。エディタの中で AI と会話しながら全部完結します。この体験を知ってしまうと、もう戻れないんですよ。 爆速になりつつ品質をいかに担保するのか?というのが直近の大きな課題です。 作業が途切れる瞬間がある ただ、途切れる瞬間があるんですよね。CI が落ちたらログを確認しないといけないし、コードを Gist に保存したくなることもある。GitHub でやりたいことが出てくるたびに、ブラウザを開いてしまうんです。その瞬間にエディタから手が離れてしまいます。 たかが数分のことなんですけど、集中してたのに一回途切れるあの「うっ」って感じ、ずっと気になってました。 よく考えると、ブラウザを開いてまでやってることって CI のログを読むとか、Gist にコードを貼るとか、そういうことなんですよね。中身はぜんぶテキストです。テキストとして手に入ればそれでいいのに、わざわざブラウザの UI をポチポチ… この記事は、VS Code でコード書いてて、GitHub のためにブラウザに飛ぶたびに「うっ」ってなる人に向けて書いています。 「ちょっとブラウザ開くだけ」がどれだけ重いか書き出してみて、それを解決する方法として gh CLI(GitHub CLI) や MCP にどんな選択肢があるか整理して、実際にどう変わるのかを具体例で見ていきます。 ブラウザを開く「ちょっとだけ」が重い理由 「ちょっとブラウザ開くだけ」。実際にちょっと開くだけです。でも、実際にやってることを書き出してみると、ちょっとじゃないんですよね。 CI が落ちたときの「ちょっとだけ」 GitHub Actions の CI が落ちたとき、ログを確認するまでの手順を書き出してみます。 ブラウザで GitHub Actions の Run ページを開く 失敗したジョブを展開する エラーログの該当箇所を探す ログをコピーする VS Code に戻る コピーしたログを読んで原因を調べる 6ステップもあります。「ちょっとだけ」とは一体何だったのか。 Gist に保存したいときの「ちょっとだけ」 Gist も似たようなもんです。 gist.github.com をブラウザで開く ファイル名を入力する コードを貼り付ける description を書く public / secret を選択する 「Create gist」ボタンを押す こちらも6ステップです。逆方向、つまり Gist からコードを取ってくるときも同じぐらいかかります。 ステップ数が問題じゃない ただ、正直に言うとステップ数自体はそこまで大した話じゃないんですよね。慣れてれば数分で終わります。 問題はそこじゃなくて、 作業の流れが切れる ことなんです。 コード書いてる最中にブラウザに飛んで、用が済んでエディタに戻ってくる。たかが数分です。でも戻ったときに「何してたっけ」「どこまでやったっけ」ってなりません? エディタの画面は変わってないのに、頭の中の作業文脈がリセットされてるんですよね。さっきまで集中してた「あの感じ」を取り戻すのに、また時間がかかります。 これだけでもダルいんですけど、生成 AI と会話しながら作業してるときはもっとキツくなります。コードの修正を進めてる最中にブラウザに飛ぶと、戻ってきてからさっきの続きを取り戻すのに時間がかかるんですよね。頭の中を巻き戻すだけじゃなくて、ブラウザで確認してきたログの内容をいちいち説明し直さないといけない。あの手間がほんとにダルいんですよ。 結局、ブラウザの GUI で得られる情報って、テキストで十分なものばかりなんです。CI のログも Gist のコードも、テキストとして手に入ればいい。それならエディタの中で完結させたいんですよね。 gh CLI・MCP・Claude Code Skills — エディタから GitHub を操作する方法 「エディタの中で GitHub の操作を呼び出したい」——この望みを叶えてくれる方法は、実はいくつかあります。 GitHub CLI(gh コマンド) GitHub CLI は、GitHub が公式に提供しているコマンドラインツールです。 gh run list で CI の実行一覧を取得したり、 gh gist create で Gist を作成したり、ブラウザでやっていた操作がターミナルのコマンドで一通りできるようになります。 VS Code のターミナルから実行すれば、ブラウザを開く必要がなくなります。情報はテキストで返ってくるので、そのまま読めるし、AI に渡すこともできます。 --json や --jq で出力形式を絞れるので、必要な情報だけを取り出しやすいのも強みです。 認証の補足 : とりあえず試すなら gh auth login のブラウザ認証が手軽です。運用するなら PAT(Personal Access Token)で必要なスコープだけに絞るのがおすすめです。認証方法の詳細は各編で触れます。 MCP(Model Context Protocol) MCP は、AI ツールが外部の API を呼び出すための仕組みです。 GitHub MCP Server を設定すると、AI が直接 GitHub の API を叩いてくれます。Issue の操作やリポジトリの情報取得など、カバー範囲は広いです。 ただし、ツールの戻り値が大きくなりがちで、トークン消費が膨らみやすいという特性があります。また、Gist 関連のツールは 2026年2月時点では提供されていません。 Claude Code Skills Claude Code の Skills を使うと、コマンドの手順を Markdown ファイルに書いておくだけで、チャットから呼び出せる仕組みを作れます。gh CLI の手順を書いておけば、「CI 失敗してるから見て」と打つだけでスキルが gh CLI を実行してログを取得し、Claude が分析する——という流れをチャットの中で完結させられます。 このシリーズのアプローチ どの方法を使っても「エディタから離れない」という目的は達成できます。 このシリーズでは gh CLI + Claude Code Skills の組み合わせを選びました。CLI なら出力形式を自在に絞れるのでトークンを無駄遣いしにくいし、SKILL.md に書く手順も Bash コマンドそのままなので設計しやすかったんですよね。選んだ理由の詳しい話は各編で触れますが、大事なのは方法論よりも「エディタから GitHub の操作を呼び出せるようになる」という体験のほうです。 シリーズ構成 記事 内容 学べること この記事(概要編) 問題提起と解決策の全体像 なぜエディタから離れたくないのか、どんな選択肢があるか CI 編 失敗ログの取得から原因分析まで SKILL.md の設計パターン、トークン効率のルール Gist 編 Gist の検索・保存・更新 CRUD をスキル化するときの安全策、段階的絞り込み GitHub Actions をよく使うなら CI 編から、スニペット管理や Gist 活用が気になるなら Gist 編から読むのがおすすめです。 gh CLI × Claude Code Skills で何が変わるか じゃあ、実際にどう変わるのか。各編の内容から1つずつ味見してもらいます。 CI の場合 エディタのチャット欄で「CI 失敗してるから見て」と打ちます。 スキルが失敗した Run を探して、ログを取得して、Claude が分析結果を返してくれます。 ## Failure Analysis **Run:** #22430458939 - Demo - Failure Workflow **Failed Jobs:** | Job | Error Summary | |-----|--------------| | Test | integration test で AssertionError(期待 200、実際 503) | **Root Cause:** test_pipeline.py の test_full_pipeline テストで、 API レスポンスのステータスコードが期待値 200 に対して 503 を返している **Suggested Fix:** - テスト対象の API サーバーが起動しているか確認 ブラウザは一度も開いていません。Run を探す → ジョブを展開する → ログをコピーする → 原因を調べる、という6ステップが「CI 失敗してるから見て」の一言に置き換わっています。そのまま「じゃあ直して」と続ければ、修正まで会話の流れの中で進められます。 CI 編 : 失敗ログの取得から修正まで VS Code で完結させる仕組みと作り方。SKILL.md の設計やトークン効率のルールも紹介します。 Gist の場合 「Python のスニペット取ってきて」と打ちます。 スキルが Gist を検索して、ファイルを特定して、中身を取得してくれます。 """Python useful snippets - よく使うコードスニペット集""" # --- flatten nested list --- def flatten(nested: list) -> list: ... gist.github.com は開いていません。検索してコードをコピーしてエディタに貼り付けて……という手順がまるごとなくなっています。 保存も同じです。コードを書いてて「これ Gist に保存しといて」と打てば、ファイル名も description もいい感じに付けて保存してくれます。URL が返ってくるので、共有したければそのまま貼るだけです。 Gist 編 : 「保存して」「取ってきて」で Gist 操作が完結する仕組みと作り方。CRUD をスキル化するときの安全策(secret デフォルト、削除前確認)も紹介します。 まとめ ブラウザに飛ぶたびに作業の流れが切れる。ステップ数じゃなくて、頭の中の文脈がリセットされるのがキツいんですよね。CI のログも Gist のコードも、テキストとして手に入ればそれでいいんです。 gh CLI や MCP を使えば、エディタの中から GitHub の操作を呼び出せます。Claude Code Skills と組み合わせれば、チャットの一言で全部完結します。仕組み自体は .claude/skills/ に Markdown ファイルを1つ置くだけなので、自分のプロジェクトに合わせてカスタマイズしやすいのもポイントです。 このシリーズでは gh CLI + Skills の組み合わせで2つのスキルを作りました。各編では SKILL.md の全文と設計の考え方を解説しているので、そのまま使うこともできるし、自分のプロジェクトに合わせてカスタマイズすることもできます。CI と Gist に限らず、gh CLI でできる操作なら同じパターンで横展開できるので、「自分のプロジェクトだとこの操作が面倒」というものがあれば、各編のやり方を参考にスキルを作ってみてください。 ではまた! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post gh CLI × Claude Code でブラウザなし GitHub 操作を実現する first appeared on SIOS Tech Lab .
ども!最近 Gist の出番が増えた龍ちゃんです。スニペットの保存はもちろん、プロジェクト横断で使い回すプロンプトテンプレートとか、ちょっとした設定ファイルとか。操作が面倒で使ってなかったんですけど、チャットで完結するようにしたら話が変わりました。 .claude/skills/gh-gist/SKILL.md という Markdown ファイル1枚で、Gist の検索・取得・保存・更新がチャットの一言で動きます。この記事ではスキルの使い方と、CRUD をスキル化するときのトークン効率・安全設計の考え方を解説します。 GitHub Gist の課題 — 検索性と保存コスト Gist 自体は優秀な仕組みなんですよね。URL 一つでコードを共有できて、バージョン管理もついてくる。複数ファイルをまとめられるし、secret / public の切り替えもできます。「ちょっとしたコードの保存と共有」にちょうどいい粒度で設計されています。 でも実態、使いこなせてなくないですか? 僕の場合がまさにそうでした。問題は2つあります。 検索性が弱い。 Gist が増えてくると、Web UI では目視スクロールで探すことになります。「あのスニペットどこだっけ」が頻発して、見つからないとそのまま諦めてしまう。 保存のハードルが高い。 ブラウザで gist.github.com を開いて、ファイル名を入力して、コードを貼り付けて、description を書いて、public か secret を選んで、Create ボタンを押す。コードを書いてる最中にこの手順をやる気にはなれないんですよね。 結果どうなるかというと、「保存するほどでもないか」→ 使わなくなる → 存在を忘れる。もったいない。 操作コストが下がれば話は変わる 「Gist に保存して」「Python のスニペット取ってきて」で済むなら話は別です。VS Code のチャットで完結するなら、コーディングの流れも切れません。 スニペットの保存・取得だけじゃなくて、操作コストが下がると 使い方の発想自体が変わる んですよね。たとえばプロジェクト横断で使い回すファイル(人格設定、プロンプトテンプレートなど)を Gist で一元管理して、必要なプロジェクトにスキルで引っ張ってくるとか。1ファイル完結 × 複数プロジェクトで共有 × バージョン管理つき、という Gist の粒度にぴったりハマります。「Gist = ちょっとしたコード置き場」から「プロジェクト横断のファイル管理」へ。 これを Claude Code の Skills (SKILL.md)と GitHub CLI( gh コマンド) で作りました。この記事ではスキルの使い方と作り方を解説します。SKILL.md の全文は付録に載せているので、すぐ試したい人はそちらもどうぞ。 なぜ gh CLI + スキルを選んだか Gist をエディタ内で操作する方法は他にもあります。 GitHub の Web UI は Gist の作成・閲覧・編集が一通りできますが、前述のとおり検索性が弱い。何よりコードを書いてる最中にブラウザに切り替えると作業の流れが切れます。 GitHub MCP Server には Gist 関連のツールがありません(2026年2月時点)。仮に対応していたとしても、MCP はツールの戻り値が大きくなりがちでトークン消費が膨らみやすいのはわりとあるあるな話です。 その上で gh CLI + SKILL.md を選んだのは、Gist の操作に合っていたからです。 gh CLI が Gist のサブコマンドを持っている。 gh gist list / view / create / edit / delete で CRUD 全部できます。 --filter や --raw --filename で出力を絞れるので、トークン効率のルールを設計しやすい 認証が gh auth で済む。 devcontainer の postCreateCommand に入れておけば環境構築時に自動で認証できる SKILL.md 一枚で完結する。 .claude/skills/gh-gist/SKILL.md に Markdown で手順を書くだけで動きます。 Skills は description だけが常時コンテキストに入り、本文は呼び出し時のみロードされるので、普段の会話を圧迫しません 選択肢が複数ある中で gh CLI を選んだのは優劣の話ではなく、自分の環境と用途に合っていたからです。 gh CLI × Claude Code で Gist を操作する(デモ) ここからは実際のデモです。検証用に Gist を事前に作成して、Claude Code のチャットで操作しました。前提として、 gh CLI がインストール済みで認証が完了している必要があります。 認証方法について : とりあえず試すなら gh auth login でブラウザ認証するのが一番手軽です。ただし OAuth はスコープが広くなりがちなので、運用するなら PAT(Personal Access Token)で最小限のスコープに絞るのがおすすめです。Classic PAT なら gist スコープだけで Gist の全操作が動きます。 # PAT を使った認証 echo "<your-pat>" | gh auth login --with-token SKILL.md は5モード対応(一覧 / 取得 / 保存 / 更新 / データ管理)ですが、よく使う3モードをデモで見ていきます。 取得 —「Python のスニペット取ってきて」 「Gist から Python のスニペット取ってきて」と打つと、スキルが以下のステップを自動で実行します。 Step 1: キーワードで Gist を検索 gh gist list --filter "Python" e7236579... Python useful snippets (updated) 2 files secret 2026-02-26T14:20:47Z Step 2: ファイル一覧を確認 gh gist view e72365796014c25d70629f6d8cfe01bc --files snippets.py todo.md Step 3: 目的のファイルを取得 gh gist view e72365796014c25d70629f6d8cfe01bc --raw --filename snippets.py """Python useful snippets - よく使うコードスニペット集""" # --- flatten nested list --- def flatten(nested: list) -> list: ... 「Python のスニペット」という曖昧な指示から、3ステップで目的のファイルに辿り着いています。 --filter で絞り → --files でファイル一覧 → --filename で中身取得。この 段階的な絞り込み がトークン効率のルールと連動していて、各ステップで情報量を削っています。このあたりの工夫は SKILL.md の解説セクションで詳しく説明します。 保存 —「このコードを Gist に保存して」 コードを渡して「Gist に保存して、description は Verification test で」と打ちます。 Step 1: 一時ファイルに書き出し ユーザーが指定したコードを application/tools/tmp/hello.py に書き出します。 gh gist create はファイルパスを引数に取るので、一時ファイル経由で作成する形です。 Step 2: Gist を作成 gh gist create application/tools/tmp/hello.py -d "Verification test" https://gist.github.com/user/xxxx デフォルトは secret で作成されます。public にしたい場合は「public で」と明示する必要があり、SKILL.md にそのルールを書いてあります。書き込み操作をスキル化するときに入れておきたい安全策の一つです。 更新 —「さっきの Gist にファイル追加して」 「さっき保存した Gist に README.md を追加して」と打つと、スキルが直前の会話のコンテキストから Gist ID を拾い、 gh gist edit でファイルを追加します。 ファイル追加 gh gist edit <gist-id> --add application/tools/tmp/README.md description 変更 gh gist edit <gist-id> --desc "Verification test (updated)" gh gist edit はデフォルトだとエディタが開いて対話的な編集になります。Claude Code から使うにはオプション引数で非対話的に更新する必要があって、このあたりも SKILL.md に手順を書いてあります。 SKILL.md の設計 — トークン効率と安全策 ここからは「どうやって作ったか」の話です。スキルの実体は .claude/skills/gh-gist/SKILL.md という Markdown ファイル1枚(全文は付録参照)。中身をパートごとに見ていきます。 メタデータ( --- で囲まれたヘッダー部分) --- name: gh-gist description: | This skill should be used when the user asks to "Gist一覧", "Gistに保存して", "Gistから取ってきて", "Gistを更新して", "コードをGistに", "Gist確認して", "/gh-gist", or needs to manage GitHub Gists via gh CLI. allowed-tools: Bash, Read --- description にスキルの起動条件を書いておくと、Claude がユーザーの発言を見て自動的にスキルを呼び出します。「Gist に保存して」のような日本語のトリガーも列挙できます。 allowed-tools: Bash, Read で、このスキルが使えるツールを制限しています。 Skills は description だけが常時コンテキストに入っていて、本文はスキルが呼び出されたときにだけロードされるので、普段の会話には影響しません。 モード判定 | モード | トリガー例 | 主なコマンド | |--------|-----------|-------------| | 一覧 | 「Gist一覧」 | `gh gist list` | | 取得 | 「Gistから取ってきて」 | `gh gist view --raw --filename` | | 保存 | 「Gistに保存して」 | `gh gist create` | | 更新 | 「Gistを更新して」 | `gh gist edit` | | データ管理 | 「Gistのデータ更新して」 | `gh gist view` + jq + `gh gist edit` | ユーザーの一言からどのモードを実行するかを、このテーブルで Claude に判断させています。 CI 編 が読み取り中心の4モードだったのに対して、Gist 編は CRUD 操作を含む5モード構成です。 トークン効率のルール ここが SKILL.md で一番重要なパートです。 CI 編 では --log に --job 必須・ watch 禁止というルールでしたが、Gist 編ではサブコマンドが違う分、ルールの中身も変わります。ただし 「必要な情報だけに絞り込む」 という設計思想は共通です。 **必ず守ること:** - `gh gist list --include-content` は使用禁止(全 Gist の中身を取得してトークンを大量消費する) - `gh gist view` で複数ファイル Gist を扱う場合は必ず `--filename` で絞る - `gh gist view --files` でファイル一覧を先に確認してから `--raw --filename` で中身取得 --include-content を禁止しているのは、 gh gist list に付けると全 Gist の中身まで取得してしまうからです。 --filter だけで description とファイル名は検索できるので、中身を全部取る必要はありません。 --filename を必須にしているのは、複数ファイルの Gist で --filename なしだと全ファイルが連結出力されるからです。検証では2ファイルの Gist で --filename ありだと6行、なしだと37行の出力差がありました。ファイル数が多い Gist だとこの差はさらに開きます。 デモで見た「 --filter → --files → --raw --filename 」という段階的な絞り込みも、このルールに基づいています。最初から全部取るのではなく、ステップを分けて必要な情報だけに辿り着く設計です。 --raw の落とし穴 検証で見つけた話なんですが、 gh gist view <id> --raw を --filename なしで実行すると、description が出力の先頭行に入ります。 $ gh gist view e72365796014c25d70629f6d8cfe01bc --raw Python useful snippets ← description が1行目に出る """Python useful snippets - よく使うコードスニペット集""" ... ターミナルで見る分には気にならないんですけど、 > file.json でリダイレクトすると JSON の先頭に description が混入してパースが壊れます。後述するデータ管理モードで JSON を取得→更新するフローがあるので、SKILL.md に 「 --raw は必ず --filename と併用する」 というルールを明記して、Claude が --filename なしで実行するのを防いでいます。 書き込み操作の安全策 CI 編 のスキルは読み取り専用でしたが、Gist 編は CRUD 全操作を含むので、安全策の設計が必要になります。 secret デフォルト : --public はユーザーが「public で」と明示した場合のみ使う。意図せず公開されるのを防ぐ 削除前確認 : gh gist delete はユーザーに確認を取ってから実行する --yes フラグ : 非インタラクティブ環境(Claude Code)では削除時に --yes が必須。検証中に --yes なしで実行してエラーになって気づいた 一時ファイル経由 : 保存・更新は application/tools/tmp/ に一時ファイルを書き出してからコマンドに渡す 読み取り専用のスキルにはない設計ですが、CRUD をスキル化するなら、こういう安全策のセットはテンプレートとして使い回せると思います。 データ管理モード SKILL.md には5つ目のモードとして「データ管理」を入れています。description に [data] プレフィックスを付けてデータ用 Gist を識別する規約で、JSON の取得 → jq で変換 → Gist に反映、というフローを定義しています。Gist を簡易 DB 的に使う発想ですね。実用レベルかはまだ試行中ですが、仕組みとしては動きます。興味がある人は付録の SKILL.md 全文を参照してください。 改善の余地 gh CLI には gh gist clone でローカルに落として編集→ push するフローや、 gh gist rename でのファイル名変更もあります。SKILL.md にはまだ組み込んでいませんが、使いながら必要になったら足していく予定です。 まとめ ざっくり振り返ると、Before / After はこうなりました。 Before : Gist は便利な仕組みだけど、操作コストが高くて使いこなせていなかった。保存するにもブラウザ、探すにもブラウザ。結局「保存するほどでもないか」で使わなくなる。 After : 「Gist に保存して」「スニペット取ってきて」とチャットで打つだけ。VS Code から離れない。操作コストが下がると、Gist を「使おう」と思えるようになる。 これを実現しているのは .claude/skills/gh-gist/SKILL.md という Markdown ファイル1枚です。特別なインフラもサーバーも不要で、プロジェクトにファイルを1つ追加するだけで動きます。 トークン効率のルール( --include-content 禁止、 --filename 必須、段階的絞り込み)は gh CLI スキル共通のパターンとして使えます。書き込み操作の安全策(secret デフォルト、削除前確認、 --yes )は CRUD をスキル化するときの設計テンプレートになると思います。 ほなまた〜 シリーズ記事 記事 内容 概要編 — ブラウザなし GitHub 操作を実現する 問題提起と解決策の全体像 CI 編 — GitHub Actions 失敗ログをチャットで即解決 失敗ログの取得から原因分析まで この記事(Gist 編) Gist の検索・保存・更新 付録 SKILL.md 全文 .claude/skills/gh-gist/SKILL.md の内容です。 --- name: gh-gist description: | This skill should be used when the user asks to "Gist一覧", "Gistに保存して", "Gistから取ってきて", "Gistを更新して", "コードをGistに", "Gist確認して", "/gh-gist", or needs to manage GitHub Gists via gh CLI. allowed-tools: Bash, Read --- # GitHub Gist Management gh CLI を使って GitHub Gist の管理(一覧・取得・保存・更新・データ管理)を行います。 ## Mode Selection ユーザーの指示から以下の5モードを自動判定して実行する。 | モード | トリガー例 | 主なコマンド | |--------|-----------|-------------| | 一覧 | 「Gist一覧」「Gist確認して」 | `gh gist list` | | 取得 | 「Gistから取ってきて」「Gistの中身見せて」 | `gh gist view --raw --filename` | | 保存 | 「Gistに保存して」「コードをGistに」 | `gh gist create` | | 更新 | 「Gistを更新して」「Gistに追加して」 | `gh gist edit` | | データ管理 | 「Gistのデータ更新して」「Gistの設定を変更」 | `gh gist view --raw` + jq + `gh gist edit` | ## Token Efficiency Rules **必ず守ること:** - `gh gist list --include-content` は使用禁止(全 Gist の中身を取得してトークンを大量消費する) - `gh gist view --raw` を `--filename` なしで使うと description が先頭行に混入する。特にリダイレクトで JSON/YAML を取得する場合は **必ず `--filename` を指定する**(パースが壊れる) - `gh gist view` で複数ファイル Gist を扱う場合は必ず `--filename` で絞る(全ファイル連結出力になる) - `gh gist view --files` でファイル一覧を先に確認してから `--raw --filename` で中身を取得する - 新規作成時はデフォルト secret(`--public` はユーザーの明示的指示がある場合のみ) - データ管理モードでは `application/tools/tmp/` に一時ファイルを書き出して `gh gist edit` で反映 --- ## Mode 1: 一覧 自分の Gist 一覧を表示する。 ### Step 1: Gist 一覧の取得 ```bash # 最新10件 gh gist list --limit 10 # フィルタ付き(description / ファイル名で検索) gh gist list --filter "keyword" # public のみ / secret のみ gh gist list --public gh gist list --secret ``` ### Step 2: 結果を報告テンプレートで表示 ## Mode 2: 取得 特定の Gist からファイル内容を取得する。 ### Step 1: 対象 Gist の特定 ユーザーが Gist ID / URL を指定していない場合は一覧から検索する。 ```bash # キーワードで検索 gh gist list --filter "keyword" ``` ### Step 2: ファイル一覧の確認 ```bash # Gist 内のファイル名を確認 gh gist view <gist-id> --files ``` ### Step 3: ファイル内容の取得 ```bash # 特定ファイルの内容を raw で取得 gh gist view <gist-id> --raw --filename <filename> ``` **重要:** 複数ファイル Gist では必ず `--filename` を指定する。省略すると全ファイルが出力されトークンを大量消費する。 ## Mode 3: 保存 新しい Gist を作成する。 ### Step 1: ファイルの準備 ユーザーが指定したコードやテキストを `application/tools/tmp/` に一時ファイルとして書き出す。 ### Step 2: Gist の作成 ```bash # 単一ファイル(secret、デフォルト) gh gist create application/tools/tmp/<filename> -d "description" # 複数ファイル gh gist create application/tools/tmp/file1 application/tools/tmp/file2 -d "description" # public(ユーザーが明示的に指示した場合のみ) gh gist create application/tools/tmp/<filename> -d "description" --public # stdin から作成 echo "content" | gh gist create -f <filename> -d "description" ``` **重要:** デフォルトは secret。`--public` はユーザーが「public で」「公開で」と明示した場合のみ使用する。 ### Step 3: 結果を報告テンプレートで表示 ## Mode 4: 更新 既存の Gist を更新する。 ### Step 1: 対象 Gist の特定 ユーザーが Gist ID / URL を指定していない場合は一覧から検索する。 ```bash gh gist list --filter "keyword" ``` ### Step 2: 現在の内容を確認 ```bash gh gist view <gist-id> --files gh gist view <gist-id> --raw --filename <filename> ``` ### Step 3: 更新の実行 ```bash # ファイル内容の上書き(一時ファイル経由) gh gist edit <gist-id> --filename <target> application/tools/tmp/<local-file> # ファイルの追加 gh gist edit <gist-id> --add application/tools/tmp/<new-file> # description の変更 gh gist edit <gist-id> --desc "new description" # ファイルの削除(ユーザーの明示的指示がある場合のみ) gh gist edit <gist-id> --remove <filename> ``` ### Step 4: 結果を報告テンプレートで表示 ## Mode 5: データ管理 JSON / YAML などの構造化データを Gist に保存し、DB 的に管理する。 ### データ用 Gist の識別 description に `[data]` プレフィックスを付けてデータ用 Gist を識別する。 ```bash # データ用 Gist の検索 gh gist list --filter "\\[data\\]" ``` ### データの取得と更新 ```bash # 1. 現在のデータを取得 gh gist view <gist-id> --raw --filename <filename> > application/tools/tmp/<filename> # 2. jq で変換(JSON の場合) jq '.key = "new_value"' application/tools/tmp/<filename> > application/tools/tmp/<filename>.updated # 3. Gist に反映 gh gist edit <gist-id> --filename <filename> application/tools/tmp/<filename>.updated ``` ### データ用 Gist の新規作成 ```bash # JSON データ gh gist create application/tools/tmp/data.json -d "[data] project-config" # YAML データ gh gist create application/tools/tmp/data.yaml -d "[data] settings" ``` **削除操作:** ユーザーの明示的指示がある場合のみ実行。必ず確認を取る。 ```bash # 削除(非インタラクティブ環境では --yes が必須) gh gist delete <gist-id> --yes ``` ## Report Templates 以下のテンプレートを使って結果を報告する。 ### 一覧 ``` ## Gist 一覧 | # | Description | Files | Visibility | Updated | |---|-------------|-------|------------|---------| | 1 | <description> | <file-count> | <public/secret> | <date> | ``` ### 取得結果 ``` ## Gist 内容 **Gist:** <description> **ID:** <gist-id> **File:** <filename> <ファイル内容をコードブロックで表示> ``` ### 保存完了 ``` ## Gist 作成完了 **URL:** <gist-url> **Description:** <description> **Visibility:** <public/secret> **Files:** <file-list> ``` ### データ管理 ``` ## データ更新完了 **Gist:** <description> **File:** <filename> **変更内容:** <変更のサマリ> ``` ## Important Notes - **gh CLI 未認証の場合**: `gh auth status` で認証状態を確認し、未認証ならユーザーに通知 - **`--include-content` は絶対に使わない**: トークン効率のため。`--filter` だけで description とファイル名は検索可能 - **secret がデフォルト**: ユーザーが明示的に public を指定しない限り secret で作成する - **削除操作は慎重に**: `gh gist delete` はユーザーの明示的な指示 + 確認の上でのみ実行。非インタラクティブ環境では `--yes` フラグが必須 - **一時ファイルの場所**: 必ず `application/tools/tmp/` を使用する(`/tmp/` は使わない) ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post gh CLI × Claude Code で Gist 操作をチャット1行で完結させる first appeared on SIOS Tech Lab .
はじめに こんにちは、サイオステクノロジーの小沼 俊治です。 「理屈はいいから、まずは実際にオブザーバビリティー(可観測性)というものを動かして体験してみたい」。 本記事は、そんな方々に向けて、システム運用に不可欠なオブザーバビリティーの基礎を手を動かしながら学習できる、実践的な入門ガイドとして用意しました。 Grafana OSS LGTM スタックを使って、メトリック・ログ・トレース・プロファイルを包括的に可視化する環境を無料で体験できるハンズオンを提供します。 本ハンズオンでは、以下のオープンソース・プロダクトのみで構成された環境でコンテナを使って一括で立ち上げ、Web アプリケーションから実際にデータを収集・可視化する流れを体験していただきます。 Grafana: 可視化ダッシュボード Mimir / Loki / Tempo: メトリクス、ログ、トレースのバックエンド Pyroscope / Faro / Alloy: プロファイリングやフロントエンド監視、データ収集 OpenTelemetry Collector:テレメトリーデータの中継・処理パイプライン なお、本記事は「どのような観測ができるのか」を体験いただくことを主目的としています。そのため、Grafana OSS LGTM Stack の環境構築手順そのものの詳細解説は割愛しており、「まずは動かしてみたい」という方に最適です。もし環境構築の裏側に興味を持っていただいた場合は、ぜひ GitHub リポジトリの設定ファイルを解析してみてください。 構成概要 本ハンズオンの動作検証を行った環境(バージョン)は以下の通りです。 記事では Windows 11 上の WSL 2 (Ubuntu) で起動する流れで記載していますが、Docker が動作する環境であれば他の OS でも実施可能です。 Windows 11 Professional WSL 2.5.9.0 Ubuntu 24.04.3 LTS Docker Engine 28.5.1 Grafana 12.3.2 Windows (WSL) 以外のOSをご利用の方も、条件が満たしていれば以下の手順からハンズオンを進められます。 Ubuntu (Linux) 環境の方: WSL の構築は不要ですので、「 Docker Engine 環境の構築 」 章から開始してください。 macOS 環境の方: Docker Desktop for Mac などでコンテナ実行環境が準備済みであれば、「 GitHub からハンズオン用のリポジトリ取得 」 章から開始してください。 ハンズオンを構成する環境は以下の通りです。 オブザーバビリティーを構成する Grafana LGTM Stack と OpenTelemetry Collector、および観測対象の Web アプリケーションはそれぞれコンテナで構築します。 Web アプリケーションをユーザーの立場として操作し、Grafana を運用担当の立場として操作してロールプレイングしながら進めます。 Web アプリケーションと Grafana LGTM Stack 間で、メトリクス、ログ、およびトレースは OpenTelemetry Collector を介し、プロファイルと Real-time User Monitoring (RUM) は Alloy を介して連携します。 Web アプリケーションから OpenTelemetry Collector を介して連携するデータと送出元は以下の通りです。 メトリクス: Micrometer (Prometheus 形式) メトリクス:Micrometer (OpenTelemetry 形式) メトリクス: Node Exporter ログ: OpenTelemetry トレース:OpenTelemetry Web アプリケーションから Alloy を介して連携するデータと送出元は以下の通りです。 プロファイル: Pyroscope Java Agent RUM: Faro Web SDK from CDN 汎用的な OpenTelemetry Collector でも Grafana LGTM Stack に連携できることを表したいので、できる限り OpenTelemetry Collector を介した連携で構成しています。 オブザーバビリティーの Grafana LGTM Stack は、Grafana、Mimir、Loki、Tempo、Pyroscope、Faro、および Alloy で構成します。 ユーザーインターフェースは Grafana が担います。 Mimir、Loki、Tempo、および Pyroscope は、それぞれの前段に Nginx で構築するロードバランサーを配置します。 Mimir、Loki、および Tempo は、それぞれの後段に MinIO で構築する永続ストレージを構成します。 Tempo の構成における主な考慮事項は以下の通りです。 OpenTelemetry Collector から送信されてくるトレースを受け取るポート番号(4318)と、Grafana で表示のために取得するポート番号(80)が異なるため、それぞれのロードバランサーを構成します。 Grafana でサービスグラフを表示するために、Tempo のメトリクスジェネレーターでトレースからメトリクスを生成し Mimir へ送信します。 メトリクスジェネレーターを始めとする Tempo の内部構造のアーキテクチャーについては「 Tempo architecture | Grafana Tempo documentation 」を参照してください。 Alloy はプロファイルと RUM の中継のみを担っています。本ハンズオンでは、汎用的な OpenTelemetry Collector でも Grafana LGTM Stack に連携できることを表したいので、あえてプロファイルと RUM のみの扱いに限定しています。 観測対象の Web アプリケーションは、WebUI、WebAPI、および MySQL で構成します。 WebUI と WebAPI の構成における主な考慮事項は以下の通りです。 Spring Boot で実装したアプリケーションで構成します。 メトリクス、ログ、トレース、およびプロファイルは、自動計装で収集しているので、ビジネスロジックに手動計装のロジックは一切実装していません。 異常検知のアラートは、アラートメールの通知先もハンズオン環境内で完結するように、SMTP サーバーと受信したメールが閲覧できる Web メールを搭載した MailDev コンテナを利用します。 環境構築や各種設定に使用するそれぞれのファイルは、以下の GitHub リポジトリで公開しています。 Toshiharu-Konuma-sti/hands-on-grafana :本ハンズオンで使うメインのリポジトリです。 $ tree ~/handson/hands-on-grafana/ hands-on-grafana/ |-- container/ …… 「環境構築」章でコンテナの作成で使う素材 | |-- docker-compose.yml | : | `-- webapp/ …… 観測対象となる Web アプリケーションを構成するリポジトリを参照するサブモジュール Toshiharu-Konuma-sti/hands-on-rollingdice-webapp :観測対象となる Web アプリケーションのリポジトリで、ハンズオンのリポジトリからサブモジュールで参照されているので、意図的に Clone する必要はありません。 $ tree ~/handson/hands-on-webapp-rolling-dice/ hands-on-webapp-rolling-dice/ : |-- mysql …… Web 三層アーキテクチャのデータ層に該当するデータベースを構成する素材 | |-- config | | `-- my.cnf | `-- init | `-- init.sql | |-- webapi …… Web 三層アーキテクチャのプレゼンテーション層に該当するフロントエンドサーバーを構成する素材 | |-- build.gradle | : | `-- webui …… Web 三層アーキテクチャのアプリケーション層に該当する API サーバーを構成する素材 |-- build.gradle : 環境構築 WSL 環境の構築 Windows PC の場合には、 以下手順を参考に WSL と Linux ディストリビューション(Ubuntu)環境を用意します。 初期環境構築: WSL 環境 on Windows Docker Engine 環境の構築 コンテナ環境を使うため、以下手順を参考に Ubuntu へ Docker Engine 環境を用意します。 初期環境構築: Docker Engine on Ubuntu GitHub からハンズオン用のリポジトリ取得 ハンズオンを進めるための環境構築用の設定ファイルやスクリプトを含んだリポジトリを GitHub からダウンロードして取得します。 本章ではターミナルを用いてハンズオンのフォルダ領域を作成して作業を実施します。 $ mkdir -p ~/handson/ $ cd ~/handson/ 「 $ git clone 」コマンドで本ハンズオン用のリポジトリを取得します。 $ git clone https://github.com/Toshiharu-Konuma-sti/hands-on-grafana.git $ cd hands-on-grafana/ コンテナ構築スクリプトの実行 本章ではターミナルを用いて以下のディレクトリで作業を実施します。 $ cd ~/handson/hands-on-grafana/container/ コンテナ構築用に用意してあるスクリプトを実行して、オブザーバビリティー環境の各種コンテナを構築します。初回はイメージのダウンロードと作成に時間がかかりますので、コンソールの表示を見守りつつ、処理が完了するまでしばらくお待ちください。 $ ./CREATE_CONTAINER.sh コンテナが構築されてから info オプションを付けてスクリプトを実行すると、ハンズオンに必要なアプリケーションの URL などを表示することができます。 $ ./CREATE_CONTAINER.sh info /************************************************************ * Information: * - Access to Grafana Web ui tools with the URL below. * - Grafana: http://localhost:3000 * - dashboard(Prometheus): https://grafana.com/grafana/dashboards/4701-jvm-micrometer/ * - dashboard(OpenTelemetry): https://grafana.com/grafana/dashboards/20352-opentelemetry-jvm-micrometer/ * - dashboard(Node Exporter): https://grafana.com/grafana/dashboards/1860-node-exporter-full/ : Grafana コンテナが稼働するのでブラウザでアクセスします。 http://localhost:3000 Web アプリケーションのコンテナが稼働するのでブラウザでアクセスします。 http://localhost:8081/ Web アプリケーションが起動したかどうかは、以下のコマンドでアプリケーションログを確認し、「Spring」のロゴが出力されていたら Web アプリケーションが利用できる状態の目安になります。「 docker logs 」に続くコマンド末尾は「webapp-webui」「webapp-webapi」のそれぞれのコンテナを指定して確認します。 $ docker logs webapp-webui > Task :bootRun . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.4.3) 2025-04-17T14:36:32.114Z INFO 412 --- [webui-app-yml] [ restartedMain] ... 2025-04-17T14:36:34.926Z INFO 412 --- [webui-app-yml] [ restartedMain] ,,, 2025-04-17T14:36:35.048Z INFO 412 --- [webui-app-yml] [ restartedMain] ... 2025-04-17T14:36:35.895Z INFO 412 --- [webui-app-yml] [ restartedMain] ... 2025-04-17T14:36:37.925Z INFO 412 --- [webui-app-yml] [ restartedMain] ... 2025-04-17T14:36:41.572Z INFO 412 --- [webui-app-yml] [nio-8081-exec-1] ... なお、コンテナ構築スクリプトで実行する内容は以下を参照してください。 コンテナ構築スクリプトの解説 Web アプリケーションの説明 オブザーバビリティーの実演に移る前に、観測対象となる Web アプリケーションの画面構成と機能を説明します。 Web ページからのリクエストごとにサイコロを振り、結果と履歴を表示します。 「Roll a dice」メニューには、単純にサイコロを振る以外にも、トラブルシューティングの練習用に特殊な挙動をするリンクも用意しています。 Roll normally: 特別な処理を行わず、通常通りサイコロを振ります。 Sleep n sec at API: サイコロを振る前に、処理時間を意図的に延ばすために指定秒間スリープします。 Loop n sec at API: サイコロを振る前に、システムへ負荷を掛けるために指定秒間ループします。 Trigger 5xx error at API: サーバー側で意図的に例外を発生させ、HTTP ステータス 500 エラーを起こし、サイコロを振るのを中断します。 Force specific value: サイコロの出目を、指定した値で強制的に固定します。 RUM Simulation at Browser: RUM 関連の動作確認が行えます。 Trigger JS error at Browser: サーバーへのリクエストは行わず、ブラウザ(フロントエンド)側で JavaScript の例外を意図的に発生させます。 Fetch API: Normal: 画面遷移を行わず、JavaScript (Fetch API) から非同期通信で サイコロを振る WebAPI を実行します。 Fetch API: Sleep 2 sec: 2秒間のスリープも指示した非同期通信を実行します。 観測対象となる Web アプリケーションのシーケンスとコンポーネント仕様を説明します。 Web アプリケーションは、WebUI、WebAPI、および Database の3つのコンポーネントで構成します。WebUI と WebAPI は Spring Boot のフレームワークで実装し、Database は MySQL を利用します。 各コンポーネントの仕様: WebUI:WebUI から WebAPI へ以下2つの API をコールして画面表示を行います。 WebAPI の「/api/v1/dices」を POST でコールしてサイコロを振ります。 WebAPI の「/api/v1/dices」を GET でコールしてサイコロ出目の一覧を取得します。 WebAPI:以下2つの API を持ちます。 POST: /api/v1/dices サイコロを振り、出目を Database に保存します。WebAPI を呼び出す際に、パラメータを付与することで観測向けの機能も実行します。 sleep パラメータを付与すると、指定秒間スリープを行います。 loop パラメータを付与すると、指定秒間ループし、ループ毎にファイルを開いて1行読むディスクアクセスの処理を行います。 error パラメータに true を付与すると、サイコロを振らずに処理を中断し、HTTP ステータスコード 500 エラーで API をレスポンスします。 GET: /api/v1/dices Database からサイコロ出目の全履歴を、振った日時の降順で取得します。 Database サイコロの出目、日時、およびシーケンス番号のフィールドで構成するテーブルを保持します。 オブザーバビリティーの実演 メトリクス閲覧 (Mimir) 観測対象の Web アプリケーション(Micrometer 実装)、および Node Exporter から収集されたメトリクスが、Mimir へと送信されています。まずは Grafana のダッシュボードを使って、これらのメトリクスを可視化してみましょう。 Grafana 公式サイトでは、データソースや用途に合わせた数多くのダッシュボードテンプレートが公開されています。今回はその中から、Micrometer (Prometheus 形式) のメトリクスを表示するのに適した「 JVM (Micrometer) | Grafana Labs 」を利用して、メトリクスを眺められるようにしてみます。 左ペインのメニューから「Dashboard」を選択して Dashboards 画面を表示し、画面右側の「New」ボタンをクリックすると表示されるメニューから「Import」を選びます。 画面中央のテキストボックスにインポートする「JVM (Micrometer)」ダッシュボードテンプレートの URL を入力し「Load」ボタンをクリックします。 ダッシュボードテンプレートの URL: https://grafana.com/grafana/dashboards/4701-jvm-micrometer/ インポートするダッシュボードの設定画面が表示(ダッシュボードにより設定内容は異なる)されるので、本テンプレートではデータソースとなる Prometheus を選択して「Import」ボタンをクリックします。 Prometheus 項目:「Mimir for Metrics」 ダッシュボードが表示されました。これで Web アプリケーションから送信されたメトリクス情報を確認できます。 なお、Grafana や Web アプリケーションを起動した直後の場合、デフォルトの表示期間(Last 24 hours)ではデータ幅が小さすぎてグラフが表示されないことがあります。その場合は、画面右上の時間設定を「Last 15 minutes」などに変更し、表示期間を狭めてみてください。 本ハンズオンの Grafana でメトリクスを表示できるダッシュボードテンプレートと、設定画面で設定する値を紹介します。なお、公式サイトには紹介するテンプレート以外にも様々なテンプレートが紹介されているので、検索してご自分に合ったテンプレートを探してみてください。 JVM (Micrometer) | Grafana Labs Micrometer (Prometheus 形式) のメトリクスを表示します。 Prometheus 項目:「Mimir for Metrics」 OpenTelemetry JVM Micrometer | Grafana Labs Micrometer (OpenTelemetry 形式) のメトリクスを表示します。 Mimir 項目:「Mimir for Metrics」 Loki 項目:「Loki」 Node Exporter Full | Grafana Labs Node Exporter のメトリクスを表示します。 Mimir 項目:「Mimir for Metrics」 ログ閲覧 (Loki) Web アプリケーションが出力するログを Loki で収集・集約しています。これにより、各サーバーやコンテナへ個別にログインすることなく、Grafana の画面上だけでログの検索・閲覧が完結します。 それでは、実際に Web アプリケーションを操作し、その挙動に合わせてリアルタイムにログが出力される様子を確認してみましょう。 左ペインのメニュー「Explore」を選択して Explore 画面を表示し、データソースのドロップダウンから「Loki」を選び「Label browser」ボタンをクリックします。 Label browser 画面にて、検索対象のラベルとして「service_name」、値として「webapp-webui」の順番で選択してから「Show logs」ボタンをクリックすることで、webapp-webui コンテナのアプリケーションログを表示できます。 値として「webapp-webapi」を選択すれば、webapp-webapi コンテナのアプリケーションログ表示を指定できます。 青色「Run query」ボタン右端の下矢印をクリックすると表示するリロード間隔一覧から「5s」を選択することで、ログ表示が5秒間隔で自動的にリロードされるため、リアルタイムでログを確認することができます。 ログがリアルタイムに表示することを確認したいので、ユーザーの立場で Web アプリケーションをアクティブにしてサイコロを振ります。 http://localhost:8081/ 再び運用担当の立場で Grafana に戻るとサイコロを振ったログが表示されていて、ログを眺めてみると先ほど Web アプリケーションで表示されていたサイコロの出目と同じ値を示すメッセージが存在することも確認できるはずです。 ログから一つメッセージを選んでクリックすると展開表示され詳細情報が確認できます。 「+ Operations」を使うことでログの表示を絞り込むこともできます。 よく使う検索指定を例示します。 「+ Operations > Label filters > Label filter expression」:ラベル、演算子、値の組み合わせで検索します。(例:「detected_level = error」は、エラーレベルで絞り込むことを意味します) 「+ Operations > Line filters > Line contains」:大文字と小文字を区別した完全一致で文字列検索します。 「+ Operations > Line filters > Line contains case insensitive」:大文字と小文字を区別せず文字列検索します。 ログからトレース閲覧 (Loki to Tempo) アプリケーションログの確認ができたら、次はログとトレースの連携機能を体験してみましょう。 ログ一覧から任意の一行を選択し、そこから紐付いているトレース情報へジャンプします。 トレースを閲覧することで、ユーザーのリクエストからレスポンスに至るまでの一連の処理フローや、各処理ごとの所要時間をウォーターフォール形式で視覚的に把握できます。「それぞれの処理で、どのくらい時間がかかっているか」が一目瞭然になる様子を確認してください。 ログ表示の中から気になるログを選びます。 選んだログをクリックして詳細情報を表示します。 詳細情報を下にスクロールすると「Links」のセクションに(閉じている場合はクリックして展開すると)「Tempo」への連携ボタンがあるので、クリックすることで該当ログのトレースが画面をスプリットして右半分に表示されます。 元から表示されている画面左半分のログ表示側で、右上部にある三点リーダーをクリックすると表示する「Close」メニューをクリックするとトレースが全面表示になります。 Web アプリケーションの1リクエストで、WebUI から WebAPI、そして WebAPI からデータベースへ連携して実行される一連の処理フローと、各フローで掛かった処理時間を確認することができます。 表示したトレースとアプリケーション仕様で説明したシーケンス図を比較すると、実際に実行された処理フローがシーケンス仕様と一致していることが確認できます。 別のリクエスト・レスポンス事例として、Web アプリケーション初回起動時の1回目にサイコロを振った際のトレースと、2回目以降のトレースを比べてみます。プログラム初回起動時には、オブジェクトの生成や外部リソースの接続準備などで処理のオーバーヘッドが高く処理時間が掛かると一般的に言われていますが、実際にトレースを比べてみるとその事実が確認することができます。 再度トレース機能の説明に戻りますが、 いずれかのトレースをクリックして詳細情報を展開すると「Log for this span」ボタンが表示され、クリックするとトレースからログへの表示も可能です。 また、画面上部にある「Service Graph」タブをクリックすることで「Node Graph」が表示され、各コンポーネント間で生じる通信の関係性が確認できます。 本ハンズオンでは user が webapp-webui だけではなく、webapp-webui と webapp-webapi の両方にもアクセスが生じているのは、OpenTelemetry Collector が Prometheusプロトコルで両方のコンポーネントへ定期的にメトリクスを取得するアクセスが発生しており、これらが user からのアクセスとして認識されているためです。 メトリクスからトレース閲覧 (Mimir to Tempo) 続いて、メトリクス(数値の変動)からトレース(詳細な処理フロー)への連携を確認します。 Web アプリケーションから送信される Micrometer(Prometheus 形式)のメトリクス、特に HTTP リクエストのパフォーマンスを示す http_server_requests_seconds_bucket などには、Exemplar と呼ばれる機能によって Trace ID が紐付けられています。 Grafana のグラフパネル上に表示される Exemplar(点やひし形のマーク)をクリックすることで、その時点の具体的なリクエストのトレースへ直接ジャンプすることができます。グラフで「遅い」と感じた箇所の裏側を即座に特定できる便利さを体験してみましょう。 Explore でデータソースに「Mimir for Metrics」を選択し、「Code」入力モードに切り替えてから下に掲載する Prom QL クエリーを入力します。クエリーを入力したら、「Exemplar」スイッチをオンにして「Run Query」ボタンをクリックすると、Exemplar が有効となったメトリクスのグラフが表示されます。 入力する Prom QL クエリーは以下の通りです。 histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[$__rate_interval])) by (le)) 今度はユーザーの立場で Web アプリケーションをアクティブにします。Grafana でメトリクスのグラフ変化が分かりやすいようにするため、Web アプリケーションの「Roll a dice」メニューで、「2. Sleep 05 sec at API」から「4. Sleep 30 sec at API」までを上から順番に、一つクリックしたら少し間隔を置いてから次をクリックしてを繰り返してサイコロを振ってみます。 続いて運用担当の立場で Grafana に戻ります。メトリクスのグラフに小中大の3つの山が現れています。Exemplar を有効にしているため、それぞれの山頂の左横には HTTP リクエストを示す点が存在しています。 気になる HTTP リクエストに対してマウスオーバーすると詳細情報が掲載されたウィンドウが現れ、Tempo へ連携できる「Query with Tempo」ボタンも表示されています。 ウィンドウ内の「Query with Tempo」ボタンをクリックすると、詳細表示していたリクエストのトレースを画面右半分に表示することができ、「 ログからトレース閲覧 (Loki to Tempo) 」章で説明したようにトレースで分析を行うことも可能です。 プロファイルで解析 (Pyroscope) メトリクスやトレースで「遅い処理」を見つけたとしても、具体的なコードのどこに原因があるかまでは分からないことがあります。そこで Pyroscope を用いたプロファイリングを行います。 ここでは、CPU 使用率やメモリ割り当て状況を可視化する「フレームグラフ (Flame Graph)」を利用して、アプリケーションの内部状態を解析します。リソースを過剰に消費している関数やメソッドをピンポイントで特定する手順を体験してみましょう。 Explore にてデータソースに「Pyroscope」を選択し、直下のドロップダウンからリソースとして「process_cpu > cpu」の順番で CPU の利用時間を選択します。ドロップダウン横のテキストボックスに「 {service_name="webapp-webapi"} 」の条件式を入力して「Run Query」ボタンをクリックすると WebAPI を対象としたプロファイルが表示されます。 入力する条件式は以下の通りです。 WebUI を対象とする場合には「 {service_name="webapp-webui"} 」を入力します。 WebAPI を対象とする場合には「 {service_name="webapp-webapi"} 」を入力します。 「Run Query」ボタン右わきをクリックし一覧から「5s」を選択すると、5秒間隔でリロードされるのでリアルタイムでプロファイルを確認できます。 プロファイル表示の左上にあるテキストボックスで絞り込みを行うことができます。試しに「java」で入力してみると、Java 言語のクラスやメソッドがリソースを利用した値が表示されます。お馴染みな Java 標準クラス名やメソッド名があれば、それらがリソースを費やしていると言うことを表します。 今度は「jp/sios」で絞り込んでみると、ハンズオン用に実装した Web アプリケーションのビジネスロジックがリソースに費やした値を表示することができます。値を確認して他の値より抜きんでて大きいシンボルがある場合には、ハードウェアリソースを占有して利用している可能性があるため、ビジネスロジックの実装を見直して頂くことも検討します。キャプチャーした実績では大きな値では無いので、問題ないと言ってよいでしょう。 プロファイルの基礎的な表示方法が分かりましたので、プロファイルの活用事例を試してみます。ユーザーの立場で Web アプリケーションをアクティブにして、メニュー「2. Sleep 5 sec at API」から「4. Sleep 30 sec at API」を上から順にクリックして、WebAPI で時間が掛かる処理を実行してみます。 運用担当の立場で Grafana に戻り、プロファイルを確認します。リアルタイム更新されるさまを暫く眺めますが、Sleep 処理ではそれほど CPU を使っていないため、大きく値が変わっていないことが確認できるはずです。 再度ユーザーの立場で Web アプリケーションをアクティブにして、今度はメニュー「5. Loop 5 sec at API」から「7. Loop 30 sec at API」を上から順にクリックして、WebAPI で時間が掛かる処理を実行してみます。 運用担当の立場で Grafana に戻り、プロファイルを確認します。引き続き、リアルタイム更新されるさまを暫く眺めると、今度は「ms(ミリ秒)」から「s(秒)」へ単位が変わり、値が大きく増えたプロセスが存在することが確認できるはずです。もう少し詳細に迫ってみましょう。 大きく値が増えたプロセスを抽出します。 jp/sios/apisl/handson/rollingdice/webapp/webapi/service/WebApiServiceImpl.readFile:47.5 s jp/sios/apisl/handson/rollingdice/webapp/webapi/service/WebApiServiceImpl.lambda$loop$1:47.9 s jp/sios/apisl/handson/rollingdice/webapp/webapi/service/WebApiServiceImpl$$Lambda_.accept:47.9 s jp/sios/apisl/handson/rollingdice/webapp/webapi/service/WebApiServiceImpl.loop:47.9 s jp/sios/apisl/handson/rollingdice/webapp/webapi/service/WebApiServiceImpl.rollDice:48.0 s jp/sios/apisl/handson/rollingdice/webapp/webapi/controller/WebApiController.rollDice:48.0 s WebAPI のシーケンス図に大きく値が増えたプロセスをマッピングしてみると、一番深い階層でコールされる「WebApiServiceImpl.readFile」が要因であることが想像できます。 プロファイル画面で示すと赤枠の一行に絞り込めることになります。 実際にソースコードを見てみると、ループ処理の中で、都度ファイルを開いて読み込む readFile メソッドが呼ばれていることが分かります。これにより、ループ回数分のファイルアクセス(=ディスクアクセス)が発生し、それに伴って CPU リソースも消費されていたことがコードレベルでも裏付けられます。 webapp/webapi/src/main/java/jp/sios/apisl/handson/rollingdice/webapp/webapi/service/WebApiServiceImpl.java : while (System.currentTimeMillis() < endTime) { line = this.readFile(FILE_PATH_IN_LOOP); : } : webapp/webapi/src/main/java/jp/sios/apisl/handson/rollingdice/webapp/webapi/service/WebApiServiceImpl.java private String readFile(final String filePath) { String line = null; try (InputStream inputStream = new ClassPathResource(filePath).getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { LOGGER.debug("Successfully loaded a file."); line = reader.readLine(); : 改めてシーケンス図で解析結果を整理すると、指定時間内にディスクアクセス処理がループで連続実行されたため、CPU 利用時間が肥大化していたと言えます。 今回はプロファイルを用いてボトルネックを特定する手順を学ぶ「意図的な実装」のため修正は行いませんが、実際の運用コードであれば、ファイル読み込みをループの外に出す、あるいはキャッシュを利用してディスクアクセスを減らすといったパフォーマンスのチューニングを行うと良いでしょう。 オリジナルのダッシュボード作成 ここまでの手順では、Explore 画面を使用して、その都度データソースやクエリを指定する「アドホックな分析」を行ってきました。 しかし実際の運用では、重要な指標や頻繁に確認するログを常に表示させ、定点観測することが求められます。そこで、よく見る検索条件やグラフをパネルとして保存し、いつでも即座にシステムの状態を把握できるオリジナルのダッシュボードを作成してみましょう。 Explore で表示しているメトリクスをダッシュボード化したいとします。メトリクスを表示している状態で、画面上部にある「Add」ボタンをクリックすると表示するメニューから「Add to dashboard」をクリックします。 表示された「Add panel to dashboard」ダイアログで「Open dashboard」ボタンをクリックします。 先ほどまで Explore で表示ていたメトリクスがパネル化して載った新たなダッシュボードが生成されました。 ブラウザで新たなタブを立ち上げて、次にダッシュボードに載せたいログを Explore で表示させ、メトリクス同様に「Add > Add to dashboard」を選択してダッシュボード化します。 メトリクス同様に、Explore で表示ていたログがパネル化して載った新たなダッシュボードが生成されましたが、ログのパネルをメトリクスのダッシュボードにコピー&ペーストするため、パネル右上角の三点リーダーをクリックしすると表示するメニューから「More… > Copy」をクリックして、ログのパネルをクリップボードにコピーします。 最初に作ったメトリクスのダッシュボードに戻り、「Add」ボタンクリックで表示するメニューから「Paste panel」をクリックします。 メトリクスとログのパネルが載ったダッシュボードが出来上がりました。このような流れで、頻繁に確認したい項目をまとめた簡易的なオリジナルダッシュボードを作成することもできます。 ここまでの手順と Variables を使ってサンプルとして作ったダッシュボードを用意してありますので、Dashboards 画面から確認してみてください。 メトリクス、ログ、ノードグラフのパネルが載ったダッシュボードで、Server Address フィールドで「webapp-webui」「webapp-webapi」を選択することで表示を切り替えることができます。「Edit」ボタンを使って構成や仕組みを確認してみてください。 フロントエンドのユーザー体験観測 (Faro) これまでの手順ではサーバーサイドの内部状態を観測してきましたが、ユーザーが実際に触れるブラウザ上(フロントエンド)での体験も同様に重要です。 本環境には Grafana Faro Web SDK が組み込まれており、実際のユーザー体験(Real User Monitoring: RUM)を可視化できます。ページの読み込み速度などのパフォーマンス指標(Web Vitals)や、ブラウザで発生した JavaScript エラー、そしてユーザーが利用しているブラウザの種類や OS といった環境ごとのアクセス傾向を確認してみましょう。 RUM の観測用にダッシュボードを用意してあります。ダッシュボード一覧から「My Real-time User Monitoring」を選択します。 ダッシュボードに遷移すると、まず始めに「Performance」のパネルでパフォーマンスに関する各種値が確認できます。 確認できる代表的な値は以下を確認ください。 TTFB (Time to First Byte):サーバーの応答待ち時間です。ブラウザがリクエストを送ってから、最初のデータが返ってくるまでの時間を指します。(参照先: Time to First Byte (TTFB)  |  Articles  |  web.dev ) FCP (First Contentful Paint):「何かが表示されるまでの時間」です。テキストや画像など、ページの一部が初めて描画された時点を指し、この値には TTFB の時間も含みます。(参照先: First Contentful Paint (FCP)  |  Articles  |  web.dev ) LCP (Largest Contentful Paint):「メインコンテンツが表示されるまでの時間」です。そのページで最も大きな画像やテキストブロックが表示された時点を指し、この値には TTFB や FCP の時間もすべて含んだトータルタイムです。( Largest Contentful Paint (LCP)  |  Articles  |  web.dev ) CLS (Cumulative Layout Shift):「視覚的なズレの量」です。画像の遅延読み込みなどでレイアウトがガクッとズレる度合いを示します。数値が低いほど、画面が安定しています。(参照先: Cumulative Layout Shift (CLS)  |  Articles  |  web.dev ) FID (First Input Delay):「操作可能になるまでの遅延」です。ユーザーがボタンをクリックしてから、ブラウザが実際にその処理を開始できるまでの待機時間を指します。(参照先: First Input Delay (FID)  |  Articles  |  web.dev ) 次に「Meta」のパネルでクライアントのOSやブラウザなどのメタ情報が確認できます。 次に「Exceptions」のパネルでクライアントサイドで発生した例外(エラー)に関する各種値を参照するために、Web アプリケーションで例外を発生させます。ブラウザの検証ウィンドウ(デベロッパーツール)を表示している状態で、Web アプリケーションの Roll a dice メニューから「10. RUM Simulation at Browser > Trigger JS error」のリンクをクリックすると、画面中央にエラー発生を知らせるメッセージ(トースト通知)が一瞬表示され、裏側では例外が発生したことが検証ウィンドウでも確認できるはずです。 ダッシュボードに戻り「Exceptions」のパネルで例外の発生件数や例外時に出力されたメッセージなどが確認できます。 次に「Events」のパネルでユーザー操作やライフサイクルの変化が発生した回数が参照できます。 次に「Faro log」のパネルでここまでの集計の元となっている実際のログが確認できます。 アラートからエラー原因の探索 (Alerting) 実際の運用現場において、24時間365日ずっとダッシュボードを監視し続けることは現実的ではありません。システム内で異常が発生した際には、自動的に通知を受け取る仕組みが必要です。 アラートを設定することで、監視の負荷を下げつつ、トラブル発生時の初動対応をいかに迅速化できるかを確認してみましょう。 本セクションでは、Alerting を利用した以下のインシデント対応フローを体験します。 Web アプリケーションのログ (Loki) を監視し、「ERROR」レベルのログ出力を検知する。 運用担当者へ即座にアラートメールを送信する。 メールのリンクから Grafana へ遷移し、前述のログやトレース機能を活用して原因を特定する。 アラーティングを機能させるには、アラートの通知先を定義する Contact points と、監視条件を定義する Alert rules の設定が必要となりますが、まず始めに Contact points の定義から説明します。 左ペインのメニューから「Contact points」を選択し、表示された Contact points 画面には2つの通知先が登録されています。1つ目の「grafana-default-email」は Grafana がデフォルトで登録している通知先で、2つ目の「Hands-on Receive E-mail」がハンズオン用に用意した通知先です。 「Hands-on Receive E-mail」の設定内容は以下の通りです。 Name: 通知先定義の名称として「Hands-on Receive E-mail」を入力しています。 Integration: ハンズオンではメールで通知するため「Email」を選択しています。 Address: 通知先のメールアドレスに MailDev コンテナで受信できる「target-address@test.com」を入力しています。 Test: Test ボタンをクリックすることで「Address」の宛先へテストメールを送信します。 続いて Alert rules で定義している監視条件を説明します。 左ペインのメニューから「Alert rules」を選択し、表示された Alert rules 画面で「Hands-on Training > Eval Interval – 10s」フォルダ内に登録されている「Error level – WebUI log」が該当します。 「Error level – WebUI log」の設定内容は以下の通りです。 1. Enter alert rule name: Name: 監視条件の名称として「Error level – WebUI log」を入力しています。 2. Define query and alert condition: アラートを発動する監視条件を定義します。 条件A: データソース: 「Loki」を選択しています。 Options: 第1条件: 「webapp-webui」から送出されたログを監視対象にします。 第2条件: エラーレベルのログを意図する、「detected_level」ラベルに大文字小文字問わず「error」の値を持ったログを抽出します。 第3条件: 過去1分間のログを監視対象とします。 第4条件: 第1~3条件に該当するログを対象に( 「message」ラベルの)件数をカウントします。 条件C: 条件Aが0件を超過(=1件以上存在)した場合にアラート判定とします。 3. Add folder and labels: Folder: 「Hands-on Training」フォルダを選択しています。 4. Set evaluation behavior: Evaluation group and interval: 監視条件の評価間隔を「Eval Interval – 10s」名称で10秒間隔で評価します。 Pending period: 監視条件が1件でも一致したら即アラートにしたいので「None」を設定しています。 5. Configure notifications: Contact point: アラートの送信先に「Hands-on Receive E-mail」を設定しています。 実演に入る前に、Contact Points で送信するメールを受信する MailDev をブラウザでアクセスします。既に「[FIRING:1] DatasourceNoData ~」などの件名のアラートメールが数通届いています。これはコンテナ起動時の Web アプリケーションがまだ起動していない最中の監視が拾った結果なので、コンテナを構築した時間帯付近のアラートメールは無視してください。 http://localhost:1080 ここからが本格的なアラートの実演で、ユーザーの立場として Web アプリケーションにアクセスし、「Roll normally」をクリックしてサイコロを振ります。 その状況で運用担当として MailDev にアクセスし、暫く経過してもアラートメールが届かないことを確認します。 再びユーザーの立場として Web アプリケーションにアクセスし、「Trigger 5xx error at API」リンクをクリックして Web アプリケーションでエラーが発生した状況にします。 運用担当として MailDev を確認すると、Web アプリケーションでエラー発生から約1分以内に件名が「FIRING」と書かれたアラートメールが届きます。これが障害発生の通知です。メール本文内の「View alert」ボタンをクリックし、Grafana のアラート詳細画面に遷移します。 エラー発生から1分以内に Grafana へ遷移できると、画面下部に「Firing」(発報中)の状態を示すラベルが表示されています。(遷移に1分を超えてラベル表示が解除されていたとしても履歴は残っているので、そのまま進めます。)画面上の「View in Explore」をクリックして Explore に遷移しエラーの原因調査を開始します。 画面下部の「Logs sample」領域で監視に引っ掛かったエラーログを確認しますが、エラー発生から1分を超えてエラーログが表示されていない場合は、画面中央の「Count over time」を「Rang=1m」から「Rang=5m」などにレンジを拡大してエラーログを表示させます。ログが確認できたら、ログ表示の右上にある「Open logs in split view」ボタンをクリックすると画面をスプリットして右半分にログを表示させます。 左半分のログ表示はアラーティングから遷移直後の Explore で機能が制限されているため、左半分のログを閉じ「Tempo」への連携ボタンが表示される右半分のログ表示を全画面表示にします。 ログをクリックして画面右側に詳細情報を展開し、下側へスクロールすると「Tempo」ボタンが現れます。これをクリックしてトレースに遷移します。 トレースを表示させると1つ目の WebUI から WebAPI への呼び出しにおいて、WebAPI 側でエラーが発生していることが一目で分かります。 トレースの中からエラーの発生源と思われる WebAPI のスパンをクリックし、出現したパネル内の「Logs for this span」をクリックします。 画面右半分がトレース表示から、「Logs for this span」をクリックしたスパンに関連するログだけにフィルタリングされた WebAPI のログに切り替わります。 ログを注視していると手掛かりになりそうなメッセージが見つかります。 ログに記録されているメッセージとソースコードを対比すると、例外が発生している箇所が見つかり、ここがアラートの原因であることが把握できます。 webapp/webapi/src/main/java/jp/sios/apisl/handson/rollingdice/webapp/webapi/service/WebApiServiceImpl.java private void error(final Optional<Boolean> optError) { UtilEnvInfo.logStartClassMethod(); if (optError.isPresent() && optError.get()) { LOGGER.error( "!!! Intentional exception triggered: '{}' !!!", "HandsOnException"); throw new HandsOnException("Intentional error triggered by request parameter."); } } 実際の運用では、把握した原因に対して改修などで応急処置や恒久対応を行うことで事故完了となりますが、今回はデモとして意図的にエラーを発生させているので、該当箇所は修正せずに、今後は同じ操作をしないと言う誓いで事故完了の扱いとします。 エラー発生から5分を経過すると、MailDev にエラー発生が解消されたことを示す「RESOLVED」メールが届いていることが確認できるので、これでエラー探索の一連の流れが終了となります。 以上で、オブザーバビリティーの実演はすべて終了です。お疲れ様でした! メトリクスの可視化からアラートを起点としたトラブルシューティングまでを体験することで、オブザーバビリティーが実際の運用でどう役立つのか、その「手触り」を掴んでいただけたなら幸いです。 環境のクリーンアップ オブザーバビリティーの実現が一通り終わったら、これまでに利用した環境をクリーンアップしてハンズオンを終了します。 コンテナ削除スクリプトの実行 ターミナルを用いて、以下のディレクトリへ移動します。 $ cd ~/handson/hands-on-grafana/container/ 環境構築時にも使用したスクリプトに down オプションを指定して実行して、オブザーバビリティー環境の各種コンテナを停止・削除します。 $ ./CREATE_CONTAINER.sh down スクリプトの実行が終わったら、 list オプションを付けてスクリプトを実行し、起動しているコンテナが存在しない(一覧に表示されない)ことを確認します。 $ ./CREATE_CONTAINER.sh list ### START: Show a list of container ########## CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 以上で環境のクリーンアップは完了です。お疲れ様でした。 続く Appendix では、このハンズオン環境を裏で支えている設定ファイルやスクリプトについて解説します。「どうやってこの環境を作ったのか詳しく知りたい!」という方は、ぜひこのままご覧ください。 Appendix ハンズオン環境の構築や設定手順で利用している各種スクリプトや設定ファイルの実装内容について解説します。 コンテナ構築スクリプトの解説 「 コンテナ構築スクリプトの実行 」章で使用する「 CREATE_CONTAINER.sh 」スクリプトの処理内容について解説します。 コンテナの構築 本ハンズオン用のリポジトリは、別リポジトリ「 Toshiharu-Konuma-sti/hands-on-rollingdice-webapp 」で管理されている Web アプリケーションを参照するサブモジュールを含んでいるので、サブモジュール配下のソースコードを最新版で取得します。 $ git submodule update --init $ git submodule update --remote webapp 用意した「docker-compose.yml」と「docker-compose-webapp.~.yml」のコンテナ定義ファイルで一気にコンテナを構築します。 $ docker-compose \ -f docker-compose.yml \ -f docker-compose-webapp.base.yml \ -f docker-compose-webapp.mode.grafana.yml \ up -d -V --remove-orphans Creating network "intra-net" with driver "bridge" Creating network "hands-net" with driver "bridge" Creating grafana ... done : Creating webapi ... done コンテナ構築に利用しているコンテナ定義ファイルの内容は以下を参照してください。 オブザーバビリティー環境の構成ファイル解説 docker-compose.yml プロダクション環境の構成ファイル解説 docker-compose-webapp.base.yml docker-compose-webapp.mode.grafana.yml オブザーバビリティー環境の構成ファイル解説 オブザーバビリティー環境のコンテナを構築する各種ファイルについて説明します。 コンテナ定義(docker-compose) オブザーバビリティー環境のコンテナを構築する「docker-compose.yml」と環境変数ファイルです。 docker-compose.yml 「x-healthcheck-minio」ノードでは、MinIO に対して実施するヘルスチェック処理として、9000番ポートが TCP 接続できるかどうかの確認を実装しています。 「grafana」コンテナの特記事項は以下の通りです。 「environment」ノードの「GF_SMTP_HOST」にて、アラート通知でメール送信する際の SMTP サーバーを指定します。 .env 「MINIO_ROOT_PASSWORD」にて、MinIO にアクセスするコンテナが接続時に必要となるパスワードを指定します。 Grafana 設定ファイル データソースの定義ファイルです。 datasources.yaml メトリクス表示用に「Mimir for Metrics」データソース、ログ表示用に「Loki」データソース、トレース表示用に「Tempo」と「Mimir for Trace」のデータソースを用意しています。 ダッシュボードの定義ファイルです。 dashboards.yaml 「My Explore Collection」「My Real-time User Monitoring」の2つのダッシュボードが認識されるように定義しています。 my-explore-collection.json 「My Explore Collection」ダッシュボードの定義ファイルで、Exemplar を有効にしたメトリクス、ログ、ノードグラフ、および CPU 利用時間とメモリ割当て量のプロファイルを確認することができます。 配置位置を示す「gridPos」ノードの考え方は以下の通りです。 「x」は横幅を表し、画面横幅全体を仮想的な24ブロックで考えます。 「y」と「h」の関係は、縦にA→B→Cとパーツが並んでいた場合、最初のパーツは「0」から始まり「y+h」が次に続くパーツの「y」になるため、 Aが「A:y=0, h=2」の場合、次に続くBは「B:y=2, h=3」、その次に続くCは「C:y=5, h=4」となります。 my-real-time-user-monitoring.json 「My Real-time User Monitoring」ダッシュボードの定義ファイルで、Faro から送信されてきた RUM を確認することができます。 アラートの定義ファイルです。 contact-points.yaml 「 アラートからエラー原因の探索 (Alerting) 」章で説明している Contact points を定義しているファイルです。 alert-rules.yaml 「 アラートからエラー原因の探索 (Alerting) 」章で説明している Alert rules を定義しているファイルです。 Mimir 設定ファイル Mimir に適用する設定ファイルです。 mimir.yaml 「common.storage.backend」と「common.storage.s3」ノードで、ストレージに S3(実際には互換ストレージの MinIO)を指定します。 Loki 設定ファイル Loki に適用する設定ファイルです。 loki.yaml 「common.storage.s3」ノードで、ストレージに MinIO を指定します。 Tempo 設定ファイル Tempo に適用する設定ファイルです。 tempo.yaml 「metrics_generator」ノードで、サービスグラフの描画用にトレースからメトリクスの生成と、生成されたメトリクスの送信先を指定します。 「storage.trace.backend」と「storage.trace.s3」ノードで、ストレージに MinIO を指定します。 Alloy 設定ファイル Alloy に適用する設定ファイルです。 config.alloy 「pyroscope.receive_http」ノードで Pyroscope から送信されてくるデータの受信ポートと、「pyroscope.write」ノードで送信先サーバーを指定します。 「faro.receiver」ノードで Faro から送信されてくるデータの受信ポートと、「faro.receiver.output」ノードで送信先を定義するノードを指定します。送信先として指定された「loki.writ」と「otelcol.exporter.otlp」ノードで送信先のサーバーアドレスを指定します。 ロードバランサー設定ファイル Mimir、Loki、Pyroscope の前段に配置するロードバランサーの Nginx に適用する設定ファイルです。 nginx-mimir.conf nginx-loki.conf nginx-pyroscope.conf Tempo の前段に配置するロードバランサーの Nginx に適用する設定ファイルです。 nginx-tempo-otlp.conf nginx-tempo-view.conf Tempo では、OpneTelemetry Collector からトレースが送られてくるポート番号(4318)と、Grafana から表示用にアクセスしてくるポート番号(80)が異なっているため、それぞれのロードバランサーを建てています。 OpenTelemetry Collector 設定ファイル OpenTelemetry Collector コンテナに適用する設定ファイルです。 otel-collector-config.yaml 「receivers.otlp.protocols.http」ノードで、Web アプリケーションから OpenTelemetry 形式のメトリクスを HTTP で受信できるように指定します。 「receivers.prometheus.config.scrape_configs」ノードの「job_name: “webapp”」設定で、OpenTelemetry Collector コンテナから Web アプリケーションへ Prometheus 形式でメトリクスを取得するように指定します。 「receivers.mysql」ノードで、MySQL サーバーからメトリクスを取得するように指定します。 プロダクション環境の構成ファイル解説 プロダクション環境のコンテナを構築する各種ファイルについて説明します。 コンテナ定義(docker-compose) アプリケーションを構成する各コンテナを構築する「docker-compose-webapp.mode.grafana.yml」ファイルです。 docker-compose-webapp.mode.grafana.yml 「webapp-webui」と「webapp-webapi」コンテナが起動する際に実行するコマンドを指定する「command」ノードでは、Web アプリケーションを Pyroscope の自動計装でプロファイリングさせたいので、Web アプリケーションの起動に「 ./gradlew bootRun 」は使わずに「 java -javaagent:pyroscope.jar 」コマンドを使い該当のライブラリをロードしながら起動します。 まとめ 実際に手を動かしてログやメトリクスを追うことで、「オブザーバビリティー(可観測性)」という言葉の解像度がぐっと上がったのではないでしょうか? 複雑な理論を学ぶことも大切ですが、こうして実際の画面でシステムの挙動を見る体験こそが、DevOps 実践への第一歩だと考えており、今回の体験を通して、「意外と自分でも構築できそうだ」「この機能は今の現場でも使えそうだ」と、少しでも身近に感じていただけたなら本望です。 なお、本記事で紹介した OSS 版の活用はもちろんのこと、運用負荷を軽減したい場合には Grafana Cloud を選択肢に入れることも可能です。「まずは OSS で小さく始めて、規模が大きくなったら Cloud へ」といった柔軟な使い分けも検討いただけます。 このデモ環境での体験を切っ掛けに、ぜひ次は皆様自身のアプリケーションやインフラ環境でも、この「見える化」に挑戦するモチベーションに繋がれば幸いです。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Grafana OSS LGTM スタックで体験する『オブザーバビリティー入門』 first appeared on SIOS Tech Lab .
こんにちは。サイオステクノロジーのひろです。 先日OSC福岡、OSC広島でセミナー登壇してきました。 今回は登壇内容についてまとめていきたいと思います。 生成AIの概要を理解できる 生成AI×ツールで新たな価値を生み出せることを理解できる この2点を目的として以下のことについてお話してきました。 生成AIにできることできないこと 生成AIにツールを使わせる技術について 生成AIにロボットを操作させるデモ セミナーに使用した資料を交えつつセミナー内容について解説していきます。 生成AIってなに? 生成AIとはコンテンツを新たに生み出してくれるAIのことを指します。 ユーザがプロンプトを入力することで生成AIは文章や画像や動画、音楽、音声等を出力してくれます。 例としては、テキスト生成であれば Gemini 3.0 GPT-5 Claude Sonnet 4.5 等がありますね。 まず、テキスト生成に焦点をあてて、LLMが文章を生成する過程について説明しました。 テキスト生成を行うLLM(大規模言語モデル)は膨大なテキストデータから言語のパターンを学習したもので、文脈から次に来る確率が高い言葉を予測し、リストアップされた言葉の中からランダムに単語を選択することを繰り返して文章を生成します。 例えば「今日はいい日だ。」という文章を生成する過程を考えてみます。 以下の図のように、まず、「今日は」の次に来る可能性が高い言葉として、「いい」、「天気」、「寒い」がリストアップされ、その中から確率で選択されます。今回は「いい」が選択されていますね。この操作を繰り返します。 ここで一点重要なのは生成AIは最も確率が高い言葉を選択するわけではないという点です。 試しに同じプロンプトを何度か生成AIに投げていただけると異なるレスポンスが来ると思いますので、この仕組みを実感できると思います。 LLMは言葉を理解しているのではなく、パターンを知っており、そのパターンに倣って言葉を連ねているということになります。こちらについては、永田さんの記事「 AIは「1+1って、2になること多いなあ」と思っている!? 」でLLM内部で起こっていることについて解説されてるので気になった方は是非ご覧ください。 次に、生成AIモデルでできることできないことを切り分けるために、まずLLMモデルと生成AIサービスの違いの説明を行いました。 LLMと生成AIサービス。一体どう違うのかというと、機能が異なります。 LLM 生成AIサービス 機能 文章の生成 LLMの機能+履歴保持、web検索、ファイルアップロード,etc 例 GPT-5等 ChatGPT,Gemini等 生成AIサービスにはLLMの機能に加えて様々な機能が追加されています。 例えば表にあるように履歴保持機能。これがあるとこれまでの会話の文脈を生成AIが理解してくれるのでしっかり会話が成り立ちますね。 web検索機能。最近の生成AIサービスは検索機能を持っており、生成AIにリアルタイムの出来事を回答させることもできます。例えば今日の天気等をGeminiに聞いてみると検索結果から回答してくれます。 ChatGPTやGemini等の生成AIサービスは純粋なLLMとは異なる機能を持っているということです。 そして、生成AIモデル単体でできることとできないことを挙げると以下のようになります。 LLM単体でできないことについて解説していきます。 最新の情報に関する回答 LLMモデルはリアルタイムで学習し知識を更新する仕組みはなく、知識のカットオフ日が存在します。 カットオフ日とは、LLMが学習したデータがいつまでのデータかを指し、LLMはその日までのデータしか知り得ません。 そのため、例えば今日の天気を聞いても学習していないので回答することができません。 試しにGPT-4o-miniに対し、カットオフ日について尋ねてみました。 私の知識のカットオフ日は2023年10月です。それ以降の情報については持っていませんので、ご了承ください。何か質問があればお答えします! このLLMは2023年10月までのことしか知らないというわけですね。 試しに「2025年は何が流行しそうか考えてみてください」と尋ねてみました。 2025年に流行しそうなトレンドについて、現在の技術や社会の動向を考慮した上でいくつかの予測を挙げてみます。 持続可能なライフスタイル: 環境意識の高まりに伴い、エコフレンドリーな製品やサービス、サステナブルなファッションが流行する可能性があります。プラスチックの削減やリサイクル製品の人気が高まるでしょう。 ウェアラブルテクノロジー: 健康管理やフィットネスのためのウェアラブルデバイスが進化し、より多機能で使いやすくなることで、一般的なアイテムとして普及するかもしれません。 メタバースとバーチャル体験: メタバース関連のプラットフォームが進化し、仮想空間でのソーシャルインタラクションやエンターテインメントが一般的になる可能性があります。特に、ゲームや仮想イベントが人気を集めるでしょう。 デジタルアートとNFT: デジタルアートやNFT(非代替性トークン)が引き続き注目され、アート市場やエンターテインメント業界で新しい形のクリエイションが流行するかもしれません。 パーソナライズされた医療と健康: 個別化医療や遺伝子ベースの健康管理が進展し、自分に最適な健康法や食事が提案されることで、健康志向のライフスタイルが流行する可能性があります。 リモートワークとフレキシブルな働き方: リモートワークやハイブリッドな働き方が一般化し、職場環境や働き方に関する新しいトレンドが形成されるでしょう。これにより、ワークライフバランスを重視する文化が広がる可能性があります。 エンターテインメントの新形態: ストリーミングサービスやポッドキャスト、バーチャルコンサートなど、デジタルコンテンツの消費スタイルが進化し、新しいエンターテインメントの形が流行するかもしれません。 これらはあくまで予測であり、実際に何が流行するかは様々な要因によって変わるでしょう。未来のトレンドは常に変化し続けるため、柔軟な視点で見ることが重要です。 もう2026年ですが2025年の流行を予想してもらいました。 あたっているかはさておき、このようにカットオフ日以降のことは知らないんですよね。 これから時間が経って、年齢を重ねたころにこのモデルと会話できたら懐かしい気分になれるかもしれません。 独自の情報に関する回答 LLMはもちろん学習したことしか知りません。 そのため、例えば会社の社内規約等のクローズドな情報について聞いても回答することができません。 情報の正確性の保証 LLMにはハルシネーションという、あたかも真実を語るように真っ赤な噓を吐くことがあります。 LLMが文章を生成する過程でもお話しましたが、LLMは、確率で単語を選び、それを繰り返して文章を作成するので、正しいこと以外も出力します。 LLMが本当に正しいことを言っているのか、人間が確認する必要があります。 複雑な計算 何か計算してとLLMに入力したとして、LLMは実際に計算しているわけではなく、学習パターンに基づいて次来る単語を生成しているため、複雑な計算は間違えることがあります。 AIは計算を理解しているわけではなく、 「1+1って、2になること多いなあ」と思っている ということですね。 現実世界やデジタル環境の操作 LLMはテキストを生成するのみで、例えば部屋の電気は消してくれませんし、notionでドキュメントを作成してくれることはありません。 このように生成AIにはできないことがありますが、これはツールと組み合わせることで解消できる場合があります。 生成AI×ツール 生成AIとツールを組み合わせることで多くのことができるようになります。 セミナーでは、RAG、FunctionCalling、MCPについてご紹介しました。 RAG RAGはRetrieval Augmented Generationと呼ばれ、検索拡張生成等と訳される技術です。 生成AI×検索ツールですね。 生成AIが検索ツールを使用してデータを検索し、取得したデータを基に回答を行います。 RAGを活用することで、生成AIはリアルタイムの情報や学習していない独自の情報を手に入れることができます。 また、情報源が明確になるため、根拠のある回答をしてくれますし、根拠をユーザが確認することができるようになります。 前章で挙げた生成AIにできないことのうち以下の項目については解消できそうと思っていただけるのではないでしょうか。 最新の情報に関する回答 独自の情報に関する回答 情報の正確性の保証 Function Calling 次にFunctionCallingです。 FunctionCallingは生成AIに関数を呼び出させる機能です。 関数の実行はアプリケーション側で行うため生成AIのレスポンスを翻訳する部分は実装する必要がありますが、生成AIがどの関数をどんな引数で実行するのか判断してくれます。 例えば検索、計算、外部APIの使用、IoT連携等、様々な機能を生成AIと組み合わせることが可能です。 複雑な計算ができる関数を用意しておけば、生成AIが苦手な計算だけ関数にさせることもできますし、ロボットを動作させる関数なんてのを作成しておけば、生成AIにロボットを操作させることもできるというわけですね。 組み合わせ次第で強力なものが生まれそうな気がします。 Azure OpenAIでFunctionCallingを行う方法については こちら のブログ記事で解説してますので興味がある方はぜひご覧ください。 MCP MCPはAnthropic社が提唱した、生成AIとツールを繋ぐUSB-typeCのような共通規格です。 これまでFunctionCallingを用いたLLMアプリを作成した場合、あるツールを別のアプリでも使用したいとなった場合、アプリ間の言語が異なったり必要なライブラリが異なれば、関数を改修する必要がありました。 また、ツールリストの定義方法はLLMによって異なるため、アプリで使用するLLMが異なれば、その点を改修する必要が出てきます。 MCPを使用した場合、MCPクライアントというものを用意し、LLMアプリと別プロセスで動作するMCPサーバをツールとして扱うようにします。 そうすると、MCPサーバ1つ作成すれば、どのLLMアプリからも使用できるようになるので、アプリ毎に関数を書いたり、ツール定義を行う必要がなくなります。 また、MCPサーバを公開しているサービスは増えており、例えばnotionやblender、googleカレンダー等のMCPサーバを組み込むことが容易です。 公開されているMCPサーバについては こちら をご確認ください。 生成AIとツールを組み合わせる技術であるRAG、FunctionCalling、MCPについて解説を行いました。 続いてデモの解説に移ります。 Qumcum連携 具体的にFunctionCallingでQumcumを生成AIに操作させるデモを行いました。 QumcumはBluetoothによる通信が可能な小型ロボットです。 主な機能は距離センサや音検知、発声等がありますが、今回使用したのは頭、腕、足の回転です。 また、LLMとしてAzure OpenAIのモデルを使用しました。 Azure OpenAIについてはデプロイから実際にAPIを叩くまでをブログ記事にしていますので こちら をご確認ください。 シーケンス図は以下のようになります。 まず、プロンプトの分析をLLMにリクエストし、結果を構造化出力させています。これは分析結果(プロンプトから読み取れる感情、プロンプトに対するロボットの感情、プロンプトの要約等)をUIとして表示するために使用しています。 構造化レスポンスについてもブログにまとめているので、 こちらの記事を ご覧ください。 その後、分析結果とプロンプト本文をLLMに渡し、FunctionCallingを行います。 使用する関数を選択してもらい、アプリケーション側でロボット動作関数を実行しています。 デモ動画はこちらです。 このデモでは、入力したプロンプトからFunctionCallingによって関数が選び取られていることを表しています。 ロボットが万歳をする関数や、足踏み、首振りを行う関数が選び取られ、実行されているのがわかります。 今後の展望 具体的な展望ではないですが、今後できたらおもしろいなと考えていることは以下のようなことです。 テキスト入力から音声入力へ修正 Qumcumの発話機能を活用し、リアルタイム会話機能実装 今までの会話内容を記録し、RAGによって相棒、友人のような会話を可能に RAGを用いて生成AIの相棒を作るはらちゃんのブログは こちら を参照ください。 生成AIとツールを組み合わせることで、某未来から来たネコ型ロボットのような友人を自分の手で作ることができるかもしれませんね。 まとめ 生成AI×ツールによって、生成AI単体ではできなかったことが可能になります。 最新の情報に関する回答 独自の情報に関する回答 現実世界やデジタル環境の操作 等が可能です。 FunctionCallingやMCPを活用して新たな組み合わせによる新たな価値を生み出していきましょう。 閲覧いただきありがとうございました。 セミナーに参加してくださった皆さん、ご清聴ありがとうございました。 わかりやすく伝えられるセミナーを今後も行っていきたいと思います。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OSC福岡&広島2025で生成AI×ツールについてセミナー登壇してきました first appeared on SIOS Tech Lab .
ども!龍ちゃんです。 前回の記事 では Draw.io の公式 MCP Tool Server を検証しました。しっかり動くし、Mermaid 入力のトークン効率もよかったのでぱっと使う分には良かったですね。問題があったんでブログを書いているんですけどもwww 今回の内容です。 MCP Tool Server の問題 — ファイルが残らない Skill + VS Code 拡張機能のセットアップ VS Code 内で完結する作業の流れ(生成 → プレビュー → 編集 → エクスポート → Git 管理) MCP Tool Server との比較と使い分け Mermaid / PlantUML も含めた図解ツール全体の選び方 MCP Tool Server の問題: 設計図が Git 管理できない 検証していて問題になったことがあります。 Draw.io で描く図って、設計情報なんですよね。アーキテクチャ図、シーケンス図、フロー図。どれもシステムの設計を表現したもので、ソースコードと同じように GitHub に置いてバージョン管理したい。PR でレビューもしたい。 ところが MCP Tool Server は URL 方式です。図を生成すると app.diagrams.net の URL が返ってきて、ブラウザで開く。図のデータは URL に埋め込まれているだけで、手元にファイルが残らない。git add できるものがないんですよね。 MCP が悪いわけじゃないです。ブラウザで図を確認・共有する用途は十分見たいしてます。Slack に URL を貼れば相手もすぐに見られるし、受け取り側に環境も要らない。ただ、設計情報を Git で管理するという用途には合わないだけですね。 同じ jgraph/drawio-mcp リポジトリに、 .drawio ファイルをローカルに生成するアプローチがあります。これと VS Code の Draw.io 拡張機能を組み合わせると、生成からプレビュー、手動編集、エクスポート、Git 管理まで VS Code の中で完結するので、そちらの検証結果をブログにまとめています。 Skill + 拡張機能のセットアップ やることは2つだけです。Skill 定義ファイルを1つと VS Code の拡張機能を1つ追加する。MCP サーバーの起動も Node.js も要りません。 Skill のセットアップ jgraph/drawio-mcp リポジトリの skill-cli/SKILL.md を取得して、プロジェクトに配置します。 mkdir -p .claude/skills/drawio curl -sL https://raw.githubusercontent.com/jgraph/drawio-mcp/main/skill-cli/SKILL.md \ > .claude/skills/drawio/SKILL.md これだけです。MCP のように .mcp.json に設定を書いたり、 npx でサーバーを起動したりする必要はありません。 VS Code 拡張機能の追加 .drawio ファイルを VS Code で開けるようにするために、Draw.io の拡張機能を追加します。 devcontainer を使っている場合は devcontainer.json に追加するだけです。 { "customizations": { "vscode": { "extensions": [ "hediet.vscode-drawio" ] } } } ローカル環境なら VS Code のマーケットプレイスから hediet.vscode-drawio をインストールしてください。 この拡張機能を入れると、 .drawio ファイルを開いたときに VS Code 内に GUI エディタが表示されます。ドラッグ&ドロップで図形を動かしたり、色を変えたり、接続線を引いたりできます。ブラウザの draw.io と同じ操作感です。 PNG や SVG へのエクスポートも、この拡張機能のメニューから手動でできます。draw.io の CLI ツールは要りません。 なぜ「CLI」ではなく「拡張機能」なのか jgraph/drawio-mcp のリポジトリでは、このアプローチを「Skill + CLI」と呼んでいます。ここでいう CLI は draw.io のデスクトップアプリをコマンドラインで使うエクスポート機能( drawio -x -f png ... )のことです。 ただ、devcontainer 環境でこの CLI を動かそうとすると面倒なんですよね。draw.io のデスクトップアプリは Electron ベースなので、ヘッドレス環境で動かすには xvfb と大量の X11 依存パッケージが必要になる。Docker イメージが 500MB くらい膨らみます。 VS Code の Draw.io 拡張機能なら、devcontainer.json に1行追加するだけで済みます。プレビュー、編集、エクスポートが全部揃います。 devcontainer 環境での現実解は Skill + 拡張機能 です。 VS Code で完結する作業の流れ セットアップが終わったら、実際の作業の流れを見ていきましょう。ブラウザを開かずに、VS Code の中だけで図の生成から Git 管理まで完結します。 生成 → プレビュー → 編集 → エクスポート → Git 管理 流れはこうなります。 Claude Code に指示 → .drawio ファイル生成 → VS Code でプレビュー(Draw.io 拡張が自動で開く) → GUI で手動微調整(色・配置・接続) → 拡張機能から PNG/SVG にエクスポート → git add → commit → push 実際に Claude Code に指示するときはこんな感じです。 ログイン処理のフローチャートを .drawio で作って。 開始 → メールアドレス入力 → パスワード入力 → 認証API呼び出し → 成功/失敗の分岐 → 完了 特別なコマンドは要りません。 .drawio で作って と言えば、Skill の定義を参照して .drawio ファイルを生成してくれます。フローチャートに限らず、アーキテクチャ図やシーケンス図も同じように自然言語で指示するだけで作れます。 AI 生成 + 手動仕上げ Claude が生成する .drawio ファイルは、そのまま使えるレベルではあります。ノードの配置も接続も合っている。ただ、色やレイアウトの微調整は人間が GUI でやったほうが速いんですよね。 ここが Mermaid や PlantUML との大きな違いです。テキストベースのツールだと、色を変えたければソースコードを編集して再レンダリングする。Draw.io なら GUI で直接ドラッグして色を塗れば終わりです。Figma を触る感覚に近いです。 AI が 80% の構造を作って、人間が 20% の見た目を GUI で仕上げる。このハイブリッドが .drawio ファイルとして Git にコミットされるのが、この流れのポイントです。 GitHub での管理 .drawio ファイルは Git にそのままコミットできます。バージョン管理される。ブランチを切って PR でレビューもできる。 設計情報を Git 管理する最大のメリットは、PR で図をレビューできることです。設計変更があったら図も一緒に PR に含めて、レビュアーが確認できる。ただ、ここで1つ問題があります。 GitHub は .drawio ファイルをレンダリングしません。リポジトリ上で開くと生の XML が表示される。これだと PR を開いてもレビュアーは図が見られないんですよね。 解決策が .drawio.svg 形式です。VS Code の拡張機能から SVG にエクスポートすると、SVG の中に Draw.io の XML が埋め込まれます。GitHub 上では画像として表示されるので、PR でレビュアーが図を確認できる。しかも draw.io で開けば再編集もできます。 .drawio ファイル(編集用ソース)と .drawio.svg (GitHub 表示・レビュー用)の両方をコミットしておくのがおすすめです。 CI で自動変換したい場合は render-drawio-action も選択肢に入ります。 MCP vs Skill の比較 ここまで Skill + 拡張機能のセットアップとワークフローを見てきました。じゃあ MCP Tool Server はもう要らないのかというと、そんなことはないです。用途が違うだけなんですよね。 比較表 比較項目 MCP Tool Server Skill + 拡張機能 出力 URL → ブラウザで確認 .drawio ファイル → VS Code で確認 Git 管理 できない(ファイルが残らない) できる(.drawio をコミット) 入力フォーマット XML / Mermaid / CSV XML のみ コンテキスト消費 3ツール分の定義が常に載る 使うときだけ読み込まれる(普段はゼロ) 編集環境 ブラウザ(app.diagrams.net) VS Code 内 オフライン 初回ダウンロード後は可能 完全オフライン対応 セットアップ .mcp.json + Node.js SKILL.md 1つ + 拡張機能 エクスポート ブラウザから手動 拡張機能から手動 Mermaid 入力に対応しているのは MCP だけです。Mermaid はトークン効率が良くて、XML の 1/10 くらいで同じ図を表現できる。フローチャートで比べると、XML だと約 800 トークンかかるところが Mermaid なら約 100 トークンで済みます。 逆に、Git 管理ができるのは Skill + 拡張機能だけです。ここは明確に分かれます。 どちらを選ぶか 判断はシンプルです。 Git で管理したい → Skill + 拡張機能。これ一択 Mermaid から変換したい → MCP Tool Server URL を共有して相手にすぐ見せたい → MCP Tool Server VS Code の中で完結したい → Skill + 拡張機能 両方使い分けたい → 併用できる。同じリポジトリの別アプローチなので競合しない 僕の場合は、設計情報を GitHub で管理するのが前提なので Skill + 拡張機能をメインで使っています。Mermaid から Draw.io に変換したいときだけ MCP を使う、という使い分けですね。 全ツールの使い分け — Draw.io だけで考えない Draw.io の話をしてきましたが、図を作るツールは Draw.io だけじゃないです。Mermaid、PlantUML、HTML ベースの図解もある。目的に合わせて選ぶのが大事なんですよね。 Draw.io の立ち位置 Draw.io の強みは GUI で直感的に編集できることです。AI が生成した図をそのままドラッグして色を塗って形を変えられる。Mermaid や PlantUML だとソースコードを書き換えて再レンダリングしないといけないけど、Draw.io ならマウスで触るだけです。 デザインの自由度も段違いで、色、形状、アイコン、グラデーション、何でもいける。素の Mermaid / PlantUML だと見た目の調整に限界があって、 Mermaid を Tailwind で拡張する記事 と PlantUML を Tailwind で仕上げる記事 を書いたくらいなんですよね。Draw.io ならそもそもその問題が起きません。 ただ弱点もあります。 Git diff が見づらい : .drawio の中身は XML なので、diff を見ても座標やスタイル情報が大量に出てきて、何が変わったのかわかりにくい。Mermaid や PlantUML はテキストベースだから diff がきれいに出る GitHub でレンダリングされない : さっき書いた通り、 .drawio のままだと生 XML が表示される。 .drawio.svg で回避はできるけど、ひと手間かかる 使い分け表 ユースケース 推奨ツール 理由 ブログ記事のフロー図・概念図 HTML + Mermaid / PlantUML PNG が直接出る。テキストで完結 テキスト管理したい仕様書の図 Mermaid / PlantUML diff がきれい。テキストで完結 デザインにこだわりたい図 Draw.io(Skill + 拡張機能) GUI 編集、デザイン自由度が高い Mermaid / CSV からの変換 Draw.io MCP 変換に対応しているのはこれだけ URL を貼って即共有 Draw.io MCP リンク1つで相手が見られる ブログ記事の図を作るだけなら、正直 HTML + Mermaid で作る図解 や PlantUML で作る図解 のほうが手軽です。PNG が直接出てくるし、テキストだけで完結する。 Draw.io が活きるのは「デザインにこだわりたい」か「GUI で編集したい」場面です。設計書に載せる図とか、お客さんに見せる図とか、見た目が大事な場面ですね。 判断フロー 迷ったらこの流れで考えるとすっきりします。 仕様書の図はAIに読ませるな — 軽量コードを添える設計パターン や 図解作成、AIに丸投げしたら「たまに自分より上手い」件 も合わせて読むと、図解ツール全体の使い分けが見えてくると思います。 まとめ Draw.io で描く図は設計情報です。設計情報なら GitHub で管理したい。MCP Tool Server は URL 方式で図が手元に残らないから、Git 管理には向かない。 だから Skill + VS Code 拡張機能を使う。SKILL.md を1つ置いて、devcontainer.json に拡張機能を1行追加する。これで .drawio ファイルの生成からプレビュー、GUI 編集、エクスポート、Git 管理まで VS Code で完結します。 MCP Tool Server が使えないわけじゃないです。Mermaid 変換や URL 共有には MCP のほうが向いている。同じリポジトリに両方のアプローチが用意されているのは、用途が違うからなんですよね。 ツールは目的で選ぶ。Git 管理が要るなら Skill + 拡張機能、共有が要るなら MCP。テキスト管理や diff 重視なら Mermaid / PlantUML もある。全部を1つで解決しようとしないで、場面に合わせて使い分けるのがいいんじゃないかなと思います。 ほなまた〜 関連ブログ Draw.io MCP シリーズ 前回の記事: Draw.io 公式 MCP でできること・セットアップガイド — MCP Tool Server のセットアップと Mermaid / CSV 入力の検証結果をまとめた記事です MCP と Skills の使い分け Claude Code MCP が遅い・重い問題、CLI + Skills で解決 — Notion・Playwright MCP の接続・トークン問題を CLI + Skills 移行で軽量化した話。今回の「用途の適合性」とは別の切り口です Claude Code: 公式MCPを補完するSkills設計パターン — 公式 MCP の不足機能を Skills で補完する設計パターン。MCP → CLI → Skill の判断基準を整理しています AI × 図解作成 図解作成、AIに丸投げしたら「たまに自分より上手い」件 — Claude Code Skill で HTML 図解を自動生成 → PNG 変換する流れ。気に入ったデザインを蓄積して AI のスキルを育てる方法も紹介 ClaudeでMermaid図作成を自動化!2時間→5分の劇的時短術 — Claude + Mermaid でフローチャートやシーケンス図を自動生成。Live Editor の活用術と日本語フォントの対処法 Claude Codeで仕様書のPlantUML図を自動生成 — PlantUML の各種図を Claude Code で自動生成し、VS Code Preview で確認する環境構築と実践例 仕様書の図はAIに読ませるな — 軽量コードを添える設計パターン — Mermaid / PlantUML のソースコードと設計意図を HTML コメントで添える設計パターン。AI が推測ではなく正確に読める形式にする方法 図解のデザイン強化 Mermaidのデザインが物足りない?Tailwindで拡張して設計書品質に — Mermaid 図に Tailwind CSS の注釈パネルを組み合わせて設計書品質にアップグレード。PNG 変換手段とテンプレートも紹介 PlantUMLの表現力をTailwind CSSで設計書品質に仕上げる — PlantUML + Tailwind CSS で設計書品質を実現。skinparam 設定と2つのレイアウトテンプレート ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Draw.io公式Skillで設計図をGitHub管理 — VS Code完結のセットアップ first appeared on SIOS Tech Lab .
ども!最近は仕様書×AIの文脈で図解まわりの検証をやってる龍ちゃんです。 Draw.io の開発元である jgraph 社が、公式の MCP サーバーを出しました。 jgraph/drawio-mcp リポジトリで Apache 2.0 ライセンスで公開されています。 コミュニティ実装の MCP サーバーはいくつかありましたが、公式となると話が変わってきます。draw.io 本体と同じ開発元が直接メンテしてくれるので、コミュニティ版よりも長くメンテされやすいんですよね。 MCP の基本的な仕組みについては「 AIエージェントの進化が分からない?秘書で理解する3段階 」で解説しているので、「MCPってなに?」という方はそちらを先にどうぞ。 jgraph/drawio-mcp リポジトリ、中を見てみると実は4つのアプローチが入っていて、それぞれ対象環境や出力形式が異なります(全体像は後半で紹介します)。 この記事では、Claude Code ユーザーに一番スタンダードな MCP Tool Server を試していきます。セットアップ方法、3つの入力フォーマット(Mermaid / XML / CSV)の使用感、そして正直「できないこと」まで、検証した結果をまとめました。 今回の内容です。 MCP Tool Server のセットアップ( .mcp.json に数行追加するだけ) 3つの入力フォーマットを実際に試した比較 MCP Tool Server の「できないこと」を正直に語る 向いている人・向いていない人の判断材料 龍ちゃん できないことを紹介していますが、それの対処法に関しては「 Draw.io公式Skillで設計図をGitHub管理 — VS Code完結のセットアップ 」で紹介しています。併せてご一読ください! セットアップ: .mcp.json に数行追加するだけ Claude Code なら、ターミナルで以下のコマンドを実行するだけ。 claude mcp add -s project drawio -- npx @drawio/mcp これで .mcp.json が自動で作られます。手動で書く場合はこう。 { "mcpServers": { "drawio": { "type": "stdio", "command": "npx", "args": ["@drawio/mcp"] } } } 前提として Node.js が必要です(npx を使うので)。検証時の環境は Node.js v25.7.0、npm パッケージ @drawio/mcp v1.1.2 でした。 以前 MCP のトークン消費問題について記事を書いた んですが、draw.io MCP はツール定義が3つしかないので、コンテキストへの負担はかなり軽い部類です。Notion MCP みたいに大量のツールが常駐するタイプとは全然違います。 使えるようになる3つのツール ツール 入力 用途 open_drawio_mermaid Mermaid.js 構文 フローチャート・UML 全般 open_drawio_xml draw.io XML(mxGraphModel) 細かいスタイル制御が必要な図 open_drawio_csv draw.io CSV インポート形式 データ駆動の組織図・ツリー どのツールも lightbox (読み取り専用モード)と dark (ダークモード)のオプションが付いています。 設定はこれだけで、すぐに使い始められます。 使ってみた: 3つの入力フォーマット Mermaid で図を生成 まずは Mermaid から。Claude Code に「ロードバランサー構成図を Mermaid で描いて」とお願いしてみました。 すると Claude が Mermaid 構文を生成して、MCP ツール経由で draw.io に渡してくれます。数秒後にブラウザがパッと開いて、draw.io のエディタに図が表示されました。 これ、良いですね。Mermaid の構文自体がシンプルなので、5ノード程度の図なら入力トークンは約100程度で済みます。しかも Mermaid エンジンが自動レイアウトしてくれるので、ノードが重なったり変な配置になったりしない。ノード数が増えても構文が簡潔なぶん、トークン消費は抑えられます。 ブラウザで開いた draw.io エディタ上で、色やフォントを変えたりノードの位置を微調整したりもできます。AI が下書きして、人間が仕上げる感じですね。 XML で図を生成 次に XML。同じ構成図を XML フォーマットで試してみます。 XML だと draw.io の全プロパティを指定できるので、ノードの色、枠線のスタイル、フォントサイズまで細かく制御できます。Mermaid ではテーマに依存する部分も、XML なら自由自在。 ただし、トレードオフがあります。 同じ図を表現するのに XML は約800トークン使います。Mermaid が約100トークンだったので、ざっくり8倍。さらに、AI がノードの座標(x, y)を自分で計算して配置するので、レイアウトが微妙になることもあります。Mermaid なら自動でいい感じに並べてくれるのに、XML だとそこは AI 任せなんですよね。 トークンもレイアウトも Mermaid に分がありますが、「この色で、このフォントで、この位置に」って指定したいなら XML 一択です。 CSV で図を生成 最後に CSV。これは少し特殊で、draw.io 固有の CSV インポート形式に従う必要があります。 CSV ヘッダーに # label: %name% のようなメタ記法を書いて、データ行で親子関係を定義していく形式です。ツリー構造や組織図を作るには向いてるんですが、ただ汎用性はあまり高くないので、フローチャートや UML を CSV で書こうとは思わないですね。 フォーマット比較 3つ試した結果をまとめます。 比較項目 Mermaid XML CSV トークン効率 高(XML の約 1/10) 低(冗長) 中 レイアウト 自動 手動(AI が座標指定) 自動 スタイル制御 低(テーマ依存) 高 中 対応図形 flowchart, sequence, class, state, ER 等 全て ツリー・組織図 結論としては、特別な理由がなければ Mermaid を使うのが正解 です。トークン効率が XML の約 1/10、自動レイアウトで配置も綺麗、対応する図形タイプも広い。XML は「どうしても色やスタイルを細かく指定したい」ときの選択肢。CSV は組織図やツリーを大量のデータから生成したいときのニッチ枠です。 正直に言う: MCP Tool Server の「できないこと」 ここまで「Mermaid いいじゃん」って話をしてきましたが、MCP Tool Server には正直「できないこと」も結構あります。 まず仕組みを知っておく さっき Mermaid で図を生成したとき、ブラウザがパッと開きましたよね。あれ、実はローカルにファイルを作ってるわけじゃないんです。 MCP Tool Server は、AI が生成したコンテンツを圧縮・エンコードして app.diagrams.net の URL に全部詰め込んでいます( ソースコード )。その URL をブラウザで開くと draw.io エディタが表示される、という仕組みです。 つまり すべてが URL に埋め込まれている 。ローカルにファイルは一切残りません。 この「URL 方式」が、以下の制約の根本原因です。 できないこと 一番大きいのは、 ローカルにファイルが残らない ことです。 .drawio ファイルが生成されないので、Git で管理したり、VS Code の Draw.io 拡張で開いたりができません。 これに連動して、VS Code 内で作業を完結させることもできません。図を確認するにはブラウザに切り替える必要があるし、PNG や SVG が欲しければ draw.io エディタから手動でエクスポートする手間が発生します。GitHub に図を置きたい場合も、URL からは .drawio ファイルを取り出せないので、リポジトリ管理のワークフローとは噛み合わない。 もう1つの本質的な制約は、 差分更新ができない こと。URL は毎回まるごと新規生成されるので、「さっきの図のここだけ修正して」ということができません。修正するには図全体を再生成するか、ブラウザの draw.io エディタ上で手動で直す必要があります。 あとは環境面の話で、 app.diagrams.net に接続できないとそもそも動きません。オフラインでは使えないです。 一方で、URL だからこそ便利な面もある URL をそのまま Slack やチャットに貼れば、相手がブラウザで即座に図を見られます。受け取る側に draw.io のインストールは不要で、ブラウザさえあれば OK。しかも URL を開いた先の draw.io エディタでそのまま編集もできるんですよね。 ファイルを共有してもらって、ツールを入れて、開いて…みたいな手間がゼロ。検証で 27ノードのマイクロサービス構成図を作ったときも、URL 長は 1851 文字でブラウザの制限内に収まっていました。 jgraph/drawio-mcp の4つのアプローチ ここまで MCP Tool Server を試してきましたが、 jgraph/drawio-mcp リポジトリには4つのアプローチが用意されています。 アプローチ 対象環境 出力形式 MCP 必要 MCP Tool Server Claude Code, Cursor 等 URL → ブラウザで draw.io を開く ○ MCP App Server Claude Desktop 等 チャット内にインライン描画 ○ Skill + CLI Claude Code .drawio ファイルをローカル生成 × Project Instructions Claude Project Python コード実行で URL 生成 × 「MCP サーバー」と聞くと1つのツールを想像しますが、対象環境と用途に応じて手段が分かれています。MCP Tool Server と MCP App Server は MCP 対応クライアントが必要で、Skill + CLI と Project Instructions は MCP なしで動作します。 まとめ: 向いている人・向いていない人 Draw.io 公式 MCP Tool Server、使い所を選べば便利だけど万能ではない、というのが正直な感想です。 向いていない人 を先に挙げておきます。 VS Code で作業を完結させたい .drawio ファイルをローカルで管理したい GitHub リポジトリに図を保存したい 向いていない人向けには、上で紹介した Skill + CLI が選択肢になります。MCP なしで .drawio ファイルをローカルに生成できるので、VS Code + Git のワークフローに乗せられます。次回の記事で Skill + CLI のセットアップと MCP Tool Server との比較をやっていく予定です。 逆に、 向いている人 はこういう方です。 ブラウザで draw.io を使い慣れている Mermaid で図を書きたい(トークン効率が圧倒的) セットアップを最小限にしたい( .mcp.json に数行追加するだけ) URL を Slack やチャットで共有したい 最後にもう1つ。Draw.io は Mermaid や PlantUML とは違って GUI エディタなので、AI が生成した図を人間がブラウザ上で手で仕上げるワークフローが成立します。テキストベースのツールだと AI の出力がそのまま最終成果物になりがちですが、draw.io なら色・配置・形状を自由に調整できる。この「AI が 80% 作って、残りを人間が仕上げる」感覚は、他のダイアグラムツールにはないものでした。 ではまた! 関連ブログ MCP と Skills の使い分け Claude Code MCP が遅い・重い問題、CLI + Skills で解決 — Notion・Playwright MCP の接続・トークン問題を CLI + Skills 移行で軽量化した話。MCP のパフォーマンス面の課題と解決策を扱っています Claude Code: 公式MCPを補完するSkills設計パターン — 公式 MCP の不足機能を Skills で補完する設計パターン。MCP → CLI → Skill の判断基準を整理しています AIエージェントの進化が分からない?秘書で理解する3段階 — MCP の基本的な仕組みを秘書の比喩で解説。「MCP ってなに?」という方向けの入門記事です AI × 図解作成 図解作成、AIに丸投げしたら「たまに自分より上手い」件 — Claude Code Skill で HTML 図解を自動生成 → PNG 変換する流れ。気に入ったデザインを蓄積して AI のスキルを育てる方法も紹介 ClaudeでMermaid図作成を自動化!2時間→5分の劇的時短術 — Claude + Mermaid でフローチャートやシーケンス図を自動生成。Live Editor の活用術と日本語フォントの対処法 Claude Codeで仕様書のPlantUML図を自動生成 — PlantUML の各種図を Claude Code で自動生成し、VS Code Preview で確認する環境構築と実践例 仕様書の図はAIに読ませるな — 軽量コードを添える設計パターン — Mermaid / PlantUML のソースコードと設計意図を HTML コメントで添える設計パターン。AI が推測ではなく正確に読める形式にする方法 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Draw.io公式MCPでできること・できないこと — 3フォーマット比較 first appeared on SIOS Tech Lab .
サイオステクノロジーのひろです。今回はAzureOpenAIを使用したFunctionCallingについて解説していきます。 このブログのゴール FunctionCallingとは何かわかる AzureOpenAIモデルを使用したFunctionCallingの実装方法がわかる FunctionCallingとは FunctionCallingはLLMに関数を使わせることができる機能です。 関数は予め作成しておく必要がありますが、このFunctionCallingを使用することで、LLMができることを拡張することが可能です。 例えば、LLMは文章の生成が可能で、様々な質問に回答してくれます。しかしなんでも正しい答えを教えてくれるわけではなく、最新の情報(例えば今日の天気等)やクローズドな情報には回答できません。 しかしながら、最新の情報を検索して取得する関数や、データベースを検索してクローズドな情報を取得する関数を用意し、FunctionCallingによってLLMに関数を使用させれば、回答させることも可能になります。 さらにそれどころではなく、外部APIを操作する関数を実行させればGoogleカレンダーへのイベント登録やメール送信も可能ですし、ロボットを動作させる関数を実行させれば現実へ干渉させることも可能になります。 組み合わせ次第で新たな価値を生み出すことができるかもしれません。 FunctionCallingでできることについて理解していただけたでしょうか。 ここから具体的な内容に入っていきたいと思います。 FunctionCallingのシーケンス どのようにLLMが関数を実行するかというと、以下のシーケンス図を見ていただければと思います。 まず、アプリケーションからLLMに対して使用可能な関数とプロンプトを渡します。 次に、LLMはプロンプトに沿って独自にどの関数を使用すべきか判断し、アプリケーションへ関数の呼び出しをリクエストします。 実行する関数を教えてもらったアプリケーションは関数を実行し、実行結果をLLMに渡します。 最終的に、LLMが実行結果をもとに回答を生成します。 このような流れでFunctionCallingが行われます。 最終的な回答を生成するまでに必要な情報が足りない場合は複数の関数を実行させることもあります。 例えば、「八王子の天気と現在時刻を教えて」とプロンプトを投げたとします。 その場合、FunctionCallingは並列で2つの関数(天気取得関数と時刻取得関数)を実行して回答します。 また、アプリケーション側で、最終的な回答がされるまでツールの実行を続ける実装を行った場合、LLMが続けて関数を実行できます。 例えば、「天気情報を取得してそれを表にまとめて」とプロンプトを投げたとします。 その場合、1回目のFunctionCallingで天気情報を取得し、2回目に表を操作する関数を使って天気情報を書きこむ等といった処理が可能になります。 生成AIが行っているのは関数と引数を渡すことのみで、関数の実行はアプリケーション側で行います。そのため、アプリケーション側でLLMから渡される関数と引数を読み取って、関数を実行する機能を実装する必要があります。 FunctionCallingの説明については以上です。 続いてAzure OpenAIにおけるFunctionCallingについて解説していきます。 Azure OpenAIのFunctionCalling Azure OpenAIのFunctionCallingは、APIを叩く際のパラメータとして、toolsとtool_choiceを追加することで可能になります。 Azure OpenAIモデルのデプロイ方法は こちら のブログで解説しております。 以下にサンプルコードを記載しています。また、サンプルコードは こちら のリポジトリで公開しています。実行方法をreadmeに記載しているのでクローンして是非試してみていただければと思います。 まずは今回FunctionCallingで使用する関数を作成しましょう。 今回非常に簡易的な、辞書型で値を返す関数を2つ作成します。 サンプルコード Python import datetime def current_time(location: str): # 簡易的に現在時刻を送信 current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") return { "current_time": current_time, "timezone": location, } def current_weather(location: str): # ダミーの天気データを返す return { "location": location, "temperature": 15, "description": "晴れ", } 今回作成した関数では、地域名を引数として、疑似的にその地域の現在時刻を返す関数と天気情報を返す関数を作成しました。これらの関数をFunctionCallingで実行していきます。 次にFunctionCallingで渡すツールについてです。 渡すツール定義のJSONは以下のようになっています。 JSON { "type": "function", "function": { "name": "関数名", "description": "関数の説明(生成AIがこの説明を読んで関数を実行するか判断します)", "parameters": { "type": "object", "properties": { "【引数名】": { "type": "データ型(string, integer, booleanなど)", "description": "引数の説明" }, }, "required": [ "必須の引数名", ] } } } 関数名と関数の説明、引数の説明や引数のデータ型を定義して渡します。 ツール定義はJSONをそのまま記述すると量が多く、メンテナンスし辛いことがあるため、今回はPythonのライブラリであるPydanticを使用します。これにより、メンテナンスし易くなるだけでなく、後ほど引数のバリデーションに使用することができます。 以下はサンプルコードです。 Python from pydantic import BaseModel, Field from typing import Dict, Any class WeatherArgs(BaseModel): """get_current_weather関数の引数モデル""" location: str = Field( ..., description="天気情報を取得したい都市名(日本語)。例: '東京'", ) class TimeArgs(BaseModel): """get_current_time関数の引数モデル""" location: str = Field( ..., description="時刻を取得したい都市名(日本語)。例: '東京', 'ニューヨーク'", ) class FunctionSchemaManager: """複数の関数スキーマを管理するクラス""" @staticmethod def get_weather_tool() -> Dict[str, Any]: """天気取得ツールのスキーマ""" return { "type": "function", "function": { "name": "current_weather", "description": "指定された都市の現在の天気情報を取得します", "parameters": WeatherArgs.model_json_schema(), }, } @staticmethod def get_time_tool() -> Dict[str, Any]: """時刻取得ツールのスキーマ""" return { "type": "function", "function": { "name": "current_time", "description": "指定された都市の現在時刻を取得します", "parameters": TimeArgs.model_json_schema(), }, } @staticmethod def get_all_tools() -> list[Dict[str, Any]]: """利用可能な全てのツールを返す""" return [ FunctionSchemaManager.get_weather_tool(), FunctionSchemaManager.get_time_tool(), ] descriptionには引数の例を入れておくことで正しい引数が期待できます。 最後にFunctionCallingを行う部分のサンプルコードです。 Python import os import json from openai import AzureOpenAI from dotenv import load_dotenv from schemas import FunctionSchemaManager, TimeArgs, WeatherArgs from functions import current_time, current_weather # .envファイルから環境変数を読み込み load_dotenv() api_key = os.getenv("AZURE_OPENAI_API_KEY") endpoint = os.getenv("AZURE_OPENAI_ENDPOINT") api_version = os.getenv("AZURE_OPENAI_API_VERSION") deployment = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME") # Azure OpenAIクライアントの作成 client = AzureOpenAI( api_version=api_version, azure_endpoint=endpoint, api_key=api_key, ) # ツール取得 tools = FunctionSchemaManager.get_all_tools() messages = [ { "role": "system", "content": "あなたは優秀なアシスタントAIです。", }, {"role": "user", "content": "八王子の今の天気と時刻を教えてください。"}, ] # 1回目のFunctionCallingリクエスト response = client.chat.completions.create( messages=messages, max_tokens=1000, temperature=0.7, model=deployment, tools=tools, tool_choice="auto", ) response_message = response.choices[0].message messages.append(response_message) print("レスポンス:") print(response_message) # 関数実行 if response_message.tool_calls: for tool_call in response_message.tool_calls: function_name = tool_call.function.name function_args = json.loads(tool_call.function.arguments) print(f"関数呼び出し: {function_name}") print(f"引数: {function_args}") if function_name == "current_weather": args = WeatherArgs.model_validate(function_args) # 引数チェック tool_response = current_weather(location=args.location) elif function_name == "current_time": args = TimeArgs.model_validate(function_args) # 引数チェック tool_response = current_time(location=args.location) else: tool_response = {"error": "不明な関数"} messages.append( { "tool_call_id": tool_call.id, "role": "tool", "name": function_name, "content": json.dumps(tool_response, ensure_ascii=False), } ) else: print("関数呼び出しはありませんでした。") # 最終回答生成 final_response = client.chat.completions.create( messages=messages, max_tokens=1000, temperature=0.7, model=deployment, ) print("最終レスポンス:") print(final_response.choices[0].message.content) 生成AIモデルからのレスポンスには使用する関数と引数が書かれているため、それを使用して関数の実行を行います。 Azure OpenAIのFunctionCallingは並列関数呼び出しが可能で、一回のレスポンスで複数の使用する関数名を返してくれます。 実行結果 実行結果は以下のようになりました。 レスポンス: ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_iFwCt1t3Lzl2WMqQJDvP26Z7', function=Function(arguments='{"location": "八王子"}', name='current_weather'), type='function'), ChatCompletionMessageFunctionToolCall(id='call_6LbONbarZs3sCqoPiZstpieN', function=Function(arguments='{"location": "八王子"}', name='current_time'), type='function')]) 関数呼び出し: current_weather 引数: {'location': '八王子'} 関数呼び出し: current_time 引数: {'location': '八王子'} 最終レスポンス: 八王子の現在の天気は晴れで、気温は15度です。また、現在の時刻は2026年2月24日の13時36分です。 current_weatherとcurrent_timeの2つの関数を一度のレスポンスで呼び出していることがわかります。 また、関数の実行結果をもとにして回答してくれています。 messagesを変更することで、1つの関数だけ実行させることも可能です。 以下にmessagesを変更した場合の実行結果を示します。 時刻を聞くmessages Python messages = [ { "role": "system", "content": "あなたは優秀なアシスタントAIです。", }, {"role": "user", "content": "八王子の時刻を教えてください。"}, ] 実行結果 レスポンス: ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_5m0PwZa4t2AIty1trBlKTGAs', function=Function(arguments='{"location":"八王子"}', name='current_time'), type='function')]) 関数呼び出し: current_time 引数: {'location': '八王子'} 最終レスポンス: 現在の八王子の時刻は、2026年2月24日 14:22です。 天気を聞くmessages Python messages = [ { "role": "system", "content": "あなたは優秀なアシスタントAIです。", }, {"role": "user", "content": "八王子の天気を教えてください。"}, ] 実行結果 レスポンス: ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_MZmeJ11LfOQufB1dFzyztQEu', function=Function(arguments='{"location":"八王子"}', name='current_weather'), type='function')]) 関数呼び出し: current_weather 引数: {'location': '八王子'} 最終レスポンス: 現在の八王子の天気は晴れで、気温は15度です。 傘が必要か聞くmessages Python messages = [ { "role": "system", "content": "あなたは優秀なアシスタントAIです。", }, {"role": "user", "content": "今から八王子に行きます。傘はいるかな"}, ] 実行結果 レスポンス: ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=[], audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_Hoa7qoq13vJa4nVqzCdegVJp', function=Function(arguments='{"location":"八王子"}', name='current_weather'), type='function')]) 関数呼び出し: current_weather 引数: {'location': '八王子'} 最終レスポンス: 八王子の天気は晴れで、気温は15度です。今のところ傘は必要なさそうですが、念のため天気予報を確認しておくと良いかもしれません。安全に行ってきてください! 直接天気や時刻を聞かなくとも関数を実行して答えてくれます。 まとめ 今回はAzure OpenAIでFunctionCallingを行う方法についてまとめました。 Azure OpenAIのFunctionCallingは並列関数呼び出しが可能で、前章の例のように複数の関数を一度のレスポンスで呼び出すことができます。 どのような関数を実行させるかはアイデア次第です。是非FunctionCallingを使用して生成AIとツールを組み合わせてみてください。 今後もAzure OpenAIについて学んだことを共有していきたいと思います。 読んでいただきありがとうございました。 関連記事 これまでのAzure OpenAI入門 Azure OpenAI入門:モデルのデプロイとpythonからAPIを実行 AzureOpenAI入門:JSON形式のデータを出力させる 参考文献 https://learn.microsoft.com/ja-jp/azure/ai-foundry/openai/how-to/function-calling?view=foundry-classic&tabs=python-secure ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post AzureOpenAI入門:FunctionCallingで生成AI×ツールを実現する first appeared on SIOS Tech Lab .
日々の業務で、見積書・請求書・報告書・管理表など、 Excelが中心になっている現場 は少なくありません。一方で、ファイルが増え続けるほど「探す」「集計する」「整える」作業が重くなり、 時間とミスのリスク が膨らみがちです。 当社では、Excelのユーザー体験はそのままに、 自然言語で検索・集計・可視化まで行えるAIエージェントシステムの構築 を行っています。 現在、 無料で体験いただけるトライアル環境 を公開中です。まずは触ってみて、貴社の課題をお聞かせください。 M365アカウントを持っていない方、アドインを社内規定で追加できない方に対しても、当社側でテスト用のアカウントを払い出すため、どなたでもトライアルに参加いただけます。 無料トライアルを試す 相談・お問い合わせ メール : ka-sasaki@sios.com AIエージェント開発やDXに関するご相談も広く受け付けています。 「こんなことできる?」というアイデアベースのご相談も歓迎です。 こんな課題を解決します 課題 AIで解決 複数ファイルから必要なデータを探すのに 何時間もかかる 自然言語で 横断検索 、数秒で回答 毎月の集計作業で 半日かかる 「先月の売上を店舗別にグラフ化して」で 自動処理 担当者しかわからない 属人化 AIが構造を理解し、 誰でも検索可能 に 各システムからCSVを出力して Excelで手作業集計 システム連携で リアルタイム分析 Excel AI エージェントでできること 1. 過去のExcel帳票をそのままデータとして活用 結合セル、複数行ヘッダー、階層構造 を持つ複雑な帳票も、AIが構造を自動解析。 ファイルを取り込むだけで、検索・分析対象になります。 見積書・請求書 売上報告書(複数行ヘッダー) 料金表(結合セル多数) 管理台帳・マスタデータ   2. 過去の類似Excel帳票からドラフト作成 ユースケース : 過去に作成した帳票を学習し、新規作成時のドラフトを自動生成。 例: 「昨年のA社向け見積書をベースに、今年の単価で新しい見積書のドラフトを作って」 入力作業の大幅削減と、過去ナレッジの活用を同時に実現します。 3. 自然言語で検索・集計・グラフ作成 AIエージェントが あいまいな指示も理解 して処理を実行します。 質問例 AIの処理 「店舗Aの決済手段別売上をグラフに」 データ検索 → 集計 → グラフ生成 「先月より売上が下がった店舗は?」 期間比較 → 条件抽出 → 一覧表示 「完了していない作業は何件?」 ステータス値を理解 → カウント 4. 既存システムとの連携 Excelだけに閉じない、企業全体のデータ活用 が可能です。 SQLエージェント : 社内データベース(SQL Server、Oracle、PostgreSQL等)と連携 MCP対応 : 外部API・サービスとの柔軟な接続 ※ システム連携は、貴社環境に合わせた個別構築となります トライアル環境について 体験できること デモ環境には、以下のサンプルデータが用意されています: サンプル 内容 特徴 デモマート 小売業の売上データ 売上報告書(結合セル)、商品・店舗マスタ、トランザクション デモリゾート ホテル・リゾートの予約データ 宿泊料金表(複数行ヘッダー)、施設・客室マスタ、予約データ 試せる機能: 自然言語でのデータ検索 複数ファイルを横断した集計 グラフ・表の自動作成 書式設定の指示(「完了行を緑色に」等) 類似帳票からのドラフト作成 入力済みデータ例 トライアルの制約事項 デモ環境は機能検証を目的としており、以下の制約があります: お客様独自のデータ投入には対応していません(サンプルデータでの検証となります) 「自社データで試したい」 という場合は、PoC(概念実証)としてご相談ください。 データの取り扱いについて 項目 内容 AI学習利用 入力されたデータはAIの学習には使用しません アクセス制御 他のユーザーに入力内容が共有されることはありません。 データ削除 トライアル終了後、一定期間で削除いたします 商用環境の導入形態 クラウド基盤での提供 本システムは クラウド基盤 で提供します。ExcelアドインはMicrosoft 365上で動作し、バックエンドのAI処理はクラウドで実行されます。 構成 内容 フロントエンド Microsoft Excel アドイン(Office.js) バックエンド クラウド基盤(AI処理・検索エンジン) セキュリティ 閉域接続の構成も相談可能 貴社専用のAI環境を構築します 当社はこの技術を基盤とした「貴社専用のAIエージェントシステム構築」を行っています。 ご要望 対応内容 既存システムとの連携 基幹システム、CRM、ERPとの接続構築 社内DBとの接続 SQLエージェントで既存DBを分析対象に 独自フォーマット対応 業界特有・社内独自の帳票に最適化 セキュリティ要件 閉域接続など、貴社ポリシーに準拠した構成 まずはトライアルで技術の可能性を体感いただき、「自社のあの業務で使えるか?」をご検討ください。 その後、無償で簡易要件ヒアリングを実施し、貴社に最適なシステム構成をご提案します。 デモ動画 https://tech-lab.sios.jp/wp-content/uploads/2026/02/c7a3cb943abf893c211da41841707cc6.mp4 よくある質問 Q. どんなExcelファイルでも対応できますか? 結合セル、複数行ヘッダー、階層構造を持つ複雑な帳票にも対応しています。見積書、請求書、売上報告書、料金表など、様々なフォーマットで動作確認済みです。 Q. 既存のExcelファイルをそのまま使えますか? はい。ファイルをシステムにインポートするだけで、検索・分析対象になります。Excelのフォーマットを変更する必要はありません。 Q. 社内の基幹システムとも連携できますか? はい。SQLエージェント技術により、SQL Server、Oracle、PostgreSQLなど主要なデータベースとの連携が可能です。連携構築は貴社環境に合わせた個別対応となります。 Q. セキュリティ面が気になります 入力されたデータはAIの学習には使用しません。また、閉域接続の構成も相談可能です。貴社のセキュリティポリシーに合わせた構成をご提案します。 Q. 費用感を知りたいです 貴社の要件に応じた個別見積もりとなります。まずはトライアルで技術を体感いただき、要件ヒアリングの上でお見積もりいたします。 お問い合わせ 無料トライアルを試す 相談・お問い合わせ メール : ka-sasaki@sios.com AIエージェント開発やDXに関するご相談も広く受け付けています。 「こんな業務を自動化したい」 「既存システムとAIを連携させたい」 「まずは話を聞いてみたい」 本トライアルではM365アカウントを持っていない方、アドインを社内規定で追加できない方に対しても、当社側でテスト用のアカウントを払い出すため、どなたでもトライアルに参加いただけます。 どんなご相談でもお気軽にお問い合わせください。   ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Excel AI エージェント 無料トライアルを開始しました! first appeared on SIOS Tech Lab .
前回の記事ではSCANOSS CLIを使ったローカルスキャンの手順 を紹介しました。ローカルで動作確認ができたら、次はCI/CDパイプラインへの統合です。 本記事では、 SCANOSS Code Scan Action を使ったGitHub Actionsでのコードスキャン自動化の手順を紹介します。 この記事でわかること : GitHub Actionsでの基本的なスキャン設定と実行方法 ポリシーチェック(Copyleft / Undeclared)の設定と挙動 API Keyあり/なしの挙動差(GitHub ActionsではAPI Key必須) scanoss.jsonによるスキャン結果の制御とポリシーチェックへの影響 サブディレクトリスキャンやスキャンチューニングの活用方法 前提条件 GitHubリポジトリにActions実行権限があること SCANOSS API Keyを取得済みであること( SCANOSSとの契約 が必要) リポジトリのSettings > Secrets に SCANOSS_KEY を登録済みであること 基本スキャン(Non-Policy) 最もシンプルな構成です。ポリシーチェックなしで、コードスキャンのみを実行します。 # .github/workflows/scanoss-scan.yml name: SCANOSS Security Scan on: workflow_dispatch: permissions: contents: write pull-requests: write checks: write actions: read jobs: scanoss-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: scanoss/gha-code-scan@v1.5.0 with: api.key: ${{ secrets.SCANOSS_KEY }} 実行すると、以下のArtifactが自動生成されます。 Artifact 内容 scanoss-raw.json スキャン結果(JSON) scanoss-cyclonedx.json CycloneDX SBOM scanoss-spdxlite.json SPDX-Lite SBOM scanoss-sbom.csv CSV形式レポート 今回の検証では、実行時間は約33秒でした(Docker imageのpull含む)。 ポリシーチェック付きスキャン(Full Policy) ライセンスポリシーの自動チェックを有効にする構成です。 - uses: scanoss/gha-code-scan@v1.5.0 with: policies: copyleft, undeclared, dt matchAnnotations: false api.key: ${{ secrets.SCANOSS_KEY }} ポリシー チェック内容 copyleft コピーレフトライセンス(GPL等)の混入検出 undeclared 未宣言のOSSコンポーネントの検出 dt Dependency Track サーバーとの連携チェック チェック結果はGitHubのChecks APIを通じてCheck Runとして表示されます。今回の検証では、Copyleft: success、Undeclared: success、Dependency Track: failure(サーバー未構築のため)という結果でした。 matchAnnotations はスニペットマッチ検出時にコミットコメントを自動作成する機能です。デフォルトは true で、不要な場合は false を指定してください。 Dependency Trackポリシーについて dt ( Dependency Track )ポリシーを使うには、Dependency Trackサーバーの構築と以下のパラメータ設定が必要です。 deptrack.url deptrack.apikey deptrack.projectid (または deptrack.projectname + deptrack.projectversion ) 設定がない場合はwarningが出ますが、ワークフロー全体はsuccessで完了します。Dependency Track連携が不要であれば、 policies: copyleft, undeclared のように dt を外しても問題ありません。 API Keyは必須 ローカルスキャンではAPI Keyなしでも動作しましたが、 GitHub ActionsではAPI Keyが必須です 。 API Keyなしで実行した場合、以下のエラーが即座に返されます。 ERROR: SCANOSS API rejected the scan request due to service limits being exceeded ERROR: Details: {"error":"Rate limit exceeded","retry_after":411781} retry_after の値は約411,788秒(約5日)です。つまり約5日に1回しかリクエストできない計算になります。GitHub Actionsの共有IPからの無料APIへのアクセスがレート制限に達しているため、API Keyなしでは実質的にスキャンできません。(お試しでは十分です!あとは週次スキャンには対応できますね…) 項目 API Keyあり API Keyなし 接続先 Premium API api.osskb.org/scan/direct ステータス success failure(HTTP 503) 実行可否 可能 不可 サブディレクトリスキャン scanPath パラメータで、スキャン対象をリポジトリの特定ディレクトリに限定できます。 - uses: scanoss/gha-code-scan@v1.5.0 with: scanPath: ./application api.key: ${{ secrets.SCANOSS_KEY }} 今回の検証では、ルートスキャンとサブディレクトリスキャンでスキャン結果が大きく変わりました。 項目 ルートスキャン サブディレクトリスキャン スニペットマッチ 0件(filtered) 5件 検出ライセンス 0 3 ルートスキャンではMarkdown等のドキュメントファイルが大量に含まれるため、コードファイルのスニペットマッチがfilteredされていました。 scanPath でコードディレクトリのみに絞ることで、検出精度が向上します。モノレポ構成では積極的に活用してください。 なお、 scanPath を指定すると scanoss.json の読み込みパスも変わります。詳しくは後述の「scanoss.jsonによるスキャン制御」セクションを参照してください。 scanoss.jsonによるスキャン制御 リポジトリに scanoss.json を配置すると、スキャン結果のフィルタリングやポリシーチェックの挙動を制御できます。GitHub Actionsではデフォルトで自動読み込みが有効( scanossSettings: true )になっているため、ファイルを配置するだけで設定が反映されます。 読み込みの仕組み scanoss.json はスキャン対象ディレクトリの直下から自動的に読み込まれます。 scanPath 読み込まれるscanoss.json . (デフォルト) リポジトリルートの scanoss.json ./application application/scanoss.json scanPath を指定している場合、ルートの scanoss.json は読み込まれません。 settingsFilepath パラメータで明示的にパスを指定するか、 scanPath で指定したディレクトリに scanoss.json を配置してください。 設定できる内容 scanoss.json では以下の3つの制御が可能です( 公式ドキュメント )。 { "bom": { "include": [ { "purl": "pkg:github/owner/repo", "comment": "宣言済みコンポーネント" } ], "remove": [ { "path": "src/app.py", "purl": "pkg:github/owner/repo", "comment": "誤検出" } ] }, "skip": { "patterns": ["*.pyc", "__pycache__/**", "docs/**"] }, "settings": { "file_snippet": { "min_snippet_hits": 3, "min_snippet_lines": 5, "ranking_enabled": true, "ranking_threshold": 5, "honour_file_exts": true } } } セクション 効果 ポリシーへの影響 bom.include コンポーネントを「宣言済み」としてAPIに送信 Undeclared違反を解消できる bom.remove 指定したpath + purlの組み合わせを結果から除外 除外されたコンポーネントはポリシーチェック対象外になる skip.patterns マッチしたファイルをスキャン対象から除外 スキャンされないためポリシーチェックにも影響しない settings.file_snippet スニペットマッチの感度を調整(v1.5.0) 感度を下げることで誤検出を減らせる Undeclaredポリシーとの連携 undeclared ポリシーは、スキャンで検出されたOSSコンポーネントが bom.include で宣言されていない場合に違反として報告します。 運用の流れは以下の通りです。 Full Policyスキャンを実行し、Undeclared違反が報告される 違反コンポーネントのPURLをスキャン結果から確認する 正しく使用しているものであれば、 bom.include にPURLを追加する 再スキャンでUndeclared違反が解消されることを確認する スキャンチューニング(v1.5.0) v1.5.0から、 scanoss.json の settings.file_snippet セクションでスニペットマッチの感度を調整できるようになりました。最小ヒット数や最小行数の閾値を設定することで、誤検出を減らすことができます。 チューニングパラメータはGitHub Actionの入力パラメータではなく、 scanoss.json で設定します。詳細は 公式ドキュメント(Scan Tuning Parameters) を参照してください。 推奨する運用フロー scanoss.json なしでスキャンを実行し、検出結果を確認する 誤検出があれば bom.remove で除外、正規利用のOSSは bom.include で宣言する 不要なファイル(テストデータ、ドキュメント等)は skip.patterns で除外する スニペットの誤検出が多い場合は settings.file_snippet で感度を調整する scanoss.json をリポジトリにコミットし、以降のCI/CDスキャンに反映させる 段階的な導入ステップ API Keyの準備 : SCANOSSとの契約後、GitHub Secretsに SCANOSS_KEY を登録 Non-Policyで開始 : 基本スキャンで動作確認( workflow_dispatch トリガー) 結果の確認 : Artifactから scanoss-raw.json をダウンロードして内容確認 Full Policyに拡張 : policies: copyleft, undeclared を追加 チューニング : 誤検出が多い場合は scanoss.json で感度を調整 PRトリガーに変更 : workflow_dispatch → pull_request に変更して自動化 まとめ SCANOSS GitHub Actionsを使ったCI/CDでのコードスキャン自動化の手順を紹介しました。 項目 ポイント API Key GitHub ActionsではAPI Key必須(無料APIはレート制限で使用不可) ポリシーチェック copyleft / undeclaredで自動チェック。Dependency Trackはサーバーが別途必要 scanPath サブディレクトリ指定で検出精度が向上。scanoss.jsonの読み込みパスに注意 チューニング v1.5.0でスニペットマッチの感度調整が可能に(scanoss.jsonで設定) バージョン v1.5.0推奨。v1.4.0から後方互換性あり 参考資料 関連リンク SCANOSS Code Scan Action(GitHub リポジトリ) SCANOSS Code Scan Action(GitHub Marketplace) SCANOSS 公式ドキュメント scanoss-py 公式ドキュメント SCANOSS Pricing Dependency Track ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post SCANOSS GitHub Actionsでコードスキャンを自動化 first appeared on SIOS Tech Lab .
AI開発ツールの普及に伴い、ソースコードに含まれるOSSライセンスリスクへの対応が避けられなくなってきました。SCA(Software Composition Analysis)ツールを使うと、コードベースに混入したOSSコンポーネントを自動検出し、ライセンス違反や既知の脆弱性を可視化できます。 本記事では、SCAツール「 SCANOSS 」のPython CLI( scanoss-py )を使ったローカルスキャンの手順を紹介します。 この記事でわかること : scanoss-pyのインストールから基本スキャン、結果の読み方 scanoss.jsonによる誤検出のチューニング方法 CycloneDX / SPDX / CSV形式でのSBOM生成 ScanCode Toolkit連携による依存関係スキャン(uv環境での回避策含む) 検証環境 項目 内容 OS Linux(WSL2 / devcontainer) Python 3.12 パッケージ管理 uv scanoss-py 1.45.1 API Key なし(匿名 / OSSKB パブリック API) 今回はAPI Keyなし(無料の OSSKBパブリックAPI )で検証しています。小〜中規模のプロジェクトであれば、API Keyなしでも十分に利用できます。 インストール pip または uv でインストールできます( PyPI: scanoss )。 # pip の場合 pip install scanoss # uv の場合(dev依存として追加) uv add --dev scanoss インストール後、バージョンを確認します。 $ scanoss-py version Version: 1.45.1 scanoss-py --help でサブコマンド一覧を確認できます。主なサブコマンドは以下の通りです。 サブコマンド 説明 scan ソースコードのスキャン fingerprint フィンガープリント(WFP)の生成 dependencies 依存関係のスキャン convert スキャン結果のフォーマット変換 file_count ファイル数・サイズのサマリー 基本スキャン ファイル数の確認 スキャン前に、対象ディレクトリのファイル構成を確認できます。 $ scanoss-py file_count ./src Found 144 files with a total size of 7.16 MB. extension,count,size(MB) .py,47,0.20 .pyc,44,0.39 .html,21,0.07 .png,21,5.90 144ファイルありますが、実際にスキャン対象となるのはソースコードファイルのみです。バイナリ(.png)や.pycは自動的に除外されます。 スキャンの実行 $ scanoss-py scan -o results.json ./src 実行すると、対象ファイルのフィンガープリントを生成し、 OSSKB (Open Source Knowledge Base)のナレッジベースと照合します。OSSKBには2億7,600万以上のURL [1] がインデックスされており、OSSファイル1億以上 [1] 、コード行数3兆行以上 [1] をカバーしています。今回の検証では48ファイルのスキャンが約5秒で完了しました。 スキャン結果の読み方 結果はJSON形式で出力されます。各ファイルごとにマッチ情報が記録されます。 { "src/app.py": [ { "id": "snippet", "component": "some-oss-project", "matched": "18%", "lines": "24-31", "oss_lines": "513-520", "purl": ["pkg:github/owner/repo"], "licenses": [{ "name": "MIT", "copyleft": "no" }], "url": "https://github.com/owner/repo", "status": "pending" } ] } 主要フィールドの意味は以下の通りです。 フィールド 説明 id マッチ種別。 none (マッチなし)/ snippet (部分一致)/ file (完全一致) matched マッチ率 lines / oss_lines 自分のコード / OSSコードの該当行範囲 purl Package URL(コンポーネントの一意識別子) licenses 検出されたライセンス情報( copyleft フラグ付き) status レビュー状態( pending = 未レビュー) 今回の検証結果は以下の通りです。 項目 件数 スキャン対象 48ファイル マッチなし(id=none) 43 スニペットマッチ(id=snippet) 5 フルファイルマッチ(id=file) 0 自社開発のコードなので、フルファイルマッチ(OSSファイルの完全コピー)は0件。5件のスニペットマッチが検出されましたが、いずれもDockerfileやpytestの定型パターンによるもので、実質的な誤検出でした。 scanoss.jsonで検出結果をチューニングする 初回スキャンで誤検出が含まれる場合、 scanoss.json で検出結果を制御できます( 公式ドキュメント )。 設定ファイルの構成 { "bom": { "include": [ { "purl": "pkg:github/owner/repo", "comment": "宣言済みコンポーネントとして登録" } ], "remove": [ { "path": "src/app.py", "purl": "pkg:github/owner/repo", "comment": "誤検出のため除外" } ] }, "skip": { "patterns": ["*.pyc", "__pycache__/**"] } } セクション 効果 bom.include スキャン時に追加コンテキストとしてPURLをAPIに送信する [2] bom.remove スキャン後の結果から特定PURLを除去する [2] skip.patterns マッチしたファイルをスキャン対象から除外する [2] 設定を適用してスキャン $ scanoss-py scan --settings /absolute/path/to/scanoss.json -o results.json ./src 設定適用前後の比較結果です。 ファイル Before After app.py ollama-workbench (18%) マッチなし(removeで除外) Dockerfile ip-query-system (62%) minimage (39%)(includeにより次候補に変化) scanoss.jsonの注意点 検証を通じて、いくつか注意すべき点が見つかりました。 --settings には絶対パスを指定する 相対パスを指定すると、カレントディレクトリではなくスキャン対象ディレクトリからの相対パスとして解決されます。 # NG: パスが「src/path/to/scanoss.json」と結合される scanoss-py scan --settings path/to/scanoss.json ./src # OK: 絶対パスなら問題なし scanoss-py scan --settings /home/user/scanoss.json ./src bom.remove はpathとpurlの完全一致が必要 スキャン結果のpurlと設定ファイルのpurlが一致しないと除外されません。必ず初回スキャン結果のpurlを確認してから設定してください。 bom.include はマッチを消すのではなく「宣言済み」にする includeに登録しても、スキャン結果からマッチ自体が消えるわけではありません。該当コンポーネントが「宣言済み」として扱われ、スキャン結果は次候補のコンポーネントに変化する場合があります。 SBOM生成 スキャン結果を業界標準のSBOM形式に変換できます。 # CycloneDX scanoss-py convert -i results.json -f cyclonedx -o sbom.cdx.json # SPDX-Lite scanoss-py convert -i results.json -f spdxlite -o sbom.spdx.json # CSV scanoss-py convert -i results.json -f csv -o results.csv 3形式の使い分けは以下の通りです。 形式 用途 CycloneDX Dependency Track等のSBOM管理ツールへの連携 SPDX-Lite ライセンスコンプライアンス管理(業界標準仕様) CSV Excelやスプレッドシートでの手動レビュー 注意点として、CycloneDX出力は拡張子を .xml にしても実際の出力はJSON形式です。XML形式での出力が必要な場合は別途変換が必要です。 依存関係スキャン scanoss-pyは、 requirements.txt や pyproject.toml 等から依存パッケージを検出する機能も備えています。ただし、この機能には ScanCode Toolkit が別途必要です。 セットアップ # 1. scancode-toolkit のインストール pip install scancode-toolkit # または uv add --dev scancode-toolkit # 2. libgomp1 のインストール(Debian系のslimイメージの場合) sudo apt-get install -y libgomp1 # 3. 動作確認 scancode --version # → ScanCode version: 32.5.0 uv環境での注意点 ScanCode Toolkitは uv.lock に対応していません( GitHub Issue #4501 、2026年2月時点でOpen)。サポート対象のパッケージマニフェスト形式は 公式ドキュメント で確認できます( requirements.txt 、 pyproject.toml 、 poetry.lock 、 Pipfile.lock 等は対応済み)。 uv環境で依存関係をスキャンする場合、 uv export で requirements.txt に変換する必要があります。 uv export --format requirements-txt --no-hashes --no-emit-workspace -o requirements.txt なお、 --no-dev オプションを付けると、直接依存がすべてdev依存のプロジェクトでは空ファイルになります。必要に応じてオプションを調整してください。 依存関係スキャンの実行 # dep サブコマンド(API送信なし、ローカルのみ) scanoss-py dep \ --sc-command /path/to/.venv/bin/scancode \ -o dependencies.json ./src # scan --dependencies(通常スキャン + 依存関係スキャン) scanoss-py scan --dependencies \ --sc-command /path/to/.venv/bin/scancode \ -o results.json ./src ディレクトリを指定すると、ScanCode Toolkitが配下の requirements.txt や pyproject.toml 等のマニフェストファイルを自動検出してパースします。個別にファイルを指定する必要はありません。 --sc-command にはscancode実行ファイルの 絶対パス を指定します。 uv run scancode のような形式は内部のsubprocess呼び出しの都合で使えません。 dep サブコマンドと scan --dependencies の違いは以下の通りです。 dep scan --dependencies SCANOSS API送信 なし あり ライセンス情報の付与 なし あり 用途 事前確認・デバッグ フルSBOM生成 フィンガープリントの活用 fingerprint サブコマンドを使うと、スキャンとAPI送信を分離できます。 # フィンガープリントの生成(オフラインでもOK) scanoss-py fingerprint -o fingerprint.wfp ./src # 後からスキャン(ネットワーク接続時) scanoss-py scan --wfp fingerprint.wfp -o results.json ネットワークに接続できない環境でフィンガープリントだけ先に生成し、接続時にスキャンを実行するワークフローに活用できます。 運用上のポイント 検証を通じて得られた実践的なポイントをまとめます。 推奨ワークフロー 初回スキャン を設定なしで実行し、検出結果を確認する 誤検出を確認し、 scanoss.json を作成してチューニングする チューニング後の結果に問題がなければ、 SBOM を生成する scanoss.jsonをリポジトリに含め、CI/CDでの継続的スキャンに移行する デフォルトの設定ファイル探索 scanoss-pyは、 --settings を指定しなくても、スキャン対象ディレクトリ直下の scanoss.json を自動的に読み込もうとします。リポジトリのルートに scanoss.json を配置しておけば、オプション指定なしでチューニング済みのスキャンを実行できます。 API Keyなしとありの違い 今回の検証はAPI Keyなし(OSSKBパブリックAPI)で実施しています。小〜中規模のプロジェクトであればAPI Keyなしで十分ですが、本番運用ではAPI Keyの利用を検討してください。 項目 API Keyなし API Keyあり 基本スキャン 利用可能 利用可能 可用性保証 なし SLA保証あり スループット保証 なし 保証あり ナレッジベース更新 四半期ごと リアルタイム同期 API Keyありでスキャンする場合は、 --key オプションを指定します。 scanoss-py scan --key YOUR_API_KEY -o results.json ./src API Keyの取得には SCANOSSとの契約 が必要です。CI/CD環境で利用する場合は、GitHub Actionsの secrets.SCANOSS_API_KEY のようにシークレットとして管理してください。 今回の検証規模(48ファイル)では、API Keyなしでもレート制限に抵触せず、スキャン速度も5秒程度と快適でした。なお、具体的なレート制限値は公式ドキュメントに記載されていないため、大規模プロジェクトでの利用時はSCANOSSへの問い合わせを推奨します。 まとめ scanoss-pyを使ったローカルスキャンの手順を一通り紹介しました。 機能 ポイント 基本スキャン API Keyなしで即実行可能。バイナリは自動除外 scanoss.json 誤検出のチューニングに必須。purlの完全一致と絶対パス指定に注意 SBOM生成 CycloneDX / SPDX / CSVの3形式に対応 依存関係スキャン ScanCode Toolkitが別途必要。uv.lockは未対応 ローカルスキャンで動作を確認した後は、CI/CDパイプラインへの統合(GitHub Actionsの SCANOSS Code Scan Action 等)を検討することで、プルリクエスト単位での自動チェックが可能になります。 参考資料 # 出典 [1] OSSKB – Software Transparency Foundation [2] scanoss-py 公式ドキュメント 関連リンク scanoss-py GitHub リポジトリ scanoss-py PyPI SCANOSS 公式ドキュメント OSSKB API ドキュメント ScanCode Toolkit GitHub リポジトリ ScanCode Toolkit 対応パッケージパーサー一覧 SCANOSS Code Scan Action(GitHub Actions) ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post SCANOSS CLIでローカルスキャン:インストールからSBOM生成まで first appeared on SIOS Tech Lab .
今日から使えるGemini活用術シリーズ(全3回) ググる前に、まずGemini。日常がちょっとラクになる3つの使い方 Geminiの回答が「ちょっとズレる」人へ。一言足すだけで変わる3つのコツ ← この記事! 毎回コピペはもう卒業。Geminiの「Gem」で選ぶだけにする方法 ども!普段はエンジニア向けにAIの記事を書いている龍ちゃんです。前回に引き続き、エンジニアじゃない方に向けて書いていきます。 前回紹介した「ググる・読む・書く」の3つの習慣、試してみましたか? 便利なんだけど、使っていくうちに「そうじゃないんだよな…」って回答が返ってくること、ありません? 聞いたことには答えてくれてるんだけど、なんか微妙にズレてる。欲しかったのはそこじゃない、みたいな。 これ、Geminiが悪いわけじゃないんですよね。自分が何を求めているか、Geminiには伝わっていないだけなんです。 今回は、そのズレをなくす3つのコツを紹介します。そんなに難しく考えなくて大丈夫です。 いつもの質問に、一言足すだけ。 前回出てきた「プロンプト」(Geminiへの指示文)に、ちょっとだけ情報を足してあげる。それだけでGeminiの回答精度はぐんと上がります。 コツ1: 「何を知りたいか」を絞る 来週の商談、相手の会社のこと調べなきゃ…ってとき、Geminiに「○○社について教えて」って聞いたことありません? 返ってきたのは、ふんわりした会社概要。設立年とか従業員数とか。知りたかったのはそこじゃないんですよね。 こういうとき、漠然と聞くとGeminiは自分が持っている情報からなんとなく答えようとします。知りたいのが最新のニュースなのか、競合との比較なのか、Geminiにはわからない。Geminiが見ている情報と、自分が欲しい情報のギャップ——それがズレの正体です。 じゃあどうするか。「何を知りたいか」を箇条書きで伝えるだけです。 下の文章をまるごとコピーして、Geminiの入力欄に貼り付けてみてください。○○の部分は自分の状況に合わせて変えてくださいね。 来週○○社と商談があります。以下の観点で情報を整理してください。 - ○○社の主力サービス(3つ以内) - 最近のプレスリリースやニュース - 当社の△△と競合する可能性がある領域 「何を知りたいか」を箇条書きにしただけで、返ってくる情報の精度が全然違います。僕がよく使うのは「今日が○月○日で、直近3ヶ月以内の情報に絞って」と日付を入れるやり方です。これだけで古い情報に引っ張られにくくなります。 ただし、Geminiの知識には更新の時点があります。「最近のニュース」と聞いても、数ヶ月前の情報が返ることがある。最新情報がどうしても必要なときは、Geminiに検索させると精度がずっとよくなります。詳しいやり方はこちら。 2026-01-28 Geminiに検索させるプロンプト術|リサーチGemの作り方 コツ2: 「誰として答えて」を伝える やってしまいがちなのが、下書きをそのまま貼って「これ直して」とだけ伝えるやつです。 Geminiは直してくれます。でも、なんか無難すぎる。温度感が違う。丁寧ではあるんだけど、自分が書いた感じがしない。 「直して」にも方向があるんですよね。丁寧にしたいのか、カジュアルにしたいのか、角を立てないようにしたいのか。それをGeminiは知らない。 ここも一言足すだけです。「あなたは○○です」と伝えるだけで、回答のトーンがガラッと変わります。 下の文章をコピーして、Geminiに貼り付けてみてください。()の中は自分の下書きに差し替えてくださいね。 あなたは10年目のベテラン営業です。 以下の断りメールを、今後の関係性を壊さないように修正してください。 私の言いたいことは変えないでください。 (自分の下書きを貼る) 相手:取引先の部長(長い付き合い) 「10年目のベテラン営業」という一言が入るだけで、言い回しに経験値が乗ります。断り方のニュアンスが、ぐっと実務寄りになる。 「私の言いたいことは変えないでください」も大事です。これがないと、Geminiが親切心で中身まで変えてくることがあります。 ただし、修正結果は必ず自分で読み返してください。特に固有名詞や数字。Geminiが「よかれと思って」変えていることがあります。最終判断は自分です。 コツ3: 「この形で出して」を指定する 会議が終わって、手元に残っているのは走り書きのメモだけ。これを議事録にまとめなきゃいけないんだけど、あの作業、地味にしんどくないですか。 Geminiに「まとめて」と投げるとまとめてくれます。ただ、出てきた形がそのまま使えない。決定事項とTODOだけ知りたいのに、考察や補足まで入ってくる。Geminiは情報と自分の考えを混ぜて出してきます。 こういうときは、見本を渡してしまえばいい。 下の文章をコピーして、走り書きメモと一緒にGeminiに貼り付けてみてください。 以下の会議の走り書きメモを、このフォーマットで整理してください。 ■ 決定事項(箇条書き) ■ TODO(担当者・期限を表で) ■ 次回までの持ち越し事項(1行ずつ) メモに書いてないことは追加しないでください。 (走り書きメモを貼る) フォーマットを見せるだけで、Geminiは「この形に合わせよう」と動きます。「メモに書いてないことは追加しないで」が地味に大事で、これがないとGeminiが補完して情報を足すことがあります。 メモが断片的すぎると、フォーマットを指定してもGeminiが空白を埋めようとすることはあります。そういうときは、フォーマットより先に走り書きの質を上げるほうが早い。箇条書きでもいいので、会議中に「誰が」「何を」決めたかだけはメモしておくと、Geminiの出力が安定します。 まとめ 今回紹介した3つのコツ、どれもやっていることは同じです。 「何を知りたいか」を絞る 「誰として答えて」を伝える 「この形で出して」を指定する いつもの質問に、一言足すだけ。 これだけで、Geminiの回答はぐんと変わります。 まずは1つ、今日の仕事で試してみてください。 でも正直、毎回こういうプロンプトを打ち込むのは面倒なんですよね。次回は、よく使うプロンプトをGeminiに覚えさせて「選ぶだけ」にする方法を紹介します。 ではまた! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Geminiの回答が「ちょっとズレる」人へ。一言足すだけで変わる3つのコツ first appeared on SIOS Tech Lab .
今日から使えるGemini活用術シリーズ(全3回) ググる前に、まずGemini。日常がちょっとラクになる3つの使い方 ← この記事 ! Geminiの回答が「ちょっとズレる」人へ。一言足すだけで変わる3つのコツ 毎回コピペはもう卒業。Geminiの「Gem」で選ぶだけにする方法 ども!普段はエンジニア向けにAIの記事を書いているんですが、最近「Geminiって何に使えばいいの?」と聞かれることが増えたので、今回はエンジニアじゃない方に向けて書いてみます。龍ちゃんです。 「会社でGemini使えるらしいんですけど、正直あんまり使ってなくて…」 これ、めちゃくちゃ聞きます。使えるのは知ってる。でも何を聞けばいいのかわからない。使い道がピンとこない。そんな方、多いんじゃないでしょうか。 安心してください。難しいテクニックの話は一切しません。やることは1つだけです。 ググる前に、Geminiを開く。 Google Workspace(Business Starter以上)を使っている会社なら、Geminiは追加コストなしで今すぐ使えます。この記事では、それだけで日常がちょっとラクになる使い方を3つ紹介します。具体的には、①気になることを聞く、②資料を要約させる、③文章を見てもらう、の3つです。 ちょっと気になってたこと、聞いてみる Geminiの使い方自体はシンプルで、聞きたいことを打ち込むだけです。ただ、いざ仕事で使おうとすると「で、何を聞けばいいんだっけ?」って手が止まりません? 実は、仕事のことじゃなくていいんですよね。まずはプレッシャーゼロのことから試してみましょう。 たとえば、こういうのありません? 「腸活って最近よく聞くけど、結局なにすればいいの?」 「新NISAって始めたほうがいいの?ざっくり知りたい」 「昼寝って何分がベストなの?逆に疲れるときあるんだけど」 気になるけど、わざわざ調べるほどでもないな…で後回しにしてきたやつです。 ググるとなると、検索結果から記事を選んで、読んで、この情報は信頼できるのかな…って判断するのが地味に面倒なんですよね。Geminiなら、なんとなく聞いたら、なんとなく答えてくれる。しかも最新の情報も拾ってきてくれます。この気軽さがいい。 試してみよう Geminiを開いたら、下の文章をまるごとコピーして、入力欄に貼り付けてみてください。(Geminiへの指示文のことを「プロンプト」と呼びます。覚えなくて大丈夫です) 最近よく聞く「腸活」って、結局なにをすればいいの? こんなのでもOKです。 「在宅勤務で腰が痛い。ストレッチ3つ教えて」 「コーヒーは1日何杯まで大丈夫?」 別に正確な答えが欲しいわけじゃなくて、「とっかかり」が欲しいだけなんですよね。そういうとき、Geminiは「ちょっと詳しい友達」くらいの感覚で使えます。 プライベートで1回試してみたら、次は仕事でも同じ感覚で使えます。 読む前に、まず要約させる 上司から「これ読んどいて」と共有された長い資料。業界ニュースの記事。「あとで読もう」と思ってタブだけ増えていく、あの感じ。 これ、Geminiに丸投げできます。やり方はシンプルです。 Webページの場合:ページのURLをコピーして、Geminiの入力欄に貼る PDFの場合:Geminiの入力欄にあるファイルアイコン( )からPDFを選ぶ その後にプロンプトを続けて入力するだけ。それだけで「読む前の仕分け」ができてしまいます。 試してみよう 放置しているURLやPDFを上の方法でGeminiに渡したら、続けて下のプロンプトをコピーして貼り付けてみてください。 この内容を以下の形式で要約してください。 - 結論(1行) - 要点(3つ) - 自分が読むべきかの判断(読むべき/斜め読みでOK/スキップ可) 「読むべきかの判断」を聞くのがコツです。結論が1行で出てくるだけで「あ、これは後でいいや」とか「ここだけ読めばOKか」って判断できる。全部読まなくていいってわかるだけで、タブを閉じる気になれます。僕はこれを知ってから「あとで読む」タブを溜め込む罪悪感がだいぶ減りました。 読む側でGeminiを使えたら、次は自分が書く側でも使ってみましょう。 送る前に、見てもらう メールやチャットを送る前に「この言い方で大丈夫かな…」って迷う瞬間、ありますよね。特に上司やクライアント宛だと、言い回しに悩んで時間が溶ける。 ここでのコツは、AIに0から書かせるんじゃなくて、 自分の下書きを見てもらう ことです。自分で書いた文章をGeminiに貼って「これで大丈夫?」と聞く。それだけで的外れにならないし、自分らしい文章のまま変なところだけ直してくれます。 試してみよう 下書きができたら、Geminiの入力欄にこう貼るだけです。 以下は私が書いた【お断りメール】の下書きです。 (ここに自分の下書きを貼る) このまま送って大丈夫か確認して、改善点があれば直してください。 相手との関係性:【クライアント】 【】の部分を変えるだけで、上司宛でも同僚宛でも使い回せます。社内の文章を使っても大丈夫。Workspaceのプランなら、入力した内容はAIのトレーニングに使われません( Google公式ドキュメント )。 まとめ 今回紹介した3つの使い方、どれも「Geminiを開いて、聞くだけ」です。 ちょっと気になること → 聞いてみる 読む前の資料 → 要約させる 送る前の文章 → 見てもらう 個人的には2番目の要約が一番おすすめです。僕もこれを使い始めてから、放置タブが目に見えて減りました。 聞き方に正解なんてありません。まず1つ、今日試してみてください。 使っていくうちに「もうちょっとこう答えてほしいんだよな」って思う瞬間が出てくるはずです。次回は、その「ズレ」をなくすための簡単なコツを紹介します。 「もっと本格的にGeminiで調べ物がしたい!」という方は、こちらの記事もどうぞ。 Geminiに検索させるプロンプト術|リサーチGemの作り方 技術ブログ品質チェック術|Gemini Deep Researchで5分検証 ではまた! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post ググる前に、まずGemini。日常がちょっとラクになる3つの使い方 first appeared on SIOS Tech Lab .
今日から使えるGemini活用術シリーズ(全3回) ググる前に、まずGemini。日常がちょっとラクになる3つの使い方 Geminiの回答が「ちょっとズレる」人へ。一言足すだけで変わる3つのコツ 毎回コピペはもう卒業。Geminiの「Gem」で選ぶだけにする方法 ← この記事! ども、龍ちゃんです。非エンジニア向けGemini活用術、最終回です。 前回の3つのコツ——「何を知りたいか絞る」「誰として答えて」「この形で出して」——は便利なんですけど、毎回打ち込むのが地味に面倒ですよね。 この記事では、その指示を一度Geminiに保存して 選ぶだけで使えるようにする 方法を紹介します。使うのは Gem(ジェム) という機能です。 Gemとは? — 30秒で理解 Gemは、自分専用のAIアシスタントを作れる機能です。 イメージとしては、スマホのホーム画面によく使うアプリを置いておく感じ。いつもGeminiに伝えている指示を先に登録しておくと、次からはメニューから選ぶだけで、その指示が入った状態から会話を始められます。 設定はかんたんで、名前をつけて指示を書くだけ。プログラミングの知識は一切いりません。 ちなみに、Gemを使うにはGoogle Workspace Business Standard以上のプランが必要です。第1回で紹介したGeminiの基本機能はStarterでも使えますが、Gemは上位プランの機能になります。 Gemを作ってみよう — リサーチアシスタント編 実際に1つ作ってみましょう。今回は「調べ物を整理してくれるGem」を作ります。 Step 1: Gemマネージャーを開く Geminiのトップ画面を開いて、左メニューにある「Gem マネージャー」をクリックしてください。 Step 2: 「Gemを作成」をクリック Gemマネージャーが開きます。Googleが最初から用意してくれているGemがいくつか並んでいますが、今回は自分で作ります。右端の「Gemを作成」をクリックしてください。 Step 3: 名前とカスタム指示を入力する Gem作成画面が開きます。入力するのは2つだけです。 名前 : 「リサーチアシスタント」と入力 カスタム指示 : ここがGemの心臓部。Geminiに毎回伝えたい指示を書く欄です カスタム指示には、下の枠内をそのままコピーして貼り付けてみてください。 あなたはリサーチアシスタントです。 ユーザーが調べたいテーマを伝えたら、以下の形式で情報を整理してください。 - 結論(1〜2行) - 要点(3〜5つ、箇条書き) - 注意点や補足(あれば1〜2行) 情報源が不確かな場合は「要確認」と明記してください。 前回紹介した「何を知りたいか絞る」コツと「この形で出して」を組み合わせたものですね。これを毎回打たなくてよくなるわけです。 ちなみに、画面にはAIがカスタム指示を自動で書き直してくれる機能もあります。見つけても使わなくて大丈夫です。僕も試したんですけど、盛り盛りに書き換えてくるので、結局自分で書いたシンプルなもののほうが使いやすかったんですよね。 Step 4: 保存して、使ってみる 「保存」をクリックすると、左メニューにGemが追加されます。Gem名をクリックすれば、専用のチャット画面が開きます。 ここがポイントです。さっき入力したカスタム指示には、「何を知りたいか絞る」「この形で出して」がもう入っています。だから、あとは「○○について教えて」と聞くだけ。観点も形式も、Gemが覚えてくれている。毎回の型入力はもう不要です。 商談前の企業調査、社内で聞かれたトピックの整理、ちょっとした技術調査——こういう「調べてまとめる」系の作業は、このGem1つでかなりラクになります。 もう1つ作ってみよう:メール添削Gem コツがわかったところで、もう1つ作ってみましょう。 前回紹介した「誰として答えて」のコツ、覚えていますか? あの役割指定を、Gemに最初から入れておけます。 Gemマネージャーを開いて「Gemを作成」をクリック——ここまではさっきと同じです。名前を「メール添削アシスタント」にして、カスタム指示に下の枠内をそのままコピーして貼り付けてください。 あなたはビジネスメールの添削者です(10年以上の実務経験あり)。 ユーザーが下書きを貼ったら、以下のルールで修正してください。 - ユーザーの言いたいことは変えない - 敬語の過不足を直す - 曖昧な表現を具体的にする - 修正した箇所は【】で囲んで示す 相手との関係性をユーザーが指定した場合は、それに合わせてトーンを調整してください。 保存したら、あとはGemを選んで下書きを貼るだけです。「相手:取引先の部長」と一言添えると、トーンまで合わせてくれます。 毎回「あなたは10年目のベテラン営業です」って打ち込まなくていい。選ぶだけ。これがGemの便利さです。 Gemを使うときの注意点 便利な機能ですが、知っておいてほしいことが3つあります。 まず前提として、Gemini自体の限界はGemでも変わりません。情報が間違っていることもあるので、数字や固有名詞は大事な場面で自分でも確認する習慣をつけておいてください。 もう1つ。 会話が長くなると精度が落ちることがあります (会話が長くなると馬鹿になるってのは実際にあります)。「なんか最近ズレるな」と感じたら、新しいチャットを始めるだけ。Gem自体は残っているので、また選び直すだけで使えます。 一番伝えたいのはこれ: カスタム指示は後からいつでも直せます。 最初から完璧を目指す必要はなくて、使いながら「もうちょっとこうしたいな」が出てきたら、そのときに直す。Gemは育てていくものです。 まとめ 第1回でGeminiを開いて聞いてみることから始めて、第2回で一言足すコツを身につけて、今回はそのコツをGemに保存して「選ぶだけ」にしました。 ここまで来たら、あとは自分の仕事に合ったGemを増やしていくだけです。今後は議事録まとめGemや企画書フィードバックGemなど、仕事で使える具体的なレシピも紹介していく予定です。 次は、自分の仕事に合ったオリジナルのGemを作ってみてください。 もっとGeminiを深掘りしたい方は、こちらも。 2026-01-28 Geminiに検索させるプロンプト術|リサーチGemの作り方 2025-07-07 【実践解説】技術ブログ品質チェック術|Gemini Deep Researchで5分検証 ではまた! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 毎回コピペはもう卒業。Geminiの「Gem」で選ぶだけにする方法 first appeared on SIOS Tech Lab .
今号では、gzip コマンドによるファイルの圧縮、展開について紹介します! 前回の記事 (tar コマンドを使ったファイルのアーカイブ・展開) と併せて見ていただければと思います。 gzip とは gzip とは、ファイルを圧縮してサイズを小さくするためのコマンドです。 前回の記事で紹介した tar コマンドとは異なり、基本的には 1つのファイルを圧縮するためのものです。 そのため、複数ファイルをまとめる (アーカイブする) 機能はありません。 基本の書式 ファイルを圧縮 gzip [ファイル名] の書式で実行します。 例: $ gzip test.txt $ ls test* test.txt.gz 上記のコマンドを実行すると、元のファイル (test.txt) が消えて圧縮後のファイル (data.txt.gz) のみになります。 ファイルを展開 gzip -d [ファイル名] もしくは gunzip [ファイル名] の書式で実行します。 例: $ gzip -d test.txt.gz $ ls test* test.txt 例: $ gunzip test.txt.gz $ ls test* test.txt ファイルの圧縮時と同様に、上記のコマンドを実行すると、元のファイル (test.txt.gz) が消えて展開後のファイル (data.txt) のみになります。 gzip コマンドのオプション gzip コマンド の基本的なオプションをご説明します。 ※すべてのオプションはご紹介せず、よく使用されると考えられるものを抜粋しています。 -r ディレクトリ内のファイルを再帰的に圧縮します。 $ gzip -r testdir $ ls testdir/subdir1 test1.txt.gz $ ls testdir/subdir2 test2.txt.gz ※圧縮されるのは、 ディレクトリ配下にあるファイルのみ です。 なお、-r を指定せずにディレクトリを指定すると、下記のエラーが表示されます。 $ gzip -d testdir gzip: testdir is a directory -- ignored -k ファイルの圧縮、展開時に元のファイルを削除せず残します。 $ gzip -k test.txt $ ls test* test.txt test.txt.gz $ gzip -dk test.txt.gz $ ls test* test.txt test.txt.gz -l 圧縮ファイルの圧縮率や元のサイズを確認します。 $ gzip -l test.txt.gz compressed uncompressed ratio uncompressed_name 29 0 0.0% test.txt ※この操作では、ファイルの展開は行われません。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 知っておくとちょっと便利!gzip コマンドを使ったファイルの圧縮・展開 first appeared on SIOS Tech Lab .
こんにちは! 今月も「OSSのサポートエンジニアが気になった!OSSの最新ニュース」をお届けします。 2/12、Google は最新の脅威追跡レポートにて、ハッカーが Gemini の技術を盗むための「抽出攻撃」を仕掛けていると発表しました。 グーグル「Gemini」の複製を狙う攻撃が判明、10万回超のプロンプトを浴びせる事案も https://japan.cnet.com/article/35243857/ Microsoft 365 Copilot が、数週間にわたり顧客の機密メールを要約していたことが判明しました。 企業向け「Microsoft 365 Copilot」、DLP設定無視で機密メール内容を要約 修正プログラム展開中 https://www.itmedia.co.jp/news/articles/2602/19/news069.html 2/20、Open Source Security Foundation (OpenSSF) より「SBOM データによるリスク管理の意思決定の改善」の日本語版が公開されました。 OpenSSFホワイトペーパー「SBOMデータによるリスク管理の意思決定の改善」を公開 https://prtimes.jp/main/html/rd/p/000000404.000042042.html ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【2026年2月】OSSサポートエンジニアが気になった!OSS最新ニュース first appeared on SIOS Tech Lab .
AIと一緒に仕様書を書く ども!最近AIを使った仕様書作りの検証とかに取り組みだした龍ちゃんです。 「AIと人間の両方で仕様書を効率的に管理するため」にはという課題に取り組んでいた時の内容です。 今回はAIツールを開発に使ってるチームで、仕様書をGitで管理してる人向けの話です。 この記事で話すこと: なぜ仕様書の図はAIに伝わりにくいのか 図解にソースコードを添える設計パターン(3パターン) 実際に試して分かった制約と注意点 まず完成形のイメージを見せます。 <!-- この図のソースコード(AI向け): sequenceDiagram Client->>+Server: ログインリクエスト Server->>+DB: ユーザー照合 DB-->>-Server: 結果 Server-->>-Client: トークン発行 設計意図: DB直接参照を避け、サービス層を経由する設計。 理由: テスタビリティとマイクロサービス移行への備え。 --> ![認証フロー図](./images/auth-flow.png) これはMarkdownファイル( .md )に書きます。リポジトリの docs/ 配下に仕様書として置いておくだけ。今はなんとなく雰囲気だけ掴んでもらえればOKです。具体的な書き方は後で3パターン紹介します。 このコメントには3つ詰め込んでます。 図のソースコード (Mermaid記法)→ AIが構造を正確に読める 設計意図 (なぜこの構造にしたか)→ AIが「なぜ」を理解できる 注釈 (制約や前提条件)→ AIがスコープを把握できる 人間はPNG画像を見るだけで、AIはHTMLコメントの中身を読む。両方が同じファイルに収まることでAIの理解と人間の視認性を確保することができます。 今の仕様書、AIに読める形になってますか? 「仕様書にきれいな図を描いた。シーケンス図、アーキテクチャ図、状態遷移図。人間のレビューは問題なく通る。」 でもこの仕様書、AIに渡したらどうなるか考えたことありますか? AIは仕様書の図を「推測」で読んでいる 試しに仕様書の図をAIに見せて「この設計について説明して」と聞いてみてください。それっぽい回答が返ってきます。実際には、2つの「推測」が存在しています。 推測その1: 構造の推測 PNG画像からAIが読み取る構造は、厳密ではないです。矢印の方向、条件分岐の条件、サービス間の依存関係。人間なら「見ればわかる」ものも、AIは画像のピクセルから推測しています。シンプルな図なら当たることが多いけど、複雑になるほど精度が落ちます。 推測その2: 意図の推測 仮に構造を正確に読めたとしても、「なぜこの構造にしたのか」は画像のどこにも書いてない。「なぜこの構成にしたのか」「なぜこのサービスを分けたのか」。AIは設計意図を推測するしかない。推測が当たることもあるけど、外れることもある。 つまりAIは、構造も意図が含まれていなければ推測が入ります。これからAI駆動開発を始めたい人も、既にやってる人も、ここがボトルネックになります。 じゃあ全部テキストで書けばいい? テキストだけの仕様書だと人間が読むのがしんどいんですよね。構造が一目でわからない。フローの分岐とか、サービス間の依存関係とか、図解があるから仕様書として機能してる部分があります。 推測をなくすには ここにジレンマがあって。 人間のためにはPNG画像がほしい AIのためにはテキスト(Mermaid/PlantUMLコード + 設計意図)がほしい ソースコードを添えれば構造の推測がなくなる。設計意図を書いておけば意図の推測がなくなる。この2つをセットで、同じファイル内に持たせる方法があります。次のセクションで具体的に見せます。 図解にソースコードを添える — 人間の視認性とAIの理解を両立する ここからが本題です。 やることはシンプルで、Markdownの仕様書内で図のPNG画像の直前に、HTMLコメントとして以下を書く。 Mermaid/PlantUMLのソースコード — 図の構造そのもの 設計意図 — なぜこの構造にしたか 注釈 (必要なら)— 異常系の考慮、将来の拡張方針など 人間の視認性とAIの理解、両方を1つのファイルで実現する方法です。 なぜHTMLコメントなのか Markdownの中にHTMLコメント( <!-- --> )を書くと、GitHubやドキュメントビューアで表示されない。人間がドキュメントを読むときには見えないんですよね。 でもAI(Claude CodeやCopilot等)がファイルを読むときは、HTMLコメントの中身もテキストとして見える。 つまり「人間には見えないけどAIには見える」メモ欄として機能する。人間は画像を見る。AIはコメントの中身を読む。お互い干渉しない。 リポジトリに置くだけでいい 自分がこのパターンを気に入ってる理由は、「食わせる(AIへのコンテキスト注入)」作業が簡単になるという点です。 GitリポジトリのMarkdownにHTMLコメント付きで置いておくだけで、Claude Codeが勝手に読んでくれる。Claude Codeはプロジェクトのリポジトリ内のファイルを直接参照できるので、わざわざプロンプトに貼り付ける必要がない。RAGの仕組みを作る必要もない。リポジトリにあるドキュメントをAIが自然に参照できる状態にしておくだけ。 これは自分が以前書いた「 AIフレンドリーなドキュメント管理 」や「 調査→構造化→注入の設計パターン 」の記事と同じ考え方です。テキストドキュメントをリポジトリに集約するアプローチの「図解版」ですね。 「それ、二重管理じゃない?」 この後のパターン集では ![認証フロー](./images/auth-sequence.png) のようにPNG画像を参照する形で書いてます。「ソースコードとPNG画像の両方を管理するのは二重管理では?」という疑問が出ると思います。 結論から言うと、 PNG画像が必要になるタイミングとソースコードが必要になるタイミングは別 なので、問題にならないかなと考えています。 エンジニア同士で設計を進めるフェーズでは、Mermaid/PlantUMLのソースコード + テキスト注釈だけで十分。AIも読める。ここでは図の記法で爆速で構造を整理していくことに集中すればいい PNG画像が必要になるのは、非エンジニア(お客さん、品質管理チームなど)に資料を出すタイミング。その瞬間にソースコードから生成すればいい 生成はMermaid CLIやPlantUML Web Service・HTML+Claude Codeを使用して自動化できる 管理するのはソースコードだけ。PNG画像は必要なときに生成する出力物 。二重管理ではなく「ソースが1つ、出力が必要なときに作る」という発想です。Claude Codeを使えばMermaidもPlantUMLも爆速で書けるので、ソースコードの作成・修正も苦になりません。具体的な方法は以下の記事で解説しています。 Mermaid/PlantUMLを知らなくても始められる 記法を知らないから無理、と思った人もいるかもしれません。でもAIに「この図のMermaidコードを書いて」と頼めば書いてくれます。既存のPNG画像を渡して「このPNG画像をMermaid記法に変換して」という方法もあります。 入門(ソースコード作成) ClaudeでMermaid図作成を自動化!2時間→5分の劇的時短術 Claude Codeで仕様書のPlantUML図を自動生成 — VS Codeプレビューで完結 発展(見た目カスタマイズ + PNG変換) Mermaid × Tailwind CSS — ハイブリッド図解の作り方 PlantUMLの表現力をTailwind CSSで設計書品質に仕上げる 記法の習得はあとからで大丈夫です。最初の一歩としては、設計意図のコメントを書くところから始めてみてください。 実装パターン集 ここからは具体的なコードサンプルを3つ見せます。全部コピペして使えます。自分の仕様書に近いパターンを選んでください。 パターン1 : シーケンス図(API設計書の認証フローなど) パターン2 : アーキテクチャ図(マイクロサービス構成など) パターン3 : 状態遷移図(注文ステータス管理など) まず: Mermaid と PlantUML どっちを使う? ソースコードの記法は2種類あります。迷ったらこの表で判断してください。 こういう図なら こっちを使う フローチャート、簡易シーケンス図、状態遷移、ER図 Mermaid アクティビティ図、ユースケース図、コンポーネント図 PlantUML UML準拠が求められる設計書 PlantUML 10ノード以上の大規模な図 PlantUML 迷ったらMermaidで始めて、限界を感じたらPlantUMLに切り替えればいい。AIとの相性はMermaidが最高、PlantUMLも高い。どちらを選んでもAIは読み取れます。 パターン1・3はMermaid、パターン2はPlantUMLで書いてます。使い分け表の通り、コンポーネント構成はPlantUMLのほうが得意です。 設計意図の書き方 パターンに入る前に1つだけ。前のセクションではHTMLコメントに「何を入れるか」(ソースコード・設計意図・注釈)を説明しました。ここでは設計意図の「書き方」の話です。ソースコードだけ貼っても、AIは構造は読めるけど「なぜ」がわからない。コメント内に最低限書くべきはこの3つ。 設計意図 : なぜこの構造にしたか(1-2行) 制約・前提 : この設計が成り立つ条件(あれば) スコープ外 : この図が扱わない範囲(あれば) 全部書く必要はないです。「なぜ」だけでも十分価値がある。以下の3パターンで書き分けの実例を見せます。 パターン1: シーケンス図 + 設計意図コメント ユースケース : API設計書の認証フロー <!-- AI向けソースコード: sequenceDiagram Client->>+API Gateway: POST /auth/login API Gateway->>+Auth Service: validateCredentials() Auth Service->>+User DB: findByEmail() User DB-->>-Auth Service: User Auth Service-->>-API Gateway: JWT Token API Gateway-->>-Client: 200 OK + Token 設計意図: Gateway がトークン発行の責務を持たず、Auth Service に委譲。 理由: 認証ロジックの変更(OAuth追加等)時に Gateway を触らなくて済む。 注意: Rate Limiting は Gateway 側で実装。Auth Service には到達しない前提。 --> ![認証フロー](./images/auth-sequence.png) 上記のソースコードから生成した図がこちら。右側の注釈パネルは、HTMLコメント内の設計意図をビジュアル化したもの。 人間が見るもの : きれいなシーケンス図の画像 AIが読むもの : Mermaidコード + 「なぜGatewayがトークンを発行しないか」の設計意図 制約 : Mermaidシーケンス図は4参加者・8メッセージ以下が読みやすい(検証済み) パターン2: アーキテクチャ図 + 責務定義コメント ユースケース : システム構成書のマイクロサービス構成 <!-- AI向けソースコード: @startuml package "Frontend" { [SPA - React] as SPA [BFF - Next.js] as BFF } package "Backend" { [Auth Service] as Auth [User Service] as User [Order Service] as Order } package "Data" { database "User DB" as UserDB database "Order DB" as OrderDB database "Redis Cache" as Cache } SPA --> BFF BFF --> Auth BFF --> User BFF --> Order Auth --> UserDB User --> UserDB User --> Cache Order --> OrderDB Order --> Cache @enduml 責務定義: - BFF: フロントエンド専用のAPI集約層。バックエンドサービスへの直接アクセスを防ぐ - Auth Service: 認証・認可のみ。ユーザー情報の参照はUser Serviceに委譲 - Cache: Read-through パターン。書き込みはDB直接 技術的制約: サービス間通信は gRPC。BFF→Backend のみ REST --> ![システム構成図](./images/architecture.png) 上記のソースコードから生成した図がこちら。責務定義が右側の注釈パネルに対応している。 人間が見るもの : マイクロサービスの全体像が一目でわかる構成図 AIが読むもの : PlantUMLコード + 各サービスの責務定義 + サービス間の通信方式 + キャッシュ戦略 PlantUMLの利点 : database や queue の専用記号が使える。パッケージでレイヤーを明示できる パターン3: 状態遷移図 + 異常系注釈コメント ユースケース : 業務フロー仕様書の注文ステータス管理 <!-- AI向けソースコード: stateDiagram-v2 [*] --> 注文受付 注文受付 --> 在庫確認中 在庫確認中 --> 決済処理中: 在庫あり 在庫確認中 --> キャンセル: 在庫なし 決済処理中 --> 出荷準備中: 決済成功 決済処理中 --> 決済エラー: 決済失敗 決済エラー --> 決済処理中: リトライ(最大3回) 決済エラー --> キャンセル: リトライ上限超過 出荷準備中 --> 出荷済み 出荷済み --> 配達完了 配達完了 --> [*] キャンセル --> [*] 異常系の設計: - 決済エラー → リトライは最大3回。exponential backoff(1秒→2秒→4秒) - 在庫なし → 即キャンセル。仮押さえはしない設計(在庫ロック競合を避ける) - 出荷後のキャンセル → この図の範囲外。返品フローは別仕様書を参照 --> ![注文ステータス遷移図](./images/order-state.png) 上記のソースコードから生成した図がこちら。正常系(青)と異常系(赤)を色で区別している。 人間が見るもの : 注文の正常系・異常系が一目でわかる状態遷移図 AIが読むもの : 状態遷移のルール + 異常系のリトライ戦略 + スコープ外の明示 制約 : 状態遷移図は8-10状態が上限(検証済み。それ以上は縦に伸びて見切れる) 3つのパターンに共通しているのは、 ソースコードだけでなく「なぜ」を書いている こと。パターン1は設計意図、パターン2は責務定義、パターン3は異常系の設計判断。AIが読んで「この設計の理由」まで理解できる状態にしてます。 実際に試して分かったこと ここまでのパターンを実際に検証して分かった注意点を2つ共有します。 ノード数の上限は思ったより低い Mermaidで図を描くとき、ノード(箱や状態)を増やしすぎると自動縮小されて文字が読めなくなります。1280x720pxの描画領域で検証した推奨上限はこれです。 図の種類 推奨上限 フローチャート 8-10ノード シーケンス図 4参加者・8メッセージ 状態遷移図 8-10状態 上限を超えたら図を分割してください。1つの図に全部詰め込みたくなる気持ちはわかるけど、分割したほうが人間にもAIにも読みやすい。 PlantUMLはサーバー側で描画するので、Mermaidほど厳しくないです。10ノード以上の大規模な図が必要なら、PlantUMLのほうが安全。 本当にAIが読み取れるのか? — 試してみてほしい 「HTMLコメントをAIが読めるって言うけど、本当に?」と思った人へ。自分で試すのが一番早いです。 パターン1のMarkdownをそのままファイルに保存する Claude Code(またはお好みのAIツール)にそのファイルを読ませる 「この仕様書の認証フローについて説明して。設計意図も含めて」と聞く HTMLコメント内の設計意図まで含めて回答してくれるはずです。「GatewayはRate Limitingだけを担当し、トークン発行はAuth Serviceに委譲しています」みたいな回答が返ってきたら、AIがコメントの中身を正確に読み取れている証拠。 やってみてください。 まとめ 仕様書の図を「人間だけが読むもの」から「人間とAIが読むもの」にする。やることはシンプルです。 図のPNG画像の横に、HTMLコメントでソースコードと設計意図を添える。 Mermaid/PlantUMLを使えば、AIが推測ではなく正確に設計構造を理解できる。設計意図を書いておけば「なぜこの構造にしたか」まで伝わる。 「AIに仕様書を食わせる」んじゃなくて、 AIが自然に読める仕様書をリポジトリに置いておく 。これだけ。 これは仕様書を書いてる人にしかできないことです。設計意図を知っているのは仕様書の著者だけだから。このパターンをチーム内で共有しておくと、AIを使ったレビューやコード生成で「設計の意図を汲んだ」出力が得られるようになります。 まずは1つの図から試してみてください。 ほなまた。 関連ブログ・参考リンク 関連ブログ Claude Code設計術:AIフレンドリーなドキュメント管理 今回の記事の前提となる考え方です。テキストドキュメントをリポジトリに集約してAIが自然に参照できる状態を作る設計パターンを解説しています。 Claude Codeに専門知識を仕込む:調査→構造化→注入の設計パターン AIへのコンテキスト注入を「調査→構造化→注入」の3ステップで設計するパターンを紹介。今回のHTMLコメント手法も同じ思想の延長線上にあります。 図解作成、AIに丸投げしたら「たまに自分より上手い」件 Claude CodeのSKILL機能でHTML図解を自動生成し、CLIでPNG変換する方法を紹介しています。図の生成手段を増やしたい人はこちらもどうぞ。 ClaudeでMermaid図作成を自動化!2時間→5分の劇的時短術 Mermaidでフローチャート・シーケンス図・パイチャートを自動生成する方法を解説。今回の記事でソースコードとして使うMermaid記法の書き方はこちらを参照してください。 Claude Codeで仕様書のPlantUML図を自動生成 — VS Codeプレビューで完結 PlantUMLのアクティビティ図・ユースケース図・コンポーネント図をClaude Codeで生成し、VS Code上でプレビューする方法を解説。Mermaidでは作れない図が必要なときはこちら。 Mermaid × Tailwind CSS — ハイブリッド図解の作り方 Mermaid図にTailwind CSSの装飾を組み合わせて設計書品質のPNGに変換する実践方法。見た目をカスタマイズしたいときはこちら。 PlantUMLの表現力をTailwind CSSで設計書品質に仕上げる PlantUML図をTailwind CSSで装飾してPNGに変換するテンプレート付き。コンポーネント図・アクティビティ図・ユースケース図に対応。 参考リンク Mermaid.js公式 Anthropic: Effective Context Engineering for AI Agents ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 仕様書の図はAIに読ませるな — 軽量コードを添える設計パターン first appeared on SIOS Tech Lab .
テキストベースの図、もっと表現力が欲しい ども! PlantUML × VS Codeの記事 を書いた龍ちゃんです。 Claude Codeを使って爆速でPlantUMLを書けるようになりました。でも!実際に設計書やブログに貼るとなると「もうちょっと見た目をなんとかしたい」ってなるんですよね。図の横に設計ポイントを添えたり、色を揃えて見やすくしたり。 そこで今回は、PlantUMLの図にTailwind CSSの装飾を組み合わせます。1つのHTMLファイルにPlantUML図 + 注釈パネルをまとめて、PNGに変換する仕組みです。 「なんでPlantUML?」理由はシンプルで、Mermaidではカバーできない図があるからです。 コンポーネント図 — database "PostgreSQL" と書くだけであのドラム型DBアイコンが出る アクティビティ図 — ワークフローの分岐・マージを if/else/endif で描ける ユースケース図 — actor "ユーザー" で棒人間アイコンが出る Mermaidはフロー図やシーケンス図が得意ですけど、この3つは守備範囲外なんですよね。PlantUMLならテキストベースのまま作れます。 Mermaid × Tailwind CSSの組み合わせも同時に記事にしてます。フロー図やシーケンス図を作りたい人は「 Mermaid × Tailwind CSS — ハイブリッド図解の作り方 」をどうぞ。 今回の内容です。 コピペ用テンプレート2種(右サイド注釈型 / 左右均等型) PNG変換の手段3つ 関連記事 : 仕様書の図にソースコードと設計意図を添える方法については「 仕様書の図はAIに読ませるな — 軽量コードを添える設計パターン 」で詳しく書いてます。AIに図の構造を正確に伝えたい人はこちらもどうぞ。 テンプレートA: 右サイド注釈型 コピペして使えるHTMLテンプレートを2種類用意しました。 仕組みはシンプルで、plantuml-encoderというライブラリでPlantUML構文をエンコードしてplantuml.comに投げるだけです。Tailwind CDNとの共存も問題なし。テンプレートをコピペすればそのまま動きます。plantuml.comへの通信が発生するのでネット接続は必要ですが、大抵の開発環境では問題にならないです。 まずはテンプレートA。左にPlantUMLで描画したコンポーネント図、右にTailwind CSSで装飾した注釈パネルを並べるレイアウトです。ドラム型のDB記号やキュー記号が見えるのがPlantUMLならではのポイントですね。 向いてる場面 : 横に広がる図(コンポーネント図、シーケンス図)に設計ポイントを3-4個添えたいとき キャンバスサイズ : 1280x720px <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>コンポーネント図: 3層アーキテクチャ</title> <script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.jsdelivr.net/npm/plantuml-encoder@1.4.0/dist/plantuml-encoder.min.js"></script> <style> body { width: 1280px; height: 720px; margin: 0; padding: 0; background: white; overflow: hidden; } </style> </head> <body class="p-8"> <div class="h-full flex flex-col"> <!-- タイトル --> <h1 class="text-2xl font-bold mb-6 text-gray-800">コンポーネント図: 3層アーキテクチャ</h1> <!-- メインコンテンツ: 2カラム --> <div class="flex gap-6 flex-1"> <!-- 左: PlantUML図 --> <div class="flex-1 flex flex-col"> <div class="bg-blue-50 border-2 border-blue-300 rounded-lg p-4 flex-1 flex items-center justify-center"> <div id="diagram-container" class="flex items-center justify-center"> <p class="text-gray-500">Loading diagram...</p> </div> </div> </div> <!-- 右: 注釈パネル --> <div class="w-72 flex flex-col gap-4"> <div class="bg-yellow-50 border border-yellow-300 rounded-lg p-4"> <h3 class="font-bold text-yellow-800 mb-2">フロントエンド層</h3> <p class="text-sm text-yellow-900">Web・モバイルの2系統。APIゲートウェイを経由して統一的にアクセス</p> </div> <div class="bg-blue-50 border border-blue-300 rounded-lg p-4"> <h3 class="font-bold text-blue-800 mb-2">バックエンド層</h3> <p class="text-sm text-blue-900">認証・記事・通知をマイクロサービスに分離。ゲートウェイでルーティング</p> </div> <div class="bg-green-50 border border-green-300 rounded-lg p-4"> <h3 class="font-bold text-green-800 mb-2">データ層</h3> <p class="text-sm text-green-900">PostgreSQL + Redis + メッセージキューの3点セット。非同期処理はキュー経由</p> </div> </div> </div> </div> <script> window.addEventListener('DOMContentLoaded', function() { const umlSource = `@startuml skinparam style strictuml skinparam backgroundColor transparent package "フロントエンド" { [Webアプリ] as Web [モバイルアプリ] as Mobile } package "バックエンド" { [APIゲートウェイ] as GW [認証サービス] as Auth [記事サービス] as Article [通知サービス] as Notify } package "データ層" { database "PostgreSQL" as DB database "Redis" as Cache queue "メッセージキュー" as MQ } Web --> GW Mobile --> GW GW --> Auth GW --> Article Article --> DB Article --> Cache Article --> MQ MQ --> Notify Auth --> DB @enduml`; try { const encoded = plantumlEncoder.encode(umlSource); const imgUrl = `https://www.plantuml.com/plantuml/svg/${encoded}`; const container = document.getElementById('diagram-container'); container.innerHTML = `<img src="${imgUrl}" alt="コンポーネント図" class="max-w-full max-h-full" />`; } catch (error) { console.error('Error encoding PlantUML:', error); document.getElementById('diagram-container').innerHTML = `<p class="text-red-500">Failed to load diagram: ${error.message}</p>`; } }); </script> </body> </html> 差し替えは3箇所だけです。 PlantUML構文 ( const umlSource の中身)を自分の図に差し替える 注釈パネルの内容 (右側の3つのパネル)を自分の設計ポイントに差し替える タイトル を差し替える 注釈パネルは増減しても大丈夫です。3個が収まりいいですけど、2個でも4個でもレイアウトは崩れません。 skinparamについて Mermaid編では themeVariables で図の配色をTailwindのカラーパレットに合わせましたね。PlantUMLでは skinparam が同じ役割です。 skinparam style strictuml skinparam backgroundColor transparent backgroundColor transparent で背景を透明にするだけで、Tailwind側の bg-blue-50 と自然に馴染みます。追加で色をカスタマイズしたい場合はこんな設定もあります。 skinparam packageBackgroundColor #f0f9ff skinparam ArrowColor #3b82f6 skinparam ParticipantBackgroundColor #dbeafe Mermaidの themeVariables ほど細かい制御はできないですけど、背景透明にするだけで大抵は十分です。もっと細かく調整したい人は PlantUML公式のskinparamリファレンス を参照してください。 PlantUML固有の記法 テンプレートのコードで使ってる記法と、他の図で使える記法をまとめておきます。 テンプレートAで使用 : 記法 表示 database "名前" ドラム型DB記号 queue "名前" キュー型記号 package "名前" { ... } パッケージでグループ化 他の図で使える記法 : 記法 用途 == フェーズ名 == シーケンス図のフェーズ分割 alt / else / end 条件分岐ブロック ref over A, B 外部参照 left to right direction ユースケース図の横向きレイアウト テンプレートB: 左右均等型 テンプレートAだと、縦長の図のときに左側のスペースが余ります。アクティビティ図やユースケース図は縦に伸びるんで、横幅を半々にして右側に説明を置くほうが収まりがいいです。 向いてる場面 : 縦長の図(アクティビティ図、ユースケース図)に説明を横に並べたいとき キャンバスサイズ : 1280x720px <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>アクティビティ図: ユーザー登録フロー</title> <script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.jsdelivr.net/npm/plantuml-encoder@1.4.0/dist/plantuml-encoder.min.js"></script> <style> body { width: 1280px; height: 720px; margin: 0; padding: 0; background-color: white; overflow: hidden; } </style> </head> <body class="flex"> <!-- 左: PlantUML図 --> <div class="w-1/2 flex items-center justify-center p-8"> <div id="diagram-container"></div> </div> <!-- 右: 注釈パネル --> <div class="w-1/2 flex flex-col justify-center p-8 space-y-6"> <h1 class="text-3xl font-bold text-gray-800 mb-4">ユーザー登録フロー</h1> <div class="bg-yellow-100 border-l-4 border-yellow-500 p-4"> <p class="text-gray-800 font-semibold">バリデーション</p> <p class="text-sm text-gray-600 mt-1">フォーム入力後、サーバー側でバリデーション。失敗時はエラーメッセージを表示してフォームに戻す</p> </div> <div class="bg-blue-100 border-l-4 border-blue-500 p-4"> <p class="text-gray-800 font-semibold">DB保存とリトライ</p> <p class="text-sm text-gray-600 mt-1">保存失敗時はエラーログを記録してリトライ画面を表示。ユーザーに再試行の機会を与える</p> </div> <div class="bg-green-100 border-l-4 border-green-500 p-4"> <p class="text-gray-800 font-semibold">完了通知</p> <p class="text-sm text-gray-600 mt-1">保存成功時は完了メールを送信してから完了画面を表示。メール送信は非同期でもOK</p> </div> </div> <script> window.addEventListener('DOMContentLoaded', () => { const plantUmlSource = `@startuml start :ユーザーがフォームを入力; if (バリデーション?) then (成功) :データベースに保存; if (保存成功?) then (はい) :完了メールを送信; :完了画面を表示; else (いいえ) :エラーログを記録; :リトライ画面を表示; endif else (失敗) :エラーメッセージを表示; :フォームに戻る; endif stop @enduml`; const encoded = plantumlEncoder.encode(plantUmlSource); const img = document.createElement('img'); img.src = `https://www.plantuml.com/plantuml/svg/${encoded}`; img.alt = 'アクティビティ図: ユーザー登録フロー'; img.className = 'max-w-full max-h-full'; document.getElementById('diagram-container').appendChild(img); }); </script> </body> </html> 差し替えポイントはテンプレートAと同じ3箇所です。PlantUML構文、注釈パネル、タイトル。実例はアクティビティ図ですけど、ユースケース図を作りたい場合も const plantUmlSource の中身を差し替えるだけです。 テンプレートAとの違いは2つです。 レイアウトが左右均等 ( w-1/2 + w-1/2 )。図と注釈が50:50で並ぶんで、縦長の図に余裕ができます 注釈のスタイルが border-l-4 (左ボーダーアクセント)。テンプレートAのカード型とは雰囲気が変わります Mermaid編のテンプレートBは縦拡張(1280x1080px)でしたけど、PlantUML編は標準の1280x720pxです。PlantUMLはサーバー側で描画するんで、Mermaidの自動縮小問題がない。CSS transformも不要です。 テンプレート使い分け 条件 テンプレート 横に広がる図(コンポーネント図、シーケンス図) A: 右サイド注釈型 縦長の図(アクティビティ図、ユースケース図) B: 左右均等型 注釈が少ない(2-3個) A 注釈にテキストが多い B 迷ったらテンプレートAで試して、図が窮屈ならBに切り替えてください。 PNG変換 — 3つの手段 手段は3つあります。好みと環境に合わせて選んでください。 手段 自動化 セットアップ 向いてる用途 CLIツール(html-screenshot) できる Python + Playwright 量産やCI/CD Playwright MCP できる MCP設定 Claude Code連携 ブラウザで直接開く 手動 なし 手軽に確認 CLIツール uv run html-screenshot --file template-a.html --output template-a.png 以前の記事 で紹介したhtml-screenshotツールがそのまま使えます。Playwrightの wait_until="networkidle" がplantuml.comからのSVG取得完了を待ってくれるんで、PlantUML図の描画が終わってからスクリーンショットを撮ってくれます。 Playwright MCP Claude CodeからPlaywrightのブラウザ操作を直接呼び出す方法もあります。HTMLファイルを開いてスクリーンショットを撮る操作がMCPのツールで完結します。 Playwright MCPの記事 で詳しく書いてるんで、Claude Code使ってる人はこっちが楽です。 ブラウザで直接開く 一番手軽なのはHTMLファイルをブラウザで直接開くことですね。Tailwind CDNとplantuml-encoder CDNが読み込まれて、PlantUML図がそのまま描画されます。PNG変換は手動(DevToolsやOS標準のスクリーンショット)になりますけど、「ちょっと確認したい」くらいならこれで十分です。 まとめ Mermaid編のテンプレート2種 + 今回のPlantUML編テンプレート2種で、計4種類が揃いました。 テンプレート 図の描画 向いてる図 Mermaid A: 右サイド注釈型 Mermaid フロー、シーケンス、状態遷移 Mermaid B: 下部グリッド注釈型 Mermaid 複雑なシーケンス PlantUML A: 右サイド注釈型 PlantUML コンポーネント、シーケンス PlantUML B: 左右均等型 PlantUML アクティビティ、ユースケース フロー図、シーケンス図、状態遷移図に加えて、アクティビティ図、ユースケース図、コンポーネント図もカバーできるようになりました。特にコンポーネント図の database でドラム型DBアイコンが出せるのは、アーキテクチャ図を書く人にはかなり便利です。 おまけとして、Mermaid編でも触れましたがこのテンプレートで作った図はAI連携にも使えます。PlantUMLもMermaidと同じく宣言的記法なんで、AIが構造を正確に読み取れます。注釈パネルに設計意図を書いておけば、人間が見ても、AIが読んでもどっちにも伝わる。この辺の話は 仕様書の図にソースコードを添える設計パターン で詳しく書いてます。 もう1つ。このテンプレートを毎回コピペするのも手ですけど、Claude Codeの SKILL機能 にreference(参考例)として登録しておくと、「シーケンス図作って」と言うだけでテンプレートに沿った図が出てきます。テンプレートのクオリティがそのままSKILLのクオリティになるんで、良いテンプレートを貯める = 図解の品質を底上げする、という流れができます。コピペ用テンプレートとSKILL化、好きなほうで使ってください。 ほなまた〜 関連ブログ 今回の記事はシリーズの一部です。 Mermaid × Tailwind CSS — ハイブリッド図解の作り方 — 今回の前編。Mermaid + Tailwind CSSのテンプレート2種を紹介してます。まだ読んでない人はこちらから。 ClaudeでMermaid図作成を自動化!プロンプトテンプレート集も公開 — シリーズの出発点。Mermaid記法をAIで生成するところから始めたい人はここから。 図解作成、AIに丸投げしたら「たまに自分より上手い」件 — HTML+Tailwind CSSで図解を丸ごとAIに作らせる方法。フロー図以外の図解(比較図、アーキテクチャ図とか)はこっちが向いてます。 仕様書の図はAIに読ませるな — 軽量コードを添える設計パターン — 仕様書をAIと共有してるチーム向け。図にソースコードと設計意図を添えて、AIの「推測」をなくす方法です。 Claude CodeでPlantUML × VS Code Preview — PlantUMLの基礎とVS Codeでのプレビュー設定。PlantUML自体が初めての人はこちらが入門になります。 Playwright MCPで始めるブラウザ自動化 — PNG変換の手段の1つとして紹介したPlaywright MCP。Claude Codeからブラウザ操作を直接呼び出せます。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post PlantUMLの表現力をTailwind CSSで設計書品質に仕上げる first appeared on SIOS Tech Lab .