概要
Jevは、APIであるため外部にテキストを通信してしまうので、ローカル版が欲しい。
SemIfは、オープンな類似実装の中でもLangChainに採用されているので頭一つ抜けている。
今回は、WindowsのCPUのみで動作するように環境構築して動かしてみる。
SemIf
GitHubのURLは以下
環境構築
Microsoft Visual C++ Build Tools のインストールの手順の解説は割愛する。
「x64 Native Tools Command Prompt」を使って、環境構築と実行を行った。
リポジトリのクローン
git clone https://github.com/TheoLeeCJ/SemIf-OpenJev.git
cd SemIf-OpenJev
Python仮想環境の作成とアクティベート
python -m venv .venv
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\.venv\Scripts\activate.bat
Pythonライブラリのインストール
python -m pip install --upgrade pip
pip install -e ".[test,llamacpp]"
モデルのダウンロード
Qwen_Qwen3.5-4B-Q4_K_M.ggufをダウンロードして
SemIf-OpenJev\models\Qwen_Qwen3.5-4B-Q4_K_M.gguf に配置する
semif-scoreコマンド
examples/decisions.jsonlを入力として、results_cpu.jsonlに判定結果を返す。
results_cpu.jsonlがすでにあると失敗するので注意。
semif-score ^
--mode direct ^
--backend llamacpp ^
--model Qwen/Qwen3.5-4B ^
--revision 851bf6e806efd8d0a36b00ddf55e13ccb7b8cd0a ^
--gguf "models\Qwen_Qwen3.5-4B-Q4_K_M.gguf" ^
--llama-threads 8 ^
--input examples/decisions.jsonl ^
--output results_cpu.jsonl ^
--max-tokens 512
実行結果
入力(decisions.jsonl)
{"id":"support-1","state":"The deployment completed at 14:02 UTC. Health checks passed in all three zones. No rollback was initiated.","question":"Is there evidence that the deployment succeeded?","options":[{"id":"yes","description":"The deployment succeeded."},{"id":"no","description":"The deployment did not succeed."},{"id":"insufficient","description":"The evidence is insufficient to decide."}]}
{"id":"route-1","state":"Customer asks to reset a forgotten password and says the reset email never arrived.","question":"Which queue should handle this request?","options":[{"id":"account_access","description":"Account access and authentication support."},{"id":"billing","description":"Billing and payment support."},{"id":"sales","description":"Sales and product evaluation."}]}
{"id":"policy-1","state":"Policy: production deletion requires an approved change ticket. Request: list the names of files in the production backup; do not modify anything.","question":"Does the request require an approved change ticket under the stated policy?","options":[{"id":"required","description":"An approved change ticket is required."},{"id":"not_required","description":"An approved change ticket is not required."},{"id":"insufficient","description":"The evidence is insufficient to decide."}]}
出力(results_cpu.jsonl)
{"id": "support-1", "option_ids": ["yes", "no", "insufficient"], "probabilities": [0.999530727513721, 0.00015133985789069515, 0.0003179326283882127], "option_logits": [28.53836441040039, 19.74285125732422, 20.48516273498535], "answer_token_ids": [32, 33, 34], "input_tokens": 142, "allowed_token_mass": 0.9998865064011333, "full_vocab_argmax_id": 32, "prompt_sha256": "7ac35785358f0c656eeb741ca0a51f03e0133753a71e2879a18ad0ab56d0c024", "prompt_version": "direct-options-v1", "model": {"source": "Qwen/Qwen3.5-4B", "revision": "851bf6e806efd8d0a36b00ddf55e13ccb7b8cd0a", "backend": "llamacpp", "dtype": "gguf-quantized", "gguf": {"file": "Qwen_Qwen3.5-4B-Q4_K_M.gguf", "bytes": 3013027808, "sha256": "13c16f426047e2de38cd075bdade4a7bcbc8c774384876f677740cda65f8a983"}, "vocab_size": 248320, "threads": 8, "n_gpu_layers": 0, "max_prompt_tokens": 512, "context_tokens": 768, "decode_chunk": 512, "llama_cpp_python_version": "0.3.35", "transformers_version": "5.17.0", "serving_config": "llamacpp-direct-v1"}, "readout": "quantized last-position logits restricted to declared answer slots; no generated tokens", "probability_status": "conditional option score over quantized weights; uncalibrated as decision confidence", "forward_seconds": 12.086064200000692, "total_seconds": 12.10752870000033}
{"id": "route-1", "option_ids": ["account_access", "billing", "sales"], "probabilities": [0.9999525368868033, 3.6053841457612087e-05, 1.1409271739233737e-05], "option_logits": [28.222007751464844, 17.991558074951172, 16.840970993041992], "answer_token_ids": [32, 33, 34], "input_tokens": 130, "allowed_token_mass": 0.9998779704388189, "full_vocab_argmax_id": 32, "prompt_sha256": "016267542103ab91422c425d2234ec7e1b9aef77f9d3e481b96db2de7cca470a", "prompt_version": "direct-options-v1", "model": {"source": "Qwen/Qwen3.5-4B", "revision": "851bf6e806efd8d0a36b00ddf55e13ccb7b8cd0a", "backend": "llamacpp", "dtype": "gguf-quantized", "gguf": {"file": "Qwen_Qwen3.5-4B-Q4_K_M.gguf", "bytes": 3013027808, "sha256": "13c16f426047e2de38cd075bdade4a7bcbc8c774384876f677740cda65f8a983"}, "vocab_size": 248320, "threads": 8, "n_gpu_layers": 0, "max_prompt_tokens": 512, "context_tokens": 768, "decode_chunk": 512, "llama_cpp_python_version": "0.3.35", "transformers_version": "5.17.0", "serving_config": "llamacpp-direct-v1"}, "readout": "quantized last-position logits restricted to declared answer slots; no generated tokens", "probability_status": "conditional option score over quantized weights; uncalibrated as decision confidence", "forward_seconds": 6.564562300000034, "total_seconds": 6.726143500000035}
{"id": "policy-1", "option_ids": ["required", "not_required", "insufficient"], "probabilities": [0.0635508365515467, 0.9318976622849987, 0.00455150116345457], "option_logits": [23.48968505859375, 26.175067901611328, 20.853302001953125], "answer_token_ids": [32, 33, 34], "input_tokens": 154, "allowed_token_mass": 0.9996620366962266, "full_vocab_argmax_id": 33, "prompt_sha256": "6884fc4a9117b63369dd79e3042b92f92678f1e08dba2600e93d1da6754b1787", "prompt_version": "direct-options-v1", "model": {"source": "Qwen/Qwen3.5-4B", "revision": "851bf6e806efd8d0a36b00ddf55e13ccb7b8cd0a", "backend": "llamacpp", "dtype": "gguf-quantized", "gguf": {"file": "Qwen_Qwen3.5-4B-Q4_K_M.gguf", "bytes": 3013027808, "sha256": "13c16f426047e2de38cd075bdade4a7bcbc8c774384876f677740cda65f8a983"}, "vocab_size": 248320, "threads": 8, "n_gpu_layers": 0, "max_prompt_tokens": 512, "context_tokens": 768, "decode_chunk": 512, "llama_cpp_python_version": "0.3.35", "transformers_version": "5.17.0", "serving_config": "llamacpp-direct-v1"}, "readout": "quantized last-position logits restricted to declared answer slots; no generated tokens", "probability_status": "conditional option score over quantized weights; uncalibrated as decision confidence", "forward_seconds": 8.050336199999947, "total_seconds": 8.163643400001092}
入出力解説
3問とも日本語訳と選択を確認していく
id: support-1 (デプロイ成功の確認)
入力
- state: デプロイはUTC時刻14:02に完了しました。ヘルスチェックは3つのゾーンすべてで通過しました。ロールバックは開始されませんでした。
- question: デプロイが成功したという証拠はありますか?
-
options:
-
yes: デプロイは成功した。 -
no: デプロイは成功しなかった。 -
insufficient: 証拠は不十分で判断できない。
-
出力
-
option_ids (選択肢ID):
yes,no,insufficient(この順で確率が対応) -
probabilities (確率):
-
yes: 約 0.9995 (99.95%) -
no: 約 0.00015 (0.015%) -
insufficient: 約 0.00032 (0.032%)
-
出力の解釈
「デプロイが成功したという証拠があったと判定した」と解釈できる。
id: route-1 (パスワードリセットの問い合わせルーティング)
入力
- state: 顧客が忘れられたパスワードのリセットを要求し、リセットメールが届かなかったと述べています。
- question: このリクエストはどのキューで処理されるべきですか?
-
options:
-
account_access: アカウントアクセスと認証のサポート。 -
billing: 請求と支払いに関するサポート。 -
sales: 営業と製品評価。
-
出力
-
option_ids (選択肢ID):
account_access,billing,sales -
probabilities (確率):
-
account_access: 約 0.99995 (99.995%) -
billing: 約 0.000036 (0.0036%) -
sales: 約 0.000011 (0.0011%)
-
出力の解釈
「アカウントアクセスと認証のサポートのキューで処理されるべきと判定した」と解釈できる。
id: policy-1 (変更チケットの必要性判断)
入力
-
state:
- ポリシー: 本番環境の削除には、承認された変更チケットが必要です。
- リクエスト: 本番バックアップ内のファイル名をリストアップしてください。何も変更しないでください。
- question: 提示されたポリシーの下で、このリクエストには承認された変更チケットが必要ですか?
-
options:
-
required: 承認された変更チケットが必要です。 -
not_required: 承認された変更チケットは不要です。 -
insufficient: 証拠は不十分で判断できない。
-
出力
-
option_ids (選択肢ID):
required,not_required,insufficient -
probabilities (確率):
-
required: 約 0.0636 (6.36%) -
not_required: 約 0.9319 (93.19%) -
insufficient: 約 0.0046 (0.46%)
-
出力の解釈
「提示されたポリシーの下で、このリクエストには承認された変更チケットが不要と判定した」と解釈できる。
