Qwen3.5-9B-UD-japanese-imatrix developed by dahara1@webbigdata
Qwen3.5-9B æ¥æ¬èªèœåã«ç¹åãããGGUFã¢ãã«
Qwen3.5-9B GGUF model specializing in Japanese language proficiency.
ç¹åŸŽ / Features
äžèšã§èšãã°æ²¢å±±ã®çްããæ¹åãããŠåºæ¥äžãã£ã匷åãªggufã¢ãã«ã§ãã
In short, it's a powerful small gguf model with many improvements.
ãã®ggufã®ç¹åŸŽ
- ã³ãã¥ããã£ãéå»ã«çºèŠããäžå ·åãé©çšããŠèª€äœåå²åãæžãããŠããŸã
- Unslothã®Dynamic Quantization 2.0圢åŒãæ¡çšããŠããŸã
- æ¥æ¬èªã倧ç®ã®ãã£ãªãã¬ãŒã·ã§ã³ããŒã¿ã䜿çšããŠããŸã
Features of this gguf
- We've applied bugs previously discovered by the community to reduce the rate of malfunctions.
- This model uses Unsloth's Dynamic Quantization 2.0 format.
- Use calibration data with a large amount of Japanese text.
åããæ¹ / How to Run
GPUããªããŠãåããŸãããã·ã¹ãã ã¡ã¢ãªã¯16GB以äžããã£ã¹ã¯å®¹éã6GB以äžå¿
èŠã§ãã
It will run without a GPU, but you will need at least 16GB of system memory and 6GB of disk space.
Linux terminalã§ã®å®è¡
llama.cppã䜿ããŸããçŽè¿ã§Qwen3.5察å¿ã®ã¢ããããŒããããã€ããã£ããããææ°çã䜿ãäºãããããããŸãã(æ¬ä»¶ã®åäœç¢ºèªã¯version: 8007 (098595411)ã§è¡ã£ãŠããŸã)
We will be using llama.cpp. Since there have been several recent updates to support Qwen 3.5, we recommend using the latest version. (This issue was confirmed to work with version: 8007 (098595411)).
llama.cppããã䜿ãã®ããŒããŠã§ã¢çšã®ZIPãã¡ã€ã«ãããŠã³ããŒãããŠèšå®ããŸãã
沢山皮é¡ãããã®ã§è¿·ããããããŸããããchatGPTãªãGeminiãªãCaludeãªãã«èããŠé©åãªãã®ãéžãã§ãã ãã
Download the zip file for your hardware from llama.cpp and set it up.
There are many options, so you may be confused, but please ask chatGPT, Gemini, or Calude to help you choose the right one.
ããŠã³ããŒãããzipãè§£ååŸããã¿ãŒããã«ãPowerShellã端æ«ãã以äžã®ã³ãã³ããæã¡èŸŒãã§èµ·åããŸã
After unzipping the downloaded zip file, run it via Terminal, PowerShell, or the terminal by typing the following command.
Linuxã§ã®ã¿ãŒããã«ã§ã®å®è¡äŸã§ã
Here is an example of running the command on Linux terminal:
ãŸãhf commandãã€ã³ã¹ããŒã«ããŠãã ãã
First, please install the hf command.
# ã¢ãã«ã®ããŠã³ããŒã / download model
hf download dahara1/Qwen3.5-9B-UD-japanese-imatrix Qwen3.5-9B-UD-Q4_K_XL.gguf --local-dir Qwen3.5-9B-UD-japanese-imatrix
# 念ã®çºjinjaãã³ãã¬ãŒãã®ããŠã³ããŒã / download jinja template
hf download dahara1/Qwen3.5-9B-UD-japanese-imatrix chat_template.jinja --local-dir Qwen3.5-9B-UD-japanese-imatrix
./llama-cli \
-m Qwen3.5-9B-UD-japanese-imatrix/Qwen3.5-9B-UD-Q4_K_XL.gguf \
--temp 0.6 \
--top-p 0.8 \
--top-k 20 \
--min-p 0.0 \
--ctx-size 12000 \
--presence_penalty 1.5 \
--jinja \
--chat-template-kwargs '{"enable_thinking":true}' \
--chat-template-file Qwen3.5-9B-UD-japanese-imatrix/chat_template.jinja \
-ub 2048 \
-b 2048
ctx-sizeãæ±ããæç« ã®é·ãã§ããé·ããããšè€æ°ã¿ãŒã³ã®é·ãäŒè©±ãæ±ããããã«ãªããŸãããå¿
èŠã¡ã¢ãªéãå¢ããŸããctx-size specifies the length of text that can be handled. Increasing this value allows for longer conversations with multiple turns, but it also increases the amount of memory required.
GPUããæã¡ã®æ¹ãž(for GPU User)
16GBã®GPUã¡ã¢ãªããããšæ¯èŒçå¿«é©ã«åããäºãã§ããŸããäžèšã®ã³ãã³ãã«-ngl 99ã远å ããŠãã ãã
If you have 16GB of GPU memory, it will run relatively smoothly. Add -ngl 99 to the above command.
Windows AMD CPU / iGPU çšã®äŸ
AMD Ryzen 9 7940HS w/ Radeon 780M Graphics ã·ã¹ãã ã¡ã¢ãª32GBã®ããPCãVulkanã»ããã¢ããæžã¿ãGPUã«ã¯8Gãå²ãåœãŠæžã¿ã®PCã§ã®ã³ãã³ãäŸ
llama.cppã¯githubãããWindows x64 (Vulkan)ããããŠã³ããŒãããŸã
-ngl 99 ãä»äžããã°é«éå®è¡ããããšãã§ããŸã
AMD Ryzen 9 7940HS w/ Radeon 780M Graphics Mini PC with 32GB of system memory, Vulkan setuped, and 8GB allocated to the GPU.
Download "Windows x64 (Vulkan)" for llama.cpp from github.
You can run it faster by adding -ngl 99.
.\llama-server ^
-m ..\Qwen3.5-9B-UD-japanese-imatrix\Qwen3.5-9B-UD-Q4_K_XL.gguf ^
--host 0.0.0.0 ^
--port 8081 ^
--top-p 0.8 ^
--top-k 20 ^
--min-p 0.0 ^
--ctx-size 24000 ^
--presence_penalty 1.5 ^
--chat-template-kwargs "{\"enable_thinking\":true}" ^
--chat-template-file ..\Qwen3.5-9B-UD-japanese-imatrix\chat_template.jinja ^
--jinja ^
-ub 2048 ^
-ngl 99 ^
-b 2048
ãµã³ãã«ã¹ã¯ãªãã / sample script
ã¯ã©ã€ã¢ã³ã/ãµãŒããŒååŒã§ã¹ã¯ãªããã§ã¢ã¯ã»ã¹ãããå Žåã¯äžèšã®AMDçã®ã³ãã³ããåèã«ããŠãã ãã
If you want to access it via script in a client/server format, please refer to the AMD version command above.
ãã©ãŠã¶ã§ãã¢ãã«ãå®è¡ããŠãããµãŒããŒã®ããŒã«ã«ã¢ãã¬ã¹ãããŒããæå®ããŠéããŠäžãããäŸ(http://127.0.0.1:8081/)
In your browser, open the local address and port of the server running the model. For example, http://127.0.0.1:8081/
client script sample
ããŒã«ãå©çšããã¹ãŒããŒããŒã±ããã®æ¡å
é³å£°äœæAIãšãŒãžã§ã³ãã®ãã¢ã§ã
This is a demo of an AI agent that creates voice guidance for supermarkets using a tool.
é³å£°åæã«ã¯webbigdata/VoiceCoreã䜿ã£ãŠããŸãããã奜ã¿ã®é³å£°åæã«å·®ãæ¿ãå¯èœã§ã
We are using webbigdata/VoiceCore for speech synthesis, but you can replace it with your preferred speech synthesis software.
VoiceCoreã®ãµã³ãã«ã¹ã¯ãªãã
VoiceCore sample script
VoiceCoreãVLLMã§ä»¥äžã§åãããŠããäºãåæã®ãã¢ã§ã
This demo assumes that VoiceCore is running with VLLM as described below.
http://192.168.1.16:8000/v1/completions
â»ã¢ãã«ããŠã³ããŒãæã«ä»¥äžã®ãããªãšã©ãŒãåºãäºããããŸãã
*The following error sometimes occurred when downloading the model.
httpx.DecodingError: brotli: decoder process called with data when 'can_accept_more_data()' is False
以äžã®ã©ã€ãã©ãªã¢ããããŒãã§è§£æ±ºããã®ã§ãã®ãšã©ãŒãåºãéã¯åèã«ããŠãã ãã
The following library update resolved the issue, so please refer to it if you encounter this error.
pip install --upgrade httpx brotli brotlicffi
import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
import json
import sys
import time
import random
import re
import argparse
import subprocess
import urllib.request
from datetime import datetime
from openai import OpenAI
# ============================================================
# ããŒã«ãã§ãŒã³ã㢠â ã¹ãŒããŒåºå
ã¢ããŠã³ã¹çæãšãŒãžã§ã³ã
# åºé·ã®æç€º â 倩æ°ã»ã€ãã³ãã»ãã¬ããžçãåé â åçš¿çæ â TTSèªã¿äžã
# ============================================================
client = OpenAI(
base_url="http://localhost:8081/v1",
api_key="dummy"
)
# --- TTSèšå® ---
TTS_SERVER_URL = "http://192.168.1.16:8000/v1/completions"
TTS_TOKENIZER_PATH = "webbigdata/VoiceCore_smoothquant"
TTS_MODEL_NAME = "VoiceCore_smoothquant"
TTS_SPEAKER = "matsukaze_male[neutral]"
# ============================================================
# è²å®çŸ©
# ============================================================
class C:
BOLD = "\033[1m"
DIM = "\033[2m"
RESET = "\033[0m"
CYAN = "\033[96m"
YELLOW = "\033[93m"
GREEN = "\033[92m"
BLUE = "\033[94m"
MAGENTA = "\033[95m"
THINK = "\033[38;5;213m" # æãããã³ã¯ããŒãã«ïŒThink衚瀺çšïŒ
RED = "\033[91m"
WHITE = "\033[97m"
BG_RED = "\033[41m"
BG_GREEN = "\033[42m"
BG_BLUE = "\033[44m"
BG_MAGENTA = "\033[45m"
BG_CYAN = "\033[46m"
GRAY = "\033[90m"
# ============================================================
# åºèãã±ãŒã·ã§ã³ïŒ4å°ç¹ããã©ã³ãã ã«1ã€éžæïŒ
# ============================================================
STORE_LOCATIONS = [
{
"name": "ãã¬ãã·ã¥ããŒã 緎銬åº",
"area": "æ±äº¬éœç·ŽéЬåº",
"forecast_code": "130000",
"nearby_schools": ["緎銬åºç«å€§æ³å°åŠæ ¡", "緎銬åºç«å€§æ³äžåŠæ ¡"],
},
{
"name": "ãã¬ãã·ã¥ããŒã æ¢
ç°åº",
"area": "倧éªåºå€§éªåžååº",
"forecast_code": "270000",
"nearby_schools": ["倧éªåžç«æçºå°åŠæ ¡", "倧éªåžç«å€©æºäžåŠæ ¡"],
},
{
"name": "ãã¬ãã·ã¥ããŒã åå€åº",
"area": "çŠå²¡ççŠå²¡åžåå€åº",
"forecast_code": "400000",
"nearby_schools": ["çŠå²¡åžç«åå€å°åŠæ ¡", "çŠå²¡åžç«åå€äžåŠæ ¡"],
},
{
"name": "ãã¬ãã·ã¥ããŒã æå¹åº",
"area": "åæµ·éæå¹åžäžå€®åº",
"forecast_code": "016000",
"nearby_schools": ["æå¹åžç«åå±±å°åŠæ ¡", "æå¹åžç«åéµäžåŠæ ¡"],
},
]
# èµ·åæã«1ã€éžæ
CURRENT_STORE = random.choice(STORE_LOCATIONS)
# ============================================================
# ã€ãã³ããã¿ãŒã³ïŒæ¥ or ç§ãã©ã³ãã éžæïŒ
# ============================================================
def _generate_events():
pattern = random.choice(["spring", "autumn"])
schools = CURRENT_STORE["nearby_schools"]
if pattern == "spring":
return {
"season": "æ¥",
"general_events": [
{"name": "ãè±èŠã·ãŒãºã³", "period": "3æäžæ¬ã4æäžæ¬", "note": "å
¬åã§ã®ãè±èŠãçæ³"},
{"name": "æ°ç掻æºå", "period": "3æã4æ", "note": "åŒè¶ãã»äžäººæ®ããéå§"},
],
"school_events": [
{"school": schools[0], "event": "忥åŒ", "date": "ä»é±æ°Žææ¥"},
{"school": schools[0], "event": "å
¥åŠåŒ", "date": "æ¥é±æææ¥"},
{"school": schools[1], "event": "å
¥åŠåŒ", "date": "æ¥é±ç«ææ¥"},
],
}
else:
return {
"season": "ç§",
"general_events": [
{"name": "ç§ã®è¡æ¥œã·ãŒãºã³", "period": "10æ", "note": "ãã¯ããã¯ã»ãã€ãã³ã°éèŠ"},
{"name": "ãããŠã£ã³", "period": "10ææ«", "note": "ãèåã»ä»®è£
ã°ããºéèŠ"},
],
"school_events": [
{"school": schools[0], "event": "éåäŒ", "date": "ä»é±åææ¥"},
{"school": schools[1], "event": "æåç¥", "date": "æ¥é±éææ¥ã»åææ¥"},
],
}
CURRENT_EVENTS = _generate_events()
# ============================================================
# ãã¬ããžDBïŒããã©ã³åºé·ã»åºå¡ã®ç¥èŠïŒ
# ============================================================
KNOWLEDGE_DB = [
{
"keywords": ["éåäŒ", "äœè²ç¥", "ã¹ããŒã"],
"content": (
"ãéåäŒã·ãŒãºã³ã®å£²ãç â ç°äžåºé·ã®çµéšåã\n"
"ã»ã¹ããŒãããªã³ã¯ïŒ2Lãããããã«ïŒãéåžžã®3å売ãã\n"
"ã»ãåŒåœçšã®åæãã»ãŠã€ã³ããŒã»åµçŒãã®ææã忥倿¹ãåœæ¥æã«éäž\n"
"ã»èгæŠçšã®ããŒã«ïŒ350ml猶6æ¬ããã¯ïŒããã¥ãŒãã€ã奜調\n"
"ã»ã¬ãžã£ãŒã·ãŒããçŽç¿ã»çŽã³ãããå¿ããã«ååºã\n"
"ã»æ¥çŒãæ¢ãã»è«é€ãã¹ãã¬ãŒãæå€ãšåºã"
),
},
{
"keywords": ["å
¥åŠåŒ", "忥åŒ", "å
¥å", "åå", "æ°ç掻", "ã»ã¬ã¢ããŒ"],
"content": (
"ãå
¥åŠã»åæ¥ã·ãŒãºã³ã®å£²ãç â äœè€å¯åºé·ã®çµéšåã\n"
"ã»ã赀飯ãçŽ
çœãŸããã
ããã±ãŒãææã䌞ã³ã\n"
"ã»èšå¿µåçã®åŸã«å®¶æã§é£äºãããã¿ãŒã³ãå€ãã倿¹ã«ã寿åžãåºèº«ã売ãã\n"
"ã»ãç¥ãçšã®ã®ãè¢ãç¥åè¢ãç®ç«ã€å Žæã«\n"
"ã»æã¯æ
ãã ããã®ã§ãã«ããããµã³ãã€ããçã®è»œé£ãåºã"
),
},
{
"keywords": ["è±èŠ", "ãè±èŠ", "æ¡", "ãã¯ããã¯"],
"content": (
"ããè±èŠã·ãŒãºã³ã®å£²ãç â ç°äžåºé·ã®çµéšåã\n"
"ã»ããŒã«ããã¥ãŒãã€ãã¯ã€ã³ãªã©ã¢ã«ã³ãŒã«é¡ãççºçã«å£²ãã\n"
"ã»ãªãŒããã«ããæ£èã®çãåããã寿åžããã¯ã人æ°\n"
"ã»äœ¿ãæšãŠå®¹åšãå²ã箞ããŠã§ãããã£ãã·ã¥ããŽãè¢ã®ã»ãã売ãã广ç\n"
"ã»é²å¯çšã«ã«ã€ãããŸã éèŠããïŒå€ã¯å·ããïŒ\n"
"ã»ãã¶ãŒãã«ãã¡ã倧çŠãå£åãæšããšåå¿ãè¯ã"
),
},
{
"keywords": ["éš", "éšå€©", "å°é¢š", "æ¢
éš", "倩æ°ãæªã"],
"content": (
"ãéšã®æ¥ã®åŸå â éŽæšããŒãã®çµéšåã\n"
"ã»æ¥å®¢æ°ã¯2ã3岿žããã客å䟡ã¯äžããåŸåïŒãŸãšãè²·ãïŒ\n"
"ã»éç©ãã·ãã¥ãŒãã«ã¬ãŒãªã©æž©ããæçã®ææã䌞ã³ã\n"
"ã»åãã«ãããå
¥å£ä»è¿ã«é
眮ãããšè¡åè²·ãããã\n"
"ã»ãæ£èããåŒåœã¯å°ãå€ãã«äœã£ãŠã売ãåããïŒèªçãé¿ããå¿çïŒ"
),
},
{
"keywords": ["æã", "çæ", "çå€", "ç±äžç"],
"content": (
"ãçææ¥ã®åŸå â ç°äžåºé·ã®çµéšåã\n"
"ã»ã¢ã€ã¹ãããæ°·ãå·ãã麺ã®å£²äžãéåžžã®2å以äž\n"
"ã»ã¹ããŒãããªã³ã¯ãçµå£è£æ°Žæ¶²ã¯åãããªãããš\n"
"ã»å·ããã¶ããµã©ããããããã€ãã®ã»ããææ¡ã广ç\n"
"ã»ããŒã«ã»çé
žé£²æã®å·èµåšåº«ãé »ç¹ã«ãã§ãã¯"
),
},
{
"keywords": ["ãããŠã£ã³", "ä»®è£
", "ãèå"],
"content": (
"ããããŠã£ã³ã®å£²ãç â äœè€å¯åºé·ã®çµéšåã\n"
"ã»å°åãã®åå
è£
ãèåïŒãã§ã³ããã£ã³ãã£ïŒã倧éã«å£²ãã\n"
"ã»ããŒã¡ãé¢é£ååïŒãŸãããšããŒã¡ããããŒã¡ãããªã³ææïŒ\n"
"ã»ããŒãã£ãŒçšã®ãžã¥ãŒã¹ãããããããã¹ããããã³ãŒã³\n"
"ã»ä»®è£
ã°ããºã¯æ©ãã«å±éããªããšä»åºã«åããã"
),
},
{
"keywords": ["çµŠææ¥", "ææ«", "25æ¥"],
"content": (
"ãçµŠææ¥ååŸã®åŸå â éŽæšããŒãã®çµéšåã\n"
"ã»çµŠææ¥çŽåŸã¯ã¡ãã£ãšè¯ãèïŒã¹ããŒãçšãããçŒãçšïŒãåã\n"
"ã»åºèº«çãåããã寿åžããã¯ãªã©ã®ãè€çŸç³»æ£èã䌞ã³ã\n"
"ã»ããŒã«ã»ã¯ã€ã³ãªã©ã¢ã«ã³ãŒã«ãã¯ã³ã©ã³ã¯äžã®ãã®ã売ãã\n"
"ã»éã«çµŠææ¥åã¯ããããè±è
ãåµãªã©ç¯çŽé£æãåé¢ã«"
),
},
{
"keywords": ["鱿«", "åæ", "æ¥æ", "äŒæ¥"],
"content": (
"ã鱿«ã®åŸå â ç°äžåºé·ã®çµéšåã\n"
"ã»å®¶æé£ããå¢ããã®ã§ãã¡ããªãŒããã¯ã倧容éååãåã\n"
"ã»BBQã»çŒèçšã®èãéèãã¿ã¬ã®ã»ããææ¡ã广ç\n"
"ã»æã¯ãã³ã»çä¹³ãããåºãïŒå¹³æ¥ããé
ãæé垯ã«ããŒã¯ïŒ\n"
"ã»æ¥æå€æ¹ã¯ç¿é±åã®ãŸãšãè²·ãéèŠ"
),
},
]
def search_knowledge(query):
"""ãã¬ããžDBãããªãŒã¯ãŒãæ€çŽ¢"""
results = []
query_lower = query.lower()
for entry in KNOWLEDGE_DB:
for kw in entry["keywords"]:
if kw in query_lower or query_lower in kw:
results.append(entry["content"])
break
if not results:
return json.dumps({
"query": query,
"found": False,
"message": f"ã{query}ãã«é¢ããç¥èŠã¯èŠã€ãããŸããã§ããã",
}, ensure_ascii=False)
return json.dumps({
"query": query,
"found": True,
"count": len(results),
"knowledge": "\n\n".join(results),
}, ensure_ascii=False)
# ============================================================
# ããŒã«å®è£
# ============================================================
def tool_get_store_info():
"""åºèæ
å ±ãè¿ã"""
now = datetime.now()
# åå/ååŸã©ã³ãã
is_morning = random.choice([True, False])
if is_morning:
period = "åå"
hours = "9:00ã13:00"
peak_note = "ååäžã®ãè²·ãç©ããŒã¯ã¯10:30ã11:30é ã§ã"
else:
period = "ååŸ"
hours = "13:00ã21:00"
peak_note = "倿¹ã®ãè²·ãç©ããŒã¯ã¯16:00ã18:00é ã§ã"
return json.dumps({
"store_name": CURRENT_STORE["name"],
"area": CURRENT_STORE["area"],
"current_period": period,
"operating_hours": f"æ¬æ¥ã®å¶æ¥æé: {hours}",
"peak_note": peak_note,
"nearby_schools": CURRENT_STORE["nearby_schools"],
}, ensure_ascii=False)
def tool_get_current_datetime():
"""çŸå𿥿ãè¿ã"""
now = datetime.now()
weekdays = ["æ", "ç«", "æ°Ž", "æš", "é", "å", "æ¥"]
wd = weekdays[now.weekday()]
return json.dumps({
"datetime": f"{now.year}幎{now.month:02d}æ{now.day:02d}æ¥({wd}) {now.hour:02d}:{now.minute:02d}",
"weekday": f"{wd}ææ¥",
"is_weekend": now.weekday() >= 5,
"day_of_month": now.day,
"is_near_payday": 23 <= now.day <= 27,
}, ensure_ascii=False)
def tool_get_weather():
"""æ°è±¡åºã®å€©æ°æŠæ³JSONãååŸ"""
code = CURRENT_STORE["forecast_code"]
area = CURRENT_STORE["area"]
url = f"https://www.jma.go.jp/bosai/forecast/data/overview_forecast/{code}.json"
try:
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode("utf-8"))
return json.dumps({
"area": area,
"reporting_time": data.get("reportDatetime", ""),
"headline": data.get("headlineText", ""),
"overview": data.get("text", ""),
}, ensure_ascii=False)
except Exception as e:
return json.dumps({
"area": area,
"error": f"å€©æ°æ
å ±ã®ååŸã«å€±æ: {str(e)}",
"fallback": "å€©æ°æ
å ±ãååŸã§ããŸããã§ããã倩æ°ã«é¢ããèšåã¯çç¥ããŠãã ããã",
}, ensure_ascii=False)
def tool_get_events():
"""å°åã€ãã³ãã»è¿é£åŠæ ¡è¡äºãè¿ã"""
return json.dumps(CURRENT_EVENTS, ensure_ascii=False)
def tool_search_knowledge(query):
"""ããã©ã³åºå¡ã®ãã¬ããžDBãæ€çŽ¢"""
return search_knowledge(query)
def tool_synthesize_speech(text):
"""VoiceCoreãµãŒããŒã§TTSåæã»åç"""
print(f"\n {C.GREEN}ð TTSåæéå§...{C.RESET}")
print(f" {C.DIM}åçš¿: {text[:80]}...{C.RESET}")
try:
import torch
from transformers import AutoTokenizer
from snac import SNAC
import sounddevice as sd
import queue
import threading
# Tokenizer & SNACããŒã
print(f" {C.DIM} Tokenizer/SNACã¢ãã«ãããŒãäž...{C.RESET}")
tts_tokenizer = AutoTokenizer.from_pretrained(TTS_TOKENIZER_PATH)
snac_model = SNAC.from_pretrained("hubertsiuzdak/snac_24khz").to("cpu")
start_token, end_tokens = [128259], [128009, 128260, 128261]
audio_start_token = 128257
prompt_ = (f"{TTS_SPEAKER}: " + text) if TTS_SPEAKER else text
input_ids = tts_tokenizer.encode(prompt_)
final_token_ids = start_token + input_ids + end_tokens
payload = {
"model": TTS_MODEL_NAME, "prompt": final_token_ids,
"max_tokens": 8192, "temperature": 0.6, "top_p": 0.90,
"repetition_penalty": 1.1, "stop_token_ids": [128258],
"stream": True,
}
# SNACãã³ãŒããŒ
def redistribute_codes(code_list):
if len(code_list) % 7 != 0:
return torch.tensor([])
layer_1, layer_2, layer_3 = [], [], []
for i in range(len(code_list) // 7):
layer_1.append(code_list[7*i])
layer_2.append(code_list[7*i+1] - 4096)
layer_3.append(code_list[7*i+2] - (2*4096))
layer_3.append(code_list[7*i+3] - (3*4096))
layer_2.append(code_list[7*i+4] - (4*4096))
layer_3.append(code_list[7*i+5] - (5*4096))
layer_3.append(code_list[7*i+6] - (6*4096))
codes = [torch.tensor(layer).unsqueeze(0) for layer in [layer_1, layer_2, layer_3]]
return snac_model.decode(codes)
# é³å£°åçã¯ãŒã«ãŒ
audio_queue = queue.Queue()
def audio_playback_worker(q, stream):
while True:
data = q.get()
if data is None:
break
stream.write(data)
playback_stream = sd.OutputStream(samplerate=24000, channels=1, dtype='float32')
playback_stream.start()
playback_thread = threading.Thread(target=audio_playback_worker, args=(audio_queue, playback_stream))
playback_thread.start()
token_buffer = []
found_audio_start = False
CHUNK_SIZE = 28
import requests as req_lib
print(f" {C.DIM} TTSãµãŒããŒã«ãªã¯ãšã¹ãéä¿¡äž...{C.RESET}")
response = req_lib.post(TTS_SERVER_URL, headers={"Content-Type": "application/json"}, json=payload, stream=True)
response.raise_for_status()
print(f" {C.GREEN} â¶ é³å£°åçäž...{C.RESET}")
for line in response.iter_lines():
if line:
decoded_line = line.decode('utf-8')
if decoded_line.startswith('data: '):
content = decoded_line[6:]
if content == '[DONE]':
break
chunk = json.loads(content)
text_chunk = chunk['choices'][0]['text']
if text_chunk:
token_buffer.extend(tts_tokenizer.encode(text_chunk, add_special_tokens=False))
if not found_audio_start:
try:
start_index = token_buffer.index(audio_start_token)
token_buffer = token_buffer[start_index + 1:]
found_audio_start = True
except ValueError:
continue
while len(token_buffer) >= CHUNK_SIZE:
tokens_to_process, token_buffer = token_buffer[:CHUNK_SIZE], token_buffer[CHUNK_SIZE:]
code_list = [t - 128266 for t in tokens_to_process]
samples = redistribute_codes(code_list)
if samples.numel() > 0:
audio_queue.put(samples.detach().squeeze().numpy())
# æ®ããããã¡åŠç
if found_audio_start and token_buffer:
remaining = (len(token_buffer) // 7) * 7
if remaining > 0:
code_list = [t - 128266 for t in token_buffer[:remaining]]
samples = redistribute_codes(code_list)
if samples.numel() > 0:
audio_queue.put(samples.detach().squeeze().numpy())
audio_queue.put(None)
playback_thread.join()
playback_stream.stop()
playback_stream.close()
return json.dumps({
"status": "success",
"message": "é³å£°ã®åçãå®äºããŸããã",
}, ensure_ascii=False)
except Exception as e:
return json.dumps({
"status": "error",
"message": f"TTSåŠçã§ãšã©ãŒãçºçããŸãã: {str(e)}",
}, ensure_ascii=False)
# ============================================================
# ããŒã«ãã£ã¹ããã
# ============================================================
def execute_tool(func_name, args):
if func_name == "get_store_info":
return tool_get_store_info()
elif func_name == "get_current_datetime":
return tool_get_current_datetime()
elif func_name == "get_weather":
return tool_get_weather()
elif func_name == "get_events":
return tool_get_events()
elif func_name == "search_knowledge":
return tool_search_knowledge(args.get("query", ""))
elif func_name == "synthesize_speech":
return tool_synthesize_speech(args.get("text", ""))
else:
return json.dumps({"error": f"Unknown tool: {func_name}"}, ensure_ascii=False)
# ============================================================
# ããŒã«å®çŸ©ïŒLLMã«æž¡ãïŒ
# ============================================================
tools = [
{
"type": "function",
"function": {
"name": "get_store_info",
"description": "åºèæ
å ±ïŒåºèåãæåšå°ãå¶æ¥æéãè¿é£åŠæ ¡åãªã©ïŒãååŸããŸãã",
"parameters": {
"type": "object",
"properties": {},
"required": [],
},
},
},
{
"type": "function",
"function": {
"name": "get_current_datetime",
"description": "çŸåšã®æ¥æãææ¥ãçµŠææ¥ä»è¿ãã©ãããªã©ã®æ
å ±ãååŸããŸãã",
"parameters": {
"type": "object",
"properties": {},
"required": [],
},
},
},
{
"type": "function",
"function": {
"name": "get_weather",
"description": "åºèæåšå°ã®å€©æ°æŠæ³ïŒå€©æ°äºå ±ããã¹ãïŒãæ°è±¡åºããååŸããŸãã",
"parameters": {
"type": "object",
"properties": {},
"required": [],
},
},
},
{
"type": "function",
"function": {
"name": "get_events",
"description": (
"å°åã®äžè¬çãªã€ãã³ãæ
å ±ïŒãè±èŠããããŠã£ã³çã®å£ç¯ã€ãã³ãïŒãšã"
"è¿é£ã®åŠæ ¡è¡äºïŒéåäŒãå
¥åŠåŒã忥åŒçïŒã®æ
å ±ãååŸããŸãã"
),
"parameters": {
"type": "object",
"properties": {},
"required": [],
},
},
},
{
"type": "function",
"function": {
"name": "search_knowledge",
"description": (
"ããã©ã³åºé·ã»åºå¡ã®çµéšã«åºã¥ããã¬ããžDBãæ€çŽ¢ããŸãã"
"ã€ãã³ãåã倩æ°ãå£ç¯ãªã©ã®ããŒã¯ãŒãã§æ€çŽ¢ãããšã"
"éå»ã®è²©å£²åŸåã売ãçååã®ç¥èŠãåŸãããŸãã"
"è€æ°ã®ããŒã¯ãŒãã§åå¥ã«æ€çŽ¢ãããšãããå€ãã®ç¥èŠãåŸãããŸãã"
),
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "æ€çŽ¢ããŒã¯ãŒãïŒäŸ: éåäŒ, éš, ãè±èŠ, çµŠææ¥ïŒ",
},
},
"required": ["query"],
},
},
},
{
"type": "function",
"function": {
"name": "synthesize_speech",
"description": (
"宿ããåºå
ã¢ããŠã³ã¹åçš¿ãé³å£°åæïŒTTSïŒã§èªã¿äžããŸãã"
"å
šãŠã®æ
å ±åéãšåçš¿äœæãå®äºããåŸã«ãæçµçãªåçš¿ããã¹ããæž¡ããŠåŒã³åºããŠãã ããã"
),
"parameters": {
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "èªã¿äžããåºå
ã¢ããŠã³ã¹åçš¿ã®ããã¹ã",
},
},
"required": ["text"],
},
},
},
]
# ============================================================
# ã¹ããªãŒãã³ã°è¡šç€º
# ============================================================
# ============================================================
# ãã©ãŒã«ããã¯: thinkingå
<tool_call> ã®ããŒãµãŒ
# ============================================================
_TOOL_CALL_ID_COUNTER = 0
def _parse_tool_calls_from_text(text):
"""
LLMãthinkingå
ã«åºåãã <tool_call>...</tool_call> ãããŒã¹ããŠ
tool_calls_list äºæã®èŸæžãªã¹ãã«å€æããã
察å¿ãã©ãŒããã:
<tool_call>
<function=func_name>
<parameter=key>value</parameter>
...
</function>
</tool_call>
"""
global _TOOL_CALL_ID_COUNTER
results = []
# <tool_call>...</tool_call> ãããã¯ãå
šãŠæœåº
blocks = re.findall(r'<tool_call>(.*?)</tool_call>', text, re.DOTALL)
if not blocks:
return results
for block in blocks:
# 颿°åãæœåº
func_match = re.search(r'<function=(\w+)>', block)
if not func_match:
continue
func_name = func_match.group(1)
# ãã©ã¡ãŒã¿ãæœåº
params = {}
param_matches = re.findall(r'<parameter=(\w+)>\s*(.*?)\s*</parameter>', block, re.DOTALL)
for key, value in param_matches:
value = value.strip()
# æ°å€ã»çåœå€ã®å€æ
if value.lower() == 'true':
params[key] = True
elif value.lower() == 'false':
params[key] = False
else:
try:
params[key] = int(value)
except ValueError:
try:
params[key] = float(value)
except ValueError:
params[key] = value
_TOOL_CALL_ID_COUNTER += 1
results.append({
"id": f"fallback_{_TOOL_CALL_ID_COUNTER}",
"name": func_name,
"arguments": json.dumps(params, ensure_ascii=False),
})
return results
# ============================================================
# ã¹ããªãŒãã³ã°è¡šç€º
# ============================================================
def stream_response(messages, debug=False, silent=False):
if debug and not silent:
print(f"\n {C.YELLOW}â³ LLMåŒã³åºãäž (streaming)...{C.RESET}")
try:
stream = client.chat.completions.create(
model="qwen3.5",
messages=messages,
tools=tools,
tool_choice="auto",
temperature=0.8,
stream=True,
)
except Exception as e:
if not silent:
print(f"\n {C.BG_RED}{C.WHITE} â API ERROR {C.RESET}")
print(f" {C.RED}{type(e).__name__}: {e}{C.RESET}")
return None, None, None, "error"
full_content = ""
full_reasoning = ""
tool_calls_map = {}
finish_reason = None
in_reasoning = False
in_content = False
for chunk in stream:
delta = chunk.choices[0].delta if chunk.choices else None
if not delta:
continue
if chunk.choices[0].finish_reason:
finish_reason = chunk.choices[0].finish_reason
reasoning_text = getattr(delta, "reasoning_content", None)
if reasoning_text:
full_reasoning += reasoning_text
if not silent:
if not in_reasoning:
in_reasoning = True
print(f"\n {C.THINK}ð <think>{C.RESET}")
print(f" {C.THINK}", end="", flush=True)
print(f"{C.THINK}{reasoning_text}{C.RESET}", end="", flush=True)
else:
in_reasoning = True
if delta.content:
text = delta.content
full_content += text
if not silent:
if in_reasoning:
in_reasoning = False
print(f"{C.RESET}")
print(f" {C.THINK}ð </think>{C.RESET}")
if not in_content:
in_content = True
print(f"\n {C.WHITE}ð¬ ", end="", flush=True)
print(f"{C.WHITE}{text}{C.RESET}", end="", flush=True)
else:
in_reasoning = False
in_content = True
if delta.tool_calls:
for tc_delta in delta.tool_calls:
idx = tc_delta.index
if idx not in tool_calls_map:
tool_calls_map[idx] = {"id": tc_delta.id or "", "name": "", "arguments": ""}
if tc_delta.id:
tool_calls_map[idx]["id"] = tc_delta.id
if tc_delta.function:
if tc_delta.function.name:
tool_calls_map[idx]["name"] = tc_delta.function.name
if tc_delta.function.arguments:
tool_calls_map[idx]["arguments"] += tc_delta.function.arguments
if not silent:
if in_reasoning:
print(f"{C.RESET}")
print(f" {C.THINK}ð </think>{C.RESET}")
if in_reasoning or in_content:
print(f"{C.RESET}")
tool_calls_list = [tool_calls_map[idx] for idx in sorted(tool_calls_map.keys())]
# âââ ãã©ãŒã«ããã¯: thinking/contentå
ã® <tool_call> ãèªåããŒã¹ âââ
if not tool_calls_list:
raw_text = (full_reasoning or "") + (full_content or "")
parsed = _parse_tool_calls_from_text(raw_text)
if parsed:
if not silent:
print(f"\n {C.YELLOW}â LLMãthinkingå
ã«tool_callãåºå â ãã©ãŒã«ããã¯ããŒã¹ ({len(parsed)}ä»¶){C.RESET}")
tool_calls_list = parsed
finish_reason = "tool_calls"
# tool_calléšåãcontentããé€å»ïŒå±¥æŽæ±æãé²ãïŒ
full_content = re.sub(
r'<tool_call>.*?</tool_call>', '', full_content or '', flags=re.DOTALL
).strip()
full_reasoning = re.sub(
r'<tool_call>.*?</tool_call>', '', full_reasoning or '', flags=re.DOTALL
).strip()
return full_content, full_reasoning, tool_calls_list, finish_reason
# ============================================================
# ãããã°çš
# ============================================================
def dump_messages_summary(messages):
print(f"\n {C.DIM}{'â'*50}{C.RESET}")
print(f" {C.DIM}ð ã¡ãã»ãŒãžå±¥æŽ: {len(messages)} ä»¶{C.RESET}")
for i, msg in enumerate(messages):
role = msg.get("role", "?")
content = msg.get("content", "")
content_len = len(content) if isinstance(content, str) else 0
has_tc = "tool_calls" in msg
name = msg.get("name", "")
if role == "system":
print(f" {C.DIM} [{i}] system: ({content_len}æå){C.RESET}")
elif role == "user":
preview = (content[:40] + "...") if content_len > 40 else content
print(f" {C.DIM} [{i}] user: \"{preview}\" ({content_len}æå){C.RESET}")
elif role == "assistant":
tc_info = ""
if has_tc:
tc_names = [tc.get("function", {}).get("name", "?") for tc in msg["tool_calls"]]
tc_info = f" + tool_calls: [{', '.join(tc_names)}]"
print(f" {C.DIM} [{i}] assistant: ({content_len}æå){tc_info}{C.RESET}")
elif role == "tool":
print(f" {C.DIM} [{i}] tool({name}): ({content_len}æå){C.RESET}")
print(f" {C.DIM}{'â'*50}{C.RESET}")
# ============================================================
# åºé·å
¥åã®ãµã³ãã«ïŒãã¢çšïŒ
# ============================================================
SAMPLE_INPUTS = [
"仿¥ã®ç¹å£²ã®ãã«ãŠã§ãŒç£ãµãŒã¢ã³ã¯ãã売ãåããã鱿«ã«ããäžåºŠã»ãŒã«ããããäºåããŠãããšãåœç£é¶ããèããŸã 倧éã«æ®ã£ãŠããã匷ãã«æšããŠã",
"ååŸããéšãéãããã ãããéç©ã»ãããæšããããããšçœèãå
¥è·ããããã®ã§åé¡ã«ããã",
"ææ¥ãè¿æã®å°åŠæ ¡ã®éåäŒã ããããåŒåœææãã¢ããŒã«ããŠãåæãçšã®é¶èã¯ä»æ¥äžãªã2å²åŒã«ããã",
]
# ============================================================
# ã¡ã€ã³ã«ãŒã
# ============================================================
def main():
parser = argparse.ArgumentParser(description="ã¹ãŒããŒåºå
ã¢ããŠã³ã¹çæãã¢")
parser.add_argument("--debug", action="store_true", help="ãããã°æ
å ±ã衚瀺")
parser.add_argument("--sample", action="store_true", help="ãµã³ãã«å
¥åã䜿çš")
args = parser.parse_args()
debug = args.debug
print(f"\n{C.BOLD}{C.CYAN}{'='*62}{C.RESET}")
print(f"{C.BOLD}{C.CYAN} ðª ããŒã«ãã§ãŒã³ã㢠â ã¹ãŒããŒåºå
ã¢ããŠã³ã¹çæ{C.RESET}")
if debug:
print(f"{C.BOLD}{C.YELLOW} ð ãããã°ã¢ãŒã ON{C.RESET}")
print(f"{C.BOLD}{C.CYAN}{'='*62}{C.RESET}")
print(f"\n {C.DIM}ð¬ åºè: {CURRENT_STORE['name']} ({CURRENT_STORE['area']}){C.RESET}")
print(f" {C.DIM}ð
ã€ãã³ããã¿ãŒã³: {CURRENT_EVENTS['season']}{C.RESET}")
print(f" {C.DIM}ð€ 倩æ°å°åã³ãŒã: {CURRENT_STORE['forecast_code']}{C.RESET}\n")
# åºé·å
¥å
if args.sample:
manager_input = random.choice(SAMPLE_INPUTS)
print(f" {C.BLUE}ð€ åºé·ïŒãµã³ãã«å
¥åïŒ:{C.RESET}")
print(f" {C.BLUE} ã{manager_input}ã{C.RESET}\n")
else:
print(f" {C.BLUE}ð€ åºé·ããã®æç€ºãå
¥åããŠãã ãã:{C.RESET}")
print(f" {C.DIM} äŸ: ç¹å£²ã®ãµãŒã¢ã³ã¯å£²ãåãããé¶ããèããŸã æ®ã£ãŠãã®ã§æšããŠã{C.RESET}")
manager_input = input(f" {C.BLUE}> {C.RESET}")
if not manager_input.strip():
print(f" {C.RED}å
¥åã空ã§ããçµäºããŸãã{C.RESET}")
return
# ã·ã¹ãã ããã³ãã
system_prompt = (
"ããªãã¯ã¹ãŒããŒããŒã±ããã®åºå
ã¢ããŠã³ã¹åçš¿ãäœæããAIã¢ã·ã¹ã¿ã³ãã§ãã\n"
"åºé·ããã®æç€ºã«åºã¥ããŠãé
åçã§å¹æçãªåºå
æŸéçšã®åçš¿ãäœæããŠãã ããã\n\n"
"ãæé ã\n"
"1. ãŸã get_store_info, get_current_datetime, get_weather, get_events ãåŒã³åºããŠåºæ¬æ
å ±ãåéãã\n"
" - ãããã¯äžŠåã§åŒã³åºããŠãã ãã\n"
"2. ã€ãã³ãæ
å ±ãå€©æ°æ
å ±ãå
ã«ãsearch_knowledge ã§é¢é£ããããã©ã³åºå¡ã®ç¥èŠãæ€çŽ¢ãã\n"
" - äŸ: éåäŒãè¿ããã°ãéåäŒãã§æ€çŽ¢ãéšãªããéšãã§æ€çŽ¢ãªã©\n"
" - è€æ°ã®ããŒã¯ãŒããèããããå Žåã¯ãããããå¥ã
ã«æ€çŽ¢ããŠãã ãã\n"
"3. åéããå
šãŠã®æ
å ±ãšåºé·ã®æç€ºãç·åããŠãåºå
ã¢ããŠã³ã¹åçš¿ãäœæãã\n"
"4. æåŸã« synthesize_speech ããŒã«ã§åçš¿ãé³å£°ã«å€æããŠåºå
æŸéãã\n\n"
"ãåçš¿äœæã®ã«ãŒã«ã\n"
"- æãã芪ãã¿ãããããŒã³ã§\n"
"- ç¹å£²æ
å ±ã¯å
·äœçãªåååãšäŸ¡æ Œ/å²åŒçãå«ãã\n"
"- 倩æ°ãã€ãã³ãã«é¢é£ããææ¡ãèªç¶ã«ç¹ã蟌ã\n"
"- é·ãããªãïŒ150ã300æåçšåºŠïŒ\n"
"- ãæ¬æ¥ã¯ãããããã£ããããŸãããªã©ã®å®åçãªæžãåºãã§OK\n"
"- ãã¬ããžDBã®ç¥èŠã掻çšããŠã売ãçååã®ææ¡ãçã蟌ã\n\n"
"ãéèŠã\n"
"- å
šãŠã®ããŒã«ã䜿ã£ãŠæ
å ±ãéããŠããåçš¿ãäœæããŠãã ãã\n"
"- åçš¿ã宿ãããå¿
ã synthesize_speech ã§èªã¿äžããŠãã ãã\n"
)
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"ãåºé·ããã®æç€ºã\n{manager_input}"},
]
step = 0
max_steps = 15
while step < max_steps:
step += 1
print(f"\n{C.BOLD}{C.WHITE}{C.BG_BLUE} STEP {step} {C.RESET}")
if debug:
dump_messages_summary(messages)
full_content, full_reasoning, tool_calls_list, finish_reason = stream_response(messages, debug)
if full_content is None:
break
if debug:
print(f"\n {C.CYAN} finish_reason: {C.BOLD}{finish_reason}{C.RESET}")
# ããŒã«åŒã³åºããªã â æçµå¿ç
if not tool_calls_list:
print(f"\n {C.GREEN}â
ã¢ããŠã³ã¹åçš¿çæå®äº{C.RESET}")
break
# ã¢ã·ã¹ã¿ã³ãã¡ãã»ãŒãžãå±¥æŽè¿œå
assistant_msg = {"role": "assistant", "content": full_content or ""}
assistant_msg["tool_calls"] = [
{
"id": tc["id"],
"type": "function",
"function": {"name": tc["name"], "arguments": tc["arguments"]},
}
for tc in tool_calls_list
]
messages.append(assistant_msg)
# ããŒã«å®è¡
print(f"\n {C.YELLOW}{'â'*50}{C.RESET}")
print(f" {C.YELLOW}â¡ ããŒã«å®è¡: {len(tool_calls_list)}ä»¶{C.RESET}")
for tc in tool_calls_list:
func_name = tc["name"]
try:
tc_args = json.loads(tc["arguments"])
except json.JSONDecodeError:
tc_args = {}
# ããŒã«å衚瀺
icon_map = {
"get_store_info": "ð¬",
"get_current_datetime": "ð
",
"get_weather": "ð€ ",
"get_events": "ð",
"search_knowledge": "ð",
"synthesize_speech": "ð",
}
icon = icon_map.get(func_name, "âïž")
print(f"\n {C.YELLOW}{icon} {func_name}{C.RESET}")
if func_name == "search_knowledge":
print(f" {C.GRAY} query: \"{tc_args.get('query', '')}\"{C.RESET}")
elif func_name == "synthesize_speech":
text_preview = tc_args.get("text", "")[:80]
print(f" {C.GRAY} text: \"{text_preview}...\"{C.RESET}")
result = execute_tool(func_name, tc_args)
result_obj = json.loads(result)
# çµæè¡šç€º
if func_name == "get_store_info":
print(f" {C.GREEN} â
{result_obj.get('store_name', '')} / {result_obj.get('current_period', '')}{C.RESET}")
elif func_name == "get_current_datetime":
print(f" {C.GREEN} â
{result_obj.get('datetime', '')}{C.RESET}")
elif func_name == "get_weather":
if "error" in result_obj:
print(f" {C.RED} â {result_obj['error']}{C.RESET}")
else:
overview = result_obj.get("overview", "")[:80]
print(f" {C.GREEN} â
{overview}...{C.RESET}")
elif func_name == "get_events":
season = result_obj.get("season", "")
ev_count = len(result_obj.get("general_events", [])) + len(result_obj.get("school_events", []))
print(f" {C.GREEN} â
{season}ãã¿ãŒã³ / {ev_count}ä»¶ã®ã€ãã³ã{C.RESET}")
elif func_name == "search_knowledge":
if result_obj.get("found"):
print(f" {C.GREEN} â
{result_obj.get('count', 0)}ä»¶ã®ç¥èŠãããã{C.RESET}")
# ãã¬ããžå
容ã®äžéšã衚瀺
knowledge = result_obj.get("knowledge", "")
for line in knowledge.split("\n")[:3]:
print(f" {C.DIM} {line}{C.RESET}")
print(f" {C.DIM} ...{C.RESET}")
else:
print(f" {C.YELLOW} â ããããªã{C.RESET}")
elif func_name == "synthesize_speech":
if result_obj.get("status") == "success":
print(f" {C.GREEN} â
é³å£°åçå®äº{C.RESET}")
else:
print(f" {C.RED} â {result_obj.get('message', '')}{C.RESET}")
messages.append({
"role": "tool",
"tool_call_id": tc["id"],
"name": func_name,
"content": result,
})
print(f" {C.YELLOW}{'â'*50}{C.RESET}")
# ãµããªãŒ
print(f"\n{C.DIM}{'='*62}{C.RESET}")
print(f"{C.DIM}æçµã¹ããã: {step}{C.RESET}")
print(f"{C.DIM}ã¡ãã»ãŒãžæ°: {len(messages)}{C.RESET}")
print(f"{C.DIM}{'='*62}{C.RESET}\n")
if __name__ == "__main__":
main()
ãã³ãããŒã¯çµæ/benchmark result
shisa-ai/M-IFEval ã䜿ã£ãŠèšæž¬ããæ¥æ¬èªã«ãããæç€ºè¿œåŸæ§èœã¯ä»¥äžã§ãã
Ability to follow Japanese instructions measured using shisa-ai/M-IFEval is as follows.
Unslothã¯éååã¢ãã«ã§äžççã«æåã§ãããããä»åã圌ãã®ã¢ãã«ã«ææŠããŸããã
è±èªãã¡ã€ã³ã«äœ¿çšããå Žåã¯Unslothã®ã¢ãã«ã®æ¹ãæ§èœãé«ããšæãããã®ã§çæããŠãã ããã
9Bã4Bããäœããªã£ãŠããçç±ã¯ã¢ãã«ãæ°ããŸãããçµæãæžç¹ãããäºãããããã§ãã
äŸãã°ãç©èªã®æžãå§ãã¯ãäžç« ãããå§ããŠãã ããããšããæç€ºã«å¯ŸããŠ
# äžç«
ã®ããã«æŽåœ¢ããŠæžç¹ãããäºããããŸãã
Since Unsloth are world-renowned experts in quantization models, I decided to try their models this time.
Please note that their models are likely to perform better if you primarily use English.
The reason why 9B is lower than 4B is that the model may have to pay attention to details, which can result in deductions.
For example, if the instruction is to start the story with "Chapter One,"
# Chapter One
you might lose points for formatting it like this.
| Model Name | Strict Prompt | Strict Inst | Loose Prompt | Loose Inst |
|---|---|---|---|---|
| Unsloth-Q4_K_XL | 0.5756 | 0.6062 | 0.6220 | 0.6416 |
| Qwen3.5-9B-UD-japanese-imatrix-Q4_K_XL | 0.6047 | 0.6504 | 0.6570 | 0.6903 |
update
- 2026/04/09 fix prompt template for cache reuse issue
è¬èŸ / Acknowledgments
äœæè / Developer
éçºïŒdahara1@Webbigdata / Developed by dahara1@Webbigdata