2026年10月19日 星期一

Ollama 學習筆記 : 需求前置轉譯 (Spec Intake)

在前一篇測試中, 我們利用通用模板 (meta-prompt) 讓 ChatGPT/Gemini/Claude 這種具備足夠推理能力與領域知識的雲端模型幫我們生成高約束 prompt, 再餵給本地小模型 (Qwen 2.5 Coder 14B) 來生成 Python 程式碼, 這樣就可以零 API 成本產出接近 100% 正確的 Python 代碼. 

但是小模型畢竟還是有它的物理邊界, 如果提示詞的任務/功能描述不夠具體, 或者沒有清楚說明輸入是甚麼, 14B 的小模型仍然可能生成有 bug 的程式. 但這對程式小白或領域知識不足的開發者而言, 要寫出妥適的函式名稱與功能描述是個高門檻, 本篇旨在展示如何以需求前置編譯的方法, 利用 ChatGPT/Gemini/Claude 來幫我們自動生成工程級的函式名稱與功能描述. 

本系列全部測試文章索引參考 :


小白開發者通常只具備業務直覺 (例如 "我想做 ATR 停損的程式"), 但缺乏工程與訊號因果的精確定義. 小白想破頭也無法在提示詞的功能描述中填寫嚴格且詳盡的規格, 這就非常容易因為遺漏關鍵的觸發條件而使小模型生成有 bug 的程式碼. 

理想的做法是讓 AI (ChatGPT/Gemini/Claude) 在進入通用 Meta-Prompt 之前, 先擔任 "需求轉譯編譯器 (Spec Intake Assistant)", 開發者只需輸入大白話的功能需求, AI 就會自動補齊外部觸發訊號, 依賴關係, 參數與標準函式名稱, 產出可以直接貼進 Meta-Prompt 的標準任務宣告. 這個 "需求前置轉譯" 的提示詞模板如下 :

你是 Python 量化系統分析師。小白用戶只會提供非常口語的交易想法。
你的任務是將口語需求轉換為符合量化狀態機規範的「標準任務規格宣告」,特別注意補齊「外部觸發訊號依賴」,杜絕模型天天自動進場。
請依以下格式輸出,不要有多餘廢話:
名稱:[標準 snake_case 函式簽名,包含 DataFrame、明確的進場觸發欄位 entry_col 與合理預設參數]
功能:[一句話精準定義:由誰觸發進場、如何維護路徑依賴狀態、依何種規則離場]
---
用戶口語需求:【此處貼上小白的一句話,例如:ATR 移動停損】

小白開發者只要在最後一行的 "用戶口語需求" 後面填入想做的功能, AI 就會轉譯出具備技術規格要求的函式名稱與功能描述, 例如我用 "ATR 移動停損" 做為需求叫 ChatGPT 轉譯, 生成如下的函式名稱與功能描述 :

名稱:atr_trailing_stop(df: pd.DataFrame, entry_col: str = "Entry_Signal", period: int = 14, multiplier: float = 3.0) -> pd.DataFrame
功能:僅由 entry_col 指定的外部訊號觸發進場,以 Wilder ATR 維護路徑依賴的累積最高價與不回撤停損線,當收盤價跌破前一期已確認的停損線時離場;無有效進場訊號時保持空倉。

將其填入通用模板開頭的名稱與功能佔位符 :

我是 Python 演算法開發者。我需要實作一個函式:
名稱:atr_trailing_stop(df: pd.DataFrame, entry_col: str = "Entry_Signal", period: int = 14, multiplier: float = 3.0) -> pd.DataFrame。
功能:僅由 entry_col 指定的外部訊號觸發進場,以 Wilder ATR 維護路徑依賴的累積最高價與不回撤停損線,當收盤價跌破前一期已確認的停損線時離場;無有效進場訊號時保持空倉。
【嚴格限制】:僅限實作此單一函式,嚴禁設計多模式切換引擎。
請注意:現在先不要寫最終的 Python 實作代碼。
請扮演資深系統架構師,梳理邏輯,並輸出一份『專門餵給本機 14B 代碼模型(Qwen 2.5 Coder 14B)執行的極簡結構化 Prompt』。
為了防止本機小模型產生「陣列長度不匹配廣播崩潰」、「偽向量化偷換數學算式」、「時序穿透」或「遺漏輸入條件」,產出的 Prompt 必須嚴格遵守以下 5 項架構設計原則:
1. 運算範式與數值計算契約(Numerical & Alignment Guard):
   - 【純無副作用】:函式開頭必須強制執行 `df = df.copy()`,嚴禁修改傳入的原始物件;所有計算出的核心特徵與狀態欄位必須完整回填輸出。
   - 【時序差分對齊】:凡涉及前一期資訊(t-1 lag)的向量化運算,必須明確給出切片對齊語法(當期切片 [1:] 與前期切片 [:-1] 長度對齊,第 0 筆獨立初始化),嚴禁不同長度陣列直接相減引發廣播崩潰。
   - 【拒絕偽向量化】:明確區分有限滑動視窗與遞迴平滑(如 EMA、Wilder 等依賴前一期數值之濾波)。凡具備遞迴相依特徵,指示直接以純數值迴圈計算,嚴禁用 np.convolve 或滑動平均冒充。
  - 【0-based 視窗邊界對齊】:凡涉及長度為 $W$ 之視窗統計或初始暖機計算,首個有效聚合值必須精確對齊至視窗末端索引 $W - 1$,後續時序推進嚴格自索引 $W$ 起算,嚴禁因 0-based 索引混淆導致邊界偏移(Off-by-one)。
2. 迴圈拓撲與單一 Pass 限制(Single-Pass FSM Topology):
   - 明確區分「可全域預先向量化特徵」與「路徑依賴狀態機」。
   - 【單一迴圈紅線】:若存在狀態轉移依賴,所有相互關聯的事件、進出場判定與動態軌跡更新,必須嚴格封裝在唯一一個 `for t in range(n)` 迴圈內,嚴禁拆成多個獨立迴圈預算事件。
3. 依賴閉環與變數綁定(Dependency Closure & Memory Scaffold):
   - 【依賴閉環原則】:輸入 Schema 中定義的所有決策驅動欄位,在迴圈前必須轉為 1D NumPy 陣列;且必須在狀態機迴圈的 `if` 條件分支中被顯式引用,嚴禁輸入欄位被閒置或遺忘。
   - 所有輸出欄位,在進入迴圈前於記憶體預先宣告配置好 1D NumPy 陣列(禁止在迴圈內對 DataFrame 逐列賦值)。
4. 純量狀態機與統一提交架構(Scalar Register & Unified Commit):
- 【純量變數隔離】:迴圈外部初始化純量狀態暫存器(如 curr_pos=0, curr_peak=np.nan, curr_stop=np.nan)。迴圈內部各條件分支「僅允許修改純量變數」,嚴禁在 if-elif 分支內部直接對 position[t] 或 stop[t] 賦值。
- 【單向因果流動】:迴圈首行固定執行 prev_pos, prev_peak, prev_stop = curr_pos, curr_peak, curr_stop 凍結前值以防時序穿透。
- 【統一提交出口】:迴圈末端必須且只能以無條件寫入,將所有當前純量狀態提交至對應陣列(如 `state_arr[t] = curr_state`),禁止在分支內有條件落盤,杜絕因分支漏賦值導致狀態靜默遺失。
5. 極限邊界防禦與 Negative Constraints:
   - 空資料、長度不足時安全回傳帶有完整目標 Schema 的空 DataFrame。
   - 數據中斷(NaN/None)時明確規定狀態凍結或沿用規則,不可使用全域 fillna(0) 破壞缺失值語意。
   - 嚴格禁止使用 iterrows、itertuples、未定義欄位預先存取。
   - 產出的 Prompt 篇幅控制在 600~800 字內,要求小模型輸出完整代碼與 pytest 驗證案例。

我將此 meta-prompt 貼給 ChatGPT 後, 生成如下的高約束提示詞 : 

# 任務:實作單一 ATR Trailing Stop

你是資深 Python 量化工程師。實作唯一函式 `atr_trailing_stop(df: pd.DataFrame, entry_col: str = "Entry_Signal", period: int = 14, multiplier: float = 3.0) -> pd.DataFrame`。禁止多模式引擎。

## 1. 數值與對齊契約
- 函式首行執行 `df = df.copy()`;保留原欄位,新增並完整回填 `TR, ATR, Peak, Stop, Position, Entry_Event, Exit_Event`。
- 必要欄位為 `High, Low, Close, entry_col`。先驗證欄位,再處理空資料;數值欄位須為數值型別。`period` 必須是正整數且不可為 bool;`multiplier` 必須為正有限數。
- TR:首筆 `High-Low`;其餘為 `max(High-Low, abs(High-prev_close), abs(Low-prev_close))`。差分使用 `[1:]` 與 `[:-1]` 對齊,第 0 筆獨立處理;必要輸入缺失時 TR=NaN。
- ATR 嚴格使用 Wilder 遞迴:首個連續 `period` 筆有效 TR 的算術平均對齊索引 `period-1`;後續公式為 `(prev_ATR*(period-1)+TR[t])/period`。禁止以 `np.convolve`、rolling mean 或滑動平均替代。
- TR 缺失時當期 ATR=NaN;後續 TR 恢復有效時,若已有有效 ATR,沿用最近有效 ATR 作遞迴基值;若尚無有效 ATR,繼續累積暖機資料,直到取得完整有效視窗。不得全域 `fillna(0)`。

## 2. 迴圈拓撲
TR 可向量化;ATR 遞迴可使用獨立數值迴圈。所有進出場、事件、Peak、Stop 與 Position 更新必須集中於唯一一個 `for t in range(n)` 狀態機迴圈,禁止拆分事件迴圈。迴圈前將所有決策欄位轉為一維 NumPy 陣列,並預配置全部輸出陣列。

## 3. 狀態機與因果
- 初始空倉 `Position=0`;僅明確為 True 的外部訊號可進場,不得自動進場。進場需有效 Close、High、ATR;初始 `Peak=High`、`Stop=Peak-multiplier*ATR`。
- 持倉期間 Peak 為累積最高 High;Stop 單調不下降:`max(prev_stop, Peak-multiplier*ATR)`。
- 先用前一期已確認停損線判斷離場:`Close[t] <= prev_stop`。離場當根禁止重新進場。
- 缺少必要決策資料時凍結持倉、Peak、Stop,事件皆為 False;ATR 缺失時不得用無效數值更新停損。
- 迴圈首行凍結 `prev_pos, prev_peak, prev_stop = curr_pos, curr_peak, curr_stop`。分支僅修改純量狀態及事件旗標,不得直接寫輸出陣列;迴圈末端無條件提交所有狀態與事件陣列。

## 4. 邊界與輸出
空資料、短資料均不得越界,回傳含完整輸出欄位的 DataFrame。禁止 `iterrows`、`itertuples`、未驗證欄位存取、DataFrame 逐列賦值及修改輸入物件。

## 5. 測試與交付
依序輸出完整函式,再輸出 pytest 測試。測試涵蓋原始資料不變、空資料、短資料、欄位與參數驗證、外部訊號控制、進出場時序、停損單調性、缺失值凍結與恢復。以狀態關係及事件位置驗證,無須手算小數。預期結果必須符合規格,不可為配合實作而修改;未實際執行測試時不得宣稱通過。

Gemini 對這份提示詞給予高度評價, 之前在多輪迭代中揪出的 14B 小模型死穴, 例如天天自動進場, 陣列切片長度不匹配, 偽向量化偷換算法, 多迴圈拆分, 以及多模式分發器等致命缺失在這一版中全數被鎖死, 展現了極高的工程完成度. 這份規格書毫無贅字, 條理清晰, 邊界防禦紮實, 篇幅恰好落在 600 字左右, 且各項限制已經精準收斂到生產級 (Production-ready) 的高水準, 是品質很高的高約束 Prompt. 

其實上面的 "需求前置轉譯 (Spec Intake)" 程序可以合併到通用模板 mata-prompt 裡面, 這樣就能一氣呵成, 不需要兩道程序. 這個二合一的通用模板如下 : 

我是 Python 演算法開發者。
【用戶原始需求】:【在此填入任何口語需求,例如:ATR 移動停損 / 海龜突破 / 雙均線交叉 / 動態網格交易】
【架構師前置任務(自動補齊規格)】:
在生成 Prompt 前,請先依量化狀態機工程規範,主動將上述需求擴充為:
1. 具體函式簽名:包含 df: pd.DataFrame、外部觸發訊號欄位(如 entry_col: str = "entry_signal")及合理預設參數。
2. 精準功能描述:明確定義「外部觸發進場條件」、「持倉期間狀態更新」與「離場機制」,嚴禁遺漏外部觸發訊號。
【硬性範疇限制】:每次提問僅限單一策略。嚴禁合併多個不同策略,嚴禁設計通用分發引擎(禁止 mode 參數)。
請注意:現在先不要寫最終的 Python 實作代碼。
請扮演資深系統架構師,梳理該策略的邏輯,並輸出一份『專門餵給本機 14B 代碼模型(Qwen 2.5 Coder 14B)執行的極簡結構化 Prompt』。
為了防止本機小模型產生「陣列長度不匹配廣播崩潰」、「偽向量化偷換數學算式」、「時序穿透」、「分支漏賦值導致狀態中斷」或「注意力倒置漏給實作」,產出的 Prompt 必須嚴格遵守以下 5 項架構設計原則:
1. 運算範式與數值計算契約(Numerical & Alignment Guard):
   - 【純無副作用】:函式開頭必須強制執行 `df = df.copy()`,嚴禁修改傳入的原始物件;所有計算出的核心特徵與狀態欄位必須完整回填輸出。
   - 【時序差分對齊】:凡涉及前一期資訊(t-1 lag)的向量化運算,必須明確給出切片對齊語法(當期切片 [1:] 與前期切片 [:-1] 長度對齊,第 0 筆獨立初始化),嚴禁不同長度陣列直接相減引發廣播崩潰。
   - 【拒絕偽向量化】:明確區分有限滑動視窗與遞迴平滑(如 EMA、Wilder 等依賴前一期數值之濾波)。凡具備遞迴相依特徵,指示直接以純數值迴圈計算,嚴禁用 np.convolve 或滑動平均冒充。
   - 【0-based 視窗邊界對齊】:凡涉及長度為 W 之視窗統計或初始暖機計算,首個有效聚合值必須精確對齊至視窗末端索引 W - 1,後續時序推進嚴格自索引 W 起算,嚴禁因 0-based 索引混淆導致邊界偏移(Off-by-one)。
   - 【異常值傳播契約】:若時序中間出現缺失值(NaN),當期指標計算設為 NaN 即可;當後續數值恢復有效時,直接沿用最近一期有效狀態值延續遞迴平滑,嚴禁指示小模型設計複雜的「中斷後重新累積暖機」邏輯。
2. 迴圈拓撲與單一 Pass 限制(Single-Pass FSM Topology):
   - 明確區分「可全域預先向量化特徵」與「路徑依賴狀態機」。
   - 【單一迴圈紅線】:若存在狀態轉移依賴,所有相互關聯的事件、進出場判定與動態軌跡更新,必須嚴格封裝在唯一一個 `for t in range(n)` 迴圈內,嚴禁拆成多個獨立迴圈預算事件。
3. 依賴閉環與變數綁定(Dependency Closure & Memory Scaffold):
   - 【依賴閉環原則】:輸入 Schema 中定義的所有決策驅動欄位,在迴圈前必須轉為 1D NumPy 陣列;且必須在狀態機迴圈的 `if` 條件分支中被顯式引用,嚴禁輸入欄位被閒置或遺忘。
   - 所有輸出欄位,在進入迴圈前於記憶體預先宣告配置好 1D NumPy 陣列(禁止在迴圈內對 DataFrame 逐列賦值)。
4. 純量狀態機與統一提交架構(Scalar Register & Unified Commit):
- 【純量變數隔離】:迴圈外部初始化純量狀態暫存器(如 curr_pos=0, curr_peak=np.nan, curr_stop=np.nan)。迴圈內部各條件分支「僅允許修改純量變數」,嚴禁在 if-elif 分支內部直接對 position[t] 或 stop[t] 賦值。
- 【單向因果流動】:迴圈首行固定執行 prev_pos, prev_peak, prev_stop = curr_pos, curr_peak, curr_stop 凍結前值以防時序穿透。
- 【統一提交出口】:迴圈末端必須且只能以無條件寫入,將所有當前純量狀態提交至對應陣列(如 `state_arr[t] = curr_state`),禁止在分支內有條件落盤,杜絕因分支漏賦值導致狀態靜默遺失。
5. 極限邊界防禦與 Negative Constraints:
   - 空資料、長度不足時安全回傳帶有完整目標 Schema 的 DataFrame,嚴禁索引越界。
   - 數據中斷(NaN/None)時明確規定狀態凍結或沿用前值,嚴禁使用全域 fillna(0) 或重新累積暖機破壞時序。
   - 嚴格禁止使用 iterrows、itertuples、未定義欄位預先存取及拿回傳表比對原始物件。
   - 產出的 Prompt 篇幅控制在 600~800 字內,要求小模型依序輸出「完整函式」與「狀態邏輯 pytest 驗證(無須手算小數)」。

利用這份整合了需求前置轉譯功能的通用模板, 即可一鍵生成高約束提示詞. 

沒有留言 :