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?

DeepSeek-V4.1-Flash-1017を自分のタスクでA/B評価する:小さな評価ハーネスの作り方

0
Posted at
title: "DeepSeek-V4.1-Flash-1017を自分のタスクでA/B評価する:小さな評価ハーネスの作り方"
tags:
  - AI
  - LLM
  - DeepSeek
  - Python
  - vLLM
private: false
---

TL;DR

  • DeepSeek-V4.1-Flash-1017(MIT、総763B、1Mコンテキスト)が公開された。公式カードの数値は魅力的だが、すべて自社値である(※1)。
  • 発表元が違う数字は並べて比べられない。たとえばTerminal-Bench 4.0のGLM-5.3は、DeepSeek表で37.9、Mistral発表で40%と、数字がずれている(※1、※2)。
  • そこで本稿では、自分のタスクで旧モデルと新モデルをA/B比較する小さな評価ハーネスを作る。OpenAI互換エンドポイントなら何でも測れる。
  • ハーネスの動作は、モックサーバーで確認した(Python 3.13、openai SDK 3.44.0、2026-11-04)。DeepSeek-V4.1-Flash-1017そのものは未検証である。

1. 前提:モデル側で分かっていること

モデルカードの記載から、評価に関係する点だけ整理する(※1)。

  • サンプリングの推奨値は temperature 1.0、top_p 1.0。
  • max_tokensは256K以上を推奨。1Mトークンのコンテキストを持つ。
  • Jinja形式のチャットテンプレートがなく、プロンプトの組み立てはencoding.py(Python参照実装)に頼る。
  • サービングはvLLM、SGLang、Docker Model Runnerが記載されている。

つまり、サーバー側が正しくメッセージを組み立てているかどうかは、最初に確認すべき点である。ベンチマークの数字を見る前に、「普通の質問に普通に答えるか」を見るほうが先である。

2. なぜ自前のA/B評価が必要か

旧版との差は、モデルカード上ではTerminal-Bench 4.0が31.2→42.3(+11.1)、DeepSWE v1.1が74.2→77.0(+2.8)である(※1)。ただし、これが自分の仕事に効くかどうかは別の話である。理由は3つある。

  1. ベンチマークの課題と、自分のタスクは違う。
  2. 評価ハーネスや設定が変われば、数字は動く。
  3. 速度・トークン量・失敗の出方は、表に載らない。

APIのdeepseek-flashは、名前と価格を保ったまま中身が1017版に入れ替わったという情報もある(※3、第三者サイト)。気づかないうちに挙動が変わっていても、手元に評価セットがあれば検知できる。

3. 評価ハーネスを作る

3.1 評価ケースを用意する

1行1ケースのJSON Lines形式にする。expectには、応答に含まれるべき文字列を入れる。最初は単純な文字列一致で十分である。

{"id":"a","prompt":"2+2は?","expect":"4"}
{"id":"b","prompt":"3+3は?","expect":"6"}

実際のタスクでは、次のようなケースを20〜50件集めるとよい。

  • 普段の依頼文(社内で実際に使っているもの)
  • 過去にモデルが間違えた例
  • 長い入力(コンテキストを使うもの)は別枠にする

3.2 ハーネス本体

次のコードは、OpenAI互換のエンドポイントに対して、同じケースを順に投げ、合否・所要時間・出力トークン数を集計する。

# ab_eval.py(Python 3.13、openai 3.44.0で動作確認:モックサーバー相手)
import json, time, statistics, sys
from openai import OpenAI

def run(base_url, model, cases, temperature=1.0, top_p=1.0, max_tokens=1024):
    client = OpenAI(base_url=base_url, api_key="dummy")
    rows = []
    for c in cases:
        t0 = time.perf_counter()
        try:
            r = client.chat.completions.create(model=model, temperature=temperature, top_p=top_p,
                max_tokens=max_tokens, messages=[{"role": "user", "content": c["prompt"]}])
            out = r.choices[0].message.content or ""
            ok = c["expect"] in out
            usage = r.usage.completion_tokens if r.usage else None
            err = None
        except Exception as e:
            out, ok, usage, err = "", False, None, repr(e)
        rows.append({"id": c["id"], "ok": ok, "sec": time.perf_counter() - t0, "tokens": usage, "err": err})
    return rows

def summarize(name, rows):
    n = len(rows); passed = sum(r["ok"] for r in rows)
    lat = [r["sec"] for r in rows]
    toks = [r["tokens"] for r in rows if r["tokens"] is not None]
    print(f"{name}: pass {passed}/{n} ({passed/n:.0%}), median {statistics.median(lat):.2f}s, "
          f"avg tokens {statistics.mean(toks) if toks else float('nan'):.0f}, errors {sum(1 for r in rows if r['err'])}")

if __name__ == "__main__":
    cases = [json.loads(l) for l in open(sys.argv[1], encoding="utf-8")]
    for spec in sys.argv[2:]:
        name, url, model = spec.split(",")
        summarize(name, run(url, model, cases))

ポイントは3つある。

  • temperatureとtop_pは、モデルカードの推奨値(1.0)を既定にした。モデルごとに変える場合は引数で渡す。
  • 例外が出ても止めず、errに記録する。タイムアウトや形式エラーは、それ自体が評価の材料になる。
  • 比較対象は名前,URL,モデル名の形で複数指定できる。

3.3 モックサーバーで動作確認

本物のモデルがなくても、ハーネスの配線を確かめられる。次のモックは、「2+2」にだけ正解を返す。

# mock.py:OpenAI互換のごく小さなモック
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
class H(BaseHTTPRequestHandler):
    def do_POST(self):
        b = json.loads(self.rfile.read(int(self.headers["Content-Length"])))
        p = b["messages"][0]["content"]
        text = "答え: 4" if "2+2" in p else "不明"
        out = json.dumps({"id":"x","object":"chat.completion","created":0,"model":b["model"],
          "choices":[{"index":0,"message":{"role":"assistant","content":text},"finish_reason":"stop"}],
          "usage":{"prompt_tokens":5,"completion_tokens":7,"total_tokens":12}}).encode()
        self.send_response(200); self.send_header("Content-Type","application/json")
        self.send_header("Content-Length", str(len(out))); self.end_headers(); self.wfile.write(out)
    def log_message(self, *a): pass
HTTPServer(("127.0.0.1", 8765), H).serve_forever()

実行結果は次のとおりだった。2件中1件が正解で、期待どおりである(2026-11-04、筆者環境)。

$ python3 ab_eval.py cases.jsonl "mock,http://127.0.0.1:8765/v1,mock-model"
mock: pass 1/2 (50%), median 0.04s, avg tokens 7, errors 0

4. 本物のモデルを測るときの手順

ここからは未検証の手順である。モデルカードの記載と、vLLMの一般的な使い方に基づく。

4.1 サーバーを用意する

重みのサイズは、総763Bのうち、F8_E4M3が中心なら概算700GB台になる(筆者の単純計算、テンソル形式が混在するため正確ではない)。複数枚のハイエンドGPUが必要で、1枚のGPUでは動かない。手元にない場合は、推論プロバイダー経由を使う。モデルカードにはNovitaが載っている(※1)。

自前で立てる場合の形は次のとおりである(未検証)。

vllm serve deepseek-ai/DeepSeek-V4.1-Flash-1017 \
  --tensor-parallel-size 8 \
  --max-model-len 262144

このモデル固有のオプションが必要かどうかは、筆者は確認できていない。起動できなければ、モデルカードのinferenceフォルダと、vLLMのドキュメントを見てほしい。

4.2 比較の実行

python3 ab_eval.py cases.jsonl \
  "old,https://YOUR-OLD-ENDPOINT/v1,YOUR-OLD-MODEL" \
  "new,http://localhost:8000/v1,deepseek-ai/DeepSeek-V4.1-Flash-1017"

4.3 結果の見方

見るべきは次の4点である。数字は、必ず同じケース・同じ設定で比べる。

見る項目 見方
合格率 差が小さいときは、ケース数を増やすか、複数回実行する(temperature 1.0なので揺れる)
中央値の所要時間 長い思考をするモデルは遅くなる。タスクの許容範囲に収まるか
平均トークン数 単価が同じでも、トークンが増えればコストは増える
エラー数 タイムアウトや形式エラーの有無。テンプレート関連の不具合の兆候になる

temperatureが1.0の場合、同じ入力でも結果が揺れる。最低でも3回は回して、合格率の幅を見ておきたい。

5. ハマりやすい点

  • チャットテンプレートがない。 サーバーがmessagesを正しく組み立てているか、最初の数件で出力を目で見て確認する。文字化けや、会話の続きを勝手に書き続ける挙動があれば、プロンプト構成の問題を疑う。
  • max_tokensの設定。 推奨は256K以上と書かれているが、評価では上限を決めないと、1件が極端に長くなる。ハーネスでは1,024に抑えている。長い思考が必要な課題では、引き上げる。
  • 文字列一致の限界。 正解の表現が複数ある課題は、expectを正規表現に変えるか、別のモデルに採点させる形に拡張する。ただし後者は、採点側のモデルのクセが入る点に注意する。
  • ベンチマークの数字と比べない。 自分のケースの合格率と、モデルカードの表の数字は、別物である。

6. 筆者の評価

ハーネス自体は、数十行で作れる。モデルが変わるたびに作り直さず、ケースを貯めていけば、「今回の更新は自分のタスクに効いたのか」を数分で確認できる。特に、APIの中身が名前を変えずに入れ替わる状況では、定期的に同じケースを流す運用が、変化の検知にも役立つ。

一方で、DeepSeek-V4.1-Flash-1017の実力そのものは、本稿では確かめられていない。公式の数値は、MITライセンスの大型モデルとして期待できる内容だが、すべて自社値である。実際に測った結果を見るまでは、「期待できる候補」として扱うのが妥当だと考える。

まとめ

DeepSeek-V4.1-Flash-1017は、数値上は旧版から大きく伸びたとされるが、第三者による再現は見つかっていない。本稿では、自分のタスクで比較するための小さなA/B評価ハーネスを作り、モックサーバーで動作を確認した。本物のモデルを使った測定は未検証である。モデルカードの数字を信じる前に、自分の20件で測る。これが一番早い。

※本記事の記載内容は筆者個人の見解であり、所属する会社や組織の立場や方針とは一切関係ありません。

筆者情報

【Tomcat-zhou】|AI/AX/AIセキュリティ専門家

AI戦略洞察、AI駆動開発の方法論設計と現場で回る仕組みづくりをしています。
noteで戦略洞察 / Zenn・Qiitaで技術・方法論を書いています。
AIセキュリティ・AIコンサル・AIエージェント開発・AI活用・AI駆動開発教育、AI人材育成サービスを一体で提供。

X: @ZY20240528
LinkedIn: Tomcat-zhou
Facebook: zhou yi
note: Tomcat-zhou
Zenn: Tomcat-zhou

参考資料

  1. deepseek-ai/DeepSeek-V4.1-Flash-1017(Hugging Face)
  2. Mistral releases open weights for its 1 trillion-parameter Large 4 model(The Next Web)
  3. AI Changelog Week 44(neomanex)

タグ

AI LLM DeepSeek Python vLLM 評価

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?