建可控的智能開發(fā)流水線)
我接手第一版 AI Coding 流程改造時(shí)最大的感受不是“效率翻倍”而是“失控”。AI 能寫代碼但它寫出來(lái)的代碼質(zhì)量時(shí)高時(shí)低它改文件但經(jīng)常順手把不該動(dòng)的配置也改了它跑測(cè)試但失敗了之后會(huì)自己給自己找理由然后換一種方式重試直到把問(wèn)題搞得更復(fù)雜。那段時(shí)間團(tuán)隊(duì)的共識(shí)是AI 很強(qiáng)但如果沒有一套流程去約束它它更像一個(gè)能力很強(qiáng)但紀(jì)律很差的新同學(xué)。后來(lái)我們把 AI Coding 從“對(duì)話框里的一問(wèn)一答”改造成了類似 CI/CD 流水線的一套工程化流程任務(wù)進(jìn)來(lái)之后要經(jīng)過(guò)解析、規(guī)劃、執(zhí)行、審查、批準(zhǔn)這套固定節(jié)點(diǎn)每個(gè)節(jié)點(diǎn)都有明確的輸入輸出、工具邊界和終止條件。這套模式就是標(biāo)題里說(shuō)的Agentic Harness Workflow 框架。它解決的并不是“讓 AI 更聰明”而是“讓 AI 的行為變得可預(yù)期、可追蹤、可回滾”。這篇文章我會(huì)從設(shè)計(jì)思路講到最小可用版本再講我們踩過(guò)的坑適合正在把 AI Coding 引入團(tuán)隊(duì)、但又不想讓代碼庫(kù)變成無(wú)人看管的荒野的開發(fā)者參考。1. 為什么需要 Harness WorkflowAI Coding 失控的根源1.1 直接對(duì)話模式更適合“結(jié)對(duì)編程”而不是“流水線生產(chǎn)”很多人剛開始用 AI 寫代碼時(shí)用的是最原始的方式把一個(gè)需求丟給大模型然后等它輸出一段代碼再手動(dòng)應(yīng)用、手動(dòng)測(cè)試、手動(dòng) review。這種模式本質(zhì)上是在做“結(jié)對(duì)編程”AI 是副駕駛?cè)耸侵黢{。問(wèn)題在于當(dāng)任務(wù)變多、參與者變多之后這種模式暴露出三個(gè)很難忍受的缺陷。第一個(gè)缺陷是不可控。AI 在生成代碼時(shí)并不清楚它被允許修改哪些文件、禁止碰哪些目錄。它可能為了完成一個(gè)小需求重寫了大半個(gè)模塊然后告訴你“我順手重構(gòu)了”這個(gè)重構(gòu)里可能帶著它自己風(fēng)格的命名、格式化方式甚至在不知情的情況下引入了新的依賴。第二個(gè)缺陷是不可觀測(cè)。你只看到最終結(jié)果看不到它中途經(jīng)歷了什么它嘗試過(guò)哪個(gè)方案、失敗了幾次、浪費(fèi)了多少 token、修改了哪些文件。第三個(gè)缺陷是不可復(fù)現(xiàn)。同樣的需求描述換一天、換一次模型版本結(jié)果可能完全不一樣。你沒法在代碼評(píng)審里說(shuō)“上次生成的不是這樣”因?yàn)闆]有可回放的過(guò)程記錄。這三個(gè)缺陷疊加起來(lái)導(dǎo)致 AI Coding 很難從“個(gè)體工具”升級(jí)為“團(tuán)隊(duì)基礎(chǔ)設(shè)施”。因?yàn)楣こ袒詈诵牡乃膫€(gè)詞——可觀察、可控制、可復(fù)現(xiàn)、可度量——它一個(gè)都不滿足。1.2 工程化的本質(zhì)不是限制而是讓能力可以被安全釋放我見過(guò)一些團(tuán)隊(duì)反過(guò)來(lái)走向另一個(gè)極端既然 AI 不可控那就干脆禁用它全部人肉寫代碼。這其實(shí)是把問(wèn)題簡(jiǎn)單化了。工程化的核心邏輯不是限制人的能力而是通過(guò)流程、工具和護(hù)欄讓一個(gè)能力強(qiáng)但可能犯錯(cuò)的執(zhí)行者穩(wěn)定地輸出結(jié)果。就像生產(chǎn)線上的機(jī)械臂它本身很有力量但真正讓它能連續(xù)工作 16 小時(shí)的是軌道、傳感器、限位開關(guān)和急停按鈕。這些約束不是削弱它而是讓它能在復(fù)雜環(huán)境里安全地做功。Harness這個(gè)詞本身就很有意思它的本意是“挽具、背帶”在測(cè)試領(lǐng)域里Test Harness 指的是“測(cè)試腳手架”一個(gè)能裝載被測(cè)對(duì)象、提供輸入、校驗(yàn)輸出、收集結(jié)果的外殼框架。放到 AI Coding 的情境里Harness 的職責(zé)就是給每個(gè) Agent 劃定活動(dòng)范圍你只能讀哪些文件、只能寫哪些目錄、只能執(zhí)行哪些命令、最多迭代幾次、輸出必須是什么格式。Agent 是在這個(gè)范圍內(nèi)自由發(fā)揮的但范圍本身是工程化設(shè)計(jì)和管理的。Workflow 解決的是另一層問(wèn)題單個(gè) Agent 被約束得再好它也只是孤軍奮戰(zhàn)。一個(gè)完整的代碼變更可能需要一個(gè) Agent 負(fù)責(zé)理解需求、一個(gè) Agent 負(fù)責(zé)生成實(shí)現(xiàn)、一個(gè) Agent 負(fù)責(zé)審查、一個(gè) Gate 負(fù)責(zé)質(zhì)量檢測(cè)最后還要一個(gè)人工節(jié)點(diǎn)去做最終批準(zhǔn)。這些節(jié)點(diǎn)之間的依賴關(guān)系、數(shù)據(jù)傳遞、失敗重試、超時(shí)降級(jí)就是 Workflow 層的工作。所以 Agentic Harness Workflow 不是某個(gè)單一工具而是一整套把“AI 干活”這件事編排成標(biāo)準(zhǔn)化流水線的方法論。1.3 這套框架適合誰(shuí)不適合誰(shuí)先說(shuō)不適合的情況。如果你的團(tuán)隊(duì)只有一兩個(gè)人日常任務(wù)都是幾百行的小腳本那直接開個(gè)對(duì)話框讓 AI 寫反而最快引入完整的工作流框架屬于過(guò)度設(shè)計(jì)。再比如你只是偶爾用 AI 查個(gè) API 用法、寫個(gè)正則表達(dá)式也不需要上 Harness。它真正適合的情況是AI 生成代碼已經(jīng)成為日常開發(fā)路徑的一部分而且團(tuán)隊(duì)對(duì)代碼質(zhì)量有硬性要求。比如某個(gè)模塊的代碼主要靠 AI 生成或者你把 AI 接入了需求到提測(cè)的完整鏈路再或者你有大量機(jī)械性代碼變更升級(jí)依賴、生成單元測(cè)試、重構(gòu)老接口需要自動(dòng)化。這類場(chǎng)景下你需要的是可審計(jì)的流程、可回滾的變更、可量化的效率。Harness Workflow 就是為這些場(chǎng)景準(zhǔn)備的。下面是直接 Prompt 模式與 Harness Workflow 模式的關(guān)鍵差異對(duì)照。對(duì)比維度直接 Prompt 模式Agentic Harness Workflow輸出結(jié)果一段代碼文本一次完整的、可回滾的代碼變更過(guò)程記錄無(wú)只有對(duì)話結(jié)構(gòu)化日志含每一步的輸入輸出與動(dòng)作工具權(quán)限由使用者自行控制白名單機(jī)制Agent 只能觸碰授權(quán)資源失敗處理人工發(fā)現(xiàn)、手動(dòng)修正自動(dòng)重試、超時(shí)終止、降級(jí)轉(zhuǎn)人工質(zhì)量校驗(yàn)依賴人工 review內(nèi)置質(zhì)量門禁不達(dá)標(biāo)不進(jìn)入下一節(jié)點(diǎn)可復(fù)現(xiàn)性幾乎不可復(fù)現(xiàn)同一任務(wù)描述 同一輸入快照 同一流程再往深一層看這套框架真正改變的是人機(jī)協(xié)作的分工模式人不再逐行盯著 AI 生成代碼而是去定義流程、設(shè)置約束、處理異常、做最終決策。這也是為什么我把標(biāo)題定為“把 AI Coding 變成工程化流程”——它把一個(gè)“玄學(xué)”問(wèn)題變成了一個(gè)“管理學(xué)”問(wèn)題。2. 核心概念拆解Harness、Agent、Workflow 各管哪一段2.1 Agent干活的執(zhí)行者不是“萬(wàn)能助手”在框架語(yǔ)境里Agent 是具備一定自主執(zhí)行能力的 AI 程序它通常由模型、提示詞、工具集三個(gè)部分組成。提示詞定義了它的角色和行為準(zhǔn)則工具集定義了它能調(diào)用哪些外部能力讀文件、寫文件、跑命令、調(diào)接口。這里的 Agent 不是對(duì)話框里的聊天機(jī)器人而是一個(gè)有明確任務(wù)目標(biāo)、按特定協(xié)議工作的執(zhí)行單元。設(shè)計(jì) Agent 時(shí)最忌諱的一點(diǎn)是“一個(gè) Agent 什么都干”。我們?cè)缙诜高^(guò)這個(gè)錯(cuò)把一個(gè) Agent 配了讀寫文件、執(zhí)行命令、搜索代碼、修改配置等一大堆工具結(jié)果它在拿到任務(wù)后容易跑偏經(jīng)常在一個(gè)任務(wù)里又是改代碼又是跑測(cè)試又是調(diào)整配置最后出錯(cuò)時(shí)根本分不清是哪一步引起的。后來(lái)我們把 Agent 拆成了專職角色需求分析 Agent 只負(fù)責(zé)產(chǎn)出結(jié)構(gòu)化任務(wù)描述實(shí)現(xiàn) Agent 只負(fù)責(zé)在授權(quán)目錄內(nèi)修改代碼審查 Agent 只負(fù)責(zé)讀代碼并產(chǎn)出審查意見。每個(gè) Agent 只做一件事工具越少越好這是整個(gè)框架里最重要的設(shè)計(jì)原則之一。一個(gè)合格 Agent 的執(zhí)行單元至少要有三樣?xùn)|西清晰的輸入格式任務(wù)描述、上下文、約束條件、清晰的輸出格式結(jié)構(gòu)化 JSON 或 Markdown 報(bào)告、以及明確的終止條件最大迭代次數(shù)、超時(shí)時(shí)間、成本上限。沒有終止條件的 Agent 是最危險(xiǎn)的它可能在一個(gè)問(wèn)題上反復(fù)橫跳消耗大量 token 后仍然沒有結(jié)果。2.2 HarnessAgent 身上的安全繩和約束帶Harness 層負(fù)責(zé)的是執(zhí)行環(huán)境與邊界控制。如果把 Agent 比作一輛跑車Harness 就是它的賽道護(hù)欄、限速器和安全氣囊。它具體包含以下機(jī)制。第一是工具白名單。Agent 能調(diào)用什么、不能調(diào)用什么必須用白名單而非黑名單來(lái)控制。黑名單永遠(yuǎn)有漏網(wǎng)之魚而白名單能保證 Agent 的活動(dòng)空間是預(yù)先設(shè)計(jì)好的。比如實(shí)現(xiàn) Agent 的工具白名單可以設(shè)置成只能讀指定目錄下的文件、只能在臨時(shí)分支上寫入、只能運(yùn)行測(cè)試命令其余全部拒絕。第二是操作邊界。包括文件系統(tǒng)的邊界只能改某個(gè)模塊或某個(gè)目錄、網(wǎng)絡(luò)請(qǐng)求的邊界只能訪問(wèn)內(nèi)網(wǎng)指定服務(wù)、執(zhí)行命令的邊界只能跑預(yù)設(shè)的腳本。我們框架里有一個(gè)必選項(xiàng)Agent 修改代碼前必須先 checkout 一個(gè)獨(dú)立分支任何寫操作都發(fā)生在隔離環(huán)境中這樣即使它闖了禍主分支也不會(huì)受影響。第三是規(guī)則護(hù)欄。比工具更進(jìn)一步的是一組自然語(yǔ)言或硬編碼的規(guī)則。例如“不允許刪除公共工具函數(shù)”“修改公共 API 時(shí)必須同步更新調(diào)用方”“不允許跳過(guò)測(cè)試直接提交”。這些規(guī)則有些可以寫成程序化檢查有些則需要在審查節(jié)點(diǎn)由另一個(gè) Agent 或人來(lái)把關(guān)。很多人在第一次搭 Harness 時(shí)會(huì)覺得“限制這么多AI 還能干活嗎”。其實(shí)是反的——邊界清晰反而讓 AI 更敢干活、更能專注。因?yàn)橐?guī)則明確之后它不需要猜“我這么干會(huì)不會(huì)違規(guī)”只需要在授權(quán)范圍內(nèi)大膽輸出。人也是一樣的如果一份工作職責(zé)范圍寫得清清楚楚你反而更愿意承擔(dān)責(zé)任。2.3 Workflow把 Agent 們串成一條流水線Workflow 層是這套框架的骨架它定義了節(jié)點(diǎn)之間的依賴關(guān)系、數(shù)據(jù)傳遞方式和狀態(tài)流轉(zhuǎn)邏輯。一個(gè)標(biāo)準(zhǔn)工作流通常包含下面幾類節(jié)點(diǎn)。任務(wù)解析節(jié)點(diǎn)把自然語(yǔ)言需求轉(zhuǎn)換成結(jié)構(gòu)化任務(wù)規(guī)格改哪個(gè)文件、達(dá)到什么效果、驗(yàn)收條件是什么。規(guī)劃節(jié)點(diǎn)讓規(guī)劃 Agent 根據(jù)任務(wù)規(guī)格生成實(shí)施計(jì)劃改動(dòng)哪些模塊、涉及哪些測(cè)試、有哪些風(fēng)險(xiǎn)點(diǎn)。執(zhí)行節(jié)點(diǎn)調(diào)用實(shí)現(xiàn) Agent 按照計(jì)劃產(chǎn)出代碼 diff。質(zhì)量節(jié)點(diǎn)跑編譯、測(cè)試、靜態(tài)檢查判斷 diff 是否滿足門檻。審查節(jié)點(diǎn)由審查 Agent 或人工 reviewer 對(duì)代碼變更做最終把關(guān)。提交節(jié)點(diǎn)將審查通過(guò)的變更合并到目標(biāo)分支或生成 MR。這些節(jié)點(diǎn)之間的依賴關(guān)系可以用 DAG 來(lái)描述下游節(jié)點(diǎn)等待上游節(jié)點(diǎn)成功完成后啟動(dòng)上游節(jié)點(diǎn)失敗時(shí)下游不執(zhí)行。每個(gè)節(jié)點(diǎn)都有自己的超時(shí)時(shí)間、重試策略和降級(jí)路徑。整體來(lái)看Workflow 解決的核心問(wèn)題是把單次對(duì)話式的 AI 交互變成多角色協(xié)作的工程過(guò)程。2.4 三個(gè)概念缺一不可單獨(dú)有 Agent 沒有 Workflow就是一堆能力很強(qiáng)但各行其是的“自由人”你無(wú)法預(yù)判它們組合起來(lái)會(huì)產(chǎn)出什么單獨(dú)有 Harness 沒有 Workflow約束是有了但任務(wù)路徑還是隨機(jī)的Agent 不知道下一步該做什么、產(chǎn)出該交給誰(shuí)單獨(dú)有 Workflow 沒有 Harness流程是串起來(lái)了但執(zhí)行者擁有無(wú)限權(quán)限流程越順暢闖的禍越大。這三個(gè)概念合在一起才構(gòu)成一個(gè)完整閉環(huán)Agent 負(fù)責(zé)出力Harness 負(fù)責(zé)兜底Workflow 負(fù)責(zé)編排。這也是為什么我堅(jiān)持用“Agentic Harness Workflow”這個(gè)名字——它強(qiáng)調(diào)的既不是某個(gè)模型有多強(qiáng)也不是某種提示詞技巧而是一整套讓 AI Coding 像流水線一樣穩(wěn)定運(yùn)轉(zhuǎn)的工程機(jī)制。3. 實(shí)操?gòu)牧愦钜粋€(gè)最小可用版本3.1 圈定任務(wù)范圍從小而痛的點(diǎn)切入第一次搭建這個(gè)框架我一貫的建議是不要貪心先挑一個(gè)垂直任務(wù)跑通全流程。我們第一個(gè)跑通的任務(wù)是“自動(dòng)生成未覆蓋模塊的單元測(cè)試”。選它有三個(gè)原因目標(biāo)清晰生成測(cè)試不修改業(yè)務(wù)代碼、驗(yàn)收標(biāo)準(zhǔn)客觀行覆蓋率是否達(dá)標(biāo)、失敗影響面小最壞情況就是測(cè)試寫得爛重跑一遍即可。任務(wù)范圍確定之后下一步是把任務(wù)的輸入輸出定義清楚。我們的輸入是一個(gè)模塊路徑輸出是一個(gè)包含測(cè)試文件 diff 和覆蓋率報(bào)告的結(jié)構(gòu)化結(jié)果。定義好輸入輸出實(shí)際上就定義了 Workflow 的邊界從哪開始到哪結(jié)束。3.2 定義工具集與權(quán)限寧可窄不可寬這個(gè)最小版本里實(shí)現(xiàn) Agent 的工具集我建議控制在三個(gè)以內(nèi)讀文件、創(chuàng)建新測(cè)試文件、運(yùn)行測(cè)試命令。不給寫業(yè)務(wù)代碼的權(quán)限不給執(zhí)行任意 shell 命令的權(quán)限不加網(wǎng)絡(luò)工具。原理很簡(jiǎn)單工具越少Agent 跑偏的空間越小出問(wèn)題時(shí)排查范圍也越小。權(quán)限的配置可以通過(guò)環(huán)境變量或配置文件實(shí)現(xiàn)。比如設(shè)置ALLOWED_PATHS/repo/testsAgent 的寫操作只能落在該目錄下ALLOWED_COMMANDSpytest啟動(dòng)的進(jìn)程只能執(zhí)行指定命令。這些配置本身要納入版本管理后續(xù)每一次放寬權(quán)限都應(yīng)當(dāng)走 review 流程而不是在跑任務(wù)時(shí)臨時(shí)改。3.3 搭建 Workflow 節(jié)點(diǎn)與狀態(tài)流轉(zhuǎn)下面是一個(gè)最小工作流的 YAML 定義示例用于演示節(jié)點(diǎn)編排方式。這個(gè)示例是我們?cè)趯?shí)踐中使用的模式的一個(gè)簡(jiǎn)化版具體字段可以按團(tuán)隊(duì)習(xí)慣調(diào)整但結(jié)構(gòu)值得參考。version: 1 name: test-generation-flow entry: task_parser nodes: task_parser: type: agent role: requirements_analyst prompt_ref: prompts/task_parser.md output_ref: task_spec plan_builder: type: agent role: architect prompt_ref: prompts/plan_builder.md depends_on: [task_parser] output_ref: implementation_plan exec_agent: type: agent role: implementer depends_on: [plan_builder] tools: [repo_read, test_file_write, test_runner] max_iterations: 5 output_ref: generated_diff quality_gate: type: gate depends_on: [exec_agent] checks: - coverage_rate 80 - test_exceptions 0 - diff_size 300 human_review: type: approval depends_on: [quality_gate] assignee: reviewer commit_node: type: git_commit depends_on: [human_review]逐節(jié)點(diǎn)解釋一下。task_parser拿到原始需求后輸出一份結(jié)構(gòu)化的任務(wù)規(guī)格書包括目標(biāo)模塊、測(cè)試策略、驗(yàn)收標(biāo)準(zhǔn)。plan_builder根據(jù)任務(wù)規(guī)格書生成實(shí)施計(jì)劃明確要寫哪幾個(gè)測(cè)試文件、mock 哪些依賴、預(yù)期覆蓋率是多少。exec_agent按照計(jì)劃去生成代碼最多迭代 5 次每次都基于上一次的測(cè)試反饋嘗試修正。quality_gate是硬性門檻不達(dá)標(biāo)直接結(jié)束流程不會(huì)流到下一步。human_review是人工審批節(jié)點(diǎn)審批通過(guò)才真正提交代碼。commit_node執(zhí)行最后的合并或提交動(dòng)作。3.4 關(guān)鍵邏輯的偽代碼實(shí)現(xiàn)如果你的團(tuán)隊(duì)更習(xí)慣用代碼來(lái)定義流程可以用類似下面的偽代碼來(lái)承載節(jié)點(diǎn)狀態(tài)機(jī)和重試邏輯。這個(gè)實(shí)現(xiàn)方式在需要復(fù)雜分支判斷時(shí)比純聲明式配置更好維護(hù)。class WorkflowNode: def __init__(self, node_id, depends_on, action, max_retries1): self.node_id node_id self.depends_on depends_on self.action action self.max_retries max_retries self.state pending def run(self, ctx): for attempt in range(self.max_retries 1): try: result self.action(ctx) self.state success return result except RetryableError as e: ctx.log(fattempt {attempt 1} failed: {e}) continue self.state blocked raise BlockedError(self.node_id) def run_workflow(nodes, ctx): ready [n for n in nodes if n.state pending] while ready: for node in ready: if not all(dep.state success for dep in node.depends_on): continue node.run(ctx) ready [n for n in nodes if n.state pending]這套邏輯非常簡(jiǎn)單只有上游節(jié)點(diǎn)全部成功后下游節(jié)點(diǎn)才會(huì)執(zhí)行某個(gè)節(jié)點(diǎn)超過(guò)重試次數(shù)后整個(gè)流程進(jìn)入阻塞狀態(tài)等待人工介入。實(shí)際生產(chǎn)環(huán)境中還要加上超時(shí)中斷、事件通知、日志收集等細(xì)節(jié)但核心骨架就是這樣一個(gè)樸素的狀態(tài)機(jī)。3.5 接入可觀測(cè)性每一步都要留痕框架跑起來(lái)之后第一件要做的事就是讓每一步都留下結(jié)構(gòu)化日志。我們的做法是每個(gè)節(jié)點(diǎn)執(zhí)行時(shí)都生成一條事件記錄包含以下字段trace_id一次完整任務(wù)的唯一標(biāo)識(shí)node_id當(dāng)前節(jié)點(diǎn)agent_role執(zhí)行該節(jié)點(diǎn)的 Agent 角色input_digest輸入內(nèi)容的摘要或 hashoutput_digest輸出內(nèi)容的摘要或 hashtoken_cost本次調(diào)用的 token 消耗latency_ms耗時(shí)status成功 / 失敗 / 重試 / 阻塞有了這些日志你就能回答一系列關(guān)鍵問(wèn)題這個(gè)任務(wù)在哪一步最耗時(shí)哪個(gè) Agent 經(jīng)常返工平均一次代碼變更消耗多少 token失敗的任務(wù)卡在全線哪個(gè)節(jié)點(diǎn)這些問(wèn)題在你后續(xù)優(yōu)化流程時(shí)都是決策依據(jù)。沒有日志的框架就像沒有儀表盤的飛機(jī)飛起來(lái)全靠感覺。4. 決定成敗的細(xì)節(jié)與關(guān)鍵參數(shù)4.1 上下文管理任務(wù)越完整輸出越可靠AI Coding 中很多“靈異現(xiàn)象”其實(shí)源于上下文管理不當(dāng)。比如 Agent 明明只需要改 A 文件上的一個(gè)函數(shù)但你把整個(gè)倉(cāng)庫(kù)的代碼都塞進(jìn)它的上下文里它可能被無(wú)關(guān)代碼干擾改出一堆不相干的東西。反過(guò)來(lái)如果你只給它一個(gè)函數(shù)名不給函數(shù)定義、調(diào)用方、相關(guān)測(cè)試它又可能憑空捏造一個(gè)錯(cuò)誤的實(shí)現(xiàn)。我們?cè)趯?shí)踐中總結(jié)了一條經(jīng)驗(yàn)輸入上下文的邊界必須和任務(wù)邊界嚴(yán)格對(duì)齊。執(zhí)行“給某個(gè)模塊寫測(cè)試”的任務(wù)時(shí)給 Agent 的上下文應(yīng)該包括該模塊的源碼、已有測(cè)試的目錄結(jié)構(gòu)、項(xiàng)目約定但不要包含整個(gè)平臺(tái)的無(wú)關(guān)模塊。這既是對(duì)正確性的保障也是對(duì) token 成本的優(yōu)化。上下文塞得越滿模型注意力越分散生成的代碼越容易“東張西望”。4.2 工具調(diào)用協(xié)議先讀后寫、先驗(yàn)證后報(bào)告每個(gè) Agent 在調(diào)用工具時(shí)都應(yīng)該遵守一套固定的協(xié)議順序不能跳步。我們的標(biāo)準(zhǔn)協(xié)議是“讀 → 思考 → 改 → 驗(yàn) → 報(bào)”。具體來(lái)說(shuō)讀先讀取目標(biāo)文件和相關(guān)依賴確認(rèn)改動(dòng)基線和約束。思考基于讀到的內(nèi)容形成方案不直接寫代碼。改按方案修改一次只改一個(gè)邏輯單元。驗(yàn)運(yùn)行相關(guān)測(cè)試或靜態(tài)檢查拿到結(jié)果再?zèng)Q定下一步。報(bào)輸出結(jié)構(gòu)化報(bào)告包含改動(dòng)清單、驗(yàn)證結(jié)果、風(fēng)險(xiǎn)說(shuō)明。這套協(xié)議看起來(lái)平淡無(wú)奇但它能有效防止兩類高頻問(wèn)題一類是“AI 連文件都沒讀就開寫改完全部報(bào)錯(cuò)”另一類是“AI 改完卻不跑測(cè)試直接宣稱任務(wù)完成”。協(xié)議本身可以寫在 Agent 的系統(tǒng)提示詞里也可以放在 Harness 的工具調(diào)用攔截層后者更可靠因?yàn)樗灰蕾?AI 自覺執(zhí)行。4.3 重試與終止條件保護(hù)資源防止死循環(huán)Agent 在執(zhí)行任務(wù)時(shí)經(jīng)常會(huì)出現(xiàn)“反復(fù)自我推翻”的情況改一次測(cè)試掛了它換個(gè)思路再改再掛再換個(gè)思路如此反復(fù)。如果沒有終止條件這一過(guò)程可以無(wú)限持續(xù)下去消耗的資源和時(shí)間都非??捎^。所以每個(gè)執(zhí)行節(jié)點(diǎn)都必須設(shè)置硬性終止條件我建議至少包含以下四個(gè)參數(shù)。參數(shù)推薦值作用max_iterations3~5限制 Agent 在同一任務(wù)上的自我修正次數(shù)timeout_sec300~600單節(jié)點(diǎn)超時(shí)保護(hù)超時(shí)強(qiáng)制終止max_token_cost視預(yù)算單個(gè)任務(wù)的 token 消耗上限error_threshold連續(xù) 2~3 次連續(xù)失敗達(dá)到閾值后自動(dòng)轉(zhuǎn)人工這里面max_iterations最容易被忽視。我發(fā)現(xiàn)很多團(tuán)隊(duì)的 AI 任務(wù)不是“能力不夠?qū)е率 倍恰笆『竺つ恐卦噷?dǎo)致局面惡化”。重試應(yīng)當(dāng)發(fā)生在“失敗原因與上次不同”的情況下如果把同樣的錯(cuò)誤重試三遍結(jié)果只會(huì)是白花錢。所以我們的策略是第一次失敗可以重試第二次失敗必須切換策略或降級(jí)到人工。4.4 多 Agent 協(xié)作時(shí)共享狀態(tài)與并發(fā)控制當(dāng)一個(gè)任務(wù)涉及多個(gè) Agent 時(shí)它們之間的狀態(tài)同步就變成了新的問(wèn)題。最危險(xiǎn)的操作是兩個(gè) Agent 同時(shí)修改同一個(gè)文件這在并發(fā)場(chǎng)景下會(huì)造成相互覆蓋或沖突。我們的做法是引入一個(gè)共享狀態(tài)存儲(chǔ)它保存每個(gè)文件當(dāng)前的“持有者”和“版本號(hào)”。Agent 在修改文件前必須先申請(qǐng)鎖定修改完成后釋放鎖定并更新版本號(hào)其他 Agent 讀到的永遠(yuǎn)是當(dāng)前版本。另外一個(gè)經(jīng)驗(yàn)是盡量用數(shù)據(jù)的單向流動(dòng)代替多 Agent 實(shí)時(shí)交互。比如執(zhí)行節(jié)點(diǎn)產(chǎn)出 diff 后審查節(jié)點(diǎn)只需要讀這個(gè) diff不需要通知執(zhí)行節(jié)點(diǎn)“我已開始審查了”。把每個(gè)節(jié)點(diǎn)的輸入輸出都物化為可讀取的對(duì)象工作流就會(huì)變得更簡(jiǎn)單、更好排查。共享狀態(tài)只在真正需要并發(fā)協(xié)同的地方使用而不是全局鋪開。5. 踩坑實(shí)錄與高頻問(wèn)題排查5.1 高頻問(wèn)題速查表搭框架的過(guò)程中我先后遇到了下面幾類高頻問(wèn)題整理成速查表供直接參考。癥狀根本原因處理辦法Agent 改動(dòng)了無(wú)關(guān)文件寫權(quán)限范圍過(guò)寬收緊 Harness 中允許寫入的目錄白名單Agent 據(jù)此編造了不存在的 API 或文件路徑它沒有讀源碼在憑印象發(fā)揮強(qiáng)制“先讀后寫”把 repo 讀取工具設(shè)為必備工具同一個(gè)問(wèn)題反復(fù)失敗結(jié)果越來(lái)越差重試策略不區(qū)分失敗類型限制重試次數(shù)連續(xù)失敗自動(dòng)轉(zhuǎn)人工提示詞稍微變化輸出就大不相同提示詞版本沒有管理將提示詞納入版本庫(kù)每次變更都要有記錄人工審批形同虛設(shè)全部秒過(guò)審批信息太多或太少?zèng)]法判斷每個(gè)審批節(jié)點(diǎn)輸出統(tǒng)一的審查簡(jiǎn)報(bào)突出關(guān)鍵風(fēng)險(xiǎn)上下文太長(zhǎng)導(dǎo)致模型注意力漂移任務(wù)拆得太粗輸入塞得太多用任務(wù)解析節(jié)點(diǎn)把大任務(wù)拆成子任務(wù)按需注入上下文5.2 三個(gè)容易被忽視的細(xì)節(jié)第一提示詞也是代碼要納入版本管理。很多團(tuán)隊(duì)寫提示詞就像記備忘錄改一版扔一版一旦模型輸出變化根本說(shuō)不清是模型升級(jí)導(dǎo)致的還是提示詞改動(dòng)導(dǎo)致的。正確的做法是把每個(gè) Agent 的提示詞作為獨(dú)立文件放入倉(cāng)庫(kù)并給它們打上版本號(hào)。這樣你可以在一次任務(wù)報(bào)告中記錄“本次執(zhí)行的 Agent 提示詞版本是 v1.3”出了問(wèn)題能精確回溯。第二成本控制要落到每個(gè)節(jié)點(diǎn)上。如果不單獨(dú)統(tǒng)計(jì)每個(gè)節(jié)點(diǎn)的 token 消耗你會(huì)發(fā)現(xiàn)月底賬單高得離譜但說(shuō)不清錢花在哪。我們的做法是每跑完一個(gè)任務(wù)把各節(jié)點(diǎn)的 token_cost 匯總成一張報(bào)表按比例排序。通常最貴的是執(zhí)行節(jié)點(diǎn)其次是審查節(jié)點(diǎn)。有了這個(gè)數(shù)據(jù)你才能做出理性決策是減少重試次數(shù)、壓縮上下文還是換一個(gè)更便宜的模型。第三每個(gè)代碼變更都要自動(dòng)生成回滾預(yù)案。即便有 Harness 和人工審批AI 生成的代碼還是可能在生產(chǎn)環(huán)境里出問(wèn)題。所以我們要求執(zhí)行節(jié)點(diǎn)在產(chǎn)出 diff 的同時(shí)還必須輸出一個(gè)回滾方案一般是“將變更提交到獨(dú)立分支 生成逆向 patch”。一旦線上出現(xiàn)異??梢砸绘I回滾而不是手忙腳亂地翻歷史版本。5.3 人工審批的門道放在關(guān)鍵變更前而不是最后我們把人工審批節(jié)點(diǎn)從流程末端挪到了關(guān)鍵變更前這是踩了多次坑之后總結(jié)出來(lái)的調(diào)整。早期流程是“AI 生成 → AI 自查 → 人工看一眼 → 合并”實(shí)際運(yùn)行起來(lái)發(fā)現(xiàn)到了人工審批環(huán)節(jié)diff 已經(jīng)很大了reviewer 根本看不過(guò)來(lái)最后基本變成了“因?yàn)槭悄闵傻奈揖忘c(diǎn)了通過(guò)”。調(diào)整后的流程是任務(wù)解析之后先請(qǐng)人確認(rèn)方向執(zhí)行出第一版 diff 后再請(qǐng)人確認(rèn)一次關(guān)鍵變更最后合并時(shí)只做輕量抽檢。這樣做的效果是問(wèn)題在早期就被發(fā)現(xiàn)和糾正而不是在最終提交前集中爆發(fā)。人工資源要花在刀刃上所謂刀刃就是決定任務(wù)方向的那個(gè)節(jié)點(diǎn)和引入高風(fēng)險(xiǎn)動(dòng)作的那個(gè)節(jié)點(diǎn)。5.4 當(dāng)我們遇到災(zāi)難性失敗時(shí)有一次我們跑一個(gè)“升級(jí)某模塊依賴”的任務(wù)Agent 在更新依賴時(shí)自作主張刪掉了一個(gè)老接口的兼容層導(dǎo)致下游十幾個(gè)模塊同時(shí)編譯失敗。當(dāng)時(shí) Harness 的反應(yīng)是編譯失敗 → 執(zhí)行節(jié)點(diǎn)重試 → 失敗 → 觸發(fā)人工審批流程。審批人看了簡(jiǎn)報(bào)之后發(fā)現(xiàn)情況不對(duì)立即終止任務(wù)。由于整個(gè)流程運(yùn)行在獨(dú)立分支上主分支完全沒受影響回滾只需要?jiǎng)h除那個(gè)分支即可。這件事給了我兩個(gè)教訓(xùn)。第一Harness 的“失敗處理”不是要把所有錯(cuò)誤都攔截在流程里而是要保證任何錯(cuò)誤都不會(huì)波及主分支和生產(chǎn)環(huán)境第二人工審批節(jié)點(diǎn)最大的價(jià)值不在“審批通過(guò)”而在“及時(shí)發(fā)現(xiàn)方向性錯(cuò)誤”——當(dāng) AI 跑偏的時(shí)候一個(gè)能看懂大局的人只要掃一眼就知道有問(wèn)題。所以不要試圖把審批節(jié)點(diǎn)完全自動(dòng)化至少在可預(yù)見的階段人仍然是整套流程里不可替代的最后一道防線。我個(gè)人在實(shí)際操作中還有個(gè)體會(huì)這類框架的價(jià)值不是一上來(lái)就全自動(dòng)而是先跑通一條最小路徑積累日志和數(shù)據(jù)再逐步放寬約束。我們第一次跑通“自動(dòng)生成單元測(cè)試”用了兩周但正是這兩周跑出來(lái)的日志讓團(tuán)隊(duì)信任了整體機(jī)制后面才敢把更復(fù)雜的重構(gòu)任務(wù)交給框架。每一次放寬規(guī)則都要有數(shù)據(jù)和復(fù)盤撐著而不是拍腦袋說(shuō)“這次試試讓它多改點(diǎn)文件吧”。工程化 AI Coding本質(zhì)上是在用管理者的耐心收斂一個(gè)創(chuàng)造者的野性。