恭喜您來到 PocketFlow-Tutorial-Codebase-Knowledge
教學系列的最後一章!在上一章 大型語言模型互動 (LLM Interaction) 中,我們探索了專案如何利用大型語言模型(LLM)的智慧來分析程式碼和生成內容。我們已經逐步收集了所有必要的組件:專案摘要、核心概念之間的關係圖、以及為每個概念精心撰寫的獨立教學章節。
現在,萬事俱備,只欠東風。這些寶貴的資訊和內容仍然是分散的片段。我們如何將它們組織起來,變成一份結構完整、易於導覽、可供學習者直接使用的教學文件呢?這就是「教學文件組合 (Tutorial Combination)」的任務所在。
想像一下,您寫完了一本書的所有章節,也畫好了插圖,還有了書籍的簡介。接下來,您需要將這些材料交給出版社進行最後的排版、設計封面、印刷和裝訂,最終才能得到一本可以發行的書籍。
教學文件組合 (Tutorial Combination) 的核心概念: 這是教學生成的最後一道工序,好比是書籍的排版和印刷。它會收集所有先前生成的獨立章節內容(Markdown 格式)、專案摘要以及抽象概念之間的關係圖,然後將它們組合成一個結構完整、帶有導覽的教學網站(實際上是一系列相互連結的 Markdown 文件,存放在一個特定資料夾中)。
這個步驟確保了我們辛勤工作的成果能夠以一種專業、有條理且方便使用者閱讀的形式呈現出來。如果沒有這個步驟,我們就只有一堆零散的文字檔案,學習者將難以系統地學習。
主要使用案例: 我們已經透過前面的流程,在共享狀態 (Shared State) 中儲存了:
「教學文件組合」會利用這些資料,在指定的輸出目錄下建立一個以專案名稱命名的資料夾。資料夾內會有一個 index.md
首頁,包含專案摘要、關係圖和指向各個章節的連結。同時,每個獨立的章節內容也會被存成各自的 .md
檔案。
負責這項最終組裝任務的節點 (Node) 是 CombineTutorial
。它的關鍵職責包括:
index.md
):.md
檔案中。檔案名稱會根據章節順序和章節標題(可能已翻譯,並經過無害化處理)來命名,例如 01_流程編排.md
(實際檔名會將中文轉為底線或拼音)。index.md
和每個章節檔案的末尾,添加固定的英文文本,例如 "Chapters", "Source Repository" (在 index.md
中) 以及專案的署名連結 (attribution footer)。根據設計,這些固定文本保持英文。CombineTutorial
節點如何運作?最後的組裝大師!CombineTutorial
是我們流程編排 (Flow Orchestration)中的最後一個節點 (Node)。它負責將所有成果匯集起來。
輸入 (從共享狀態讀取):
在其 prep
(準備)階段,CombineTutorial
節點會從共享狀態 (Shared State)中讀取以下關鍵資訊:
project_name
(字串):專案的名稱,用於命名輸出資料夾。relationships
(字典):包含 summary
(專案摘要,可能已翻譯) 和 details
(關係列表,from
, to
為概念索引,label
為關係描述,標籤可能已翻譯)。chapter_order
(列表):核心概念的索引列表,代表教學章節的順序。abstractions
(列表):所有核心概念的詳細資訊列表,每個元素包含 name
(概念名稱,可能已翻譯) 和 description
(概念描述,可能已翻譯)。chapters
(列表):一個包含多個 Markdown 字串的列表,每個字串是一篇獨立的教學章節內容 (可能已翻譯)。repo_url
(字串,可選):原始程式碼庫的網址。output_dir
(字串):存放所有輸出教學的基礎目錄 (預設為 "output")。輸出 (寫入共享狀態):
在其 post
(收尾)階段,CombineTutorial
節點會將最終教學文件存放的資料夾路徑寫入共享狀態 (Shared State):
final_output_dir
(字串):例如 "output/MyProjectName"
。運作流程示意圖:
CombineTutorial
的 prep
, exec
, post
讓我們更深入地了解 CombineTutorial
節點是如何透過其三個主要方法來完成組裝工作的。
prep
方法:準備所有組裝材料CombineTutorial
的 prep
方法是組裝工作的藍圖規劃階段。它不實際寫入檔案,而是將所有要寫入的內容和檔案結構準備好。
# 檔案: nodes.py (CombineTutorial 節點的 prep 方法 - 簡化示意)
class CombineTutorial(Node):
def prep(self, shared):
project_name = shared["project_name"]
output_base_dir = shared.get("output_dir", "output")
output_path = os.path.join(output_base_dir, project_name) # 最終輸出資料夾路徑
relationships_data = shared["relationships"] # 包含已翻譯的摘要和關係標籤
chapter_order = shared["chapter_order"]
abstractions = shared["abstractions"] # 包含已翻譯的概念名稱
chapters_content = shared["chapters"] # 包含已翻譯的章節內容
repo_url = shared.get("repo_url")
# --- 產生 Mermaid 圖表 ---
mermaid_lines = ["flowchart TD"]
for i, abstr in enumerate(abstractions):
node_id = f"A{i}"
# 使用已翻譯的概念名稱,並做簡單的無害化處理
sanitized_name = abstr["name"].replace('"', "")
mermaid_lines.append(f' {node_id}["{sanitized_name}"]') # 節點標籤使用已翻譯名稱
for rel in relationships_data["details"]:
from_node_id = f"A{rel['from']}"
to_node_id = f"A{rel['to']}"
# 使用已翻譯的關係標籤,並做無害化處理和長度限制
edge_label = rel["label"].replace('"', "").replace("\n", " ")
# ... (省略標籤長度修剪邏輯) ...
mermaid_lines.append(f' {from_node_id} -- "{edge_label}" --> {to_node_id}') # 邊標籤使用已翻譯標籤
mermaid_diagram = "\n".join(mermaid_lines)
# --- 準備 index.md 內容 ---
index_content = f"# Tutorial: {project_name}\n\n"
index_content += f"{relationships_data['summary']}\n\n" # 使用已翻譯的摘要
if repo_url: # 固定的 "Source Repository" 標籤 (英文)
index_content += f"**Source Repository:** [{repo_url}]({repo_url})\n\n"
index_content += "```mermaid\n" # 嵌入 Mermaid 圖
index_content += mermaid_diagram + "\n"
index_content += "```\n\n"
index_content += f"## Chapters\n\n" # 固定的 "Chapters" 標題 (英文)
chapter_files_to_write = [] # 儲存要寫入的章節檔案資訊
for i, abstraction_index in enumerate(chapter_order):
abstraction_name = abstractions[abstraction_index]["name"] # 已翻譯的概念名稱
# 根據已翻譯的概念名稱產生無害化檔名
safe_name = "".join(c if c.isalnum() else "_" for c in abstraction_name).lower()
# 如果 safe_name 因中文而變成空或只有底線,可能需要備用策略,但目前程式碼是這樣
# 例如 "流程編排" 會變成 "__" 或類似,取決於isalnum對中文的處理
filename = f"{i+1:02d}_{safe_name if safe_name else f'chapter_{i+1}'}.md" # 確保檔名不為空
index_content += f"{i+1}. [{abstraction_name}]({filename})\n" # 連結文字使用已翻譯名稱
chapter_md_content = chapters_content[i] # 已翻譯的章節內容
# 添加固定的英文署名
chapter_md_content += f"\n\n---\n\n"
chapter_files_to_write.append({"filename": filename, "content": chapter_md_content})
# 為 index.md 添加固定的英文署名
index_content += f"\n\n---\n\n"
return {
"output_path": output_path,
"index_content": index_content,
"chapter_files": chapter_files_to_write,
}
在 prep
方法中,節點精心準備了 index.md
的完整內容(包括標題、摘要、Mermaid 圖和章節連結),以及一個包含所有獨立章節檔案名稱和其對應內容的列表。檔案名稱是根據章節順序和無害化處理後的章節名稱(可能已翻譯)生成的。例如,如果一個章節的(已翻譯)名稱是「流程編排」,經過 safe_name
處理後,檔名可能會變成像 01____.md
或 01_liucheng_bianpai.md
(如果系統進行了拼音轉換,但目前程式碼只做簡單的非字母數字字元替換)。連結的顯示文字則會是原始的(已翻譯)章節名稱。
exec
方法:執行檔案寫入exec
方法接收 prep
方法準備好的材料,並實際執行檔案系統操作——建立資料夾和寫入檔案。
# 檔案: nodes.py (CombineTutorial 節點的 exec 方法 - 簡化示意)
class CombineTutorial(Node):
# ... prep 方法 ...
def exec(self, prep_res):
output_path = prep_res["output_path"] # 例如 "output/MyProjectName"
index_content = prep_res["index_content"] # 準備好的 index.md 內容
chapter_files = prep_res["chapter_files"] # 包含 {"filename": ..., "content": ...} 的列表
print(f"開始組合教學文件至資料夾: {output_path}")
os.makedirs(output_path, exist_ok=True) # 建立輸出資料夾,如果已存在則不報錯
# 寫入 index.md
index_filepath = os.path.join(output_path, "index.md")
with open(index_filepath, "w", encoding="utf-8") as f:
f.write(index_content)
print(f" - 已寫入 {index_filepath}")
# 寫入所有章節檔案
for chapter_info in chapter_files:
chapter_filepath = os.path.join(output_path, chapter_info["filename"])
with open(chapter_filepath, "w", encoding="utf-8") as f:
f.write(chapter_info["content"])
print(f" - 已寫入 {chapter_filepath}")
return output_path # 回傳最終教學文件所在的資料夾路徑
這個方法的核心就是使用 Python 的檔案操作功能,將 prep
階段準備好的內容一一寫入到目標資料夾中。
post
方法:宣告任務完成post
方法非常簡單,它只是將 exec
方法回傳的最終輸出路徑儲存到共享狀態 (Shared State)中,並打印一條完成訊息。
# 檔案: nodes.py (CombineTutorial 節點的 post 方法 - 簡化示意)
class CombineTutorial(Node):
# ... prep 和 exec 方法 ...
def post(self, shared, prep_res, exec_res):
# exec_res 就是 exec 方法回傳的 output_path
shared["final_output_dir"] = exec_res
print(f"\n教學文件生成完畢!檔案位於: {exec_res}")
至此,整個自動化教學生成流程就圓滿結束了!
當 CombineTutorial
節點執行完畢後,您會在指定的輸出目錄下(例如 output/YourProjectName/
)找到一個包含以下內容的資料夾:
index.md
:01_sanitized_chapter_name.md
(例如 01____.md
或 01_flow_orchestration.md
):02_sanitized_chapter_name.md
:這樣,學習者就可以從 index.md
開始,輕鬆地瀏覽整個教學內容了。
在本章中,我們深入了解了「教學文件組合 (Tutorial Combination)」這個畫龍點睛的步驟。它由 CombineTutorial
節點 (Node) 負責,將所有先前生成的元素——摘要、關係圖資料、獨立章節——巧妙地編織成一個結構化、可導覽的教學文件集。
index.md
(包含摘要、Mermaid 圖、章節連結),並將各個獨立章節寫入對應的 .md
檔案。CombineTutorial
節點會使用先前步驟中可能已經翻譯好的概念名稱、摘要、關係標籤和章節內容。固定的界面文字(如 "Chapters", "Source Repository", 署名)則保持英文。index.md
和多個章節 .md
檔案的資料夾,構成一份完整的教學。至此,我們已經完成了 PocketFlow-Tutorial-Codebase-Knowledge
專案所有核心概念的學習之旅!從最初的流程編排 (Flow Orchestration),到節點 (Node)的定義、共享狀態 (Shared State)的資訊傳遞,再到具體的程式碼擷取 (Code Fetching)、教學章節生成 (Chapter Generation)(其中涉及了大型語言模型互動 (LLM Interaction)),最後到本章的「教學文件組合」,我們一步步揭開了自動化程式碼庫知識教學生成的神秘面紗。
希望本系列教學能幫助您理解這個專案的運作原理,並激發您探索更多自動化和 AI 輔助開發的可能性!感謝您的學習!