<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[我在 DeepSeek Harness 本地 Web UI 跑了五個真的會用到的工作：能完成，但不是每件事都快]]></title><description><![CDATA[<p dir="auto">這篇測的是 DeepSeek Harness 裝好之後出現的本地 Web UI，不是 headless CLI，也不是把模型排行榜上的 tok/s 拿來當成自己的成績。</p>
<p dir="auto">我真正想知道的是：把一個有明確需求的小型工作交給它，它能不能自己讀檔、寫檔、執行命令、看測試結果、發現問題，再把結果交付出來？如果只問一句「請介紹 MCP」，得到的答案再漂亮，也不能回答這個問題。</p>
<p dir="auto">所以這次我在 Windows 的 DeepSeek Harness Web UI 裡，讓它連續完成五種不同的工作。五項都在掄槌者工作區內另外建立的隔離資料夾進行，沒有碰原本的 danial 專案，也沒有把測試檔案放進既有專案。每一項都有不同的目標和產物，不是同一個 prompt 換五種說法。</p>
<p dir="auto">這次五項工作的總結果先放在前面：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>工作</th>
<th style="text-align:right">Web UI 實際耗時</th>
<th style="text-align:right">Agent steps</th>
<th style="text-align:right">工具呼叫</th>
<th>交付結果</th>
</tr>
</thead>
<tbody>
<tr>
<td>把既有 Python 工具接成 MCP Server</td>
<td style="text-align:right">492.53 秒</td>
<td style="text-align:right">25</td>
<td style="text-align:right">28</td>
<td>12/12 測試通過</td>
</tr>
<tr>
<td>自己建立輸入規模與錯誤恢復 benchmark</td>
<td style="text-align:right">249.87 秒</td>
<td style="text-align:right">7</td>
<td style="text-align:right">8</td>
<td>20/20 正確</td>
</tr>
<tr>
<td>對成果做獨立程式碼審查與邊界探針</td>
<td style="text-align:right">445.44 秒</td>
<td style="text-align:right">13</td>
<td style="text-align:right">15</td>
<td>找到 8 個 Low/Info 問題</td>
</tr>
<tr>
<td>整理成可以交給別人使用的文件</td>
<td style="text-align:right">200.58 秒</td>
<td style="text-align:right">9</td>
<td style="text-align:right">12</td>
<td>README 完成並核對</td>
</tr>
<tr>
<td>複製到乾淨副本重新執行</td>
<td style="text-align:right">99.26 秒</td>
<td style="text-align:right">7</td>
<td style="text-align:right">8</td>
<td>測試、demo、benchmark 全通過</td>
</tr>
</tbody>
</table>
<p dir="auto">五項主要工作合計約 24 分 48 秒、61 個 Agent steps、71 次工具呼叫。下面不是只列結果，而是把每項到底交代了什麼、實際留下什麼，以及數字代表什麼寫清楚。</p>
<h2>測試環境和限制</h2>
<ul>
<li>DeepSeek Harness 本地 Web UI，網址是 127.0.0.1:3080。</li>
<li>Web UI session 實際使用模型：DeepSeek V4 Pro。</li>
<li>reasoning effort：Max。</li>
<li>Windows 10，Python 3.14.3，PowerShell。</li>
<li>工作資料夾只使用 Python 標準函式庫，不安裝額外套件、不連網。</li>
<li>原始 input_tool.py 只讀取，不允許修改。</li>
</ul>
<p dir="auto">原本的工具很小：input_tool.py 接受 Markdown 文字，回傳第一個標題、標題數、字元數和非空行數。這個大小剛好能讓我把注意力放在 Harness 的工作流程，而不是把外部框架、套件安裝和大型專案本身混進來。</p>
<p dir="auto">我記錄的不是只有最後一句回答。每項都記錄 Web UI 顯示的耗時、Agent steps、工具呼叫、實際建立或修改的檔案、命令退出碼，以及能不能在本地重新核對。費用則根據 session 遙測估算，因為我沒有拿到帳戶實際帳單。</p>
<h2>第一項：把既有 Python 工具接成真的 MCP Server</h2>
<p dir="auto">第一項是主要工程任務，也是最接近日常使用 Agent 的一項。</p>
<p dir="auto">我給它的要求不是「幫我寫一個 MCP 範例」，而是把目前已經存在的 input_tool.py 包成可以用 stdio 溝通的 MCP Server。Server 要處理 initialize、notifications/initialized、tools/list 和 tools/call；分析邏輯必須直接呼叫原本的 input_tool，不可以複製一份同樣的 Markdown 計算邏輯。</p>
<p dir="auto">除此之外，它還要自己完成兩個能被真正執行的交付物：</p>
<ul>
<li>用 subprocess 啟動 Server 的測試，而不是只在同一個 Python process 裡呼叫函式。</li>
<li>一個獨立的 MCP client，實際送出 JSON-RPC，讀取 Server 回應，最後留下結果報告。</li>
</ul>
<p dir="auto">這項任務的驗收條件也包含錯誤路徑。我要求它測短文、中文和 Emoji、多層標題、空字串、同一個 Server 連續呼叫、未知工具、無效 JSON、缺少 method、未知 method 和缺少 arguments。換句話說，不能只讓一條正常輸入跑通就算完成。</p>
<h3>實際交付</h3>
<p dir="auto">它最後留下：</p>
<ul>
<li>mcp_server.py：stdlib MCP stdio JSON-RPC Server。</li>
<li>test_mcp_server.py：12 個 subprocess 測試情境。</li>
<li>demo_mcp_client.py：獨立 client，包含正常、錯誤和錯誤後恢復的呼叫。</li>
<li><a href="http://RESULTS.md" rel="nofollow ugc">RESULTS.md</a>：驗收結果、遙測和費用估算。</li>
</ul>
<p dir="auto">這一輪不是一次成功。它在執行過程中遇到兩個實際問題：一個 Unicode 測試的斷言和工具真正回傳的內容不一致，另一個是 demo client 讀錯誤回應時的讀取順序不對。它重新讀取結果、修改測試和 client，再跑一次。</p>
<p dir="auto">另外，獨立 review 發現 demo client 遇到 stdout timeout 或 Server 提前關閉時，原本可能只回傳 None，主程式卻仍以退出碼 0 結束。這會把失敗誤報成成功。修正成直接拋出 RuntimeError 後，再重新跑 unittest 和 demo，結果仍然通過。</p>
<p dir="auto">最後的實際結果是：</p>
<ul>
<li>unittest：12/12 通過，退出碼 0。</li>
<li>最新獨立重跑：12 tests in 0.583 秒。</li>
<li>demo client：client exit 0，server exit 0。</li>
<li>PowerShell 原始 stdin 管線：9 行 JSON-RPC，Server exit 0。</li>
<li>initialized 通知沒有多送回應，錯誤後仍能再做正常呼叫。</li>
</ul>
<p dir="auto">12 個測試的實際情境如下：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>類型</th>
<th>驗證內容</th>
</tr>
</thead>
<tbody>
<tr>
<td>握手</td>
<td>initialize 回傳 protocolVersion、capabilities、serverInfo</td>
</tr>
<tr>
<td>通知</td>
<td>notifications/initialized 不回應</td>
</tr>
<tr>
<td>工具發現</td>
<td>tools/list 暴露 analyze_markdown 及 input schema</td>
</tr>
<tr>
<td>正常資料</td>
<td>短文、Unicode、多層標題、空字串</td>
</tr>
<tr>
<td>連續性</td>
<td>同一個 Server 連續兩次呼叫</td>
</tr>
<tr>
<td>錯誤輸入</td>
<td>未知工具、無效 JSON、格式錯誤、未知 method、缺少 arguments</td>
</tr>
</tbody>
</table>
<p dir="auto">這項實測可以證明的是：在需求有限、驗收條件清楚的小型工程任務裡，DeepSeek Harness 能走完讀檔、實作、執行、看錯誤、修正、重跑和交付。它不能證明大型專案一定成功，但至少不是只產生一段看起來像程式的文字。</p>
<h2>第二項：讓它自己建立輸入規模和錯誤恢復 benchmark</h2>
<p dir="auto">第二項不再叫它繼續加功能，而是要求它把剛完成的 Server 當成待測對象，自己建立一個可以重複執行的 benchmark。</p>
<p dir="auto">這個任務有三個硬條件：</p>
<ol>
<li>不修改 mcp_server.py 和既有測試。</li>
<li>不能只量一次，要有四種輸入大小、每種五次重複。</li>
<li>每次不只記時間，也要把回應和 input_tool 的參考值逐欄核對。</li>
</ol>
<p dir="auto">四種輸入是 20 bytes、1 KB、100 KB 和 1 MB；每種各呼叫五次，而且是在同一個 Server process 裡完成，不是每次都重啟。量測的 roundtrip 是從建立請求到解析完成回應的總時間，包含 JSON encode、pipe 寫入、Server 處理、pipe 讀取和 decode。它不是模型生成速度，也不是顯卡 decode 速度。</p>
<h3>原始結果</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>輸入大小</th>
<th style="text-align:right">呼叫次數</th>
<th style="text-align:right">最小 roundtrip</th>
<th style="text-align:right">中位數</th>
<th style="text-align:right">最大 roundtrip</th>
<th style="text-align:right">正確率</th>
</tr>
</thead>
<tbody>
<tr>
<td>20 B</td>
<td style="text-align:right">5</td>
<td style="text-align:right">0.053 ms</td>
<td style="text-align:right">0.078 ms</td>
<td style="text-align:right">0.114 ms</td>
<td style="text-align:right">5/5</td>
</tr>
<tr>
<td>1 KB</td>
<td style="text-align:right">5</td>
<td style="text-align:right">0.060 ms</td>
<td style="text-align:right">0.087 ms</td>
<td style="text-align:right">0.177 ms</td>
<td style="text-align:right">5/5</td>
</tr>
<tr>
<td>100 KB</td>
<td style="text-align:right">5</td>
<td style="text-align:right">1.498 ms</td>
<td style="text-align:right">1.752 ms</td>
<td style="text-align:right">2.077 ms</td>
<td style="text-align:right">5/5</td>
</tr>
<tr>
<td>1 MB</td>
<td style="text-align:right">5</td>
<td style="text-align:right">18.747 ms</td>
<td style="text-align:right">20.196 ms</td>
<td style="text-align:right">24.671 ms</td>
<td style="text-align:right">5/5</td>
</tr>
</tbody>
</table>
<p dir="auto">20 次正常呼叫全部正確。1 MB 輸入的標題原樣保留，字元數沒有截斷，也沒有出現亂碼。以 20 B 的中位數作基準，1 KB 約 1.1 倍、100 KB 約 22.5 倍、1 MB 約 258.9 倍。</p>
<p dir="auto">這個結果有一個很實際的解讀：對這個只做文字分析的 stdio Server，小檔案延遲幾乎可以忽略，但資料放大後 roundtrip 會明顯上升。1 MB 的 pipe 寫入中位數約 1.094 ms，整體 roundtrip 中位數是 20.196 ms，表示主要時間不只是把資料寫進 pipe。</p>
<p dir="auto">接著我讓它送出未知工具 benchmark_no_such_tool。Server 回傳 -32602，錯誤 roundtrip 是 0.544 ms；下一個正常的 20 bytes 呼叫在 0.108 ms 完成，Server 仍存活，最後正常關閉的 exit code 是 0。</p>
<p dir="auto">這是五項裡面最像「硬數據」的一項，但仍然要把範圍說清楚：這些數字只代表本機 Windows、Python 3.14.3、這個 stdio Server 和這個輸入工具。它不能拿來和論壇文章裡的 GPU tok/s 比較，也不能推論 DeepSeek V4 Pro 本身每秒能生成多少 token。</p>
<h2>第三項：對剛完成的成果做獨立程式碼審查</h2>
<p dir="auto">第三項我把角色換掉，不讓它繼續扮演原作者，而是要求它像另一位 reviewer 一樣，只讀取 mcp_server.py、input_tool.py、test_mcp_server.py 和 demo_mcp_client.py，重新執行測試，再用額外的 stdin 探針攻擊協定邊界。</p>
<p dir="auto">這一項的限制是「只讀」。不可以為了讓報告看起來乾淨而順手修改程式。審查前後要比對 sha256 和 mtime，證明被審查的檔案沒有被動過。</p>
<p dir="auto">它執行了：</p>
<ul>
<li>unittest 和 demo client。</li>
<li>18 組唯讀 protocol edge probes。</li>
<li>無效 JSON、缺 method、缺 params、params 非物件、text 非字串、id=null、batch、CRLF、空行、非法 UTF-8 和 client 提前關閉 stdout 等情境。</li>
<li>前後 sha256 和 mtime 比對。</li>
</ul>
<p dir="auto">審查結論沒有 High 或 Medium 級問題，列出 8 個 Low/Info 問題。其中幾個比較有代表性：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>發現</th>
<th>實際行為</th>
<th>影響</th>
</tr>
</thead>
<tbody>
<tr>
<td>F1</td>
<td>缺少 method 的畸形通知仍回 -32600</td>
<td>和嚴格 JSON-RPC 通知規則不完全一致</td>
</tr>
<tr>
<td>F2</td>
<td>字串內非法 UTF-8 以 U+FFFD 靜默替換</td>
<td>client 送出的內容可能和 Server 分析內容不同</td>
</tr>
<tr>
<td>F3</td>
<td>client 提前關閉 stdout 時，_send 可能拋 OSError</td>
<td>Server 出現 traceback，探針 exit 120</td>
</tr>
<tr>
<td>T1</td>
<td>測試 helper 使用裸 assert</td>
<td>python -O 時 envelope 檢查會被移除</td>
</tr>
<tr>
<td>T2</td>
<td>Server stderr 導向 DEVNULL</td>
<td>Server 崩潰時看不到 traceback</td>
</tr>
<tr>
<td>D1</td>
<td>demo timeout 後 kill 沒有立即 wait</td>
<td>錯誤路徑的子程序回收不完整</td>
</tr>
</tbody>
</table>
<p dir="auto">這裡有一點我覺得比「找到幾個問題」更重要：它沒有把所有問題都誇大成嚴重漏洞。報告把 F1、F2、F3、T1、T2、D1 定為 Low，把寬鬆接受 initialize 前呼叫、空白行和 batch 陣列等行為列為 Info，也明確寫出沒有 High/Medium。</p>
<p dir="auto">審查還列出 17 個 unittest 沒有覆蓋、但探針可以觀察到的情境。例如 initialize 版本協商、params 完全缺失、重複 request id、id=null、batch、lone surrogate 和 1 MB 大輸入。這讓報告不只是「程式碼看起來沒問題」，而是把已測、未測和已知偏差分開。</p>
<p dir="auto">這項任務的實際價值在於，它測到 Harness 能不能停下來檢查自己的產物。很多 Agent 會把第一輪產出的程式直接宣布完成；這次至少能在第二個角色裡找到測試工具本身的弱點，也能指出 Server 的規範邊界。</p>
<h2>第四項：把程式和數據整理成真的能用的文件</h2>
<p dir="auto">第四項看起來不像 benchmark，但很接近日常工程工作。讓模型寫一份 README 很容易，難的是 README 裡的檔名、命令、輸出和限制不能靠想像。</p>
<p dir="auto">我要求它只讀取已經存在的程式和兩份實測報告，建立 README_MCP.md。文件必須說明：</p>
<ul>
<li>Server 支援哪些 method。</li>
<li>Python 版本和安裝前提。</li>
<li>如何啟動 Server。</li>
<li>initialize、tools/list、tools/call 的實際例子。</li>
<li>正常回應、錯誤回應和錯誤後恢復。</li>
<li>unittest、demo 和 benchmark 的命令。</li>
<li>20 B 到 1 MB 的實測結果。</li>
<li>已知限制和沒有測到的整合情境。</li>
</ul>
<p dir="auto">它完成後，又逐一檢查 README 提到的檔案和命令是否真的存在，沒有把不存在的 requirements.txt 或第三方套件寫進去。最後的 README 也保留了這個專案最重要的限制：沒有使用 Claude Desktop、Cursor 或其他 MCP client，只有 stdlib client 和 PowerShell 管線。</p>
<p dir="auto">這一輪花了 200.58 秒、9 個 Agent steps、12 次工具呼叫。時間不算短，因為它要讀程式、讀結果、組織文件，再核對命令。可是這一項不能用「字寫得順不順」判斷，真正的驗收是別人拿到 README 後能不能照著跑。</p>
<p dir="auto">我把這項列為獨立任務，是因為實際使用 Agent 時，程式完成不是終點。沒有命令、輸出範例、限制和重現方式，下一個人還是得重新猜一次。這也是 Harness 評測裡容易被忽略、但很能看出交付品質的一段。</p>
<h2>第五項：複製到乾淨副本，看看是不是只在原資料夾能跑</h2>
<p dir="auto">第五項是重現性測試。我要求它建立新的 repro_check 資料夾，只複製必要檔案，不能依賴原本目錄裡的暫存檔、設定檔、套件或某個剛好存在的狀態。</p>
<p dir="auto">乾淨副本只放五個檔案：</p>
<ul>
<li>mcp_server.py</li>
<li>input_tool.py</li>
<li>test_mcp_server.py</li>
<li>demo_mcp_client.py</li>
<li>benchmark_mcp.py</li>
</ul>
<p dir="auto">它在副本裡重新跑三條命令：</p>
<ol>
<li>python -X utf8 -m unittest -v：12/12，0.886 秒，exit 0。</li>
<li>python -X utf8 demo_mcp_client.py：client 0，server 0。</li>
<li>python benchmark_mcp.py：20/20 正確，未知工具後恢復，server exit 0。</li>
</ol>
<p dir="auto">副本內的 benchmark 數字和原始目錄不同：20 B 中位數 0.078 ms、1 KB 0.132 ms、100 KB 1.606 ms、1 MB 16.697 ms。這不是矛盾，因為是不同次執行；真正要看的不是把兩次毫秒數硬湊成排名，而是正確率、錯誤後恢復和退出碼是否一致。</p>
<p dir="auto">它也比對了原始檔案的 sha256。mcp_server.py、input_tool.py、test_mcp_server.py、demo_mcp_client.py 和根目錄 <a href="http://PERFORMANCE.md" rel="nofollow ugc">PERFORMANCE.md</a> 前後一致，沒有被乾淨副本測試改掉。副本不需要 pip install、不需要 requirements、不需要網路；執行後新增的只有 <strong>pycache</strong> 和副本內由 benchmark 產生的 <a href="http://PERFORMANCE.md" rel="nofollow ugc">PERFORMANCE.md</a>。</p>
<p dir="auto">這項只花了 99.26 秒，是五項裡最快的一項，因為大部分實作都已經存在。但它回答了一個很實際的問題：前面那些「12/12」和「20/20」是不是只在原本那個工作目錄裡成立？這次答案是，至少在這個乾淨副本條件下，主要流程可以重現。</p>
<h2>五項任務的費用</h2>
<p dir="auto">以下不是帳單截圖，而是 DSH session 遙測加上 DeepSeek 官方 V4 Pro 價格的估算。inputTokens 依 adapter 定義拆成 cache miss input；cacheReadTokens 是 cache hit；outputTokens 用於輸出計價；reasoningTokens 另外記錄，但不再重複加進 output，避免把同一段 token 算兩次。</p>
<p dir="auto">官方價格頁：<a href="https://api-docs.deepseek.com/quick_start/pricing" rel="nofollow ugc">DeepSeek API Pricing</a></p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>任務</th>
<th style="text-align:right">inputTokens</th>
<th style="text-align:right">cacheReadTokens</th>
<th style="text-align:right">outputTokens</th>
<th style="text-align:right">reasoningTokens</th>
<th style="text-align:right">費用估算</th>
</tr>
</thead>
<tbody>
<tr>
<td>MCP Server 工程化</td>
<td style="text-align:right">18,404</td>
<td style="text-align:right">876,544</td>
<td style="text-align:right">37,696</td>
<td style="text-align:right">21,288</td>
<td style="text-align:right">US$0.04398</td>
</tr>
<tr>
<td>輸入規模 benchmark</td>
<td style="text-align:right">4,246</td>
<td style="text-align:right">762,624</td>
<td style="text-align:right">16,917</td>
<td style="text-align:right">10,605</td>
<td style="text-align:right">US$0.01933</td>
</tr>
<tr>
<td>程式碼審查</td>
<td style="text-align:right">15,098</td>
<td style="text-align:right">1,779,328</td>
<td style="text-align:right">27,880</td>
<td style="text-align:right">17,833</td>
<td style="text-align:right">US$0.03727</td>
</tr>
<tr>
<td>文件生成</td>
<td style="text-align:right">13,940</td>
<td style="text-align:right">1,540,992</td>
<td style="text-align:right">13,749</td>
<td style="text-align:right">8,085</td>
<td style="text-align:right">US$0.02361</td>
</tr>
<tr>
<td>乾淨副本重現</td>
<td style="text-align:right">2,442</td>
<td style="text-align:right">1,295,104</td>
<td style="text-align:right">6,143</td>
<td style="text-align:right">2,517</td>
<td style="text-align:right">US$0.01110</td>
</tr>
<tr>
<td><strong>五項合計</strong></td>
<td style="text-align:right">54,130</td>
<td style="text-align:right">6,254,480</td>
<td style="text-align:right">102,385</td>
<td style="text-align:right">60,328</td>
<td style="text-align:right"><strong>US$0.13529</strong></td>
</tr>
</tbody>
</table>
<p dir="auto">計算使用的單價是 cache miss input 每百萬 token US$0.435、cache hit input 每百萬 token US$0.003625、output 每百萬 token US$0.87。五項任務的實際帳單沒有取得，因此 US$0.13529 只能寫成估算，不可以寫成信用卡真的被扣了這個數字。</p>
<p dir="auto">另外還有一個後來停止的核對 session，估算約 US$0.05441。它沒有列進上面的五項，因為那一輪沒有形成完整交付結果；如果把它也算入整個 Web UI session，總估算約 US$0.18971。這兩個數字我分開列，避免把未完成工作混成成功測試的成本。</p>
<h2>這五項實測真正測到什麼</h2>
<p dir="auto">把所有結果放在一起，我的判斷是：</p>
<p dir="auto">第一，DeepSeek Harness 在本地 Web UI 裡確實能做多步驟工作。第一項不是只寫檔案，它要把程式接起來、執行 subprocess、看失敗、修正，再重新驗收；最後有可以直接執行的 Server、測試和 client。</p>
<p dir="auto">第二，它可以使用工具完成相對完整的驗收閉環。第二項留下了每筆呼叫的原始數據，第三項留下了只讀 review 和邊界探針，第五項再把流程搬到乾淨副本。這幾項都不是模型自己說「完成」，而是有退出碼、hash、測試結果或逐筆數字可以核對。</p>
<p dir="auto">第三，它的速度不能只看最後產物。最小的 20 B benchmark 本身只花不到 0.2 ms，但讓 Harness 建立 benchmark、讀結果和寫報告，整輪花了 249.87 秒。程式碼審查沒有修改程式，仍然花了 445.44 秒。對使用者來說，真正的等待時間是 Agent 的規劃和工具迴圈，不是 Server 本身的毫秒級處理時間。</p>
<p dir="auto">第四，費用主要跟 Agent 讀了多少上下文、產生多少 output 有關，不是跟本地 Server 的 roundtrip 毫秒數直接相關。第二項的本地程式執行很快，但 DSH session 仍估算 US$0.01933；第一項因為需要多次讀檔、改檔和驗證，估算到 US$0.04398。</p>
<p dir="auto">第五，它仍然需要人定義驗收條件。這次能得到 12/12、20/20、hash 一致和 exit 0，是因為我在任務開始前把這些條件寫清楚。如果只叫它「做一個完整 MCP」，最後很可能只得到一個看似完整、但不知道怎麼驗證的資料夾。</p>
]]></description><link>https://lcz.me/topic/1319</link><generator>RSS for Node</generator><lastBuildDate>Mon, 21 Sep 2026 04:55:33 GMT</lastBuildDate><atom:link href="https://lcz.me/topic/1319.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 25 Aug 2026 15:37:12 GMT</pubDate><ttl>60</ttl></channel></rss>