AI 一連上 MCP 就知道從哪開始(leo 追問揪出的最後一哩)

leo:「arcrun_get_skill 放在 MCP 裡,現在人類說『幫我用 arcrun 寫 xxx』,
Haiku 會說『arcrun 是什麼?我看看』然後發現有個 arcrun mcp 就去執行?
如果不會,要寫什麼在外面讓它一聽到就知道要用這些資源?」

實測答案:**不會**。
① 總管寫的指引沒有任何入口指向它(真實 AI 找不到)
② MCP 五個 skill 沒有「怎麼寫意圖工作流」這支
③ AI 只看到 41 個工具名 → 自己猜 → 很可能直接 push_workflow 瞎編,
   或去讀 registry/examples 那 8/13 引用不存在零件的壞範例

兩件修法:
1. registry/skills/write_intent_workflow.md — 把指引變成 AI 拿得到的 skill
   (範本全取自實跑 verdict=success 的四支 workflow;含「查詢現在回假 found」的已知限制警告)
2. mcp-handler.ts instructions 開場指路 — instructions 是唯一「AI 一連上就必看」的欄位
   ⇒ 開場就寫明五步順序(先讀 write_intent_workflow → whoami → 查零件 → list_skills → 缺件怎麼補)
   +邊只有兩種、第一個節點是 input、不要因查不到就改寫 code
   ⚠️ 靜態常數:KBDB 掛了也必出現(守「不擋連線」鐵律)

驗:tsc 零錯誤。 待部署後由 leo 真的問 haiku「幫我用 arcrun 做 X」驗證它會不會自己讀 skill。
This commit is contained in:
2026-07-30 22:29:28 +08:00
parent 0686d39fa1
commit fac7d6c9bb
2 changed files with 179 additions and 1 deletions
+26 -1
View File
@@ -15,10 +15,35 @@ export async function handleMcpRequest(
//(選型理由見 lib/library-map.ts 檔頭);任何失敗回 null → 靜默略過,絕不擋 MCP 連線(鐵律)。
const mapInstructions = await buildLibraryMapInstructions(env);
// 2026-07-30leo 問「人類說『幫我用 arcrun 寫 xxx』,Haiku 會知道要用這些資源嗎?
// 如果不會,要寫什麼在外面讓它一聽到就知道?」):
// 實測答案是**不會**——AI 只看到 41 個工具名,會自己猜(很可能直接跳到 push_workflow
// 瞎編,或去讀 registry/examples 那 8/13 引用不存在零件的壞範例)。
// instructions 是唯一「AI 一連上就必看」的欄位 ⇒ 開場就指路,不依賴任何查詢成功。
// ⚠️ 這段是靜態常數:即使 KBDB 掛了、藏書地圖抓不到,它也必須出現(鐵律:不擋連線)。
const startHere = [
"【先讀這裡】要在 Arcrun 上做任何事(用戶說「幫我用 Arcrun 做 X」),**照這個順序**",
"",
"1. `arcrun_get_skill('write_intent_workflow')` — **必讀第一支**。",
" 教你用 `>>` 寫「意圖工作流」。你**不需要先知道有哪些零件**,先寫意圖。",
"2. `arcrun_whoami()` — 確認連到哪個帳號(勿自行 curl 猜帳號 URL)。",
"3. 把意圖丟 `POST /cypher/search` 或 `arcrun_validate_yaml` — 系統告訴你哪些零件存在。",
"4. `arcrun_list_skills()` — 看有沒有更貼近你這件事的 skillwatcherRAGdebug…)。",
"5. 缺零件時:缺 API → 寫 recipe`arcrun_recipe_push`);缺能力 → 投稿零件 PR。",
" 🔴 **不要因為查不到零件就改寫成 `code` 節點**——那叫「腹語術」(表面用 Arcrun、",
" 實際全寫 JS)。`code` 只用於局部整形(例:剝掉 LLM 回應的雜訊)。",
"",
"邊只有兩種:`ON_SUCCESS` 與 `對每個 <變數>`FOREACH)。",
"**沒有** `ON_TRUE``ON_FALSE``ON_FAILURE`——引擎目前不支援條件分支。",
"第一個節點固定是 `input`。",
].join("\n");
const instructions = mapInstructions ? `${startHere}\n\n---\n\n${mapInstructions}` : startHere;
const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined });
const server = new McpServer(
{ name: "arcrun-mcp-server", version: "1.0.0" },
mapInstructions ? { instructions: mapInstructions } : undefined,
{ instructions },
);
registerAllTools(server, env, orgNamespace, partnerToken);