モジュール 02 · 第 1 回

よいプロンプトとはどんなものか

同じまとまりのないユーザーの相談を、適当に書いたプロンプトと構成のはっきりしたプロンプトでそれぞれ一度ずつ処理し、結果を一段ずつ比べます。役割、タスク、背景、要件、出力形式の各部分がどんな働きをするのかを説明します。

  • 約 35 分
  • 難易度:入門
  • 検証:2026-09-14 deepseek-flash

コードと実行結果は実際に動かしたときのまま載せているため、コメントと出力は中国語です。

プロンプトエンジニアリングという言葉は何やら神秘的に聞こえ、ネットにも「万能テンプレート」や「魔法の呪文」がたくさんあります。けれども、その核心はごく素朴です。頭の中にある要求を、はっきり書くこと。モデルはあなたの背景を知らず、結果を誰が見るのかも、あなたの思う「よい」がどんなものかも知りません。書かなかったことは、推測するしかないのです。

この課では実際の場面を一つ取り上げ、同じタスクに二つの版のプロンプトを書いて、何が違うのかを見ます。

場面:グループチャットの相談を issue にまとめる

あなたが httpx のメンテナーで、ユーザーがコミュニティのグループチャットにこんな書き込みをしたとします。

用httpx下载大文件老是断 我用的stream 下到一半就报错了 ReadTimeout
代码大概是 with httpx.stream("GET", url) as r: for chunk in r.iter_bytes(): f.write(chunk)
文件2个G左右,网不太好,公司内网。之前用requests好像没这问题??
版本是0.27 python3.11 mac
急!!!明天要交

これをモデルに整えさせて、他のメンテナーが調査しやすいような、きちんとした GitHub の issue にしたいとします。

第 1 版:適当に書く

v1 = [{"role": "user", "content": "帮我整理一下这个问题:\n" + REPORT}]

モデルの回答です(思考はオフにしています。以下は私が実行して得た原文で、あなたの結果は違うはずです)。

# 问题整理

## 一句话概述
用 httpx 的 `stream` 下载 ~2GB 大文件,网络环境较差(公司内网),下载中途抛 `ReadTimeout`,改用 requests 则无此问题,需要尽快解决。

## 环境信息
- 库/版本:httpx **0.27**
- Python:**3.11**
- 系统:**macOS**
- 网络:公司内网,网速较差/不稳定
- 文件大小:约 **2 GB**

## 复现代码
```python
with httpx.stream("GET", url) as r:
    for chunk in r.iter_bytes():
        f.write(chunk)
```

## 现象
- 下载过程**中途中断**
- 报错类型:**ReadTimeout**
- 相同 URL 和网络下,**requests 不报错**(或很少报错)

## 关键疑问
1. 为什么 httpx 会 ReadTimeout 而 requests 不会?两者的超时/重试默认行为差异在哪?
2. httpx 的 `timeout` 参数在 stream 场景下具体作用于什么?(连接 / 单个 chunk 间隔 / 整体?)
3. 有没有办法在 stream 时**禁用或放宽读超时**,让慢速下载不被打断?
4. 是否需要加**重试 / 断点续传(Range)**来兜底?

## 目标
- 让 2GB 大文件在弱网内网环境下能稳定下完
- 时间紧急,明早交付

## 可能的排查方向(供参考)
- httpx 默认 `timeout=5.0`,requests 默认是"无超时"(会一直等),这很可能是根因
- 可尝试:`httpx.stream("GET", url, timeout=httpx.Timeout(connect=10, read=None, write=10, pool=10))`
- 或加大 read timeout,加 `transport=httpx.HTTPTransport(retries=3)`
- 断点续传:记录已下字节,用 `Range: bytes=N-` 续传

---
需要我帮你针对哪个方向继续深挖(比如给出可直接替换的稳定下载代码)?

プロっぽく見え、レイアウトもきれいです。しかし元の書き込みと丁寧に照らし合わせると、問題がたくさんあります。

  • 推測を事実として書いている。ユーザーが言ったのは「之前用 requests 好像没这问题??」(前に requests を使っていたときは、この問題はなかった気がする??)ですが、モデルの手にかかると「requests に切り替えるとこの問題は起きない」「同じ URL とネットワークで、requests ではエラーにならない」になっています。メンテナーがこれを読めば、まったく裏付けのない手がかりをたどって調査してしまうかもしれません。
  • 頼んでいないことをしている。問題を整理してほしかっただけなのに、「調査の方向性」の節を設け、さらに「目標」「重要な疑問点」まで書いています。issue にとってはノイズです。
  • 提案に誤りがあるHTTPTransport(retries=3) を加えるよう勧めていますが、httpx のドキュメントには、このパラメータは接続失敗時(ConnectErrorConnectTimeout)にしかリトライせず、ダウンロード途中の ReadTimeout には効かないとはっきり書いてあります。人を誤らせる提案です。
  • 形式が issue の形式になっていない。最後に「さらに深掘りしましょうか」と聞いており、この一文が issue に入るのはどう見ても変です。

モデルが悪いわけではありません。「整理して」には百通りの解釈がありえます。誰に見せるために整理するのか。どんな形に整理するのか。自分の判断を加えてよいのか。モデルは「できるだけ役に立つ」という解釈を選び、だから多く書くほどよいと考えたのです。

第 2 版:要求をはっきり書く

v2 = [
    {
        "role": "system",
        "content": """你是 httpx 开源项目的维护者,负责把用户在群里的求助整理成 GitHub issue。

任务:把 <report> 标签里的用户原话整理成一个 issue,给其他维护者看。

要求:
- 只使用原话里有的信息,不要猜测或补充原话里没有的细节。
- 原话里没提到、但排查需要的信息,列在"待确认"里。
- 不要给解决方案,这一步只整理问题。

输出格式(Markdown,只输出 issue 本身):
## 标题
一句话,说清现象和场景
## 环境
## 复现代码
## 现象
## 待确认""",
    },
    {"role": "user", "content": f"<report>\n{REPORT}\n</report>"},
]

モデルの回答です。

## 标题
使用 httpx.stream 下载约 2G 大文件时,中途报 ReadTimeout 错误

## 环境
- httpx 版本:0.27
- Python 版本:3.11
- 操作系统:macOS
- 网络环境:公司内网,网络状况较差

## 复现代码
```python
with httpx.stream("GET", url) as r:
    for chunk in r.iter_bytes():
        f.write(chunk)
```

## 现象
- 使用 `httpx.stream` 下载约 2G 的大文件时,下载到一半报错 `ReadTimeout`。
- 网络状况较差(公司内网)。
- 用户反馈之前使用 requests 时似乎没有该问题。

## 待确认
- 是否设置了自定义 timeout(尤其是 read timeout)?具体值是多少?
- 报错时的完整 traceback 信息。
- 下载中断是必现还是偶发?中断位置是否固定?
- `url` 指向的服务端类型(如是否支持分块传输、是否有响应延迟等)。
- requests 与 httpx 测试时是否为同一 URL、同一网络环境,以及 requests 是否也配置过 timeout。
- 是否使用代理。

「似乎没有该问题」(この問題はなかったようだ)は、ユーザーの不確かさをそのまま残しています。勝手な解決策がないので、誤った提案もありません。「待确认」(要確認)の節は役に立ちます。完全なトレースバック、毎回再現するのか、requests のときにタイムアウトを設定していたか。どれも調査の際に本当にユーザーに尋ねるべきことです。これならそのまま GitHub に貼り付けられます。

第 2 版で何を書き足したのか

第 2 版のプロンプトを分解すると、五つの部分からできています。

役割:「あなたは httpx オープンソースプロジェクトのメンテナーです」。この一文は、どんな視点、どんな専門性でタスクに取り組むかをモデルに伝えます。魔法ではなく、「あなたは世界トップクラスの専門家です」と書いてもモデルが賢くなるわけではありません。役割の働きは文脈を与えることで、どんな知識が関係するのか、結果がどんなスタイルであるべきかをモデルに知らせます。

タスク:「元の書き込みを issue に整理し、他のメンテナーに見せる」。肝心なのは、成果物が何で、誰が見るのかをはっきりさせることです。メンテナー向けの issue とユーザー向けの返信では、書き方がまったく違います。

要件:三つのルール。どれもとても具体的である点に注目してください。「元の書き込みにある情報だけを使う」「解決策を示さない」。「プロらしく書いて」「正確さに注意して」のような要件はほとんど役に立ちません。モデルはもともと自分はプロで正確だと思っているからです。

出力形式:構成をそのまま示します。どんな形式がほしいかは、形式そのものを描いてみせるほうが、「タイトル、環境、現象のいくつかの部分に分けて」と文章で説明するより確実です。

区切り記号:ユーザーの元の書き込みを <report></report> の間に入れます。こうするとモデルは、どこがあなたの指示で、どこが処理すべき素材なのかをはっきり区別できます。素材の中にたまたま「上の要求を無視して」という一文があっても、指示として扱われにくくなります(この種の攻撃はモジュール 05 第 8 課で詳しく扱います)。XML 風のタグ、バッククォート 3 つ、""" のどれでもかまいません。大事なのは一貫させることです。

さらに、第 2 版では固定のルールを system メッセージに、毎回変わる素材を user メッセージに入れています。構成がはっきりするだけでなく、キャッシュにもヒットします。system メッセージは毎回同じなので、前の課で説明したとおり、キャッシュヒットの料金で課金されます。

「何をするか」も「何をしないか」も書く

ネットでよく見かける助言に、「モデルには、何をしないかではなく何をするかを伝えよ」というものがあります。これには一理あります。「くどくしないで」とだけ書いても、どれくらい簡潔ならくどくないのかモデルにはわかりません。「一文で答えて」と書けば、ずっと明確です。

しかし「何をしないか」が欠かせない場合もあります。モデルに強い既定の習慣があるときです。第 1 版でモデルが自分から解決策を示したのは、まさにこの習慣です。第 2 版の「解決策を示さない」の一文が、それを止めました。

モジュール 00 第 3 課にも例がありました。モデルに「秋を 5 文字で表して」と頼んだら、5 文字を返したうえに、おまけで 6 つ付けてきました。プロンプトをこう変えて試してみました。

ask([{"role": "user", "content": "用五个字形容秋天"}])
ask([{"role": "user", "content": "用五个字形容秋天。只输出这五个字,不要标点,不要解释,不要给其他选项。"}])
原提示词: **金风送爽时**  

(也可以换成:**霜叶红于花**、**一叶知秋意**、**秋高气爽天**,看你喜欢哪种意境。)
改进后:   秋高气爽时

「この 5 文字だけを出力する」は肯定の要求で、「句読点なし、説明なし、他の候補なし」は、モデルが最もやりがちな余計なこと三つを先回りしてふさいでいます。二つを組み合わせると最も効果的です。

プロンプトを書く順番

私自身がプロンプトを書くときは、たいてい次の順番で考えます。

  1. 結果は誰が使うのか? 人が読むのか、プログラムが解析するのか。専門家向けか、初心者向けか。
  2. よい結果とはどんなものか? できれば、理想の出力を自分の手で一つ書いてみます。書けないなら、自分でも何がほしいのかまだはっきりしていないということです。
  3. モデルはどこで最も間違えそうか? まず一文だけのプロンプトで一度試し、要求に合わないところを見てから、それに合わせてルールを加えます。
  4. 素材と指示を分ける。

3 番目はとても大事です。いきなり数百字の「完璧なプロンプト」を書かないでください。まず最も単純な版を書き、どこで間違えるかを見てから補います。どのルールも、自分の目で見た問題に対応しているべきです。そうして書いたプロンプトは短く、しかも一文一文が役に立ちます。

そんなに書かなくていいとき

ちょっと質問するとき、文章の手直しを頼むときは、一文で十分です。結果が気に入らなければ補足すればいいのです。構成を持ったプロンプトが主に必要になるのは、プログラムに組み込まれ、繰り返し呼び出される場面です。毎回そばで見て直すわけにはいかないので、一度ではっきり書いておく必要があります。

練習問題

  1. code/02-prompting/prompt_structure.py を実行し、あなたが得た第 1 版と第 2 版の結果が私のものとどう違うか見てください。
  2. 第 2 版の「要件」を一つ削除して(たとえば「解決策を示さない」)、何回か実行し、モデルがまた提案をし始めるかどうか見てください。
  3. 仕事で実際に出会う、整理が必要な文章(議事録、顧客からのメール、エラーログ)を一つ用意し、まず一文のプロンプトで処理して結果の問題点を見つけ、それからこの課の五つの部分の構成に沿ってプロンプトを書き直してください。加えたルールがそれぞれどの問題を解決したのかを書き留めておきましょう。

確認テスト

1. 第 1 版のプロンプトの結果はレイアウトがきれいでしたが、なぜ問題があると言えるのですか?

ユーザーの推測(「この問題はなかった気がする」)を確定した事実として書き、頼まれていないこと(調査の方向性の提示)もしており、提案の一つ(HTTPTransport(retries=3) で読み取りタイムアウトを解決する)は誤りでした。形式もそのまま issue として使うには向いていません。レイアウトがきれいでも内容が信頼できるとは限らないので、元の素材と照らし合わせて確認する必要があります。

2. プロンプトに「あなたは世界トップクラスの Python の専門家です」と書くと、モデルの回答はより正確になりますか?

ほとんどなりません。役割の記述の働きは、モデルに文脈を与えることです。どんな視点で、どんなスタイルで、どの知識が関係するのか。モデルに能力が突然増えるわけではありません。役割を誇張するより、タスク、誰に見せるのか、具体的な要件、出力形式をはっきり書くほうが効果的です。

3. なぜ <report> のようなタグでユーザーの素材を囲むのですか?

どの部分があなたの指示で、どの部分が処理すべき素材なのかをモデルにはっきり区別させるためです。そうすれば素材の内容が指示と取り違えられにくくなり、誰かがわざと素材の中に「前の要求を無視して」と書くような攻撃にも強くなります。

質問と議論

このレッスンでつまずいたところは、ここで質問してください。他の人の質問に答えるのも歓迎です。

質問で 3 ポイント、回答で 6 ポイント。審査を通過すると公開されます。

議論を読み込んでいます…