はじめに
Anthropic が提案した Agent Skills が注目されています。
Agent Skills とは、AIエージェントが特定のタスクを実行する際に必要な専門知識やワークフローを、再利用可能な形式で定義・共有する仕組みです。従来、エージェントに複雑なタスクを任せるには、毎回詳細な指示をプロンプトに含める必要がありました。Skills はこの問題を解決し、「必要なときに、必要な知識だけを読み込む」というスマートなアプローチを可能にします。
本記事では、AI コーディングアシスタント Cline に実装された Skills 機能を実際に使いながら、以下の点を確認していきます。
- Skills が解決する具体的な課題(コンテキスト消費、コスト、性能)
- Skills の有効化と設定方法
- 実践例:Oracle Database の AWR レポート生成・分析スキルの作成と活用
- Skills が「必要なときだけ」読み込まれることの検証
AIエージェントを業務で活用する際、専門的なルールやワークフローをどう管理するかは重要な課題です。Skills はその解決策の一つとして、今後ますます重要になると考えられます。
なお、コーディングエージェントを使った AWRレポートの生成分析やその環境構築については末尾に掲載した関連ブログでご紹介しています。
Skills が解決する課題
Skills には、タスクに専門特化したプロンプト(ルールやワークフロー)を誰もが利用できるように共有・流通させるという重要な価値がありますが、そのような目的に特化した多数のプロンプトを毎回コンテキストとして LLM に読み込ませることは、コンテキストウィンドウを超過するリスク、目的外のプロンプトによるノイズやコンフリクトの増加による性能低下、推論速度の低下、APIコスト(多くの場合、トークン単価もしくはキャラクター単価であるため)の増大を招いてしまいます。
例えば、Cline の "Global Rules" も "Workspace Rules"も無い状態で「こんにちは」と問いかけるとトークン消費量は以下のように 15.3k トークンとなります。このトークンの大半は、Cline 自体のシステムプロンプトと推定されます。
次に、"Workspace Rules" に以下のようなルールを設定した状態で Cline に「こんにちは」と問いかけてみます。
AWRレポート生成・分析のルール
# Cline Global Rules
## [CRITICAL] ORA-00904 (invalid identifier) 発生時の強制プロトコル
このセクションは全ルールより優先される。違反は許容されない。
### 強制フロー
```
[TRIGGER] ORA-00904 または "invalid identifier" エラーが発生
|
v
[STOP] 次のクエリ実行を禁止。修正したSQLをすぐに実行してはならない。
|
v
[REQUIRED] DESCRIBE <エラーが発生したテーブル/ビュー> を実行
|
v
[REQUIRED] カラム一覧を確認し、存在するカラムのみでSQLを再構築
|
v
[REQUIRED] 修正理由を説明してから、修正したSQLを実行
```
### 禁止行動
以下の行動は絶対に禁止する:
- DESCRIBEを実行せずにカラム名を変更・削除して再試行すること
- 「おそらくこのカラム名だろう」という推測での修正
- エラーメッセージだけを見て修正を試みること
- DESCRIBEの結果を確認せずに次のクエリを発行すること
### 必須行動
以下の行動は必ず実行する:
- DESCRIBE または `SELECT column_name FROM all_tab_columns WHERE table_name = '...'` を実行してカラム一覧を取得
- 取得したカラム一覧と照合してからSQLを修正
- 確認結果を応答に含める(例:「DESCRIBEの結果、SNAP_IDカラムは存在しませんでした。利用可能なカラムは...」)
### 具体例
[FORBIDDEN] 誤った対応:
```
1. SELECT SNAP_ID, OBJECT_NAME FROM DBA_HIST_SQL_PLAN ...
→ エラー: ORA-00904: SNAP_ID: invalid identifier
2. [DESCRIBEを実行しない] ← ルール違反
3. SELECT OBJECT_NAME FROM DBA_HIST_SQL_PLAN ... を再試行
```
[CORRECT] 正しい対応:
```
1. SELECT SNAP_ID, OBJECT_NAME FROM DBA_HIST_SQL_PLAN ...
→ エラー: ORA-00904: SNAP_ID: invalid identifier
2. DESCRIBE DBA_HIST_SQL_PLAN を実行 ← 必須ステップ
3. [結果を確認: SNAP_IDは存在しない。存在するカラム: DBID, SQL_ID, PLAN_HASH_VALUE, ID, OPERATION, ...]
4. ユーザーに報告:「DESCRIBEの結果、SNAP_IDカラムは存在しません。利用可能なカラムは...」
5. 存在するカラムのみを使用して修正したSQLを実行
```
---
## [CRITICAL] Actモードでのツール実行
- Actモードでは必ず1つ以上のツールを呼び出す(例外なし)
- 質問・確認が必要な場合: `ask_followup_question` ツールを使用
- 作業完了時: `attempt_completion` を呼び出す
- 確認だけの応答(ツールを使わない応答)は禁止
---
## [CRITICAL] SQLエラー発生後の共通ルール
### 禁止事項
- 同じクエリを繰り返し実行すること
- 原因を特定せずに単純にSQLを書き換えること
- メタデータを確認せずに修正を試みること
### 必須事項
- エラー発生後は、まずメタデータを確認する(DESCRIBE、データディクショナリ参照)
- エラーメッセージから根本原因を特定してから次のアクションを決定する
- 3回同じエラーが発生したら、アプローチを根本的に変更する
### エラー種別ごとの対処
ORA-00904 (invalid identifier):
→ 上記の「強制プロトコル」に従う
ORA-00942 (table or view does not exist):
→ `SELECT table_name FROM user_tables WHERE table_name LIKE '%キーワード%'` でテーブル存在確認
→ `SELECT owner, table_name FROM all_tables WHERE table_name = '...'` でスキーマ所有者を確認
→ ユーザーに報告
---
## 進捗管理
- `task_progress` を使って、常に「現在何をしていて、次に何をするか」を明示
- 長時間タスクの場合: 定期的にTODOリストを更新し、進捗を記録
---
## ユーザーとのコミュニケーション
### 不明点の確認
- タスクの目的や環境設定が不明確な場合は、推測で進めず `ask_followup_question` を使用してユーザーに確認
- タスクが空または不明確な場合は、まず確認する
### エラー報告
エラーが発生した場合は、`ask_followup_question` を使用してユーザーにエラーの状況と対策案を提示:
- エラーの種類(ORA-XXXXX, MCPエラーなど)
- 発生した状況(どのツール、どのSQL)
- 次に試みる対策
### タスクが中断された場合の再開
ユーザーへの質問ではなくツールで環境を確認:
- データベースの接続状態、利用可能なデータベース接続
- TODOリスト(進捗確認)
---
## URLの提示をしない
URLを参考リンクとして出力しない。
---
## MCPツール実行の基本原則
### 基本方針
- すべてのデータベースクエリはMCPツールを通じて実行する
- MCPツールのレスポンスは、正常に返された場合のみ事実として扱う
- 事前知識やコンテキストに基づいて、出力を推測、仮定、捏造してはならない
- MCPツールのレスポンスが空の場合も出力を推測、仮定、捏造してはならない
### MCPサーバーの正確な利用
- MCPサーバーの名称は必ず正確なサーバー名を使用する
- 推測や略称は絶対に使わない
- 初回接続時は必ずサーバー名を確認してからtoolを呼び出す
[FORBIDDEN] サーバー名の省略:
- 本当のサーバー名が `SQLcl - SQL Developer` であるとき、`SQLcl` と省略することは禁止
### SQLcl MCPサーバーのルール
- クエリ実行には `run-sql` よりも `run-sqlcl` を優先する
- 純粋なSQL実行が必要な場合のみ `run-sql` を使用する
[FORBIDDEN] 以下のコマンドはMCPツールでエラーとなる:
- SET PAGESIZE
- SET LINESIZE
- SET COLSEP
- SET SQLFORMAT
- SPOOL
### ツール実行が失敗、タイムアウト、またはデータが返されない場合
- 結果が取得できなかったことをユーザーに明示的に伝える
- 結果を補完、推定、推測しようとしてはならない
- 再試行するか、クエリを修正するか、追加情報を提供するかをユーザーに確認する
- ツールの結果が部分的な場合は、ユーザーに確認されるまで信頼性がないものとして扱う
### JSONパラメータのフォーマット
- パラメータは必ず有効なJSON形式で記述
- 特殊文字(`\n`, `"`, `'` など)は適切にエスケープ
- 複雑なSQLを渡す場合は、JSON文字列として適切にエンコード
- JSON形式の後に通常のテキストやXMLタグなどを出力しない
---
## データベースクエリのワークフロー
### 接続とセッションの管理
1. 利用可能な接続のリストの事前確認: データベース操作を伴うタスクでは、まずツールで利用可能な接続を確認
2. 使用する接続をユーザーに確認: 接続のリストを `ask_followup_question` ツールのオプションとしてユーザーに提示
3. 接続確立: ツールで接続を確立
4. 接続エラー後の対応: `Connection closed` などのエラーが発生した場合は、利用可能な接続のリストをツールで再確認してから再接続
### メタデータの事前確認
ORA-00942やORA-00904エラーを回避するため、クエリを実行する前に以下を確認する:
テーブルやビューの一覧の取得:
- データベースオブジェクトのリストを取得するツールがあれば使用
- 無い場合は `SELECT table_name FROM user_tables` などを実行
[REQUIRED] テーブルやビューの構造の確認:
- データベースオブジェクトの詳細を取得するツールがあれば使用
- 無い場合は `DESCRIBE table_name` を実行、または `SELECT * FROM all_tab_columns WHERE table_name = 'TABLE_NAME'` を実行
- スキーマの所有者の確認
### 3ステップ実行ルール
すべてのSQLクエリリクエストはこのワークフローに従う。いかなるステップもスキップしてはならない。
| ステップ | アクション | 目的 |
|----------|------------|------|
| 1 | DESCRIBE | スキーマ確認 |
| 2 | SELECT COUNT(*) | 行数の検証 |
| 3 | 実際のクエリ | ユーザーの元のリクエストを実行 |
[WARNING] ステップ3は必須。DESCRIBEとSELECT COUNT(*)は準備ステップに過ぎず、実際のクエリの代わりにはならない。
#### ステップ1: スキーマ確認(DESCRIBE)
- 現在のセッションで初めて登場するテーブル名、ビュー名については、まず `DESCRIBE` を実行してテーブルやビューの構造を確認
- カラム定義を確認してから、実際のSQLクエリを構築
- 自然言語だけでカラム名やデータ型を仮定してはならない
- `DESCRIBE` が失敗した場合やテーブルが存在しない場合は、推測せずにユーザーに確認
#### ステップ2: 行数の検証(COUNT)
- 実際のクエリと同じテーブル、ビュー、WHERE句を使用した `SELECT COUNT(*)` クエリを実行
- 行数が1000行を超える場合: ユーザーに通知し、フィルター追加や制限を提案、承認を待つ
#### ステップ3: 実際のクエリを実行
[REQUIRED] ステップ1と2を完了した後、ユーザーがリクエストした元のSQLクエリを必ず実行する。
[REQUIRED] SQLがステップ1で確認したテーブル構造、カラム名、データ型に基づいていることを確認する。
- このステップの実際のツール出力のみに基づいて結果を報告する
### 100行を超える結果セットの処理
- データ全体をそのまま出力することは避ける
- 要約を提供する: 集計統計、上位Nレコード、またはサマリーテーブル
### タイムゾーンに関する注意事項
- テーブルやビューのタイムスタンプ型のカラムにタイムゾーンを保持した型(TIMESTAMP WITH TIME ZONE)がある場合には、それを使用する
- カラムにタイムゾーンを保持した型(TIMESTAMP WITH TIME ZONE)がない場合は、カラムデータはデータベースタイムゾーンで保存されているものとして、セッションタイムゾーンに正しく変換する
---
## Oracleデータディクショナリの使用
- どのデータディクショナリビューが利用可能かを推測してはならない
- まず `DICTIONARY` ビューをクエリする:
```sql
SELECT table_name, comments FROM DICTIONARY ORDER BY table_name;
```
- 実際にアクセス可能なビューのみを選択する
- ディクショナリビューについても3ステップワークフローに従う
- 必要なビューがDICTIONARYに表示されない場合は、ユーザーにその制限を説明する
---
## PL/SQLパッケージ・プロシージャ呼び出しのルール
PL/SQLパッケージのプロシージャ/ファンクションを呼び出す前に、必ずシグネチャを確認する。
### シグネチャ確認方法
```sql
SELECT argument_name, position, data_type, defaulted, in_out
FROM all_arguments
WHERE package_name = 'PACKAGE_NAME'
AND object_name = 'PROCEDURE_NAME'
ORDER BY position;
```
### 禁止事項
- パラメータの推測: 事前知識やドキュメントの記憶に基づいてパラメータを推測してはならない
- 存在確認なしの呼び出し: シグネチャを確認せずにPL/SQLプロシージャを実行してはならない
- 「便利そうな」パラメータの追加: データディクショナリで確認できたパラメータのみを使用する
### 正しいフロー例
```
ユーザー: "ジョブを停止して"
1. 実行: DBMS_SCHEDULER について ALL_ARGUMENTS をクエリ
2. 確認: STOP_JOB のパラメータは job_name, force, commit_semantics のみ
3. 実行: BEGIN DBMS_SCHEDULER.STOP_JOB('JOB_NAME', force => TRUE); END;
```
### 誤ったフロー例
```
ユーザー: "ジョブを停止して"
1. スキップ: シグネチャ確認なし ← ルール違反
2. 実行: BEGIN DBMS_SCHEDULER.STOP_JOB('JOB_NAME', force => TRUE, timeout => 300); END;
↑ timeout は存在しないパラメータ(PLS-00306 エラー)
```
---
## [CRITICAL] CDB/PDB環境でのAWR関連ビュー選択ルール
このルールは、AWRレポート生成だけでなく、AWR関連データを直接クエリするすべての場面に適用される。
### 適用範囲
以下のいずれかに該当する場合、このルールを適用する:
- AWRレポートを生成する場合
- AWR関連のパフォーマンス統計を取得する場合(例:バッファキャッシュヒット率、I/O統計、待機イベントなど)
- DBA_HIST_* または AWR_PDB_* ビューを使用する場合
### CDB/PDB環境の判定(必須)
[REQUIRED] AWR関連のビューを使用する前に、必ず以下のクエリで環境を判定する:
```sql
SELECT
SYS_CONTEXT('USERENV', 'CON_NAME') AS CONTAINER_NAME,
SYS_CONTEXT('USERENV', 'CON_ID') AS CONTAINER_ID,
CASE
WHEN SYS_CONTEXT('USERENV', 'CON_ID') = 1 THEN 'CDB$ROOT'
WHEN SYS_CONTEXT('USERENV', 'CON_ID') = 0 THEN 'Non-CDB'
ELSE 'PDB'
END AS ENVIRONMENT_TYPE
FROM DUAL;
```
### ビュー選択マッピング
| 環境タイプ | スナップショットビュー | 統計ビュー | SQLSTATビュー | 他のAWRビュー |
|------------|------------------------|------------|---------------|---------------|
| Non-CDB (CON_ID=0) | DBA_HIST_SNAPSHOT | DBA_HIST_SYSSTAT | DBA_HIST_SQLSTAT | DBA_HIST_* |
| CDB$ROOT (CON_ID=1) | DBA_HIST_SNAPSHOT | DBA_HIST_SYSSTAT | DBA_HIST_SQLSTAT | DBA_HIST_* |
| PDB (CON_ID>=2) | AWR_PDB_SNAPSHOT | AWR_PDB_SYSSTAT | AWR_PDB_SQLSTAT | AWR_PDB_* |
### 強制ルール
[REQUIRED] PDB環境(CON_ID >= 2)では、以下のビューマッピングを必ず適用する:
| CDB/Non-CDBビュー | PDB環境での対応ビュー |
|-------------------|----------------------|
| DBA_HIST_SNAPSHOT | AWR_PDB_SNAPSHOT |
| DBA_HIST_SYSSTAT | AWR_PDB_SYSSTAT |
| DBA_HIST_SQLSTAT | AWR_PDB_SQLSTAT |
| DBA_HIST_SQLTEXT | AWR_PDB_SQLTEXT |
| DBA_HIST_SQL_PLAN | AWR_PDB_SQL_PLAN |
| DBA_HIST_ACTIVE_SESS_HISTORY | AWR_PDB_ACTIVE_SESS_HISTORY |
| DBA_HIST_SYSTEM_EVENT | AWR_PDB_SYSTEM_EVENT |
| DBA_HIST_SYS_TIME_MODEL | AWR_PDB_SYS_TIME_MODEL |
[FORBIDDEN] PDB環境で DBA_HIST_* ビューを使用すること(CDBレベルのデータが返されるため不正確)
### 検証フロー
```
[TRIGGER] AWR関連のクエリ実行リクエスト
|
v
[STEP 1] CDB/PDB環境を判定(SYS_CONTEXTで確認)
|
v
[STEP 2] 環境に応じたビューを選択
|
+---> CON_ID = 0 または CON_ID = 1
| |
| v
| DBA_HIST_* ビューを使用
|
+---> CON_ID >= 2 (PDB)
|
v
[REQUIRED] AWR_PDB_* ビューを使用
[FORBIDDEN] DBA_HIST_* ビューの使用
|
v
[STEP 3] 選択したビューでDESCRIBEを実行(3ステップ実行ルールに従う)
|
v
[STEP 4] クエリを実行
```
### 正しい例と誤った例
#### 例1: バッファキャッシュヒット率の計算
[FORBIDDEN] PDB環境での誤った対応:
```sql
-- 環境判定: CON_ID = 747 (PDB)
-- 誤り: DBA_HIST_SYSSTATを使用
SELECT STAT_NAME, VALUE
FROM DBA_HIST_SYSSTAT
WHERE STAT_NAME IN ('db block gets', 'consistent gets', 'physical reads');
```
[CORRECT] PDB環境での正しい対応:
```sql
-- 環境判定: CON_ID = 747 (PDB)
-- 正しい: AWR_PDB_SYSSTATを使用
SELECT STAT_NAME, VALUE
FROM AWR_PDB_SYSSTAT
WHERE STAT_NAME IN ('db block gets', 'consistent gets', 'physical reads');
```
#### 例2: SQL実行統計の取得
[FORBIDDEN] PDB環境での誤った対応:
```sql
-- 環境判定: CON_ID = 747 (PDB)
SELECT SQL_ID, EXECUTIONS, ELAPSED_TIME
FROM DBA_HIST_SQLSTAT; -- 誤り
```
[CORRECT] PDB環境での正しい対応:
```sql
-- 環境判定: CON_ID = 747 (PDB)
SELECT SQL_ID, EXECUTIONS, ELAPSED_TIME
FROM AWR_PDB_SQLSTAT; -- 正しい
```
### 一貫性チェック
[REQUIRED] 計画策定時と実行時のビュー選択が一貫していることを確認する:
- 計画で「AWR_PDB_SNAPSHOT」を使用すると決定した場合、統計ビューも「AWR_PDB_SYSSTAT」を使用すること
- 計画で「DBA_HIST_SNAPSHOT」と「AWR_PDB_SYSSTAT」を混在させることは禁止
---
## AWRレポート関数(DBMS_WORKLOAD_REPOSITORY)使用時のルール
注意: AWR関連ビューを直接クエリする場合は「CDB/PDB環境でのAWR関連ビュー選択ルール」セクションを参照すること。
### CDB/PDB環境の判定
[REQUIRED] AWRレポートを生成する前に、まず現在の接続環境がCDBかPDBかを確認する:
```sql
SELECT
SYS_CONTEXT('USERENV', 'CON_NAME') AS CONTAINER_NAME,
SYS_CONTEXT('USERENV', 'CON_ID') AS CONTAINER_ID,
CASE
WHEN SYS_CONTEXT('USERENV', 'CON_ID') = 1 THEN 'CDB$ROOT'
WHEN SYS_CONTEXT('USERENV', 'CON_ID') = 0 THEN 'Non-CDB'
ELSE 'PDB'
END AS ENVIRONMENT_TYPE
FROM DUAL;
```
### 環境に応じたDBIDとスナップショットの確認
#### CDB$ROOT または Non-CDB の場合
CDB$ROOTまたはNon-CDB環境では、`DBA_HIST_SNAPSHOT` と `GV$INSTANCE` を使用する:
```sql
SELECT
S.DBID,
I.INSTANCE_NUMBER,
S.SNAP_ID,
S.BEGIN_INTERVAL_TIME,
S.END_INTERVAL_TIME
FROM
DBA_HIST_SNAPSHOT S,
GV$INSTANCE I
WHERE
S.INSTANCE_NUMBER = I.INSTANCE_NUMBER
AND S.END_INTERVAL_TIME >= SYSTIMESTAMP - INTERVAL '24' HOUR
AND S.END_INTERVAL_TIME < SYSTIMESTAMP
ORDER BY
S.SNAP_ID;
```
#### PDB の場合
[FORBIDDEN] PDB環境では `V$DATABASE` からDBIDを取得すること(CDBのDBIDが返されるため)
[REQUIRED] PDB環境では、`AWR_PDB_SNAPSHOT` と `GV$INSTANCE` をジョインして確認する:
```sql
SELECT
A.DBID,
I.INSTANCE_NUMBER,
A.SNAP_ID,
A.BEGIN_INTERVAL_TIME_TZ,
A.END_INTERVAL_TIME_TZ
FROM
AWR_PDB_SNAPSHOT A,
GV$INSTANCE I
WHERE
A.INSTANCE_NUMBER = I.INSTANCE_NUMBER
AND A.END_INTERVAL_TIME_TZ >= SYSTIMESTAMP - INTERVAL '24' HOUR
AND A.END_INTERVAL_TIME_TZ < SYSTIMESTAMP
ORDER BY
A.SNAP_ID;
```
### AWRレポート関数の使用
- 特段の必要性がなければ、テキスト形式のAWRレポート関数を使用
- AWRレポート関数はテーブル関数である
- シグネチャはALL_ARGUMENTSを確認する
#### CDB$ROOT または Non-CDB の場合
```sql
SELECT OUTPUT
FROM TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_TEXT(DBID, INSTANCE_NUMBER, SNAP_ID_START, SNAP_ID_END));
```
#### PDB の場合
```sql
SELECT OUTPUT
FROM TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_PDB_REPORT_TEXT(DBID, INSTANCE_NUMBER, SNAP_ID_START, SNAP_ID_END));
```
### 判定フローのまとめ
```
[START] AWRレポート生成リクエスト
|
v
[STEP 1] CDB/PDB環境を判定(SYS_CONTEXTで確認)
|
+---> CON_ID = 0 (Non-CDB) または CON_ID = 1 (CDB$ROOT)
| |
| v
| DBA_HIST_SNAPSHOT を使用
| DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_TEXT を使用
|
+---> CON_ID >= 2 (PDB)
|
v
AWR_PDB_SNAPSHOT を使用
DBMS_WORKLOAD_REPOSITORY.AWR_PDB_REPORT_TEXT を使用
```
---
## ハルシネーション防止の検証
### レスポンス前チェックリスト
クエリ結果をユーザーに提供する前に、以下のすべてを確認する:
| チェック | 質問 |
|----------|------|
| [ ] | 実際のクエリを実行したか(DESCRIBEやCOUNTだけではなく)? |
| [ ] | 実際のツール出力から結果を報告しているか(仮定ではなく)? |
| [ ] | ツールが失敗した、または何も返さなかった場合、その事実を明確に述べているか? |
| [ ] | ORA-00904発生時はDESCRIBEを実行してからSQLを修正したか? |
すべてのチェックを確認できない場合、クエリ結果を提供してはならない。
### よくある間違いパターン
[FORBIDDEN] 誤ったパターン:
1. DESCRIBEを実行
2. COUNT(*)を実行
3. 実際のクエリをスキップ ← ルール違反
4. スキーマ/カウント情報に基づいて結果を捏造または仮定
[CORRECT] 正しいパターン:
1. DESCRIBEを実行
2. COUNT(*)を実行
3. 実際のクエリを実行 ← 必須
4. 実際のツール出力からのみ結果を報告
### ツール失敗時の正しい応答
```
「ツールの実行がタイムアウトしました。結果を取得できませんでした。
再実行しますか?または条件を変更しますか?」
```
### ツール失敗時の誤った応答
[FORBIDDEN] 以下のような応答は禁止:
```
「ツールはおそらくAWRデータのサマリーを返したと思われます。」
```
このルールは、Oracle Database の AWRレポートを生成して分析するためのルールを記述したプロンプトですので「こんにちは」に対して応答するためには不要なものです。
このファイルの文字数は 12,868 文字です。
実際にやってみると、トークンの消費量が 23k トークンに増えました。およそ 7.7k トークン増えています。日本語で、かつ、このルールのように英単語が多く含まれている場合は、1トークンが1.5文字程度になるのは妥当な数字だと思いますので、ほぼ丸々「AWRレポート生成・分析のルール」分のコンテキストが追加で消費されていることがわかります。
このようなルールを多数登録すると Cline の性能低下やコスト増を招くのは明らかですね。
Cline の Skills を使ってみる
Skills を有効にする
それでは、前記の問題を解決するために Skills が役立つことを見てみましょう。
Cline 右上の歯車マーク(Settings)をクリックして、左メニューの "Features" を選択します

一番下までスクロールダウンして、"Enable Skills"をチェックして、"Done"をクリックします

Skills が有効化されたことを確認する
左下の天秤マーク(Manage Cline Rules & Workflows)をクリックしたとき、上のタブに "Skills"が現れていることを確認します
これで、Skills が利用可能となりました。
"Global Rules" と "Workspace Rules" を無効化しておく
これは、先程の "Workspace Rules" で、AWRレポートと無関係なタスクでも AWRレポートのルール分のトークンが消費されてしまったことが解決されるかどうか確かめるためです
Cline の左下の天秤マーク(Manage Cline Rules & Workflows)をクリックして、すべての"Global Rules" と "Workspace Rules" を無効化(スライダースイッチを青からグレーに変更する)して、天秤から出ている吹き出し以外のどこかをクリックして閉じます
これで、"Global Rules" と "Workspace Rules" がすべて無効になりました
Skills を登録する
Cline の左下の天秤マーク(Manage Cline Rules & Workflows)をクリックして、"Skills"タブを選択して、"Workspace Skills"に "awr-skill"などと Skills の名前を入力して、右端の"+"をクリックします

エディターに "SKILL.md" ファイルが表示されますので、Skill を定義します。今回は、先程の AWRレポートのルールをベースに以下のような Skill を定義しました。
AWRレポート生成分析スキル
---
name: awr-skill
description: Oracle AWRレポートの生成、問題SQLの特定・分析、改善策の提案を行うスキル。CDB/PDB環境に対応し、厳格なエラーハンドリングと3ステップ実行ルールに従う。
---
# awr-skill
Oracle Database環境でAWRレポートを生成し、パフォーマンス問題を引き起こしているSQLを特定・分析して改善策を提案するためのスキル。
## 適用条件
以下のいずれかに該当する場合、このスキルを適用する:
- AWRレポートを生成する場合
- AWR関連のパフォーマンス統計を取得する場合(バッファキャッシュヒット率、I/O統計、待機イベントなど)
- DBA_HIST_* または AWR_PDB_* ビューを使用する場合
- 問題SQLの素性調査や改善策提案を行う場合
---
## 基本ルール
### 3ステップ実行ルール(必須)
すべてのSQLクエリは以下のワークフローに従う。いかなるステップもスキップしてはならない。
| ステップ | アクション | 目的 |
|----------|------------|------|
| 1 | DESCRIBE | スキーマ確認 |
| 2 | SELECT COUNT(*) | 行数の検証 |
| 3 | 実際のクエリ | ユーザーのリクエストを実行 |
**警告**: ステップ3は必須。DESCRIBEとSELECT COUNT(*)は準備ステップに過ぎず、実際のクエリの代わりにはならない。
### ORA-00904(invalid identifier)発生時の強制プロトコル
```
[TRIGGER] ORA-00904 または "invalid identifier" エラーが発生
↓
[STOP] 次のクエリ実行を禁止。修正したSQLをすぐに実行してはならない。
↓
[REQUIRED] DESCRIBE <エラーが発生したテーブル/ビュー> を実行
↓
[REQUIRED] カラム一覧を確認し、存在するカラムのみでSQLを再構築
↓
[REQUIRED] 修正理由を説明してから、修正したSQLを実行
```
**禁止行動:**
- DESCRIBEを実行せずにカラム名を変更・削除して再試行すること
- 「おそらくこのカラム名だろう」という推測での修正
- エラーメッセージだけを見て修正を試みること
### MCPツール実行ルール
- すべてのデータベースクエリは `sqlcl:run-sqlcl` ツール経由で実行する
- MCPツールのレスポンスが空の場合も出力を推測、仮定、捏造してはならない
- ツール実行が失敗した場合は、その事実をユーザーに明示的に伝える
**禁止コマンド(MCPツールでエラーとなる):**
- SET PAGESIZE / SET LINESIZE / SET COLSEP / SET SQLFORMAT / SPOOL
---
## Phase 1: 環境準備とAWRレポート生成
### Step 1.1: データベース接続の確立
1. `sqlcl:list-connections` で利用可能な接続をリスト表示
2. ユーザーに使用する接続を選択してもらう
3. `sqlcl:connect` で選択された接続に接続
### Step 1.2: CDB/PDB環境の判定(必須)
**AWR関連のビューを使用する前に、必ず以下のクエリで環境を判定する:**
```sql
SELECT
SYS_CONTEXT('USERENV', 'CON_NAME') AS CONTAINER_NAME,
SYS_CONTEXT('USERENV', 'CON_ID') AS CONTAINER_ID,
CASE
WHEN SYS_CONTEXT('USERENV', 'CON_ID') = 1 THEN 'CDB$ROOT'
WHEN SYS_CONTEXT('USERENV', 'CON_ID') = 0 THEN 'Non-CDB'
ELSE 'PDB'
END AS ENVIRONMENT_TYPE
FROM DUAL;
```
### Step 1.3: 環境に応じたビュー選択
| 環境タイプ | スナップショットビュー | 統計ビュー | 他のAWRビュー |
|------------|------------------------|------------|---------------|
| Non-CDB (CON_ID=0) | DBA_HIST_SNAPSHOT | DBA_HIST_SYSSTAT | DBA_HIST_* |
| CDB$ROOT (CON_ID=1) | DBA_HIST_SNAPSHOT | DBA_HIST_SYSSTAT | DBA_HIST_* |
| PDB (CON_ID>=2) | AWR_PDB_SNAPSHOT | AWR_PDB_SYSSTAT | AWR_PDB_* |
**禁止**: PDB環境で DBA_HIST_* ビューを使用すること(CDBレベルのデータが返されるため不正確)
### Step 1.4: AWRスナップショット情報の取得
**PDB環境の場合(AWR_PDB_SNAPSHOT を使用):**
```sql
-- 1. 構造確認
DESCRIBE AWR_PDB_SNAPSHOT
-- 2. 件数確認
SELECT COUNT(*) as snapshot_count
FROM AWR_PDB_SNAPSHOT A, GV$INSTANCE I
WHERE A.INSTANCE_NUMBER = I.INSTANCE_NUMBER
AND END_INTERVAL_TIME_TZ >= SYSTIMESTAMP - INTERVAL '24' HOUR
-- 3. スナップショット情報取得
SELECT A.DBID, I.INSTANCE_NUMBER, A.SNAP_ID,
A.BEGIN_INTERVAL_TIME_TZ, A.END_INTERVAL_TIME_TZ
FROM AWR_PDB_SNAPSHOT A, GV$INSTANCE I
WHERE A.INSTANCE_NUMBER = I.INSTANCE_NUMBER
AND END_INTERVAL_TIME_TZ >= SYSTIMESTAMP - INTERVAL '24' HOUR
AND END_INTERVAL_TIME_TZ < SYSTIMESTAMP
ORDER BY SNAP_ID
```
**CDB$ROOT / Non-CDB環境の場合(DBA_HIST_SNAPSHOT を使用):**
```sql
SELECT S.DBID, I.INSTANCE_NUMBER, S.SNAP_ID,
S.BEGIN_INTERVAL_TIME, S.END_INTERVAL_TIME
FROM DBA_HIST_SNAPSHOT S, GV$INSTANCE I
WHERE S.INSTANCE_NUMBER = I.INSTANCE_NUMBER
AND S.END_INTERVAL_TIME >= SYSTIMESTAMP - INTERVAL '24' HOUR
AND S.END_INTERVAL_TIME < SYSTIMESTAMP
ORDER BY S.SNAP_ID
```
**記録する情報:**
- DBID
- INSTANCE_NUMBER
- 開始SNAP_ID(最小値)
- 終了SNAP_ID(最大値)
### Step 1.5: AWRレポート関数のシグネチャ確認(必須)
```sql
SELECT argument_name, position, data_type, defaulted, in_out
FROM all_arguments
WHERE package_name = 'DBMS_WORKLOAD_REPOSITORY'
AND object_name = 'AWR_REPORT_TEXT'
ORDER BY position
```
### Step 1.6: AWRレポート生成
**PDB環境:**
```sql
SELECT OUTPUT
FROM TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_PDB_REPORT_TEXT(
<DBID>, <INSTANCE_NUMBER>, <開始SNAP_ID>, <終了SNAP_ID>
))
```
**CDB$ROOT / Non-CDB環境:**
```sql
SELECT OUTPUT
FROM TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_TEXT(
<DBID>, <INSTANCE_NUMBER>, <開始SNAP_ID>, <終了SNAP_ID>
))
```
**レポートから注目するセクション:**
- Top Wait Events
- Top SQL by Elapsed Time / CPU Time / Gets / Executions
---
## Phase 2: 問題SQLの特定
### Step 2.1: CPU時間が高いSQL Top 10を取得
```sql
-- 1. 構造確認
DESCRIBE DBA_HIST_SQLSTAT
-- 2. 件数確認
SELECT COUNT(*) as record_count
FROM DBA_HIST_SQLSTAT
WHERE snap_id BETWEEN <開始SNAP_ID> AND <終了SNAP_ID>
AND dbid = <DBID>
-- 3. Top 10 取得
SELECT sql_id,
SUM(cpu_time_delta)/1000000 as cpu_seconds,
SUM(elapsed_time_delta)/1000000 as elapsed_seconds,
SUM(executions_delta) as executions,
SUM(buffer_gets_delta) as buffer_gets
FROM DBA_HIST_SQLSTAT
WHERE snap_id BETWEEN <開始SNAP_ID> AND <終了SNAP_ID>
AND dbid = <DBID>
GROUP BY sql_id
ORDER BY cpu_seconds DESC
FETCH FIRST 10 ROWS ONLY
```
---
## Phase 3: 問題SQLの素性調査
各問題SQL_IDに対して以下を実行する。
### Step 3.1: 誰が実行したか?(Who)
```sql
SELECT DISTINCT
h.user_id, u.username, h.module, h.action, h.program, h.client_id
FROM DBA_HIST_ACTIVE_SESS_HISTORY h
LEFT JOIN dba_users u ON h.user_id = u.user_id
WHERE h.sql_id = '<SQL_ID>'
AND h.snap_id BETWEEN <開始SNAP_ID> AND <終了SNAP_ID>
AND h.dbid = <DBID>
```
### Step 3.2: いつ・どのくらいの頻度で?(When & Frequency)
```sql
SELECT
TO_CHAR(s.end_interval_time_tz, 'YYYY-MM-DD HH24') as hour,
SUM(st.executions_delta) as executions,
SUM(st.cpu_time_delta)/1000000 as cpu_seconds
FROM DBA_HIST_SQLSTAT st
JOIN AWR_PDB_SNAPSHOT s ON st.snap_id = s.snap_id
AND st.dbid = s.dbid AND st.instance_number = s.instance_number
WHERE st.sql_id = '<SQL_ID>'
AND st.snap_id BETWEEN <開始SNAP_ID> AND <終了SNAP_ID>
AND st.dbid = <DBID>
GROUP BY TO_CHAR(s.end_interval_time_tz, 'YYYY-MM-DD HH24')
ORDER BY hour
```
### Step 3.3: 対象オブジェクトは?(What Objects)
```sql
SELECT DISTINCT
object_owner, object_name, object_type, operation, options
FROM DBA_HIST_SQL_PLAN
WHERE sql_id = '<SQL_ID>' AND dbid = <DBID> AND object_name IS NOT NULL
ORDER BY object_owner, object_name
```
### Step 3.4: SQL文と実行計画(What Processing)
```sql
-- SQL文
SELECT sql_text FROM DBA_HIST_SQLTEXT
WHERE sql_id = '<SQL_ID>' AND dbid = <DBID>
-- 実行計画
SELECT id, parent_id, operation, options, object_owner, object_name,
cardinality, bytes, cost
FROM DBA_HIST_SQL_PLAN
WHERE sql_id = '<SQL_ID>' AND dbid = <DBID>
AND plan_hash_value = <PLAN_HASH_VALUE>
ORDER BY id
```
---
## Phase 4: 改善策の提案
以下の観点から改善策を検討・提案する:
1. **インデックスの最適化** - フルテーブルスキャン、適切なインデックス有無
2. **SQL文の書き換え** - 非効率な結合、不要なソート、サブクエリ最適化
3. **統計情報の更新** - オブジェクト統計、ヒストグラム
4. **アプリケーション改善** - バッチ処理、実行頻度、トランザクション設計
5. **システムパラメータ調整** - メモリ割り当て、パラレル処理
6. **アーキテクチャ改善** - パーティショニング、マテリアライズドビュー
---
## Phase 5: 最終レポート作成
マークダウン形式で以下の構成のレポートを作成し、ファイルに出力する:
- 実行期間とスナップショット範囲
- 主要な問題領域
- 問題SQL一覧(各SQLについて)
- 影響度メトリクス
- 素性情報(実行ユーザー、MODULE、時刻帯、対象オブジェクト)
- SQL文
- 実行計画の問題点
- 推奨される改善策
---
## エラーハンドリング
### ORA-00942(table or view does not exist)
```sql
SELECT table_name FROM user_tables WHERE table_name LIKE '%キーワード%'
SELECT owner, table_name FROM all_tables WHERE table_name = '...'
```
### 3回同じエラーが発生した場合
アプローチを根本的に変更し、ユーザーに状況を報告する。
### ツール実行失敗・タイムアウト時
- 結果を取得できなかったことをユーザーに明示的に伝える
- 結果を補完、推定、推測しない
- 再試行するか確認する
Skill の入力が終わったら Ctrl-S で保存して、エディターを閉じます
Cline の "Workspace Skills" の "awr-skill"がスライドスイッチが青くなっている(有効である)ことを確認して、天秤マークから出ている吹き出しの外をクリックして閉じます
Skill が不要なタスクを実行してみる
Cline 右上の"+"をクリックして新しいタスクを開始して、「こんにちは」と問いかけて消費コンテキストを確認します

消費コンテキストは、15.5k でした。これは、最初に実行した "Global Rules" も "Workspace Rules"も "Skills" も無い状態とほぼ同じ消費量です。つまり、先程定義した Skill は読み込まれていないようです。「こんにちは」に応えるためにAWRの知識は必要ありませんので期待した動作です。
Skill が必要なタスクを実行してみる
天秤マークから"Skills"タブを開いて、先程定義したSkill(例では、 "awr-skill")のスライドスイッチがオン(青)であることを確認した上で、Cline 右上の"*"をクリックして新しいタスクを開始します。右下の"PLan/Act"の"Plan"をクリックして、Planモードに変更して、チャット窓に「過去24時間のAWRレポートを取得して性能分析して改善案を提案する計画を立ててください。」などの指示を入力して送信します
Cline が Skill をロードしていることがわかります

コンテキスト削減の観点で期待通りの動作をしていることが確認できました
このまま、MCPツールの利用を許可して計画を続けてもらうと以下のような計画が立案されました
過去24時間のAWRレポート取得・性能分析・改善案提案の実行計画
awr-skillを基に、Oracle DatabaseのAWRデータを活用した体系的な計画を立てました。この計画は、スキルの3ステップ実行ルール(DESCRIBE → COUNT(*) → 実際クエリ)とCDB/PDB環境対応を厳守します。MCPツール(SQLcl-SQL-Developer)を使用して安全に実行します。
前提確認
- 対象期間: 現在(2026/1/24 18:34頃)から過去24時間(2026/1/23 18:34頃〜2026/1/24 18:34頃未満)。
-
利用可能接続(list-connectionsで確認済み):
(...中略...)
最初のアクション: 分析対象のデータベース接続名を選択してください(例: "......")。PDB環境推奨(AWR_PDB_*ビュー使用)。
実行フェーズ(ACT MODEで実施)
Phase 1: 環境準備とAWRレポート生成
-
接続確立:
-
sqlcl:connectで選択接続に接続。
-
-
CDB/PDB環境判定(必須):
DESCRIBE DUAL; SELECT COUNT(*) FROM DUAL; SELECT SYS_CONTEXT('USERENV', 'CON_NAME') AS CONTAINER_NAME, ... FROM DUAL;- Non-CDB/CDB$ROOT: DBA_HIST_*
- PDB: AWR_PDB_*
-
スナップショット取得(過去24時間、環境対応ビュー):
- DESCRIBE / COUNT(*) / SELECT で開始/終了SNAP_ID、DBID、INSTANCE_NUMBER取得。
-
AWRレポート関数確認:
SELECT argument_name, ... FROM all_arguments WHERE package_name = 'DBMS_WORKLOAD_REPOSITORY' AND object_name = 'AWR_REPORT_TEXT'; -
AWRレポート生成:
SELECT OUTPUT FROM TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_REPORT_TEXT(DBID, INSTANCE_NUMBER, 開始SNAP_ID, 終了SNAP_ID));- 注目: Top Wait Events, Top SQL (Elapsed/CPU/Get/Executions)。
Phase 2: 問題SQL特定
-
Top 10 CPU時間SQL:
DESCRIBE DBA_HIST_SQLSTAT; COUNT(*); SELECT sql_id, SUM(cpu_time_delta)/1e6 AS cpu_seconds, ... ORDER BY cpu_seconds DESC FETCH FIRST 10 ROWS ONLY;
Phase 3: 問題SQL分析(各Top SQLに対し)
- Who: DBA_HIST_ACTIVE_SESS_HISTORY でユーザー/MODULE/ACTION/PROGRAM。
- When/Frequency: 時間帯別実行回数/CPU。
- What Objects: DBA_HIST_SQL_PLAN でオブジェクト。
- SQL文/実行計画: DBA_HIST_SQLTEXT / DBA_HIST_SQL_PLAN。
Phase 4: 改善策提案
- インデックス最適化、SQL書き換え、統計更新、アプリ改善、パラメータ調整、アーキテクチャ変更。
Phase 5: 最終レポート
- Markdownファイル出力(例:
AWR_Analysis_Report_20260124_24hours.md)。 - 構成: 期間/問題領域/SQL詳細(メトリクス/素性/SQL/計画/改善策)。
リスク・エラーハンドリング
- ORA-00904: DESCRIBE必須でカラム修正。
- ビュー不存在: 環境判定後テーブル検索。
- ツール失敗: ユーザー通知、再試行確認。
- 過去レポート(AWR_Analysis_Report_*.md)と比較可能。
次のステップ
- 接続名を教えてください(例: "Dev Day Tokyo orasejapan - labuser")。
- この計画でOKなら、"toggle to Act mode" を実行してACT MODEに切り替え、実施開始。
- 修正希望があれば教えてください。
この計画で過去24時間の性能問題を網羅的に分析・改善提案可能です。
右下の"Plan/Act"の "Act" をクリックして Actモードへ切り替えると実際にタスクの処理が開始されます。
実行結果は以下のとおりでした。

そして、AWRレポート本体と分析結果レポートがファイルにマークダウン形式で保存されました
過去24時間 AWR性能分析レポート
過去24時間 AWR性能分析レポート (2026/1/23 09:01 GMT - 2026/1/24 09:00 GMT)
概要
- 分析範囲: SNAP_ID 6074-6097 (DBID=1587474289, INSTANCE=8, PDB: SYA6VPHK3PZLKHQ_DEVDAY25ARAKAWA)
- 期間: 約23時間経過時間, DB Time 2977分 (49.6時間, AAS 2.2)
- 環境: Oracle 23c PDB, Exadata (cell smart scan使用)
- Raw AWR: AWR_Report_20260123_09_to_20260124_09_raw.txt
主要メトリクス
| メトリクス | 値 (per sec / txn) |
|---|---|
| DB CPU | 95.7% |
| User I/O | 1.7% (cell smart table scan主) |
| Concurrency | 1.1% (library cache mutex) |
| Logical Reads | 209k blks/sec |
| Physical Reads | 2.5k blks/sec (20MB/sec) |
| Executes | 3.3k /sec |
主要問題領域
- DB CPU消費高 (95.7%): Top SQLがCPU大半消費。
- User I/O (cell scan): Stats job / autotask がフルスキャン。
- Library Cache Mutex: 高頻度parse/execute (parallel chunk tasks)。
問題SQL一覧
1. SQL_ID: fwbhcwv7mmwyy (93.6% DB Time)
- メトリクス: CPU 168k sec, Elapsed 174k sec, Exec 10k, Gets 17B
-
SQL:
call C##CLOUD$SERVICE.DBMS_CLOUD_PIPELINE.RUN_PIPELINE ( :0,:1 ) - Module: DBMS_SCHEDULER (自動スケジュール)
- Who: ADMIN / SYS (autotask)
- When: 全期間均等
- Objects: DBMS_PARALLEL_EXECUTE_CHUNKS$, PIPELINE$*_STATUS (vector index pipeline)
- 実行計画: 未取得だがchild PL/SQL多 (run_parallel_task_chunk)
- 問題点: Vector index構築パイプラインがCPU/Parse負荷高。
改善策:
- パイプラインスケジュール変更 (off-peak)。
- chunk_size増 / parallel_servers低減。
- Vector embedding model最適化 (smaller model)。
- Resource Managerでlimit。
2. SQL_ID: b39m8n96gxk7c (autotask, 5.6%)
- メトリクス: CPU 8k sec, Elapsed 10k sec, Exec 242, Gets 264M, Phys Read 200M blks
-
SQL:
call dbms_autotask_prvt.run_autotask ( :0,:1 ) - Module: DBMS_SCHEDULER
- 問題点: High IO (stats/index analyze full scan)。
改善策:
-
DBMS_AUTO_TASK_ADMIN.COALESCE_STATS使用。 - Maintenance window外実行。
-
STATISTICS_LEVEL=TYPICAL確認。
3. SQL_ID: 93w8sdhx08qwf (stats job, 4.5%)
- メトリクス: CPU 6k sec, Elapsed 8k sec, Exec 91, Gets 251M, Phys Read 190M
-
SQL:
begin /* KAPS */ dbms_stats.gather_st_job_continuous_proc; end; - 問題点: Continuous stats high IO。
改善策:
-
DBMS_STATS.SET_GLOBAL_PREFS('DEGREE',4)低減。 - Incremental stats有効テーブル増。
4. Parallel chunk tasks (1nw8wgn4z2bsg, 9n11d2m4m8d6jなど)
- High exec (18M), mutex waits。
- 改善: Pipeline内でchunk並列度調整。
全体改善策
- DBMS_CLOUD Pipeline最適化 (最大影響): スケジュール/パラメータ調整 → 80-90%改善期待。
- Maintenance Jobs: Window外/degree低減 → IO 50%減。
-
パラメータ:
parallel_degree_policy=MANUAL, cursor_sharing=EXACT確認。 - モニタ: AWR hourly + ASHでpipeline監視。
-
Stats:
GATHER STATS PROGdisable検討。
期待効果: CPU負荷50-70%減, AAS 1未満。
詳細Raw AWR参照。
あとがき
Cline の Skills によって目的、タスクに専門特化したスキル(ルールやワークフロー)を予め定義しておくことで必要に応じてスキルが呼び出されてエージェントの動作をガイドできること、必要なときにだけスキルがコンテキストに読み込まれることでコンテキスト消費を抑えることができることが確認できました。なお、この記事では、AWRレポートの分析結果の評価は行っていません。
関連ブログご紹介







