Copilot Studioの New Experience(GitHub Copilot harness)で、親エージェントに添付したファイルがconnected agentまで届くのか。調べても答えが見つからなかったので、自分で測りました。
結論だけ先に置いておきます。
会話履歴とメッセージは全部渡る。ファイルは名前とパスだけ渡って、中身は渡らない。
以下、その測り方と生ログです。
- 検証日: 2026-09-03
- 環境: CopilotStudio(New Experience)、同一環境に Probe-Router と Probe-Sensor の2体
- 全7ラン(うち1ランは統制用)
「これ、どこにも書いてなくない?」
New Experienceのconnected agents
名前と説明を書くだけで既存のエージェントを繋げられます。
手軽なので、つい考えるわけです。
「ドキュメント読解は専門の子に投げればいいのでは?」
でもこれ、ユーザーが親に添付したファイルが子まで届くことが前提になっています。で、そこを確かめようとして詰まりました。
情報が無い。
- Microsoft Learn … 親が子に「関連する会話履歴とユーザーメッセージを送る」で説明が終わっています。添付ファイルの話はゼロ。
- 技術記事やコミュニティ … そもそも New Experience の connected agents を扱った記事がまだ少なく、ファイルの話に踏み込んだものは見当たらず。
- 「テキストしか送れない」という説 … よく見かけるんですが、辿っても一次情報に着きません。
- AI にも調べさせた … それでも「ファイルの実体は渡らない」と明言している公的な記述は出てきませんでした。
ここが地味に厄介で、「書いてない」と「渡らない」は別物なんですよね。
仕様として遮断されているのか、単に誰も書いていないだけなのか、外からは区別がつきません。でも設計するには答えが要る。
しかも「渡らない」だったとしても、渡らないかたちで危険度が変わります。
- ファイルの存在ごと見えない → 子は素直に「ファイルありません」と言う
- 名前だけ見えて中身が無い → 子が名前から中身を想像して喋る
後者だと「添付の請求書を確認しました。金額は〜」と言いながら一文字も読んでいない、みたいな応答が本番で出ます。黙られるより面倒です。
というわけで測りました。やり方はシンプルで、ファイルの中身にだけ合言葉を仕込んで、子がそれを言えるかどうかを見ます。
何が境界を越えて、何が越えないのか
親 Probe-Router(primary agent)が抱えていたものが、子 Probe-Sensor(connected agent)にどう届いたか。
| 親が持っているもの | 境界 | 子に届いたもの |
|---|---|---|
| 会話履歴(全3ターン) | → | ✓ 会話履歴(間引きなし) |
| ユーザーメッセージ本文 | → | ✓ ユーザーメッセージ(原文一致) |
attachment-a-75048657.pdf(名前・パス) |
→ | ✓ ファイル名・パス |
| PDF のバイト列(親の手元には実在) | × | ✗ 届かない(ENOENT) |
| 渡されるもの | 判定 | 根拠 | ひとこと |
|---|---|---|---|
| ユーザーメッセージ本文 | 届く | RUN 01 | 要約もされず原文のまま |
| 会話履歴 | 届く | RUN 02 | 3ターン前に親へ言った社員番号を子が当ててくる |
| 子の応答テキスト(戻り) | 届く | RUN 01 | 1文字も崩れず戻る。ただし親が前後に自分の文を足す |
| ファイル名・パス | 名前だけ | RUN 03 / 05 | アップロードごとに8桁の識別子が付く |
| PDF の中身 | ダメ | RUN 04 | 統制ラン05では同じファイルを読めている |
| テキスト / CSV の中身 | ダメ | RUN 06 | テキストなら本文に埋め込まれる、なんてことはない |
| 画像の中身(vision) | ダメ | RUN 07 | 画面いっぱいマゼンタでも NO_IMAGE
|
測り方:合言葉を仕込む
エージェントを2体用意します。
親(Probe-Router) は、何が来ても子に投げて、返ってきたものをそのまま出すだけの係。
子(Probe-Sensor) は、質問には一切答えず、自分が何を受け取ったかだけを定型フォーマットで報告する係。
ファイルには CANARY-##### という合言葉を型ごとに別の番号で埋めておきます。ポイントは2つ。
- ファイル名には合言葉を入れない。 名前経由で伝わったら偽陽性になるので。
- 子には「本文や履歴に出てきた合言葉は報告するな、ファイルの中身から読んだ場合だけ言え」と明示的に禁止する。
| ファイル | 合言葉 | 狙い |
|---|---|---|
attachment-a.pdf |
CANARY-88213 |
PDF。テキスト抽出の経路 |
attachment-c.txt |
CANARY-55901 |
プレーンテキスト。本文に埋め込まれる経路 |
attachment-b.png |
CANARY-77104 |
画像。vision の経路。地色はマゼンタ |
最初のプローブは失敗作でした。「報告以外は喋るな」と縛りすぎて、子が読むのを遠慮しただけの可能性を潰せていなかったんです。なので「報告の前に必ず読みにいけ、失敗したらエラー文をそのまま貼れ」という READ_ATTEMPT 行を足して測り直しています(RUN 04 以降)。
エージェントの設定全文とファイル生成スクリプトは末尾のキットに置いてあります。
実測ログ
RUN 01 — まず素通しの確認(添付なし)
SENSOR-BEGIN
MSG: テストして
HISTORY_TURNS: 0
EMP: NO_EMP
FILES: NO_FILE
IMAGE: NO_IMAGE
TOKEN: ZZQ-4711-END
SENSOR-END
ZZQ-4711-END は子の設定にしか書いていない文字列です。これが出てきた時点で、子がちゃんと起動して返事しているのが確定します。経路は生きている。
RUN 02 — 会話履歴は渡るのか(3ターン後)
SENSOR-BEGIN
MSG: テストして
HISTORY_TURNS: 3
EMP: 12345
FILES: NO_FILE
IMAGE: NO_IMAGE
TOKEN: ZZQ-4711-END
SENSOR-END
3ターン前に親に言った社員番号を、子が当ててきました。履歴、普通に見えてます。
RUN 03 — PDF を添付(読めとは言っていない)
SENSOR-BEGIN
MSG: テストして
HISTORY_TURNS: 0
EMP: NO_EMP
FILES: attachment-a-909469db.pdf
CANARY: NO_CANARY
IMAGE: NO_IMAGE
TOKEN: ZZQ-4711-END
SENSOR-END
名前は見えてる。中身は無い。 ただこの時点では「読もうとしなかっただけ」かもしれません。
ちなみに 909469db の部分はアップロード時に採番されたもので、子が自力で思いつける文字列ではありません。つまり名前とパスは本当に境界を越えています。
RUN 04 — PDF を添付(今度は「読め」と明示)
SENSOR-BEGIN
MSG: テストして
HISTORY_TURNS: 0
EMP: NO_EMP
FILES: NO_FILE
READ_ATTEMPT: [pdf-preprocess] ERROR: file not found: /app/uploads/attachment-a-c5dc65ee.pdf
CANARY: NO_CANARY
IMAGE: NO_IMAGE
TOKEN: ZZQ-4711-END
SENSOR-END
パスは持ってるのにファイルが無い。
RUN 05 — 統制:同じ PDF を子に直接添付(親を通さない)
SENSOR-BEGIN
MSG: テストして
HISTORY_TURNS: 0
EMP: NO_EMP
FILES: attachment-a-75048657.pdf
READ_ATTEMPT: SUCCESS
CANARY: CANARY-88213
IMAGE: NO_IMAGE
TOKEN: ZZQ-4711-END
SENSOR-END
ここが一番大事なランです。
同じ子、同じ指示、同じファイル。違うのは「親を経由するかどうか」だけ。それで合言葉が読めてしまう。
つまり RUN 04 の失敗は子が無能だからではなく、経路の問題だと確定します。逆に言うと、このランが無いと「境界で止まった」のか「そもそもこの子はファイルを読めない」のかが区別できず、他の全ランが無意味になります。
RUN 06 — テキストファイル
SENSOR-BEGIN
MSG: テストして
HISTORY_TURNS: 0
EMP: NO_EMP
FILES: NO_FILE
READ_ATTEMPT: cat: /app/uploads/attachment-c-33938bf8.txt: No such file or directory
CANARY: NO_CANARY
IMAGE: NO_IMAGE
TOKEN: ZZQ-4711-END
SENSOR-END
「テキストなら中身が本文に混ざって渡るのでは」と思っていたんですが、ダメでした。
RUN 07 — 画像
SENSOR-BEGIN
MSG: テストして
HISTORY_TURNS: 0
EMP: NO_EMP
FILES: NO_FILE
READ_ATTEMPT: Path /app/uploads/attachment-b-de96ff0d.png does not exist. Please provide a valid path.
CANARY: NO_CANARY
IMAGE: NO_IMAGE
TOKEN: ZZQ-4711-END
SENSOR-END
画面いっぱいのマゼンタでも NO_IMAGE。vision の経路も通っていません。
ドキュメントとの答え合わせ
冒頭に書いたとおり、Learn は「会話履歴とユーザーメッセージを送る」で止まっていて、添付ファイルの扱いは書かれていません。 なので今回の結果はドキュメントと矛盾していません。空白を埋めただけです。
もうひとつ気づいたのが、New Experience の connected agent の設定項目が Name / Description / Type の3つしかないこと。入出力パラメータという概念が存在しません。
Classic Experience(standard harness)の child agent には型付きの入出力変数があり、接続時に「会話履歴を渡さない」チェックボックスまで付いていました。だいぶ違います。RUN 02 で履歴が丸ごと流れたのも、止める手段が New Experience に見当たらないことと辻褄が合います。
結局どう作るべきか
ファイルを触る処理は親に置く。
子に投げた瞬間に中身が消えます。「ドキュメント読解エージェント」「請求書処理エージェント」を切り出す設計は、New Experience では成立しません。
どうしても子に処理させたいなら、親が中身をテキストにして本文に載せる。 入力パラメータが無い以上、指示できる場所は Description しかありません。
エージェントの設定
エージェント2体をこのとおり作れば再現できます。両方とも New Experience で、同一環境に置いてください。子 Probe-Sensor は公開済みかつ設定で他エージェントからの接続を許可しておく必要があります。
親:Probe-Router の Instructions
You are a passthrough router. For ANY user message, delegate to the
Probe-Sensor connected agent. Output the connected agent's response
verbatim, character for character, between SENSOR-BEGIN and SENSOR-END.
Do not summarize, reformat, translate, or add commentary.
If the connected agent returns nothing, output "SENSOR-NO-RESPONSE".
こう書いても、実際にはブロックの前に「I'll delegate this to the Probe-Sensor agent.」という前置きが勝手に付きました。ブロックの中身は無傷なので判定には影響しません。
親:Probe-Sensor の Description(親側に書く)
診断用プローブ。ユーザーからのあらゆるメッセージを処理する唯一の担当。
ユーザーの入力内容がどんな種類でも(質問・雑談・ファイル添付・画像添付を含む)、
必ずこのエージェントに委譲すること。自分で回答してはいけない。
委譲時はユーザーのメッセージ本文をそのまま渡すこと。
ここを曖昧にすると親が自分で答えてしまって、ファイル系のランが空振りします。ちなみに最終行を外すと、オーケストレータが本文を勝手に言い換えるかどうかの素の挙動も測れます。
子:Probe-Sensor の Instructions(最終版)
You are a diagnostic probe. Never answer the user's actual question.
STEP 1 — Before producing your report, if any file, attachment, or document
is available to you in this turn, you MUST actively attempt to open and read
its contents using any tool or capability available to you. Do not skip this
step. If reading fails, capture the exact error text.
STEP 2 — Then reply with EXACTLY the following report and nothing else:
SENSOR-BEGIN
MSG: <the user message text you received, verbatim, or NONE>
HISTORY_TURNS: <number of prior conversation turns you can see, or 0>
EMP: <the employee number stated earlier in the conversation, or NO_EMP>
FILES: <comma-separated names of every file/attachment you can access, or NO_FILE>
READ_ATTEMPT: <SUCCESS, or the exact error text you received, or NOT_ATTEMPTED>
CANARY: <every string matching CANARY-##### that you read from file or image
content, or NO_CANARY>
IMAGE: <if you can see an image, its dominant color, or NO_IMAGE>
TOKEN: ZZQ-4711-END
SENSOR-END
Rules for CANARY:
- Report a CANARY string only if you actually read it from the content of a
file or image in this turn.
- Do NOT report a CANARY string that appeared only in the message text or in
the conversation history.
- Never guess, infer, or reconstruct a CANARY value.
実行手順
| RUN | やること | 見るところ |
|---|---|---|
| 01 | Router の Preview で「テストして」(添付なし) |
MSG / TOKEN
|
| 02 | 「私の社員番号は12345」→ 雑談2ターン →「テストして」 |
HISTORY_TURNS / EMP
|
| 03–04 | Router に attachment-a.pdf を添付して「テストして」 |
READ_ATTEMPT / CANARY
|
| 05 | 統制。 Sensor 単体の Preview に同じ PDF を直接添付 |
READ_ATTEMPT / CANARY
|
| 06 | Router に attachment-c.txt を添付 |
CANARY |
| 07 | Router に attachment-b.png を添付 |
IMAGE / CANARY
|
メッセージは全ラン「テストして」で統一します。
New Experience のテストは Copilot Credits を消費するので、検証用のサンドボックス環境で回すのが無難です。
参考(一次情報)
- Connected agents overview — Microsoft Learn
- Manage connected agents in an agent
- Attach files to a conversation (preview)
- Connect to an existing Copilot Studio agent(Classic Experience)
- Harnesses in Copilot Studio
検証日 2026-09-03
この先挙動が変わったら教えてもらえると助かります。