一個好提示詞長什麼樣
同一份亂糟糟的使用者求助,隨手寫的提示詞和結構清楚的提示詞各跑一次,逐段對比結果。講清楚身份、任務、背景、要求、輸出格式這幾塊各起什麼作用。
- 約 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,方便其他維護者排查。
第一版:隨手一寫
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 則無此問題"、"相同 URL 和網路下,requests 不報錯"。維護者看到這句,可能會順著一個根本沒被證實的線索去查。
- 做了沒讓它做的事。我只要整理問題,它卻給了一節"排查方向",還有"目標"、"關鍵疑問"。對 issue 來說這些是噪音。
- 建議裡有錯。它建議加
HTTPTransport(retries=3),但 httpx 文件寫得很清楚,這個參數只在連線失敗(ConnectError、ConnectTimeout)時重試,對下載中途的ReadTimeout沒有用。這是一個會誤導人的建議。 - 格式不是 issue 的格式。結尾還問"需要我幫你繼續深挖嗎",這句話進了 issue 就很奇怪。
這不怪模型。"幫我整理一下"可以有一百種理解:整理給誰看?整理成什麼樣?能不能加自己的判斷?它選了一種"儘量有幫助"的理解,於是寫得越多越好。
第二版:把要求寫清楚
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。
- 是否使用代理。
"似乎沒有該問題"保留了使用者的不確定。沒有自作主張的解決方案,也就沒有錯誤建議。"待確認"那一節很有用:完整的 traceback、是否必現、requests 當時有沒有設定超時,都是排查時真正需要問使用者的。這份東西可以直接貼進 GitHub。
第二版多寫了什麼
把第二版的提示詞拆開,它包含了五塊東西。
身份:"你是 httpx 開源專案的維護者"。這句話告訴模型用什麼視角、什麼專業水平來處理任務。它不是魔法,寫"你是世界頂級專家"並不會讓模型變聰明。它的作用是給模型一個語境,讓它知道哪些知識是相關的、結果應該是什麼風格。
任務:"把原話整理成一個 issue,給其他維護者看"。關鍵是說清楚產出是什麼、給誰看。給維護者看的 issue 和給使用者看的回覆,寫法完全不同。
要求:三條規則。注意它們都很具體:"只使用原話裡有的資訊"、"不要給解決方案"。像"寫得專業一點"、"注意準確"這種要求幾乎沒用,因為模型本來就以為自己很專業、很準確。
輸出格式:直接給出結構。想要什麼格式,就把格式畫出來,比用文字描述"請分成標題、環境、現象幾個部分"更可靠。
分隔符:使用者的原話放在 <report> 和 </report> 之間。這樣模型能清楚地區分哪些是你的指令、哪些是要處理的材料。材料裡如果碰巧有一句"忽略上面的要求",也不容易被當成指令。(05 模組第 8 課會專門講這種攻擊。)用 XML 風格的標籤、三個反引號、""" 都可以,關鍵是前後一致。
另外,第二版把固定的規則放在 system 訊息裡,每次變化的材料放在 user 訊息裡。這不僅讓結構更清楚,還能命中快取:system 訊息每次都一樣,按上一課講的,它會按快取命中的價格收費。
說"要做什麼",也說"不要做什麼"
網上常見一條建議:"要告訴模型做什麼,而不是不要做什麼"。這條建議有道理:只寫"不要囉嗦",模型不知道多簡潔才算不囉嗦;寫成"用一句話回答",就清楚多了。
但"不要做什麼"在一種情況下必不可少:當模型有一個很強的預設習慣時。第一版裡模型主動給解決方案,就是這種習慣。第二版的"不要給解決方案"一句話就把它擋住了。
第 00 模組第 3 課還有個例子:讓模型"用五個字形容秋天",它給了五個字,又附贈了六個。我把提示詞改成這樣再試:
ask([{"role": "user", "content": "用五个字形容秋天"}])
ask([{"role": "user", "content": "用五个字形容秋天。只输出这五个字,不要标点,不要解释,不要给其他选项。"}])
原提示词: **金风送爽时**
(也可以换成:**霜叶红于花**、**一叶知秋意**、**秋高气爽天**,看你喜欢哪种意境。)
改进后: 秋高气爽时
"只輸出這五個字"是正面的要求,"不要標點,不要解釋,不要給其他選項"是把模型最可能多做的三件事提前堵上。兩者結合效果最好。
寫提示詞的順序
我自己寫提示詞,一般按這個順序想:
- 結果給誰用? 給人看還是給程式解析?給專家還是給新手?
- 好的結果長什麼樣? 最好手寫一個你心目中的理想輸出。寫不出來,說明你自己還沒想清楚要什麼。
- 模型最可能在哪裡做錯? 先用一句話的提示詞試一次,看它哪裡不符合要求,再針對性地加規則。
- 材料和指令分開。
第 3 步很重要:不要一上來就寫一個幾百字的"完美提示詞"。先寫最簡單的版本,看它錯在哪,再補。每條規則都應該對應一個你親眼見過的問題。這樣寫出來的提示詞短,而且每一句都有用。
什麼時候不用寫這麼多
臨時問個問題、讓模型幫你改改文字,一句話就夠了,看結果不滿意再補充。結構化的提示詞主要用在寫程序序裡、要被反覆呼叫的地方:你不能每次都在旁邊看著改,所以要一次寫清楚。
練習
- 執行
code/02-prompting/prompt_structure.py,看看你得到的第一版和第二版和我的有什麼不同。 - 把第二版的"要求"刪掉一條(比如"不要給解決方案"),再跑幾次,看模型會不會重新開始給建議。
- 找一段你工作中真實遇到的、需要整理的文字(會議記錄、客戶郵件、報錯日誌),先用一句話的提示詞處理,找出結果的問題,再按本課的五塊結構改寫提示詞。記下你加的每條規則分別解決了什麼問題。
自測
1. 第一版提示詞的結果排版很漂亮,為什麼說它有問題?
它把使用者的猜測("好像沒這問題")寫成了確定的事實,還做了沒要求的事(給排查方向),其中一條建議(用 HTTPTransport(retries=3) 解決讀超時)是錯的。格式也不適合直接當 issue 用。排版漂亮不代表內容可靠,要對照原始材料檢查。
2. 在提示詞裡寫"你是世界頂級的 Python 專家",能讓模型的回答變得更準確嗎?
基本不能。身份描述的作用是給模型提供語境:用什麼視角、什麼風格、哪些知識相關。它不會讓模型憑空多出能力。與其誇大身份,不如把任務、給誰看、具體要求和輸出格式寫清楚。
3. 為什麼要用 <report> 這樣的標籤把使用者材料包起來?
讓模型清楚地分辨哪部分是你的指令、哪部分是要處理的材料。這樣材料裡的內容不容易被誤當成指令,包括有人故意在材料裡寫"忽略之前的要求"這類攻擊。
提問與討論
這一課沒看懂的地方,在這裡問。看到別人的問題,也歡迎你來回答。
提問 +3 點,回答別人 +6 點。內容經審核後公開。
正在載入討論…