實(shí)戰(zhàn):?jiǎn)稳司艂€(gè)月二十萬行代碼的AI應(yīng)用開發(fā)之路)
1. 先聊聊這個(gè)項(xiàng)目到底在做什么一個(gè)人九個(gè)月二十萬行代碼每個(gè)月燒掉四十多億token最終交付的是一款基于Harness架構(gòu)的應(yīng)用。這幾個(gè)數(shù)字?jǐn)[在一起任何一個(gè)寫過代碼的人都會(huì)先愣一下——不是被規(guī)模嚇到而是被“一個(gè)人”這三個(gè)字釘住。九個(gè)月二十萬行平均下來每天要產(chǎn)出七百多行有效代碼而且不是那種復(fù)制粘貼的樣板代碼是真正要跑起來、要能用的業(yè)務(wù)邏輯。更別提每個(gè)月四十多億token的消耗量這個(gè)數(shù)字背后意味著大量的模型調(diào)用、反復(fù)的推理驗(yàn)證、以及幾乎不間斷的自動(dòng)化流程在運(yùn)轉(zhuǎn)。我第一眼看到這個(gè)標(biāo)題的時(shí)候腦子里冒出來的問題不是“怎么做到的”而是“為什么要這么做”。因?yàn)榘凑粘R?guī)思路這種體量的項(xiàng)目應(yīng)該是一個(gè)團(tuán)隊(duì)花一年半載來推進(jìn)的事情一個(gè)人扛下來要么是極度自信要么是被逼到墻角沒有退路。后來我仔細(xì)拆解了一下Harness架構(gòu)的特點(diǎn)才慢慢理解了這個(gè)選擇背后的邏輯——Harness本質(zhì)上是一種“編排層”的思路它不直接干活而是負(fù)責(zé)調(diào)度、協(xié)調(diào)、串聯(lián)各種能力單元。這種架構(gòu)天然適合單人開發(fā)者因?yàn)樗褟?fù)雜度從“寫代碼”轉(zhuǎn)移到了“設(shè)計(jì)流程”上。所謂Harness架構(gòu)你可以把它想象成一個(gè)樂隊(duì)的指揮。指揮自己不演奏任何樂器但他知道什么時(shí)候該讓小提琴進(jìn)來什么時(shí)候該讓鼓手收住什么時(shí)候全體合奏。在軟件世界里Harness就是那個(gè)指揮它不實(shí)現(xiàn)具體的業(yè)務(wù)邏輯而是定義“什么條件下觸發(fā)什么動(dòng)作、什么結(jié)果傳遞給下一步”。這種模式最大的好處是你不需要在一個(gè)文件里寫幾千行代碼來維護(hù)復(fù)雜的流程而是把每個(gè)環(huán)節(jié)拆成獨(dú)立的、可替換的模塊用Harness把它們串起來。這個(gè)項(xiàng)目之所以值得拿出來聊不是因?yàn)樗昧硕嗝辞把氐募夹g(shù)棧而是因?yàn)樗故玖艘环N在資源極度受限的情況下如何用架構(gòu)設(shè)計(jì)來對(duì)沖人力不足的思路。適合誰來參考如果你是一個(gè)獨(dú)立開發(fā)者正在做一個(gè)復(fù)雜度不低的項(xiàng)目如果你是一個(gè)小團(tuán)隊(duì)的tech lead需要在人手有限的情況下推進(jìn)一個(gè)平臺(tái)級(jí)的產(chǎn)品或者你只是一個(gè)對(duì)Agent開發(fā)、Harness架構(gòu)、Claude Code這類工具鏈感興趣的工程師這篇文章里的很多細(xì)節(jié)都值得你花時(shí)間琢磨。2. 為什么是Harness架構(gòu)而不是別的2.1 傳統(tǒng)架構(gòu)在單人項(xiàng)目里的死穴我先說說為什么一個(gè)人做項(xiàng)目傳統(tǒng)架構(gòu)會(huì)讓你痛不欲生。假設(shè)你要做一個(gè)功能完整的應(yīng)用按照經(jīng)典的MVC或者分層架構(gòu)來組織代碼你會(huì)遇到幾個(gè)幾乎無解的問題。第一個(gè)問題是上下文切換成本。你今天寫Controller層明天寫Service層后天調(diào)DAO層每次切換你都要重新加載腦子里關(guān)于那一層的所有細(xì)節(jié)。一個(gè)人做項(xiàng)目最怕的就是這種頻繁的上下文切換因?yàn)槟愕拇竽X不是數(shù)據(jù)庫沒法瞬間索引到某個(gè)接口的參數(shù)列表。傳統(tǒng)架構(gòu)要求你在不同抽象層之間來回跳每跳一次就損耗一次注意力和短期記憶。第二個(gè)問題是測(cè)試和維護(hù)的邊際成本遞增。當(dāng)你寫到第五萬行代碼的時(shí)候改一個(gè)底層的工具類可能要花半天時(shí)間確認(rèn)它不會(huì)影響上面幾十個(gè)調(diào)用點(diǎn)。這種恐懼感會(huì)嚴(yán)重拖慢你的開發(fā)速度因?yàn)槟汩_始不敢改代碼了。一個(gè)人做項(xiàng)目最寶貴的就是“敢改”的勇氣一旦這個(gè)勇氣被復(fù)雜的依賴關(guān)系消磨掉項(xiàng)目就進(jìn)入死亡螺旋了。第三個(gè)問題是知識(shí)孤島。傳統(tǒng)架構(gòu)里業(yè)務(wù)邏輯散落在各個(gè)Service和Controller里你很難一眼看出“用戶下單”這個(gè)動(dòng)作到底經(jīng)過了哪些步驟、每個(gè)步驟依賴什么條件。當(dāng)你三個(gè)月后回頭看這段代碼你會(huì)像讀別人的代碼一樣陌生。這種陌生感在單人項(xiàng)目里是致命的因?yàn)槟銢]有同事可以問。2.2 Harness架構(gòu)的核心思路Harness架構(gòu)的核心思路可以用一句話概括把“做什么”和“怎么做”徹底分開。在Harness的世界里你首先定義的是一個(gè)流程或者叫管道Pipeline這個(gè)管道由若干個(gè)階段Stage組成每個(gè)階段負(fù)責(zé)一個(gè)明確的、原子性的任務(wù)。階段之間通過明確定義的輸入輸出契約來通信而不是通過共享內(nèi)存或者全局狀態(tài)。這種設(shè)計(jì)的好處是你每次只需要關(guān)注一個(gè)階段。寫“解析用戶輸入”這個(gè)階段的時(shí)候你完全不用管后面“調(diào)用模型生成回復(fù)”是怎么實(shí)現(xiàn)的你只需要保證你的輸出格式符合約定就行。這就像工廠的流水線每個(gè)工位只負(fù)責(zé)擰一顆螺絲擰完就傳給下一個(gè)工位不需要知道整臺(tái)機(jī)器最終長(zhǎng)什么樣。Harness架構(gòu)還有一個(gè)關(guān)鍵特性是可觀測(cè)性。因?yàn)槊總€(gè)階段都是獨(dú)立的你可以很方便地在階段之間插入日志、監(jiān)控、重試邏輯。哪個(gè)階段慢了、哪個(gè)階段報(bào)錯(cuò)了、哪個(gè)階段的輸出不符合預(yù)期一目了然。在單人項(xiàng)目里這種可觀測(cè)性就是你的“同事”它幫你盯著系統(tǒng)的運(yùn)行狀態(tài)讓你不用時(shí)刻緊繃著神經(jīng)。2.3 為什么這個(gè)項(xiàng)目選了Harness回到這個(gè)項(xiàng)目本身。九個(gè)月二十萬行代碼如果按照傳統(tǒng)架構(gòu)來寫大概率會(huì)在第十五萬行左右的時(shí)候陷入泥潭——改不動(dòng)、測(cè)不了、看不懂。但Harness架構(gòu)把復(fù)雜度從“代碼量”轉(zhuǎn)移到了“流程設(shè)計(jì)”上你寫的每一行代碼都是某個(gè)階段的具體實(shí)現(xiàn)階段之間是松耦合的。這意味著你可以今天寫十個(gè)階段明天寫另外八個(gè)階段后天回頭改前天的階段只要輸入輸出契約不變改哪個(gè)階段都不會(huì)影響其他階段。每個(gè)月四十多億token的消耗量也說明了另一個(gè)問題這個(gè)項(xiàng)目大量依賴模型調(diào)用來完成實(shí)際工作。Harness架構(gòu)天然適合這種場(chǎng)景因?yàn)槟P驼{(diào)用本身就是一個(gè)“輸入-處理-輸出”的原子操作非常適合封裝成一個(gè)階段。你可以設(shè)計(jì)一個(gè)“意圖識(shí)別”階段把用戶輸入丟給模型拿到意圖分類結(jié)果然后根據(jù)意圖分類路由到不同的“處理”階段每個(gè)處理階段可能又調(diào)用模型來生成具體內(nèi)容。整個(gè)流程清晰、可追蹤、可替換。還有一個(gè)很現(xiàn)實(shí)的原因Claude Code這類工具的出現(xiàn)讓Harness架構(gòu)的落地成本大幅降低。Claude Code本身就是一個(gè)Agent化的開發(fā)環(huán)境它理解你的項(xiàng)目結(jié)構(gòu)能幫你生成符合Harness模式的代碼骨架。你只需要告訴它“我要一個(gè)處理用戶登錄的階段輸入是用戶名密碼輸出是token或者錯(cuò)誤信息”它就能幫你把階段的基本結(jié)構(gòu)搭出來。這種效率提升在單人項(xiàng)目里是決定性的。3. 核心細(xì)節(jié)拆解二十萬行代碼是怎么堆出來的3.1 階段劃分的粒度控制Harness架構(gòu)里最容易犯的錯(cuò)誤是階段劃分得太粗或者太細(xì)。太粗了一個(gè)階段里塞了幾百行代碼又回到了傳統(tǒng)架構(gòu)的老路太細(xì)了階段數(shù)量爆炸流程編排的復(fù)雜度反而超過了業(yè)務(wù)本身的復(fù)雜度。這個(gè)項(xiàng)目在階段劃分上有一個(gè)很實(shí)用的原則一個(gè)階段只做一件可以用一句話描述清楚的事情。比如“從Markdown文本中提取所有二級(jí)標(biāo)題”是一個(gè)合格的階段“解析Markdown并生成目錄結(jié)構(gòu)”就太粗了因?yàn)椤敖馕觥焙汀吧伞笔莾杉?。反過來“讀取文件第一行”又太細(xì)了因?yàn)檫@種操作不值得單獨(dú)成為一個(gè)階段它應(yīng)該作為“讀取文件”階段的一部分。我自己的經(jīng)驗(yàn)是一個(gè)階段的代碼量控制在五十到兩百行之間比較合適。少于五十行說明你可能過度拆分了多于兩百行說明這個(gè)階段承擔(dān)了太多職責(zé)應(yīng)該考慮拆分。當(dāng)然這不是硬性標(biāo)準(zhǔn)只是一個(gè)參考區(qū)間。3.2 輸入輸出契約的設(shè)計(jì)階段之間的通信靠的是輸入輸出契約。這個(gè)契約設(shè)計(jì)得好不好直接決定了整個(gè)系統(tǒng)的可維護(hù)性。這個(gè)項(xiàng)目在契約設(shè)計(jì)上采用了強(qiáng)類型加版本號(hào)的方案。強(qiáng)類型的意思是每個(gè)階段的輸入和輸出都有明確的數(shù)據(jù)結(jié)構(gòu)定義不是隨便傳一個(gè)字典或者JSON對(duì)象。比如“用戶意圖識(shí)別”階段的輸出是一個(gè)枚舉類型只能是“查詢”、“創(chuàng)建”、“刪除”、“更新”這四個(gè)值之一。這樣做的好處是當(dāng)你把“查詢”階段的輸出接到“創(chuàng)建”階段的輸入時(shí)類型檢查會(huì)直接報(bào)錯(cuò)你立刻就知道接錯(cuò)了。版本號(hào)的意思是每個(gè)契約都有一個(gè)版本標(biāo)識(shí)。當(dāng)你需要修改某個(gè)階段的輸出格式時(shí)不是直接改而是新增一個(gè)版本。舊版本的階段繼續(xù)用舊契約新版本的階段用新契約兩者可以共存。這在單人項(xiàng)目里特別重要因?yàn)槟悴豢赡芤淮涡园阉邢嚓P(guān)階段都改完版本號(hào)給了你漸進(jìn)式遷移的空間。3.3 錯(cuò)誤處理和重試機(jī)制Harness架構(gòu)里錯(cuò)誤處理不是在每個(gè)階段內(nèi)部各自為政而是有一套統(tǒng)一的機(jī)制。這個(gè)項(xiàng)目采用了階段級(jí)重試加流程級(jí)回滾的策略。階段級(jí)重試的意思是每個(gè)階段可以配置自己的重試策略。比如調(diào)用模型生成內(nèi)容的階段如果遇到超時(shí)或者限流可以自動(dòng)重試三次每次間隔遞增。而像“寫入數(shù)據(jù)庫”這種階段重試策略就要謹(jǐn)慎得多因?yàn)橹貜?fù)寫入可能導(dǎo)致數(shù)據(jù)不一致。流程級(jí)回滾的意思是當(dāng)某個(gè)階段最終失敗后整個(gè)流程可以回滾到之前某個(gè)檢查點(diǎn)。這要求每個(gè)階段都要實(shí)現(xiàn)一個(gè)“撤銷”操作或者至少要把狀態(tài)變更記錄成可回滾的形式。在單人項(xiàng)目里回滾機(jī)制能幫你省下大量手動(dòng)修復(fù)數(shù)據(jù)的時(shí)間。注意重試機(jī)制一定要配合冪等性設(shè)計(jì)。如果一個(gè)階段不是冪等的重試可能會(huì)導(dǎo)致重復(fù)操作。比如“發(fā)送郵件”這個(gè)階段重試三次就可能發(fā)出三封郵件。解決辦法是在階段內(nèi)部維護(hù)一個(gè)操作ID重復(fù)的操作ID直接跳過。3.4 可觀測(cè)性的落地方式可觀測(cè)性在Harness架構(gòu)里不是可選項(xiàng)而是必選項(xiàng)。這個(gè)項(xiàng)目在每個(gè)階段的前后都埋了點(diǎn)位記錄輸入、輸出、耗時(shí)、狀態(tài)。這些數(shù)據(jù)匯總到一個(gè)統(tǒng)一的日志系統(tǒng)里你可以隨時(shí)查詢“過去一小時(shí)里哪個(gè)階段失敗率最高”、“哪個(gè)階段的平均耗時(shí)超過了閾值”。具體實(shí)現(xiàn)上可以用簡(jiǎn)單的結(jié)構(gòu)化日志每條日志包含階段名稱、流程實(shí)例ID、時(shí)間戳、事件類型開始/成功/失敗、以及相關(guān)的上下文數(shù)據(jù)。查詢的時(shí)候用grep或者簡(jiǎn)單的日志分析工具就能定位問題。不需要上很重的監(jiān)控系統(tǒng)單人項(xiàng)目講究的是夠用就好。4. 實(shí)操過程從零搭建一個(gè)Harness應(yīng)用的完整路徑4.1 環(huán)境準(zhǔn)備與工具選型這個(gè)項(xiàng)目用到的核心工具鏈包括Claude Code作為主要的開發(fā)助手Obsidian作為知識(shí)管理和文檔編寫的工具以及Markdown作為所有文檔和配置的格式標(biāo)準(zhǔn)。為什么選這幾個(gè)工具我一個(gè)個(gè)說。Claude Code的選擇理由很直接它理解項(xiàng)目上下文能幫你生成符合Harness模式的代碼而且支持自定義的skill和插件。你可以在項(xiàng)目根目錄放一個(gè)配置文件告訴Claude Code這個(gè)項(xiàng)目的架構(gòu)約定它生成的代碼就會(huì)自動(dòng)遵循這些約定。這比你自己手動(dòng)寫模板要高效得多。Obsidian的選擇理由稍微繞一點(diǎn)。Harness架構(gòu)的項(xiàng)目會(huì)產(chǎn)生大量的流程文檔、階段說明、契約定義這些內(nèi)容如果用Word或者在線文檔來管理很快就會(huì)亂成一鍋粥。Obsidian的雙向鏈接和本地Markdown存儲(chǔ)特性讓你可以很方便地在階段文檔之間建立關(guān)聯(lián)而且所有內(nèi)容都是純文本可以直接被Claude Code讀取和理解。Markdown作為格式標(biāo)準(zhǔn)是因?yàn)樗銐蚝?jiǎn)單人和機(jī)器都能讀。你的階段定義、契約說明、配置參數(shù)全部用Markdown來寫Claude Code可以直接解析這些文件來理解你的意圖。4.2 項(xiàng)目目錄結(jié)構(gòu)的組織這個(gè)項(xiàng)目的目錄結(jié)構(gòu)大致是這樣的project/ ├── harness/ │ ├── pipelines/ # 流程定義 │ │ ├── user_onboarding.md │ │ └── content_generation.md │ ├── stages/ # 階段實(shí)現(xiàn) │ │ ├── parse_input/ │ │ ├── call_model/ │ │ └── format_output/ │ └── contracts/ # 契約定義 │ ├── input_schema.md │ └── output_schema.md ├── docs/ # Obsidian文檔 │ ├── architecture.md │ └── stage_catalog.md └── config/ └── harness.yaml # 全局配置這個(gè)結(jié)構(gòu)的關(guān)鍵點(diǎn)是流程定義和階段實(shí)現(xiàn)分離。pipelines目錄里放的是Markdown格式的流程描述說明這個(gè)流程有哪些階段、階段之間的依賴關(guān)系是什么。stages目錄里放的是每個(gè)階段的具體代碼實(shí)現(xiàn)。contracts目錄里放的是輸入輸出的數(shù)據(jù)結(jié)構(gòu)定義。這樣做的好處是你可以先寫流程定義把整個(gè)管道的骨架搭出來然后再逐個(gè)實(shí)現(xiàn)階段。流程定義用Markdown寫意味著你可以用自然語言描述流程Claude Code能直接理解并幫你生成對(duì)應(yīng)的代碼骨架。4.3 用Claude Code生成階段代碼具體操作是這樣的你先在pipelines目錄里新建一個(gè)Markdown文件描述你要做的流程。比如# 內(nèi)容生成流程 ## 階段1解析用戶輸入 - 輸入原始文本 - 輸出結(jié)構(gòu)化的請(qǐng)求對(duì)象 - 依賴無 ## 階段2調(diào)用模型生成內(nèi)容 - 輸入結(jié)構(gòu)化的請(qǐng)求對(duì)象 - 輸出生成的內(nèi)容文本 - 依賴階段1 ## 階段3格式化輸出 - 輸入生成的內(nèi)容文本 - 輸出符合Markdown規(guī)范的最終文檔 - 依賴階段2然后你打開Claude Code告訴它“根據(jù)pipelines/content_generation.md生成對(duì)應(yīng)的階段代碼”。Claude Code會(huì)讀取這個(gè)Markdown文件理解每個(gè)階段的輸入輸出要求然后在stages目錄下生成對(duì)應(yīng)的代碼文件。每個(gè)文件里包含階段的基本結(jié)構(gòu)、輸入輸出的類型定義、以及一個(gè)待實(shí)現(xiàn)的處理函數(shù)。你接下來要做的就是填充每個(gè)處理函數(shù)的具體邏輯。因?yàn)镃laude Code已經(jīng)幫你把骨架搭好了你只需要關(guān)注核心邏輯不用操心目錄結(jié)構(gòu)、命名規(guī)范、類型定義這些瑣事。4.4 參數(shù)計(jì)算與性能調(diào)優(yōu)每個(gè)月四十多億token的消耗量意味著token成本是一個(gè)必須認(rèn)真對(duì)待的問題。這個(gè)項(xiàng)目在參數(shù)調(diào)優(yōu)上做了幾件事。第一是模型分級(jí)。不是所有階段都需要用最強(qiáng)的模型。像“解析用戶輸入”這種任務(wù)用輕量級(jí)模型就夠了“生成創(chuàng)意內(nèi)容”才需要上大模型。通過分級(jí)可以把大部分token消耗轉(zhuǎn)移到低成本模型上。第二是緩存策略。很多階段的輸入是重復(fù)的比如“查詢天氣”這個(gè)階段同一個(gè)城市在短時(shí)間內(nèi)多次查詢結(jié)果是一樣的。給這類階段加上緩存可以大幅減少模型調(diào)用次數(shù)。緩存的key可以用輸入?yún)?shù)的哈希值緩存的過期時(shí)間根據(jù)業(yè)務(wù)特點(diǎn)來定。第三是批處理。有些階段可以批量處理多個(gè)請(qǐng)求比如“生成摘要”這個(gè)階段可以把十個(gè)文檔的摘要請(qǐng)求合并成一次模型調(diào)用。批處理能顯著降低token消耗因?yàn)槟P驼{(diào)用的固定開銷被攤薄了。實(shí)操心得token消耗的大頭往往不是模型推理本身而是上下文窗口里塞了太多無關(guān)信息。每次調(diào)用模型之前仔細(xì)檢查一下你傳進(jìn)去的上下文把不必要的內(nèi)容刪掉。我試過在一個(gè)階段里把上下文從八千token壓縮到兩千token效果幾乎沒變但成本降了四分之三。4.5 用Obsidian管理項(xiàng)目知識(shí)Obsidian在這個(gè)項(xiàng)目里扮演的是“第二大腦”的角色。每個(gè)階段的設(shè)計(jì)決策、每個(gè)契約的變更歷史、每個(gè)踩過的坑都記錄在Obsidian的筆記里。這些筆記通過雙向鏈接關(guān)聯(lián)起來形成一個(gè)知識(shí)網(wǎng)絡(luò)。具體用法是這樣的你為每個(gè)階段建一個(gè)筆記筆記里記錄這個(gè)階段的職責(zé)、輸入輸出、依賴關(guān)系、已知問題、優(yōu)化歷史。然后在流程筆記里鏈接到相關(guān)的階段筆記。當(dāng)你三個(gè)月后回頭看某個(gè)流程時(shí)你可以順著鏈接一路點(diǎn)進(jìn)去快速回憶起所有相關(guān)細(xì)節(jié)。Obsidian還有一個(gè)好處是它的插件生態(tài)。比如你可以用Dataview插件來查詢“所有標(biāo)記為待優(yōu)化的階段”或者用Templater插件來快速創(chuàng)建符合規(guī)范的新階段筆記。這些插件能幫你把知識(shí)管理變成一種自動(dòng)化流程減少手動(dòng)維護(hù)的負(fù)擔(dān)。5. 常見問題與排查技巧實(shí)錄5.1 階段加載失敗怎么辦Harness架構(gòu)里最常見的問題之一是階段加載失敗。表現(xiàn)是流程啟動(dòng)時(shí)報(bào)錯(cuò)提示某個(gè)階段無法加載。排查思路是這樣的首先檢查階段文件的路徑是否正確。Harness通常按照約定來查找階段文件如果你的目錄結(jié)構(gòu)不符合約定就會(huì)找不到。其次檢查階段文件的語法是否正確特別是如果你用Markdown來定義階段格式錯(cuò)誤會(huì)導(dǎo)致解析失敗。最后檢查依賴是否完整有些階段可能依賴外部庫或者環(huán)境變量這些缺失也會(huì)導(dǎo)致加載失敗。排查技巧在Harness的配置里打開詳細(xì)日志它會(huì)告訴你具體是哪個(gè)文件、哪一行出了問題。不要靠猜直接看日志。5.2 流程執(zhí)行中斷的定位方法流程執(zhí)行到一半中斷了但日志里沒有明顯的錯(cuò)誤信息這種情況最讓人頭疼。我的經(jīng)驗(yàn)是先確認(rèn)中斷發(fā)生在哪個(gè)階段。如果Harness有流程實(shí)例的狀態(tài)記錄直接查狀態(tài)表就能看到最后一個(gè)成功的階段是哪個(gè)。如果沒有狀態(tài)記錄就在每個(gè)階段的入口和出口加日志重新跑一次流程看日志停在哪個(gè)階段。定位到階段之后再細(xì)分是階段內(nèi)部的哪個(gè)步驟出了問題。通常是在階段內(nèi)部的關(guān)鍵操作前后加日志逐步縮小范圍。這個(gè)過程可能比較繁瑣但比盲目猜測(cè)要快得多。5.3 模型調(diào)用超時(shí)和限流的應(yīng)對(duì)模型調(diào)用超時(shí)和限流是高頻問題特別是在token消耗量大的項(xiàng)目里。應(yīng)對(duì)策略分三層第一層是超時(shí)設(shè)置。每個(gè)模型調(diào)用都要設(shè)置合理的超時(shí)時(shí)間不能無限等待。超時(shí)時(shí)間根據(jù)任務(wù)復(fù)雜度來定簡(jiǎn)單的分類任務(wù)可以設(shè)短一點(diǎn)復(fù)雜的生成任務(wù)設(shè)長(zhǎng)一點(diǎn)。第二層是重試策略。超時(shí)后自動(dòng)重試但重試次數(shù)和間隔要控制好。通常重試三次就夠了間隔采用指數(shù)退避比如第一次等一秒第二次等兩秒第三次等四秒。第三層是降級(jí)方案。如果重試后仍然失敗要有降級(jí)方案。比如切換到備用模型或者返回一個(gè)默認(rèn)結(jié)果或者把請(qǐng)求放入隊(duì)列稍后處理。降級(jí)方案的具體選擇取決于業(yè)務(wù)對(duì)失敗的容忍度。5.4 常見問題速查表問題現(xiàn)象可能原因排查方法解決方案階段加載失敗路徑錯(cuò)誤或語法錯(cuò)誤查看詳細(xì)日志修正路徑或語法流程執(zhí)行中斷某個(gè)階段內(nèi)部異常檢查階段入口出口日志修復(fù)異常階段模型調(diào)用超時(shí)網(wǎng)絡(luò)問題或模型負(fù)載高查看超時(shí)日志增加超時(shí)時(shí)間或重試token消耗異常高上下文冗余或緩存失效分析調(diào)用日志壓縮上下文或修復(fù)緩存輸出格式不符合預(yù)期契約定義不清晰對(duì)比輸入輸出更新契約定義階段間數(shù)據(jù)傳遞錯(cuò)誤類型不匹配檢查類型定義修正類型或轉(zhuǎn)換邏輯5.5 幾個(gè)踩過的坑第一個(gè)坑是過度依賴模型生成代碼。Claude Code確實(shí)能幫你生成階段骨架但如果你不仔細(xì)審查生成的代碼可能會(huì)引入一些隱蔽的問題。比如它可能會(huì)生成一個(gè)看起來正確但實(shí)際上沒有處理邊界情況的函數(shù)。我的做法是生成的代碼必須經(jīng)過人工審查特別是錯(cuò)誤處理和邊界條件部分。第二個(gè)坑是契約版本管理混亂。一開始我覺得版本號(hào)是多余的直接改契約多方便。結(jié)果改了三次之后我自己都記不清哪個(gè)階段用的是哪個(gè)版本的契約了。后來老老實(shí)實(shí)加上了版本號(hào)每次改契約都新增版本舊版本保留問題就消失了。第三個(gè)坑是日志太多反而找不到有用信息。一開始我在每個(gè)階段里加了很多日志結(jié)果日志文件每天幾十個(gè)G查問題的時(shí)候像大海撈針。后來我調(diào)整了策略只在關(guān)鍵節(jié)點(diǎn)加日志并且給日志加上結(jié)構(gòu)化的標(biāo)簽查詢效率大幅提升。第四個(gè)坑是忽略了本地開發(fā)環(huán)境的模擬。有些階段依賴外部服務(wù)本地開發(fā)時(shí)這些服務(wù)不可用導(dǎo)致流程跑不起來。后來我加了一層mock機(jī)制本地開發(fā)時(shí)自動(dòng)切換到mock實(shí)現(xiàn)開發(fā)效率提升了很多。6. 這套架構(gòu)還能怎么擴(kuò)展Harness架構(gòu)最大的優(yōu)勢(shì)是可擴(kuò)展性。當(dāng)你把流程和階段分離之后增加新功能就變成了“寫一個(gè)新階段然后在流程里加一個(gè)節(jié)點(diǎn)”這么簡(jiǎn)單。這個(gè)項(xiàng)目后續(xù)可以往幾個(gè)方向擴(kuò)展。第一個(gè)方向是增加更多的階段類型。目前項(xiàng)目里的階段主要是模型調(diào)用和數(shù)據(jù)處理未來可以增加“人工審核”階段、“外部API調(diào)用”階段、“定時(shí)觸發(fā)”階段等。每增加一種階段類型流程的表達(dá)能力就增強(qiáng)一分。第二個(gè)方向是流程的可視化編輯。目前流程定義是用Markdown寫的雖然靈活但不夠直觀??梢宰鲆粋€(gè)簡(jiǎn)單的Web界面用拖拽的方式編排流程底層還是生成Markdown文件。這樣非技術(shù)用戶也能參與流程設(shè)計(jì)。第三個(gè)方向是階段的復(fù)用和共享。當(dāng)階段數(shù)量積累到一定程度后可以建立一個(gè)階段庫把通用的階段比如“發(fā)送郵件”、“生成PDF”、“壓縮圖片”抽出來在不同項(xiàng)目之間復(fù)用。這能大幅降低新項(xiàng)目的啟動(dòng)成本。第四個(gè)方向是性能的持續(xù)優(yōu)化。隨著流程復(fù)雜度增加性能瓶頸會(huì)逐漸顯現(xiàn)??梢酝ㄟ^分析每個(gè)階段的耗時(shí)分布找出瓶頸階段針對(duì)性地優(yōu)化。優(yōu)化的手段包括緩存、批處理、并行化、模型分級(jí)等。我在實(shí)際使用中發(fā)現(xiàn)Harness架構(gòu)最迷人的地方在于它讓“改變”變得廉價(jià)。你想調(diào)整流程改Markdown文件就行。你想替換某個(gè)階段的實(shí)現(xiàn)只要契約不變隨便換。你想加一個(gè)新功能加一個(gè)階段連上去就行。這種“改變廉價(jià)”的特性在快速迭代的項(xiàng)目里是巨大的優(yōu)勢(shì)。最后再分享一個(gè)小技巧定期回顧你的階段目錄把那些超過三個(gè)月沒有被任何流程引用的階段標(biāo)記出來。這些階段要么是廢棄的要么是設(shè)計(jì)有問題的。清理掉它們能讓你的項(xiàng)目保持清爽。我每隔一個(gè)月做一次這樣的清理每次都能刪掉百分之十左右的冗余階段效果很明顯。