議事録の整理
実行ステップ
入力に識別可能な会議内容が含まれているか確認する。 討論の意見、最終的な結論、保留中の質問を区別する。 アクションアイテム、担当者、締め切りを抽出する。 検証できない情報を「確認待ち」としてマークする。 指定されたテンプレートに従って出力し、元の記録と照合する。
ここで、`name`と`description`は仕様の必須フィールドです。`name`は現在のスキルに名前を付け、`description`は現在のスキルのタスク説明を提供します。それでは、スキルはどのようにタスクを開始し、完了するのでしょうか?
スキルをインストールすると、システムはすべてのファイルを一度に大きなモデルに渡しません。一般的な実行プロセスには3つのステップがあります:
1. システムはまずインストールされたスキルの名前と説明を提供します。大きなモデルはユーザーのタスクに基づいて、どの能力が関連するかを判断します。
2. スキルが選択されると、システムはその`SKILL.md`を読み込みます。大きなモデルは据此で入力をチェックし、コアステップを実行します。
3. 特定のステップを実行する時のみ、指示に従って参照資料を読み込み、テンプレートを適用し、スクリプトを実行します。
例えば、ユーザーが会議記録を議事録に整理するよう依頼した場合、大きなモデルやAgentツールは複数のスキルから議事録能力をマッチさせ、その完全なルールを読み込みます。タスクがExcelのアクションアイテム表の生成も要求する場合、表処理スキルも同時に選択されることがあります。大きなモデルは現在のタスクに基づいて判断を行い、スキルは安定した方法を提供し、プラットフォームやAgentフレームワークはファイルのロードとツールの呼び出しを行います。
維持管理されるスキルと比較して、Prompt、ワークフロー、MCPにはどのような違いがあるのでしょうか?以下で整理します。
<a id="c28-s2"></a>
## <strong>スキルとプロンプトの違い</strong>
プロンプトは現在のタスクで大きなモデルまたはエージェントに入力するもので、通常は目標、材料、制約条件、出力要求を含みます。これは今回何をするかに答えます。例えば:
```bash
この会議の文字起こしを議事録に整理してください。結論とアクションアイテムをリストアップしてください。
このプロンプトは今回の目標を説明していますが、何が最終結論とみなされるか、担当者が不足している場合どうするか、原文にない情報を補完できるか、出力にどのような構造を使用するかなどは完全に規定されていません。スキルはこれら比較的安定したルールを事前に保存します。次回会議記録を処理する際は、今回の材料と具体的な要求を提供するだけで、一式の方法を再作成する必要はありません。役割、媒体、ロード方式、バージョン管理などの観点から、プロンプトとスキルを比較します:
次元 | Prompt | Skill |
主な機能 | 現在のタスクを記述 | タスクタイプがどのように達成されるかを定義 |
使用サイクル | 主に現在のリクエストにのみ使用 | 複数回呼び出し、継続的にメンテナンス可能 |
媒体 | 会話内のテキスト、ファイル、コンテキスト |
|
もちろん、プロンプトとスキルは二者択一ではありません。プロンプトは今回のタスクで大きなモデルやAgentにどの材料を処理するか、どのような臨時要求があるかを伝える役割を果たし、スキルはこの種のタスクで既に確立された方法を提供します。同じスキルでも異なる入力面對する場合は、プロンプトで今回の目標を説明する必要があります。すべてのプロンプトがスキルとして作成する価値があるわけではありません。一度だけで目標も変化するタスクには、まずプロンプトで回すのが適切です。同様のタスクが繰り返し発生し、処理方法が徐々に安定してきたら、それをスキルとしてまとめると良いでしょう。
ワークフローは複数のタスクノードを組織するための一連の運用配置で、通常は順序、条件分岐、データ伝送、失敗後の行き先を規定します。これは複数のステップがどのように連携するかに答えます。
例えば、週報ワークフローは以下のようになります:
生データを読み込む → フィールドをクリーンアップ → チャートを生成 → 分析を書く → 週報をエクスポート
スキルが注力するのは、ある能力ユニットがどのように完成すべきかです。上記の各ステップはスキルによって方法を提供することも、スクリプト、手動操作、その他のツールによって完了することもできます。両者の違いはどちらが固定でどちらが柔軟かではなく、注力対象が異なる点にあります:
スキル内部には固定ステップを含めることも、条件分岐を含めることもできます。ワークフローもあるノードでAgentを呼び出し、状況に応じて次のステップを決定させることができます。例えば、議事録スキルは入力に基づいて異なる処理を行えます:
ログイン ディスカッションに参加
実際のシステムでは、スキルとワークフローは頻繁に組み合わせて使用されます:ワークフローは複数のステップを串刺しにし、スキルはその中のあるステップを安定した方法で完了させます。
MCPはモデルコンテキストプロトコルで、Agentに外部ツール、リソース、プロンプトテンプレートを統一された方法で提供するために使用されます。これはAgentが外部能力にどう接続し、呼び出すかに答えます。MCPを通じて、Agentはデータベース、ナレッジベース、プロジェクト管理システム、地図サービス、その他のビジネスシステムに接続できます。しかし、接続が成功したことはAgentがその能力を使用できることを示すだけで、ビジネスタスクをどのように完了すべきかを知っていることを意味しません。Agentが既にプロジェクト管理システムにアクセスできるとしても、まだ以下のことを知る必要があります:
これらのタスクルールはスキルに書くのが適切です。両者の関係を要約すると:MCPは外部ツールやデータに接続する標準方法を提供し、スキルはこれらの能力を使ってある種のタスクをどのように完了するかを記述します。
スキルはAgentにMCPツールの呼び出しを指示することも、MCPをまったく使用せずに完了することもできます。MCPサービスも複数のスキルによって使用され得ます。メッセージ送信、記録修正、データ削除、コスト発生、公開発行が関係する場合、スキルは確認ポイントを明確に規定すべきであり、ツールが接続されているという理由で実行を許可するべきではありません。
概念 | 主に答える問題 | 典型的な内容 |
Prompt | 今回は何をするか | 現在の目標、材料、臨時要求 |
Skill | この種のタスクは通常どう行うか | 方法、ルール、リソース、ツール、検収 |
ワークフロー | 複数のステップはどう連携するか | ノード、順序、分岐、結果の伝送 |
MCP | Agentはどう外部能力に接続するか | ツール、リソース、パラメータ、呼び出しインターフェース |
完全なスキルには、タスクメソッドを記述するコンテンツと、そのコンテンツを運ぶファイルの両方が必要です。タスク自体としては、トリガー条件、入力、実行ステップ、ツールとリソース、出力、例外処理を明記する必要があります。ファイル組織としては、少なくともエントリファイルSKILL.mdが必要で、少し複雑なスキルには参照資料、テンプレート、スクリプト、テストケースが追加されます。議事録スキルを例にすると、完全なディレクトリは以下のように構成できます:
meeting-notes/
├── SKILL.md # 入口:名称、説明、入力、ステップ、検収条件
├── references/
│ ├── terms.md # 用語集とコンテンツ分類ルール
│ └── privacy-rules.md # 機密情報と脱敏要求
├── assets/
│ └── meeting-template.md # 議事録出力テンプレート
├── scripts/
│ └── clean-transcript.py # タイムスタンプと繰り返し口癖のクリーンアップ
└── tests/
├── normal-case.md # 情報が完全なテストケース
├── boundary-case.md # 情報が不足または矛盾するケース
└── failure-case.md # 処理を継続できないケース
このうち、SKILL.mdはディレクトリ全体の入口です。Agentはまずここからスキルがどのようなタスクの処理に適しているか、どのような入力が必要か、どのようなステップで実行するかを理解します。さらに、他の制約に応じて、上記のディレクトリ構成で専門用語やプライバシー要件に遭遇した場合はreferences/ディレクトリから関連情報を読み込み、結果生成フェーズではassets/のテンプレートを適用し、テキストクリーンアップなどの機械的な操作を安定して完了する必要がある場合はscripts/のプログラムを実行します。tests/は主に開発や改版後の検証用で、毎回タスクを実行する際にロードするものではありません。構築フェーズでは、ディレクトリは一度に完全に構築する必要はありません。ルールが少ない場合は、1つのSKILL.mdだけで実行可能なスキルを構成できます。メインファイルが長くなるか、ある資料、テンプレート、スクリプトを繰り返し使用する必要がある場合は、さらに分割できます。ファイルの数に関係なく、Agentが実際に実行するのは以下のタスクチェーンです:
ユーザーがタスクを提出
↓
大きなモデルが名前とdescriptionに基づいて関連スキルをフィルタリング
↓
選択されたスキルのSKILL.mdをロード
↓
入力をチェック → ステップを実行 → ツールとリソースを使用 → 出力を生成してチェック
↓
異常が発生した場合はルールに従って停止、降格、または補充を依頼
複数のスキルが同時に存在する場合、大きなモデルは通常、各スキルの名前と説明を比較し、現在の意図に最も関連する最小集合を選択します。例えば、会議記録を議事録に整理してアクションアイテム表をエクスポートする場合、議事録スキルと表処理スキルの両方が必要な場合があります。テキストの整理のみを要求される場合、表処理能力をロードする必要はありません。具体的なフィルタリングと呼び出し方法は使用するプラットフォームやAgentフレームワークの実装に依存しますが、スキル作成者は適用シナリオと境界を明確に記述し、大きなモデルが正しい選択を行えるようにする必要があります。
以下では、トリガー条件、入力チェック、実行ステップ、ツールとリソース、出力制御などの観点から紹介します。
トリガー条件とは、スキルが大きなモデルに多くのスキルから現在必要となる能力を見つけることを提供するもので、主にSKILL.mdの先頭にあるnameとdescriptionに表れます。議事録スキル为例、nameはスキルの識別名で、通常は小文字、数字、ハイフンを使用し、ディレクトリ名と一致させます。短く明確で、人間とシステムの両方がこの能力を区別できるようにする必要があります。例:
name: meeting-notes
descriptionはこのスキルが何をできるか、どのようなタスクに遭遇した場合に使用すべきかを説明します。大きなモデルがユーザーのタスクを読んだ後、タスクの意図をインストール済みスキルの名前と説明と比較します。マッチが成功した場合のみ、完全なSKILL.mdのロードが継続されます。議事録スキルのdescriptionは以下のように書けます:
description: 会議の文字起こし、チャット記録、散らかったメモを構造化された議事録に整理します。ユーザーが会議の要約を生成し、結論、アクションアイテム、または未確認の問題を抽出するよう要求した場合に使用します。
トリガー確率を高めるために大量の無関係なキーワードを詰め込んではいけません。説明が広すぎると、Agentが無関係なタスクで誤って使用し、説明が狭すぎると、本当に必要になった場合に見つかりません。最終的にスキルの作成を完了するにはテストに依存する必要があり、トリガーすべきタスクとトリガーすべきでないタスクの両方を検証する必要があります。例えば、会議録音のASR認識スキルは、議事録関連タスクではトリガーされるべきではありません。
入力チェックとは、スキルの実行を開始する際、Agentや大きなモデルがタスクを完了するために何が必要か、どの材料が必須で、どの材料が省略可能で、重要な情報が不足している場合どう処理するかを知る必要があることを指します。したがって、スキルが選択された後の次のステップはすぐに結果を生成するのではなく、材料が十分かどうかをチェックすることです。議事録スキル为例、入力部分は以下のように約束できます:
入力チェックが通過した後、Agentは正式にタスクの処理を開始します。実行ステップは材料の読み取りから成果物の配信までの完全な順序を明記する必要があります:各ステップで何を処理し、どのような中間結果を得、異なる状況に遭遇した場合はどこに転送するか。分析内容や重点の抽出だけを書いたのでは、Agentが安定して実行できません。議事録スキルは以下の順序で処理できます:
1. 会議材料すべてを読み込む;ファイルが空または読み取りできない場合は例外処理に転送。
2. 会議のテーマ、時間、参加者を識別し、不足したフィールドは一時的に空白を維持。
3. 原意に影響しない口癖や繰り返し内容をクリーンアップし、同時に元の材料は変更しない。
4. 議題に基づいて内容を整理し、発言を意見、決定、未確認の問題に分類。
5. 会議内容から明確に割り当てられたアクションアイテムを抽出し、タスク、担当者、締め切りを記録。
6. 担当者または締め切りが原文に出現しない場合、対応するフィールドを「確認待ち」としてマーク。
7. 整理結果を議事録テンプレートに入力。
8. 原文を項ずつ再確認;根拠が見つからない結論とアクションアイテムは配信してはならない。
上記の例示のステップには、明確な入口、処理順序、終了条件があります。ステップ1はタスクが継続できるかどうかを決定し、ステップ2から6は構造化されたコンテンツを形成し、ステップ7は配信結果を生成し、ステップ8は検収を担当します。実行ステップがこの程度まで書かれていると、後続のツール、テンプレート、例外ルールがどのステップに接続すべきかが明確になります。
実行ステップは何をするかを説明し、ツールとリソースは具体的に何に依存して完了するかを説明します。ツールはアクションを実行し、例えばファイルの読み取り、スクリプトの実行を行います。リソースはルールとテンプレートを提供し、例えば用語集、プライバシー要件、議事録形式を提供します。両方とも具体的な名称と使用タイミングを記述する必要があります。議事録スキルは以下の内容を使用できます:
タイプ | 具体的なツールまたはリソース | 使用タイミング | 役割 |
ファイル読み取りツール | Pythonの | ステップ1の実行時 | UTF-8エンコードのTXTまたはMarkdownの会議記録を読み取る |
Word読み取りツール |
| 入力がDOCXの場合 | Wordドキュメントの段落と表のテキストを読み取る |
クリーンアップスクリプト |
| 議題分割前 | タイムスタンプ、連続繰り返し文、原意に影響しない口癖をクリーンアップ |
用語リソース |
| 略語や専門用語に遭遇した場合 | プロジェクト名、製品名、人物の呼称を統一 |
プライバシーリソース |
| 出力前の確認時 | 個人情報やビジネスの機密コンテンツが脱敏が必要かどうかを判断 |
出力テンプレート |
| 議事録生成時 | 会議情報、結論、アクションアイテム、未確認の問題の配置方法を規定 |
SKILL.mdはこれらの名前を列挙するだけでなく、いつ呼び出すかを説明する必要があります。例えば、通常のTXTはpathlibで直接読み取ります。DOCXはpython-docxに変更します。テキストにプロジェクトの略語が出現した場合のみ用語集を読み取ります。外部送信が必要な場合はプライバシーリールを確認します。スクリプトは入力、出力、依存関係も説明し、実行失敗時はどの例外処理に進むべきかを記述する必要があります。アクセストークンやパスワードはスキルファイルやスクリプトに記述してはなりません。
処理完了後、Agentはどのように配信するかを知る必要があります。出力制御フェーズでは、議事録を生成するだけでなく、構造、形式、完了基準を説明する必要があります。要求に応じて、出力形式を約束できます。例えば:
議事録
一、会議情報
会議テーマ:
会議時間:
参加者:
二、重要結論
……
三、アクションアイテム
四、未確認の問題
結果をファイルとして保存する必要がある場合は、ファイルタイプ、命名規則、保存場所も説明する必要があります。
例外処理は入力、実行、ツール呼び出し、出力チェックにわたるもので、最後に追加する説明ではありません。Agentが問題に遭遇した場合に継続するか、降格するか、停止するか、ユーザーに確認を依頼するかを決定します。
一般的な例外には、入力が空、ファイルが破損、依存関係が不足、外部サービスが利用不可、ツールの権限不足、異なる材料間の情報矛盾などがあります。以下の4つの統一原則を使用できます:
前章ではスキルがどのように発見され、どのように実行されるか、また完全な能力に哪些部分が必要かを説明しました。ここでは、これらの内容を議事録のケースに落とし込みます。
スキルの設計の核心は、まずディレクトリを構築するか長いプロンプトを書くことではなく、人の業務経験をAgentが実行・検証できる方法に整理することです。このプロセスは6つのステップに分けられます:カプセル化に適したタスクの選択、目標と境界の確定、人間の方法の振り返り、経験をルールに書き換える、実行可能な初版の作成、最短のクローズドループの実現。各ステップは次のステップに必要な内容を生成します:タスクの範囲は入出力を決定し、人間の方法は実行ステップを形成し、初版はこれらの内容を組織し、テスト結果は次の改版への修正を推進します。
以下では引き続き議事録スキルを例に、曖昧な要求からModelScopeで実行可能な能力を段階的に形成する過程を説明します。
スキルとして作成するのに適したタスクには、いくつかの共通点があります:
議事録の整理はこれらの条件を満たしています:毎回の会議内容は異なりますが、材料の確認、結論の識別、アクションアイテムの抽出、出力の組織化の方法は基本的に同じです。結果は原文に戻って項ずつ確認できます。そこで、本章ではこれを通貫ケースとして選択します。
タスクの目標自体がまだ明確でない場合や、毎回完全に現場の判断に依存する必要がある場合は、急いでスキルを作成する必要はありません。まずプロンプトで数回実行し、方法が安定してからまとめると良いでしょう。
タスクを選択した後、幅広い願望を配信・検収可能な目標に絞り込む必要があります。オフィスアシスタントを作ると範囲が広すぎ、安定したスキルにはなりません。
議事録スキルの初版の目標は以下のように書けます:
生の会議記録を受信し、会議情報、重要結論、アクションアイテム、未確認の問題を含む構造化された議事録を出力する。常識に基づいて原文にない担当者、日付、結論を補完しない。
この目標は入力、出力、禁止事項を明確にしています。初版の入力は既にテキスト化された会議記録で、録音の文字起こしは担当しません。結果はまずMarkdownとして保存し、自動でメールを送ったり、プロジェクト管理システムに書き込んだりしません。境界が明確であるほど、後のステップ、例外、テストの定義が容易になります。
目標が明確になったら、まず人間がタスクを完了する際に実際に使用する方法を特定し、どのアクションを固定でき、どの部分がまだコンテキストに基づいて判断する必要があるかを判断します。整理のロジックは以下の方法に従えます:まず3層フィルタリングを行い、次に4次元抽出を完了します。
3層フィルタリングとは、会議の文字起こしを順に処理することです:
クリーンアップを完了した後、4つの次元から情報を整理します:
1. 議題:会議でどの問題が議論されたか;
2. 見解:各議題に関して、各方がどの重要な意見を表明したか;
3. 決定:どの事項が明確な合意に至ったか;
4. タスク:誰がいつまでに何を完了すべきか。
この方法は議事録タスクの振り返りに非常に適しています。なぜなら、これは人間が整理する際の真の順序を再現しているからです:まず元の材料のノイズを低減し、次にコンテンツ間の関係を識別し、最後に実行する必要があるタスクを抽出します。振り返りの際にはさらにいくつかの詳細を追求する必要があります:コンテンツの削減は原意を変えるかどうか、何が正式な決定とみなせるかどうか、担当者や締め切りが不足している場合どう処理するか、材料が矛盾している場合ユーザーに確認を依頼する必要があるかどうか。このステップを経て得られるのは、一般的な経験のまとめではなく、さらに分解可能な処理ルートです。次のセクションでは、フィルタリング、分類、抽出、確認をAgentが実行可能なアクション、条件、チェックポイントに書き換えます。
次に、上記の記録にある経験を、Agentが実行可能な3つのカテゴリのステートメントに書き換えます:
3つのカテゴリのステートメントは連携して使用します。まずアクションを実行し、異なる状況に遭遇した場合は条件に従って分岐し、完了後はチェックポイントで検収します。例えば、まずアクションアイテムを抽出する;担当者または締め切りが不足している場合はアクションアイテムを維持して「確認待ち」とマークし、出力前に各タスクが原文で根拠を見出せるかを確認する。1つの要求で完了を判断できない場合は、さらに細かく分解します。
前章の整理を経て、初版SKILL.mdには材料が揃っています。書く際はAgentがタスクを処理する順序に従って組織化できます。例えば議事録タスクでは、まず通常の会議の結論をまとめ、さらに次のステップのタスクや未確認の問題を整理するなど、この順序でスキルの記述情報を出力します。例:
---
name: meeting-notes
description: 会議記録を結論、アクションアイテム、未確認の問題を含む構造化された議事録に整理します。ユーザーが会議内容の整理や会議タスクの抽出を要求した場合に使用します。
---
# 議事録の整理
## 入力要件
- 読み取り可能な会議本文を提供すること。
- 会議名、時間、参加者は欠落也可だが、自行で補完してはならない。
## 実行ステップ
1. 会議本文が読み取り可能かを確認する。
2. 討論意見、確認済みの結論、未確認の問題を区別する。
3. アクションアイテム、担当者、締め切りを抽出する。
4. 原文と照合して結論とアクションアイテムを確認する。
## 出力要件
- 会議情報、重要結論、アクションアイテム、未確認の問題を出力する。
- 原文に欠落している担当者または締め切りは「確認待ち」としてマークする。
## 例外処理
- 会議本文がない場合は停止し、ユーザーに材料の補充を依頼する。
- 異なるコンテンツが矛盾している場合は矛盾を維持し、自行で答えを選択しない。
実際の使用における基盤モデルやAgentツールをさらに考慮するために、現在整理したスキルを検証する必要があります。まずスキルが入力から合格出力までたどり着けるかを検証する必要があります。初版は以下の観点から観察できます:タスクの識別状況、コアステップの実行状況、出力結果が条件を満たすかどうかなど。さらに、以下の方法で最初の検証を行えます:
SKILL.md、情報が完全な会議記録、期待される議事録構造のみを用意する。meeting.txtを読み取り、議事録スキルを使用してMarkdown議事録を生成し、原文にない情報を補完しない。スキルが安定して選択され、正しく入力が読み取られ、規定の構造で出力され、かつ情報が不足している場合にコンテンツを捏造しなければ、全体の実行プロセスと出力コンテンツがスキルの予定と基本的に一致したと言えます。その後、実際のニーズに応じてデータクリーンナップツール、脱敏ルール、長文分割、外部システム接続などの追加要件を追加します。次のセクションではModelScopeの環境でこの最短ルートを実現します。
前章では議事録スキルの設計を完了しました。以下ではModelScope Notebookでこの能力を実装し、差旅費精算と顧客接待のオフィス定例会議を例に、会議記録を確認済み事項、タスク事項、未確認事項に整理し、スキルの呼び出しプロセスを確認します。実験ステップに従って主な操作とキーコードを紹介します。関連するヘルパー関数と変数は事前に定義が必要です。
本実験ではQwen3-4Bを使用して推論を完了します。ここでは主にスキルに必要なコンポーネントを補足し、ms-swiftとモデルデプロイの基本的な使い方については前の章を参照してください。
まず、以下のコードを実行して、現在のPythonと依存パッケージのバージョンを確認します:
import sys
import importlib.metadata as metadata
print("Python:", sys.version)
for package in ["ms-agent", "modelscope", "omegaconf"]:
try:
print(package, metadata.version(package)
except metadata.PackageNotFoundError:
print(package, "未インストール")
今回の実験ではPython 3.12.13、ms-agent 1.6.0、modelscope 1.39.0、omegaconf 2.3.0を使用します。このうち、ms-agentはスキルのロードと参照ファイルの読み取りを担当し、modelscopeはコミュニティリソースへのアクセスに使用し、ms-swiftとvLLMはモデル推論サービスを提供します。依存関係がまだ準備されていない場合は、まずms-agent==1.6.0などの実験コンポーネントをインストールし、既存のトレーニングパッケージと基礎数値計算パッケージのバージョンを保持します。インストール完了後、カーネルを再起動してから後続の操作を继续します。modelscope_skill_labの下にタイムスタンプ付きのディレクトリを作成し、各実験のスキル、ケース、レポートを別々に保存します。コードは以下の通りです:
WORK_DIR = (Path.cwd() / "modelscope_skill_lab").resolve()
RUN_DIR = WORK_DIR / (
datetime.now().strftime("%Y%m%d_%H%M%S") + "_" + uuid.uuid4().hex[:6]
)
for name in ["releases", "tests", "reports", "downloads", "config"]:
(RUN_DIR / name).mkdir(parents=True, exist_ok=True)
このうち、releasesはスキルバージョンを保存し、testsはテスト入力を保存し、reportsは結果を保存し、configはモデル設定を保存し、後続の照合と比較に役立ちます。
前章ではスキルの構成を説明しました。ここでは直接議事録ルールをファイルに書き込みます。本実験ではエントリファイルと出力約束のみが必要で、ディレクトリ形式は以下の通りです:
releases/
└── 1.0.0/
└── meeting-notes/
├── SKILL.md
└── references/
└── output-contract.md
SKILL.mdは適用範囲、処理ステップ、例外ルールを保存し、先頭の名称、説明、バージョンはこの能力を識別します。ヘッダー内容は以下の通りです:
---
name: meeting-notes
description: 会議の文字起こし、グループチャットの会議記録、または会議メモを中国語の議事録に整理し、確認済みの結論、アクションアイテム、未確認の問題を抽出します。ユーザーが議事録や会議アクションアイテムを要求した場合に使用します。一般的な知識問答やモデルトレーニングの原理解説には使用しません。
version: "1.0.0"
---
実行ステップでは、本実験は特に3つの制約を維持しています:会議本文がない場合は材料の補充を依頼すること;担当者と締め切りが明確に出現しない場合は「確認待ち」とマークすること;結論とアクションアイテムは原文を引用根拠とすること。これらのルールは17.8のテストで項ずつ確認されます。
確認しやすいように、まずモデルがJSONを出力し、その後プログラムが議事録に整理します。output-contract.mdは出力フィールドを規定し、処理ステータスと原文根拠を追加します。主な内容は以下の通りです:
フィールド | 内容 |
|
|
| 会議テーマ |
| 確認済みの結論と原文根拠 |
| タスク、担当者、締め切り、原文根拠 |
| 未確認事項または存在する矛盾 |
| 補充が必要な材料または処理不能な理由 |
このうち、decisionsとactionsのevidenceフィールドは原文の連続した断片を引用することが要求されます。モデルはタスク内容を要約できますが、確認用の証拠は改変してはなりません。statusがokでない場合、結論とアクションアイテムは空の配列とし、messageで理由を説明する必要があります。
エントリ内容と出力約束をそれぞれSKILL_V1、OUTPUT_CONTRACTの2つの変数に保存し、対応するファイルに書き込みます:
V1_DIR = RUN_DIR / "releases" / "1.0.0" / SKILL_NAME
(V1_DIR / "references").mkdir(parents=True, exist_ok=True)
(V1_DIR / "SKILL.md").write_text(SKILL_V1, encoding="utf-8")
(V1_DIR / "references" / "output-contract.md").write_text(
OUTPUT_CONTRACT, encoding="utf-8"
)
実行後、ファイルブラウザで上記のディレクトリを見つけ、SKILL.mdを開いて内容が書き込まれたことを確認できます。関連内容は以下の図の通りです。
もちろん、ModelScopeスキルセンター(https://modelscope.cn/skills)も関連リソースを提供しており、読者はModelScopeスキルセンターから既存のリソースを選択し、ページのインストール識別子をCOMMUNITY_SKILL_IDに記入し、以下のインターフェースでダウンロードできます:
COMMUNITY_SKILL_ID = "" # コミュニティページからコピーしたインストール識別子を記入。
if COMMUNITY_SKILL_ID:
COMMUNITY_DIR = Path(HubApi().download_skill(
skill_id=COMMUNITY_SKILL_ID,
local_dir=str(RUN_DIR / "downloads"),
).resolve()
print((COMMUNITY_DIR / "SKILL.md").read_text(encoding="utf-8")
ファイルの準備が完了したら、ms-agentのSkillLoaderを使用してローカルディレクトリをロードし、名称、説明、バージョン、リソースパスを読み取ります。コードは以下の通りです:
from ms_agent.skill.loader import SkillLoader
from ms_agent.skill.schema import SkillContext
loader = SkillLoader()
registered = loader.load_skills(str(V1_DIR.resolve())
print(loader.list_skills()
今回のロード記録は['meeting-notes@1.0.0']です。このうち、meeting-notesはスキルのIDで、1.0.0はルールバージョンで、ms-agentパッケージのバージョンとは異なります。ディレクトリのロード後、SkillContextを使用して参照ファイルを読み取れます。以下のコードはoutput-contract.mdという名前の参照資料のみをロードします:
skill = next(iter(registered.values()
context = SkillContext(skill=skill, root_path=V1_DIR)
references = context.load_references(names=["output-contract.md"])
print(references[0]["content"])
モデルにファイルの読み取りを要求させるために、本実験ではカスタムのNotebookSkillToolsで2つのツール関数をカプセル化しています:
ツール関数 | 役割 | 主要パラメータ |
| ロード済みスキルのID、バージョン、用途を列挙 | なし |
| スキルエントリまたは指定された参照ファイルを読み取る |
|
エントリを読み取る場合はskill_viewを呼び出し、{"skill_id": "meeting-notes"}を渡します。参照ファイルを読み取る場合はfile_pathを指定します。このうち、meeting-notesは読み取り対象で、skill_viewは読み取りを実行するツールです。
ロードと読み取りの確認は以下の通りです:
ACTIVE_DIR = V1_DIR
runtime = make_runtime(ACTIVE_DIR)
viewed = runtime.tools.call_tool(
tool_name="skill_view",
tool_args={"skill_id": SKILL_NAME},
)
reference = runtime.tools.call_tool(
tool_name="skill_view",
tool_args={
"skill_id": SKILL_NAME,
"file_path": "references/output-contract.md",
},
)
print("エントリ読み取り成功:", "content" in json.loads(viewed)
print("参照資料読み取り成功:", "content" in json.loads(reference)
make_runtime()はディレクトリの検証、バージョンのロード、ツールの準備を担当します。今回のエントリと参照資料の読み取り結果はどちらもTrueで、ファイルが正常にアクセスできることを示しています。これでモデルが読み取りリクエストを発信できるようになりました。スキルのロードとリソースの読み取り結果は以下の通りです。
本実験ではModelScopeコミュニティのQwen/Qwen3-4Bを使用し、ms-swiftでOpenAI互換インターフェースとしてデプロイします。ms-swiftとvLLMがインストールされたGPU環境のターミナルで実行します:
CUDA_VISIBLE_DEVICES=0 swift deploy \
--model Qwen/Qwen3-4B \
--load_args false \
--infer_backend vllm \
--enable_thinking false \
--host 0.0.0.0 \
--port 18002 \
--api_key 123 \
--vllm_gpu_memory_utilization 0.8 \
--vllm_max_model_len 8000 \
--max_new_tokens 2000
ModelScopeでのモデル起動段階の結果は以下の通りです:
サービスログで、以下の内容が出力された場合はサービスの起動が完了しています:
INFO:Application startup complete.
INFO:Uvicorn running on http://0.0.0.0:18002 (Press CTRL+C to quit)
ModelScope側の起動成功ログは以下の通りです:
以下では行政定例会議の記録を使用して呼び出します。材料には確認済みの2つのアレンジ、2名の担当者の具体的なタスク、およびまだ確認が必要な情報が含まれています:
会議テーマ:今週の行政作業アレンジ。会議時間:2026-09-04。
主管:今日確認することは2つ。第一に、今月の差旅費精算材料は来週火曜日までに一括して回収すること;
第二に、顧客接待会は来週水曜日の午後3時で、会場は3階の会議室。
李明:精算材料は私が収集します、締め切りは2026-09-08です。
王敏:3階の会議室の予約と会議招待状の送信を担当します、締め切りは2026-09-07です。
小周:顧客が2人オンライン参加する可能性がありますが、まだ確認されていません。
主管:オンライン参加者リストはまず「確認待ち」として記録し、他の事項は先ほどのアレンジに従って進めます。
モデルは会議で確認済みのアレンジを整理し、タスク、担当者、締め切りを列挙し、未確定の情報を維持する必要があります。ここでは議事録を生成し、実際の精算や招待状の送信は行いません。まず明確にスキルを指定したリクエストを使用し、次に日常のオフィスで一般的な自然言語リクエストを使用し、2つの表現が同じ能力を呼び出せるかを比較します。コールコードは以下の通りです:
explicit_result = await run_skill_task(
"用 meeting-notes 帮我整理一下刚才的办公例会,"
"把报销和客户接待的安排、负责人、截止时间列清楚。"
+ "\n\n会议记录:\n" + DEMO_TEXT,
ACTIVE_DIR,
)
natural_result = await run_skill_task(
"这是刚才例会的记录,帮我整理成一份简短纪要,"
"方便发到工作群。还没确定的事情单独列出来。"
+ "\n\n会议记录:\n" + DEMO_TEXT,
ACTIVE_DIR,
)
このうち、run_skill_task()は各タスクごとに新しい会話を作成し、スキルインデックスとツール定義をモデルに送信します。モデルが読み取りリクエストを提出した後、プログラムがファイルの読み取りを実行し、内容をモデルに返します。モデルが既に取得した資料を繰り返し読み取るのを防ぐために、プログラムはエントリと出力約束が両方とも正常に読み取れたかを確認します。両方が揃った後、最終回答生成フェーズに入ります。重要な判断は以下の通りです:
ready_to_answer = (
read_skill_successfully(result)
and read_skill_successfully(result, "references/output-contract.md")
)
if ready_to_answer:
messages[0]["content"] = (
system + "\nスキルエントリと出力ルールの読み取りが完了しました。"
"現在、元の会議材料に基づいて最終結果を生成し、"
"ルールに適合するJSONのみを出力し、ツールは呼び出しません。"
)
message, finish_reason, usage = await asyncio.to_thread(
model_call, messages, [] if ready_to_answer else api_tools
)
資料の読み取り完了後、リクエストはtool_choice="none"を使用し、モデルに最終回答を生成させます。プロンプトの更新は既存のsystemメッセージで行われ、ツール結果の後もモデルが返答し、ロールの順序を維持します。今回の2つのリクエストはどちらもスキルと出力約束を読み取り、オフィス議事録を生成しました。結果は差旅費精算と顧客接待のアレンジを維持し、李明と王敏のタスクを列挙し、オンライン参加者数は「確認待ち」と記録しました。異なる呼び出しの表現はわずかに異なりますが、原文と照合して確認できます。
ページに表示されるのは整理済みの議事録で、保存されるJSONにはevidenceなどのフィールドが含まれています。原文の引用と異常入力の処理は、後続のテストで引き続き確認します。
呼び出し完了後、エントリと出力約束が読み取られたか、読み取り失敗時に理由を報告できるかを確認します。traceは各ラウンドのモデル返答、ツールパラメータ、返却内容を保存し、問題の特定に使用できます。例えば、前回の2回の呼び出しの読み取り状況を確認するには、以下のコードが使用できます:
rows = []
for label, result in [("明示的呼び出し", explicit_result), ("自然言語呼び出し", natural_result)]:
rows.append({
"呼び出し方式": label,
"リクエストステータス": result["run_status"],
"エントリ読み取り済み": read_skill_successfully(result),
"ルール読み取り済み": read_skill_successfully(
result, "references/output-contract.md"
),
})
display(pd.DataFrame(rows)
今回の2つの呼び出しはどちらもcompletedで、エントリとルールの読み取りはどちらもTrueで、リクエストが終了し資料が読み取られたことを示しています。議事録の内容が正しいかどうかは、さらに確認が必要です。ツールの例外処理を確認するために、わざと存在しないスキルIDと存在しない参照ファイルを渡すこともできます。例:
missing_resource = runtime.tools.call_tool(
tool_name="skill_view",
tool_args={
"skill_id": SKILL_NAME,
"file_path": "references/does-not-exist.md",
},
)
print("欠落ファイルの処理が期待通りか:", "error" in json.loads(missing_resource)
这里ではわざと存在しないファイルを使用し、errorが返されることで問題が正しく識別されたことを示しています。今回の入力内容を「処理が期待通りか」としてマークすることで、実際の実行障害との混同を避けることができます。
通常の表示では確認結果を保持即可です。トラブルシューティングが必要な場合は、reportsから対応するラウンドの完全な返答とツール記録を確認します。
1回の呼び出しが完了した後、異なる材料を使用してスキルが信頼できるかを確認する必要があります。以下では固定ケースを準備し、情報抽出と例外処理を検証し、結果をスキルバージョンとともに保存します。
本セクションでは引き続き同一の議事録スキルを使用します。まずテストマトリクスと確認条件を構築し、初版テストを実行し、最後にルールを修正して2つのバージョンを比較し、ロールバックをデモします。
ケースには入力と期待される動作を同時に記録する必要があります。正常ケースは情報抽出を確認し、境界ケースは不確定情報の処理を確認し、失敗ケースは停止と理由説明を確認し、無関係なタスクは誤トリガーを確認します。
テストマトリクスは以下の通りです:
番号 | カテゴリ | 入力特徴 | 期待動作 |
N01 | 正常 | 精算と顧客接待アレンジを含む完全なオフィス定例会議 | 結論、タスク、担当者、締め切りを維持 |
N02 | 正常 | 既にアクションアイテムが記載された簡潔な会議メモ | 明確なタスク、担当者、日付を抽出 |
B01 | 境界 | タスクはアレンジ済みだが締め切り未確定 | 日付に「確認待ち」を記入 |
B02 | 境界 | 誰かが提案したが、会議で承認されていない | 確認済みの決定は生成せず、未確認事項を維持 |
B03 | 境界 | 2つの記録が同一事項の時間について矛盾 | 矛盾を維持し、自行で結論を選択しない |
B04 | 境界 | 誰かが業務完了が必要と述べたが、担当者を指定していない | 発言者を自動的に担当者としない |
F01 | 失敗 | 会議本文がない |
|
F02 | 失敗 | 提供されたのは製品説明書 |
|
T01 | トリガー不可 | 一般的な知識問答で、議事録と無関係 | 直接回答し、議事録スキルは読み取らない |
各ケースは辞書で入力と確認条件を保存します。以下では正常ケース、境界ケース、失敗ケースをそれぞれ1つ選び、その書き方を示します:
# オフィス定例会議の2つの締め切りは原文と一致すべき。
normal_case = {
"id": "N01", "kind": "正常", "text": DEMO_TEXT, "status": "ok",
"owners": ["李明", "王敏"],
"due_values": ["2026-09-08", "2026-09-07"],
"min_actions": 2, "min_decisions": 1,
}
boundary_case = {
"id": "B01", "kind": "境界",
"text": "テスト会議記録:陳晨にテストケースの整理がアレンジ済み、会上で締め切りは未確定。",
"status": "ok", "owners": ["陳晨"],
"due_values": ["確認待ち"], "min_actions": 1,
}
failure_case = {
"id": "F01", "kind": "失敗", "text": "", "status": "needs_input",
}
statusは期待されるステータスを規定し、ownersとdue_valuesは担当者と日付を確認し、min_actionsは最小アクションアイテム数を規定します。これらの条件は検収用のみで、モデルが受け取るのはユーザーリクエストとケース本文です。
材料を変更した場合、期待される日付と担当者も同期して更新する必要があります。上記のN01はオフィス定例会議に合わせて日付を記入しています。保存済みのテスト記録には古い日付の期待が残っており、後でその影響を説明します。
ケースの準備が完了したら、「正しく完了する」要求を実行可能な確認として書く必要があります。check_output()を使用してモデルの返却結果の検収を行います。主に以下の観点を含みます:
確認内容 | 判定方法 |
リクエストが終了したか |
|
資料が読み取れたか | ツール記録におけるエントリと出力約束の実際の返却を確認 |
出力形式が正しいか | JSONが解析できるか、フィールド名と型が約束に適合するかを確認 |
重要情報がケースに適合するか | ステータス、担当者、締め切り、項目数を確認 |
原文根拠が存在するか |
|
失敗入力で生成を停止したか | 異常ステータスで結論とアクションアイテムが空で、理由が説明されているかを確認 |
スキルを誤用していないか | 無関係なタスクで |
原文根拠を例にすると、モデルが生成した結論は要約的なテキストでも構いませんが、evidenceは元の表現を維持する必要があります。検収関数の重要な判断は以下の通りです:
if item["evidence"] not in case["text"]:
problems.append(field + " の証拠が原文に存在しない")
itemは現在の項目を表し、fieldは確認中のフィールドを表します。この判断は引用が改変された場合や引用元が間違っている場合を検出できますが、証拠が結論を支持できるかどうかは引き続き人間による確認が必要です。本文がない場合や材料が適用できないケースでは、モデルが議事録コンテンツの生成を停止したかを確認する必要があります。主なコードは以下の通りです:
if data["status"] != case["status"]:
problems.append("status が期待と一致しない")
if case["status"] != "ok":
if data["decisions"] or data["actions"] or not data["message"].strip():
problems.append("失敗ケースでは議事録コンテンツの生成を停止し、理由を説明すべき")
例えば、F01はneeds_inputを返すべきです。仍然okを返した場合や、材料不足と説明しながら会議決定を生成した場合は要求に適合しません。人为的に誤った日付を追加したり、読み取り記録を削除したりして、検収関数が問題を識別できるかを確認することもできます。これはコードの自己テストで、実際のモデルテストの代わりにはなりません。ファイルの欠落、サービス失敗のシミュレーション、入力過長はプログラムが異常を報告できるかの確認用です。F01とF02はモデルが異常材料に直面した場合の回答を確認します。2種類の結果は別々に記録されます。
run_suite()はケースを順に実行し、各回新しい会話を開始し、結果とツール記録を保存し、check_output()を呼び出して問題一覧を生成します。主なコードは以下の通りです:
CASE_IDS = None # Noneは全ケースを実行することを意味。
REPEATS = 1 # 今回の各ケースは1回実行。
v1_results, v1_report_dir = await run_suite(
V1_DIR, case_ids=CASE_IDS, repeats=REPEATS
)
display(v1_results)
print("元の出力とトレース:", v1_report_dir)
PASS_AUTOは自動チェック通過を意味し、FAILは結果が要求に適合しないことを意味し、ERRORは実行が正常に完了しなかったことを意味します。human_reviewは人間による確認ステータスを記録し、今回はまだpendingです。今回の1.0.0バージョンの実際の記録では、9ケース中6ケースが自動通過、3ケースが失敗、ERRORとしてマークされたケースはありませんでした。結果は以下の通りです:
ケース | 自動チェック結果 | 記録上の主な問題 |
N01 | FAIL | 結論の証拠が原文と一致しない;古い締め切りの期待が満たされない |
N02 | PASS_AUTO | 現在の確認条件をトリガーする問題なし |
B01 | PASS_AUTO | 現在の確認条件をトリガーする問題なし |
B02 | PASS_AUTO | 現在の確認条件をトリガーする問題なし |
B03 | PASS_AUTO | 現在の確認条件をトリガーする問題なし |
B04 | PASS_AUTO | 現在の確認条件をトリガーする問題なし |
F01 | FAIL | 処理ステータスが期待と一致せず、異常入力の生成停止要求を満たさない |
F02 | FAIL | 処理ステータスが期待と一致せず、異常入力の生成停止要求を満たさない |
T01 | PASS_AUTO | 議事録スキルの読み取りリクエストが発生しなかった |
N01にはまずテスト期待の不一致問題があります:本文では王敏の締め切りが2026-09-07ですが、テストコードはまだ2026-09-09を要求しています。したがって、この日付エラーは直接モデルエラーに帰属させるべきではなく、まずdue_valuesを修正して再実行すべきです。N01には証拠が原文と一致しない問題もあります。同じオフィスサンプルの呼び出しトレースでは、モデルが原文「第二,客户接待会定在下周三下午三点,地点是三楼会议室。」を「主管:客户接待会定在下周三下午三点,地点是三楼会议室。」に変更しています。意味は近いですが、この断片に含まれていない敬称を追加しており、evidenceの逐字抄録要求に適合しません。
F01は本文がないため、材料の補充を依頼すべきです。F02は製品説明書を提供しており、材料が適用できないことを説明すべきです。今回の2つはどちらもステータスと生成停止要求を満たしておらず、ケースレポートの最終テキストとツールトレースを结合起来さらに分析する必要があります。後続ではまずテスト期待を較正し、次に証拠引用と例外処理ルールを改善すべきです。自動通過したケースも原文と照合して確認する必要があります。
1.0.0を維持したまま、新しいディレクトリに候補バージョン1.0.1を作成し、担当者判定ルールを追加します。2つのバージョンをそれぞれロード・テストし、比較しやすくします。以下はバージョン作成コードの主要部分です:
V2_DIR = RUN_DIR / "releases" / "1.0.1" / SKILL_NAME
if not V2_DIR.exists():
shutil.copytree(V1_DIR, V2_DIR)
updated = (V2_DIR / "SKILL.md").read_text(encoding="utf-8")
updated = updated.replace('version: "1.0.0"', 'version: "1.0.1"', 1)
updated += (
"\n## 担当者判定の補足\n"
"発言者は自動的に担当者にはならない;アレンジ、提案、または質問を述べた人が"
"明確にタスクを受けない場合、担当者は仍然「確認待ち」になる。\n"
)
(V2_DIR / "SKILL.md").write_text(updated, encoding="utf-8")
このルールはB04に対応しています:業務を述べた人が必ずしも担当者とは限らない。入出力構造が変更されていないため、本実験ではこれを改定バージョンとし、CHANGELOG.mdでルール、関連ケース、候補ステータスを記録します。
次に同じモデル、ケース、繰り返し回数で候補バージョンをテストし、ケース番号に基づいてマージ比較します。コアコードは以下の通りです:
v2_results, v2_report_dir = await run_suite(
V2_DIR, case_ids=CASE_IDS, repeats=REPEATS
)
comparison = v1_results.merge(
v2_results,
on=["case_id", "repeat", "kind"],
suffixes=("_v1", "_v2"),
)
display(comparison[[
"case_id", "automatic_result_v1", "automatic_result_v2",
"problems_v1", "problems_v2",
]])
関連する過程結果は以下の通りです:
今回の保存記録では、1.0.0は6項目が自動通過、1.0.1は7項目が自動通過でした。項ずつ比較した後、変化がF01に集中していることがわかります:
今回はF01が失敗から自動通過に変わったことのみ観察され、追加ルールが安定した改善をもたらしたことは証明できていません。修正は担当者判定に向けられていますが、変化は空入力ケースで発生しています。各ケースも1回のみ実行され、N01の期待は仍然較正が必要です。候補バージョンを採用する前に、テスト条件を修正して2バージョンが同じケースを再実行し、REPEATSを上げて安定性を確認すべきです。人間による確認の後、採用するかどうかを決定します。F02など未通過の場合は引き続きルールを改善します。
各バージョンには完全なファイルとテスト記録を保存する必要があります。本実験ではrelease-manifest.jsonでファイル一覧とハッシュを記録し、同時に変更説明、設定、レポートを保存します。主な成果物は以下の通りです:
ファイルまたはディレクトリ | 保存内容 |
| 2つのバージョンのスキルディレクトリとバージョン一覧 |
| ルール変化と関連ケース |
| 固定のテスト入力と期待条件 |
| モデル出力、ツールトレース、自動チェック結果、バージョン比較表 |
| 現在使用中のバージョン、パス、ファイルハッシュ |
| 本次の実行環境記録 |
activate_version()はディレクトリとファイルハッシュを確認し、新しいランナーを作成し、バージョン一覧と実際のルールが一致することを保証します。
ACTIVE_DIR, runtime = activate_version("1.0.1")
print("候補バージョンに切替:", ACTIVE_DIR)
ACTIVE_DIR, runtime = activate_version("1.0.0")
print("古いバージョンにロールバック:", ACTIVE_DIR)
今回は1.0.1から1.0.0へのファイル検証とロードが完了しましたが、ロールバック後モデルは再呼び出ししておらず、ロールバック後のテスト結果はまだ検証されていません。
ロールバック後の動作を確認する必要がある場合は、現在のディレクトリに対してテストをcontinueすべきです:
rollback_results, rollback_report_dir = await run_suite(
ACTIVE_DIR, case_ids=CASE_IDS, repeats=REPEATS
)
display(rollback_results)
ルール、ケース、結果、環境情報を保存すれば、各バージョンのパフォーマンスを追溯できます。後続の修正は具体的なケースに対応し、テストと確認を経て、新しいバージョンを採用するか元のバージョンに戻すかを決定します。
本章のすべての実験データとコードは以下で入手できます:
https://modelscope.cn/gallery/liucong/0e182f07-3330-40cc-ba59-173b7cc609b7