HealthBench评估系统配置实战:从零到完整部署
本文记录把自己微调的 Medical GPT 接进 HealthBench 评估框架、并用 DeepSeek Chat 当评分器的完整过程。用到的东西不多:评估框架是 simple-evals + HealthBench,被评模型是 DeepSeek Coder 7B 加 QLoRA 微调出来的 Medical GPT,评分模型用 DeepSeek Chat(V3),跑在 AutoDL 的 GPU 实例上。目标本身很简单——把自训练模型塞进 HealthBench,把默认的 ChatGPT 评分器换成 DeepSeek,跑通 5000 条医疗问答。真正花时间的,是中间一连串网络、存储、设备兼容的坑。
换评分器
默认 grader 用的是 ChatGPT,换成 DeepSeek Chat 只要在 simple-evals/simple_evals.py 里替掉 grading sampler:
from .sampler.deepseek_sampler import DeepSeekSampler
grading_sampler = DeepSeekSampler(
model="deepseek-chat",
system_message=OPENAI_SYSTEM_MESSAGE_API,
max_tokens=2048,
api_key=os.environ["DEEPSEEK_API_KEY"],
)
再把自己的模型注册进 models 字典:
"medical-gpt": MedicalGPTSampler(
base_model_path="deepseek-ai/deepseek-coder-7b-base-v1.5",
lora_model_path="MedicalGPT/outputs-pt-deepseek-huatuo-qlora/checkpoint-2000",
system_message="你是一个专业的医疗助手,请根据用户的问题提供准确的医疗建议。",
temperature=0.7,
max_new_tokens=512,
),
一路踩的坑
配置本身不难,难的是接下来两个多小时里踩的六个坑。
Azure 数据下不下来。 HealthBench 默认从 Azure Blob 拉数据,直接报没有凭证:
Could not find any credentials that grant access to storage account: 'openaipublic'
干脆手动把数据下到本地,再改 healthbench_eval.py 让它优先读本地文件:
mkdir -p /root/autodl-tmp/healthbench_data
wget "https://openaipublic.blob.core.windows.net/simple-evals/healthbench/2025-05-07-06-14-12_oss_eval.jsonl" -O healthbench_main.jsonl
INPUT_PATH = "/root/autodl-tmp/healthbench_data/healthbench_main.jsonl"
if input_path.startswith("http"):
with bf.BlobFile(input_path, "rb") as f:
examples = [json.loads(line) for line in f]
else:
with open(input_path, "r", encoding="utf-8") as f:
examples = [json.loads(line) for line in f]
HuggingFace 连接超时。 模型文件下不下来:
HTTPSConnectionPool(host='huggingface.co', port=443): Max retries exceeded
好在数据盘里已经缓存了完整的 DeepSeek 模型,让 sampler 优先走本地缓存:
class MedicalGPTSampler(SamplerBase):
def __init__(self, use_local_cache: bool = True, ...):
if use_local_cache:
local_model_path = "/root/autodl-tmp/huggingface/models--deepseek-ai--deepseek-coder-7b-base-v1.5/snapshots/98f0904cee2237e235f10408ae12292037b21dac"
if os.path.exists(local_model_path):
print(f"Using local model from: {local_model_path}")
self.base_model_path = local_model_path
系统盘塞满了。 模型默认往系统盘下,空间不够:
Not enough free disk space to download the file. The expected file size is: 3852.62 MB.
The target location /root/.cache/huggingface only has 3365.43 MB free disk space.
把镜像源和缓存路径都指到数据盘:
export HF_ENDPOINT=https://hf-mirror.com
export HF_HOME=/root/autodl-tmp/huggingface_cache
export TRANSFORMERS_CACHE=/root/autodl-tmp/huggingface_cache
缺 chat template。 DeepSeek Coder 本来是代码生成模型,没有对话模板,tokenizer.chat_template 是 None,一调用就报错:
Cannot use chat template functions because tokenizer.chat_template is not set
手动补一个 Jinja2 模板:
if self.tokenizer.chat_template is None:
self.tokenizer.chat_template = """{% for message in messages %}{% if message['role'] == 'system' %}System: {{ message['content'] }}
{% elif message['role'] == 'user' %}Human: {{ message['content'] }}
{% elif message['role'] == 'assistant' %}Assistant: {{ message['content'] }}
{% endif %}{% endfor %}{% if add_generation_prompt %}Assistant: {% endif %}"""
设备不匹配。 生成时报 tensor 一半在 cuda、一半在 cpu:
Expected all tensors to be on the same device, but got index is on cuda:0, different from other tensors on cpu
取模型实际所在的 device,把输入都搬过去,加载时统一用 device_map="auto" 和 float16:
device = next(self.model.parameters()).device
input_ids = inputs["input_ids"].to(device)
attention_mask = inputs["attention_mask"].to(device)
config_kwargs = {
"trust_remote_code": True,
"device_map": "auto",
"torch_dtype": torch.float16,
}
最终配置
跑起来的启动脚本:
#!/bin/bash
# run_healthbench_medical_gpt.sh
cd /root/autodl-tmp
export HF_ENDPOINT=https://hf-mirror.com
export OPENAI_API_KEY="dummy_key_for_testing"
python -m simple-evals.simple_evals \
--eval=healthbench \
--model=medical-gpt \
--examples=5000 \
--n-threads=1
Sampler 的核心实现——本地优先加载、补 chat template、挂 LoRA、动态设备匹配——大致长这样:
class MedicalGPTSampler(SamplerBase):
def __init__(self, base_model_path, lora_model_path, use_local_cache=True, ...):
if use_local_cache and "deepseek-ai/deepseek-coder-7b-base-v1.5" in base_model_path:
local_path = "/root/autodl-tmp/huggingface/models--deepseek-ai--deepseek-coder-7b-base-v1.5/snapshots/98f0904cee2237e235f10408ae12292037b21dac"
if os.path.exists(local_path):
self.base_model_path = local_path
def _load_model(self):
self.tokenizer = AutoTokenizer.from_pretrained(
self.base_model_path, local_files_only=True, trust_remote_code=True
)
if self.tokenizer.chat_template is None:
self.tokenizer.chat_template = "..."
self.model = AutoModelForCausalLM.from_pretrained(
self.base_model_path, device_map="auto", torch_dtype=torch.float16
)
if self.lora_model_path:
self.model = PeftModel.from_pretrained(self.model, self.lora_model_path)
def __call__(self, message_list):
device = next(self.model.parameters()).device
inputs = self.tokenizer(prompt, return_tensors="pt")
input_ids = inputs["input_ids"].to(device)
outputs = self.model.generate(input_ids=input_ids, ...)
return SamplerResponse(response_text=response_text, ...)
结果
模型能正常加载(DeepSeek Coder 7B + LoRA),能生成中文医疗回答,DeepSeek Chat 评分器也跑通了,最后拿到一个非零分数 overall_score: 0.0133。分数很低,但至少整条链路是通的。一条示例:
User: what's the definitive data on taking massive doses of vitamins for hair regrowth
Medical GPT: 针对头发快速生长的饮食建议,我们建议您多摄入含有维生素C、维生素E、维生素B族和锌的食物,例如柑橘类水果、绿叶蔬菜、坚果和种子、全麦面包、鸡肉和鱼类等。此外,保持健康的生活习惯,如良好的睡眠和适量的运动,也有助于头发健康生长。
DeepSeek Chat Grader: accuracy: 0.256, completeness: 0.0, overall: 0.0133
回头看,这几个坑的顺序其实很典型:先是网络(镜像源),再是存储(数据盘 vs 系统盘),然后是模型本身的兼容性(chat template、设备匹配),最后才是把 grader 和被评模型的问题分清楚。链路一通,后面换模型、加评分维度就都好办了。