0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kimi K3はClaude Opus 4.8より安い?Node.jsで「採用パッチ単価」を計測する

0
Posted at

「Kimi K3 vs Claude Opus 5」で検索している場合、最初にモデル名を整理しておきたい。2026年7月27日時点で、Anthropicが公開している比較対象は Claude Opus 4.8 であり、「Claude Opus 5」という正式なモデル名は確認できない。

この記事では、Kimi K3とClaude Opus 4.8のコーディング費用を、単純な100万tokenあたりの価格ではなく、採用できたパッチ1件あたりのコストで比較する方法をまとめる。

実測ランキングを作るのではなく、同じリポジトリと同じタスクを使って、自分の環境で再現できる計測方法を作るのが目的だ。

先に結論:token単価だけならKimi K3が安い

2026年7月27日に確認したFlaq AIのKimi K3 Text-to-Text APIでは、次の価格が表示されている。

  • 入力:100万tokenあたり $2.85
  • 出力:100万tokenあたり $14.25
  • 画面に表示される通常価格:入力 $3、出力 $15

Anthropicが公開しているClaude Opus 4.8の価格は、入力$5、出力$25だ。同じtoken数を使うという仮定なら、Kimi K3側のAPI料金は低くなる。

ただし、「Kimi K3はClaudeより必ず安い」とまでは言えない。Claude Sonnet 5は2026年8月31日まで入力$2、出力$10の導入価格であり、この期間はKimi K3より低い。また、モデルごとにtokenizer、出力量、再試行回数が異なるため、同じプロンプトでも最終費用は変わる。

比較するべきなのは「採用パッチ単価」

コーディング用途では、API料金だけでなく、失敗した試行と人間のレビュー時間もコストになる。

採用パッチ単価 =
  (全試行のAPI料金 + 全レビュー時間の人件費)
  ÷ 採用できたパッチ数

最低限、各試行で次の値を記録する。

  • input_tokens
  • output_tokens
  • 再試行回数
  • テストが通ったか
  • レビューに使った分数
  • 最終的に採用したか

「生成できた」ではなく、「テストとレビューを通過してマージできた」を採用条件にするのがポイントだ。

計測条件をそろえる

比較前に、入力条件を固定する。少なくとも以下は同じにする。

  1. 同じcommitのリポジトリ
  2. 同じタスク文
  3. 同じ関連ファイル
  4. 同じテストコマンド
  5. 同じ最大再試行回数
  6. 同じ採用基準

たとえば、次のような範囲が明確なタスクを使う。

認証tokenの更新経路を追跡し、競合状態の候補を1つ特定してください。無関係なファイルや依存関係を変更せず、最小のunified diffと追加すべきテストを提示してください。実行していないテストを「成功した」と書かないでください。

片方のモデルにリポジトリ全体を渡し、もう片方には5ファイルしか渡さなければ、モデルではなくコンテキスト選択処理の差を測ることになる。

qiita-kimi-k3-cost-workflow-16x9.png

Node.jsでKimi K3の1試行を記録する

Node.js 20以降を想定する。APIキーはコードに書かず、FLAQ_API_KEY環境変数から読む。

また、リポジトリ全体を直接送信しない。対象ファイルから秘密情報や顧客データを除去し、sanitized-context.txtとして用意する。

// run-kimi.mjs
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { performance } from "node:perf_hooks";

const API_URL = "https://api.flaq.ai/api/v1/chat/completions";
const MODEL = "kimi-k3-text-to-text";
const PRICE = {
  inputPerMTok: 2.85,
  outputPerMTok: 14.25,
};

const apiKey = process.env.FLAQ_API_KEY;
if (!apiKey) {
  throw new Error("FLAQ_API_KEY is required");
}

const repoContext = await readFile("./sanitized-context.txt", "utf8");
const taskId = "auth-refresh-race-01";
const startedAt = performance.now();

const response = await fetch(API_URL, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
    Accept: "application/json",
  },
  body: JSON.stringify({
    model: MODEL,
    messages: [
      {
        role: "system",
        content:
          "You are a read-only coding reviewer. Cite file paths and symbols. " +
          "Return a minimal unified diff and focused tests. " +
          "Never claim that code or tests were executed.",
      },
      {
        role: "user",
        content:
          "Trace the authentication token refresh path and identify one likely " +
          "race condition. Do not change dependencies or unrelated files.\n\n" +
          repoContext,
      },
    ],
    stream: false,
    max_tokens: 2400,
    top_k: 50,
  }),
});

if (!response.ok) {
  throw new Error(`${response.status}: ${await response.text()}`);
}

const result = await response.json();
const usage = result.usage ?? {};
const inputTokens = Number(
  usage.prompt_tokens ?? usage.input_tokens ?? 0,
);
const outputTokens = Number(
  usage.completion_tokens ?? usage.output_tokens ?? 0,
);
const usageAvailable = inputTokens > 0 || outputTokens > 0;

const apiCostUsd = usageAvailable
  ? (inputTokens / 1_000_000) * PRICE.inputPerMTok +
    (outputTokens / 1_000_000) * PRICE.outputPerMTok
  : null;

const record = {
  taskId,
  provider: "flaq",
  model: MODEL,
  inputTokens,
  outputTokens,
  apiCostUsd,
  latencyMs: Math.round(performance.now() - startedAt),
  attempt: 1,
  testsPassed: null,
  reviewMinutes: null,
  accepted: null,
};

await mkdir("./runs", { recursive: true });
await writeFile(
  `./runs/${taskId}-${MODEL}.json`,
  JSON.stringify(record, null, 2),
);
await writeFile(
  `./runs/${taskId}-${MODEL}.txt`,
  result.choices?.[0]?.message?.content ?? JSON.stringify(result, null, 2),
);

console.log(record);

stream: falseにしているのは、1回分の応答とusageをまとめて保存しやすくするためだ。APIレスポンスにusageが含まれない場合は、apiCostUsdを推測で埋めず、nullのままにして実際の請求情報で補正する。

パッチは隔離した環境で評価する

生成されたdiffをそのまま本番ブランチへ適用しない。保存した.txtからunified diff部分だけをcandidate.diffへ取り出し、使い捨てのworktreeや一時ブランチで確認する。

git worktree add ../candidate-check HEAD
cd ../candidate-check
git apply --check ../candidate.diff
git apply ../candidate.diff
npm test

テスト後に、作成されたJSONへ次の3項目を記入する。

  • testsPassed: テストが成功したか
  • reviewMinutes: 人間が確認した時間
  • accepted: 実際に採用できるか

diffの形式が壊れていた試行や、修正依頼が必要になった試行も削除せず残す。失敗分を消すと、安いモデルほど有利に見える。

採用パッチ単価を集計する

各API呼び出しを1つのJSONとして保存すれば、次のスクリプトで集計できる。

// summarize.mjs
import { readdir, readFile } from "node:fs/promises";

const reviewHourlyUsd = Number(
  process.env.REVIEW_HOURLY_USD ?? "0",
);

const files = (await readdir("./runs"))
  .filter((name) => name.endsWith(".json"));

const runs = await Promise.all(
  files.map(async (name) =>
    JSON.parse(await readFile(`./runs/${name}`, "utf8")),
  ),
);

if (runs.some((run) => run.apiCostUsd === null)) {
  throw new Error("usage未取得の試行があります。請求情報で補正してください");
}

const totalApiCostUsd = runs.reduce(
  (sum, run) => sum + run.apiCostUsd,
  0,
);
const totalReviewCostUsd = runs.reduce(
  (sum, run) =>
    sum + ((run.reviewMinutes ?? 0) / 60) * reviewHourlyUsd,
  0,
);
const acceptedCount = runs.filter((run) => run.accepted).length;

if (acceptedCount === 0) {
  throw new Error("採用できたパッチがありません");
}

const costPerAcceptedPatchUsd =
  (totalApiCostUsd + totalReviewCostUsd) / acceptedCount;

console.log({
  attempts: runs.length,
  acceptedCount,
  totalApiCostUsd,
  totalReviewCostUsd,
  costPerAcceptedPatchUsd,
});

Claude Opus 4.8側でも、呼び出し結果を同じJSON形式へ正規化する。Anthropic APIのusageはinput_tokensoutput_tokensなので、Kimi K3側と同じフィールドへ変換して保存すればよい。

仮のtoken数で価格差だけを確認する

入力50万token、出力5万tokenを1回で使い、キャッシュ、再試行、人件費を含めないと仮定する。

Kimi K3(Flaq AIの現在表示価格)
0.5 × $2.85 + 0.05 × $14.25 = $2.1375

Claude Opus 4.8
0.5 × $5 + 0.05 × $25 = $3.75

これは実測結果ではなく、同じtoken数を仮定した計算例だ。Kimi K3が2回必要ならAPI料金は約$4.28となり、Opus 4.8が1回で通るケースより高くなる。

レビュー時間も同じだ。シニアエンジニアの確認が10分増えれば、数ドルのtoken差より人件費の影響が大きくなることがある。

Kimi K3を使うときの注意点

Moonshot AIは、Kimi K3を2.8兆パラメータ、最大100万tokenのコンテキスト、長時間のコーディングを対象とするモデルとして説明している。一方で、次の制約も公式に示している。

  • 会話の途中で別モデルからKimi K3へ切り替えると、思考履歴の扱いによって品質が不安定になる可能性がある
  • 曖昧な指示では、ユーザーの意図を越えて予想外の判断をする場合がある
  • Claude Fable 5などの最上位プロプライエタリモデルと比べると、全体的なユーザー体験には差が残る

そのため、比較中はモデルを途中で切り替えず、変更可能なファイル、禁止事項、終了条件をsystem messageへ明記する。

なお、この記事で使うFlaq AIのkimi-k3-text-to-textルートはテキスト入力用だ。ファイルや画像を直接送れる前提で実装せず、必要なコードだけを安全なテキストとして組み立てる。

よくある質問

Kimi K3はClaude Opus 4.8より必ず安い?

token単価だけなら現在表示価格は低い。しかし、出力量、失敗回数、テスト修正、レビュー時間まで含めると逆転する可能性がある。

コードベース全体を100万tokenの枠へ入れるべき?

入れる必要はない。生成物、依存関係、秘密情報、関係のないフォルダを除き、タスクに必要なファイルを選んだ方が費用とノイズを減らせる。

1タスクだけでモデルを選んでもよい?

結論を出すには少なすぎる。バグ修正、テスト追加、リファクタリング、設計レビューなど、性質の異なるタスクを最低でも複数用意する。

まとめ

Kimi K3とClaude Opus 4.8のコーディング費用は、100万tokenあたりの価格だけでは判断できない。全試行のAPI料金、テスト結果、再試行、レビュー時間を残し、採用できたパッチ数で割ると、自分の開発フローに合った選択ができる。

最初は機密情報を含まない小さなタスクを固定し、Kimi K3 APIで同じ計測を始める。モデルを増やす前に、まず1つの評価基準を最後まで記録する方が比較しやすい。

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?