突破 Anthropic 模型鎖定,保留 Claude Code 完整 Harness,底層推理切換至 GPT-5.4。
2026 年 3 月 31 日,Anthropic 的 Claude Code(版本 2.1.88)完整源代碼透過 npm registry 的 source map 文件(cli.js.map,57MB)意外公開。洩露內容涵蓋完整 /src 目錄,包括 QueryEngine、SwarmOrchestrator、Tool 系統、MCP 整合、Hooks、Skills 等核心模塊的完整實現邏輯。
此事件揭示了 Claude Code 作為 AI 編程助手的完整架構設計,包括其高效的 Harness 系統、3,000+ MCP 工具整合,以及 40+ 原生工具的調用鏈。這些能力是 Anthropic 數年研發積累的工程成果。
本方案利用這一契機,以洩露源代碼為基礎,將 Claude Code 的完整 Harness 保留,同時將底層推理模型切換至 OpenAI 最新發布的 GPT-5.4。GPT-5.4 在 Terminal-Bench 2.0(77.3%)、多步工具調用(Toolathlon 54.6%)及代碼生成(BenchLM 73.9%)方面優於 Claude Opus 4.6,與 Claude Code 的工程 Harness 結合後,形成兩者優勢互補的最佳組合。
| Benchmark | GPT-5.4 × Claude Harness | 原生 Claude Code + Opus 4.6 | 差異 |
|---|---|---|---|
| SWE-bench Verified | 持平(業界頂點) | ||
| BenchLM 綜合編碼 | +1.4pp ↑ | ||
| Terminal-Bench 2.0 | +7.4pp ↑ | ||
| Toolathlon 多步工具 | 首建基準 ↑ | ||
| Tool 首次調用準確率 | +3pp ↑ | ||
| Token 消耗效率 | 顯著節省 ↑ | ||
| SWE-Rebench 實際 PR | Opus 4.6 領先 |
// 修補 GPT-5.4 的 apply_patch schema 不兼容問題 import fs from 'fs' import { Tool } from './Tool' export class ApplyPatchTool extends Tool { name = 'apply_patch' description = `Apply unified diff patch. *** Begin Patch *** Update File: path/to/file @@ -N,M +N,M @@ -removed line +added line *** End Patch` async execute(input: { patch: string }) { const blocks = this.parsePatchBlocks(input.patch) const results: string[] = [] for (const block of blocks) { await this.applyBlock(block) results.push(`✓ ${block.action}: ${block.filePath}`) } return { content: results.join(' ') } } private applyHunk(lines: string[], hunk: string) { const match = hunk.match(/^@@ -(\d+)/m) let ptr = match ? parseInt(match[1]) - 1 : 0 for (const line of hunk.split(' ').slice(1)) { if (line[0] === '-') lines.splice(ptr, 1) else if (line[0] === '+') lines.splice(ptr++, 0, line.slice(1)) else if (line[0] === ' ') ptr++ } } }
import { SwarmEventBus } from './SwarmEventBus' export class GPTSwarmOrchestrator { private bus = new SwarmEventBus() private model = 'gpt-5.4' async runSwarm(task: string, parallelism = 8) { // Step 1 — Planner 分解任務 const raw = await this.callModel({ messages: [{ role: 'user', content: `Decompose into ≤${parallelism} independent subtasks. JSON: {"tasks":["..."]} ${task}` }], response_format: { type: 'json_object' } }) const { tasks } = JSON.parse(raw) // Step 2 — Workers 並行 const results = await Promise.all( tasks.map((t: string, i: number) => this.runWorker(`worker-${i}`, t)) ) // Step 3 — Validator 整合 return this.callModel({ messages: [{ role: 'user', content: `Merge and validate: ${results.join(' --- ')}` }] }) } private async runWorker(id: string, task: string) { const result = await this.callModel({ messages: [{ role: 'user', content: task }], tools: ['read_file', 'write_file', 'bash', 'apply_patch'] }) this.bus.broadcastFinding(id, { type: 'result', content: result }) return result } }
import EventEmitter from 'events' export class SwarmEventBus extends EventEmitter { broadcastFinding(from: string, finding: { type: 'blocker' | 'discovery' | 'result' content: string targets?: string[] }) { const to = finding.targets ?? ['*'] to.forEach(t => this.emit(`agent:${t}:msg`, { from, ...finding, ts: Date.now() })) } // Council 投票:多數決 async councilVote(q: string, agents: string[]): Promise<string> { const votes = await Promise.all(agents.map(id => this.queryAgent(id, q))) const tally = votes.reduce((acc, v) => ({ ...acc, [v]: (acc[v] || 0) + 1 }), {} as Record<string, number>) return Object.entries(tally).sort(([,a],[,b]) => b - a)[0][0] } }
# 全部 Claude 模型路由至 gpt-5.4 routes: - when: model: claude-opus-4-6 use: openai/gpt-5.4 - when: model: claude-sonnet-4-6 use: openai/gpt-5.4 - when: model: claude-haiku-4-6 use: openai/gpt-5.4 litellm: base_url: https://api.openai.com/v1 api_key: ${OPENAI_API_KEY}
# 將 Anthropic API 請求重定向至 CLIproxyAPI export ANTHROPIC_BASE_URL="http://localhost:3001" export ANTHROPIC_API_KEY="any-string" # proxy 不驗證此值 export OPENAI_API_KEY="sk-your-actual-openai-key" # 啟動 CLIproxyAPI(另開終端) # npx cliproxy --port 3001 --config ccproxy-config.yaml
server: port: 3001 host: 127.0.0.1 upstream: provider: openai base_url: https://api.openai.com/v1 api_key: ${OPENAI_API_KEY} routes: - when: { model: claude-opus-4-6 } use: gpt-5.4 - when: { model: claude-sonnet-4-6 } use: gpt-5.4 - when: { model: claude-haiku-4-6 } use: gpt-5.4 transform: anthropic_to_openai: true # 自動轉換 tool schema stream_passthrough: true # 保持 SSE streaming
import Anthropic from '@anthropic-ai/sdk' const client = new Anthropic({ // 指向 CLIproxyAPI,覆蓋預設 api.anthropic.com baseURL: process.env.ANTHROPIC_BASE_URL ?? 'http://localhost:3001', apiKey: process.env.ANTHROPIC_API_KEY ?? 'proxy-key', }) // 請求時仍使用 claude-opus-4-6 名稱 // CLIproxyAPI 攔截後自動替換為 gpt-5.4 const response = await client.messages.create({ model: 'claude-opus-4-6', max_tokens: 8192, messages: context.messages, tools: context.tools, })
# 測試 proxy 是否正常運行 $ curl http://localhost:3001/v1/models | jq # 預期輸出包含 gpt-5.4 # { "data": [{ "id": "gpt-5.4", ... }] } # 啟動 Claude Code,確認 model 攔截日誌 $ claude # CLIproxyAPI log: claude-opus-4-6 → gpt-5.4 ✓
// 修補 GPT-5.4 的 apply_patch schema 不兼容問題 import fs from 'fs' import { Tool } from './Tool' export class ApplyPatchTool extends Tool { name = 'apply_patch' description = `Apply unified diff patch. *** Begin Patch *** Update File: path/to/file @@ -N,M +N,M @@ -removed line +added line *** End Patch` async execute(input: { patch: string }) { const blocks = this.parsePatchBlocks(input.patch) const results: string[] = [] for (const block of blocks) { await this.applyBlock(block) results.push(`✓ ${block.action}: ${block.filePath}`) } return { content: results.join(' ') } } private applyHunk(lines: string[], hunk: string) { const match = hunk.match(/^@@ -(\d+)/m) let ptr = match ? parseInt(match[1]) - 1 : 0 for (const line of hunk.split(' ').slice(1)) { if (line[0] === '-') lines.splice(ptr, 1) else if (line[0] === '+') lines.splice(ptr++, 0, line.slice(1)) else if (line[0] === ' ') ptr++ } } }
import { SwarmEventBus } from './SwarmEventBus' export class GPTSwarmOrchestrator { private bus = new SwarmEventBus() private model = 'gpt-5.4' async runSwarm(task: string, parallelism = 8) { // Step 1 — Planner 分解任務 const raw = await this.callModel({ messages: [{ role: 'user', content: `Decompose into ≤${parallelism} independent subtasks. JSON: {"tasks":["..."]} ${task}` }], response_format: { type: 'json_object' } }) const { tasks } = JSON.parse(raw) // Step 2 — Workers 並行 const results = await Promise.all( tasks.map((t: string, i: number) => this.runWorker(`worker-${i}`, t)) ) // Step 3 — Validator 整合 return this.callModel({ messages: [{ role: 'user', content: `Merge and validate: ${results.join(' --- ')}` }] }) } private async runWorker(id: string, task: string) { const result = await this.callModel({ messages: [{ role: 'user', content: task }], tools: ['read_file', 'write_file', 'bash', 'apply_patch'] }) this.bus.broadcastFinding(id, { type: 'result', content: result }) return result } }
import EventEmitter from 'events' export class SwarmEventBus extends EventEmitter { broadcastFinding(from: string, finding: { type: 'blocker' | 'discovery' | 'result' content: string targets?: string[] }) { const to = finding.targets ?? ['*'] to.forEach(t => this.emit(`agent:${t}:msg`, { from, ...finding, ts: Date.now() })) } // Council 投票:多數決 async councilVote(q: string, agents: string[]): Promise<string> { const votes = await Promise.all(agents.map(id => this.queryAgent(id, q))) const tally = votes.reduce((acc, v) => ({ ...acc, [v]: (acc[v] || 0) + 1 }), {} as Record<string, number>) return Object.entries(tally).sort(([,a],[,b]) => b - a)[0][0] } }
# 全部 Claude 模型路由至 gpt-5.4 routes: - when: model: claude-opus-4-6 use: openai/gpt-5.4 - when: model: claude-sonnet-4-6 use: openai/gpt-5.4 - when: model: claude-haiku-4-6 use: openai/gpt-5.4 litellm: base_url: https://api.openai.com/v1 api_key: ${OPENAI_API_KEY}
# 將 Anthropic API 請求重定向至 CLIproxyAPI export ANTHROPIC_BASE_URL="http://localhost:3001" export ANTHROPIC_API_KEY="any-string" # proxy 不驗證此值 export OPENAI_API_KEY="sk-your-actual-openai-key" # 啟動 CLIproxyAPI(另開終端) # npx cliproxy --port 3001 --config ccproxy-config.yaml
server: port: 3001 host: 127.0.0.1 upstream: provider: openai base_url: https://api.openai.com/v1 api_key: ${OPENAI_API_KEY} routes: - when: { model: claude-opus-4-6 } use: gpt-5.4 - when: { model: claude-sonnet-4-6 } use: gpt-5.4 - when: { model: claude-haiku-4-6 } use: gpt-5.4 transform: anthropic_to_openai: true # 自動轉換 tool schema stream_passthrough: true # 保持 SSE streaming
import Anthropic from '@anthropic-ai/sdk' const client = new Anthropic({ // 指向 CLIproxyAPI,覆蓋預設 api.anthropic.com baseURL: process.env.ANTHROPIC_BASE_URL ?? 'http://localhost:3001', apiKey: process.env.ANTHROPIC_API_KEY ?? 'proxy-key', }) // 請求時仍使用 claude-opus-4-6 名稱 // CLIproxyAPI 攔截後自動替換為 gpt-5.4 const response = await client.messages.create({ model: 'claude-opus-4-6', max_tokens: 8192, messages: context.messages, tools: context.tools, })
# 測試 proxy 是否正常運行 $ curl http://localhost:3001/v1/models | jq # 預期輸出包含 gpt-5.4 # { "data": [{ "id": "gpt-5.4", ... }] } # 啟動 Claude Code,確認 model 攔截日誌 $ claude # CLIproxyAPI log: claude-opus-4-6 → gpt-5.4 ✓