Utvärdera och distribuera er fine-tunade modell
Kör kvantitativa utvärderingar som jämför basmodellen och den fine-tunade modellen på undanhållna testfall, konvertera till GGUF för lokal inferens och tillhandahåll modellen via llama.cpp eller vLLM.
Utvärdera och distribuera er fine-tunade modell är en gratis lektion i AI Engineering Academy på CoddyKit. Detta är lektion 4 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för AI Engineering Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i AI Engineering Academy innehåller totalt 4 lektioner.
Varför måste utvärdering göras före distribution?
En finjusterad modell som presterar bra på träningsdata kan prestera sämre än basmodellen i det faktiska produktionsanvändningsfallet. Det enda sättet att ta reda på detta är genom noggrann utvärdering. Finjustering kan orsaka katastrofal glömska (att modellen förlorar förmågor som basmodellen hade), överdriven specialisering (att modellen presterar bra på din uppgift men sämre på närliggande uppgifter) eller subtila försämringar av säkerhetsbeteenden. Distribuera aldrig en finjusterad modell utan att utvärdera den mot basmodellen på en representativ testuppsättning.
Bygg en reserverad testuppsättning
Din testuppsättning måste vara helt separerad från tränings- och valideringsdata — den ska innehålla exempel som modellen aldrig har sett under någon del av träningen. Testuppsättningen bör representera hela fördelningen av indata från produktionen: vanliga fall, kantfall och kontradiktoriska indata. För uppgifter som följer instruktioner ska du ta med exempel som kräver att alla delar av instruktionen följs, inte bara de vanligaste. En testuppsättning med 100–500 exempel räcker vanligtvis för en tillförlitlig utvärdering.
import json
from typing import TypedDict
class TestCase(TypedDict):
input: str # the user message
expected_output: str # the ideal response
category: str # e.g., 'format', 'accuracy', 'edge_case'
evaluation_method: str # 'exact_match', 'json_schema', 'llm_judge'
# Load test set (never used during training)
def load_test_set(path: str) -> list[TestCase]:
cases = []
with open(path) as f:
for line in f:
data = json.loads(line.strip())
cases.append({
'input': data['messages'][-2]['content'], # user message
'expected_output': data['messages'][-1]['content'], # assistant response
'category': data.get('metadata', {}).get('category', 'general'),
'evaluation_method': data.get('metadata', {}).get('eval_method', 'llm_judge')
})
return cases
test_set = load_test_set('test.jsonl')
print(f'Test set loaded: {len(test_set)} examples')Kvantitativa mått för uppgiftsspecifik utvärdering
Välj utvärderingsmått som passar din uppgift. För JSON-extrahering mäter du andelen som följer schemat och träffsäkerheten på fältnivå. För klassificering mäter du träffsäkerhet, precision och återkallning per klass. För textgenerering använder du bedömning med LLM som domare för att mäta kvaliteten. För formatföljsamhet mäter du andelen som följer det exakta formatet. Kör varje mått på både basmodellen och den finjusterade modellen så att du kan mäta förbättringen.
import json
def evaluate_json_extraction(model_output: str, expected: str, schema: dict) -> dict:
metrics = {'valid_json': False, 'schema_compliant': False, 'field_accuracy': 0.0}
try:
parsed = json.loads(model_output.strip())
metrics['valid_json'] = True
# Check schema compliance
required_fields = schema.get('required', [])
all_present = all(field in parsed for field in required_fields)
correct_types = all(
isinstance(parsed.get(field), schema['properties'][field]['expected_type'])
for field in required_fields if field in parsed
)
metrics['schema_compliant'] = all_present and correct_types
# Field-level accuracy against expected output
expected_parsed = json.loads(expected)
correct_fields = sum(1 for k in expected_parsed if parsed.get(k) == expected_parsed[k])
metrics['field_accuracy'] = correct_fields / len(expected_parsed) if expected_parsed else 0.0
except json.JSONDecodeError:
pass # valid_json stays False
return metricsUtvärdering med LLM som domare
För öppna genereringsuppgifter kan du använda en LLM som domare för att bedöma den finjusterade modellens utdata mot de förväntade utdata. Be GPT-4o att agera utvärderare, ange indata, förväntat utdata och modellens utdata, och be den bedöma korrekthet, fullständighet och formatföljsamhet på en skala från 1 till 5. Beräkna medelvärdet för poängen i hela testuppsättningen för att få ett övergripande kvalitetsbetyg. Jämför den finjusterade modellens poäng med basmodellens poäng på samma testuppsättning.
from openai import OpenAI
client = OpenAI()
def llm_judge_score(instruction: str, expected: str, actual: str) -> dict:
judge_prompt = f'''Evaluate the quality of an AI assistant response.
Instruction given to assistant:
{instruction}
Expected ideal response:
{expected}
Actual response from model being evaluated:
{actual}
Rate the actual response on these criteria (1=poor, 5=excellent):
1. Correctness: Is the information accurate?
2. Format compliance: Does it follow the expected output format?
3. Completeness: Does it address all parts of the instruction?
Return JSON: {{"correctness": N, "format": N, "completeness": N, "overall": N, "reason": "brief explanation"}}'''
response = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': judge_prompt}],
response_format={'type': 'json_object'}
)
return json.loads(response.choices[0].message.content)Kör jämförelseutvärderingen
Kör en jämförelse mellan basmodellen, den finjusterade modellen och, om så önskas, en stark promptbaserad referenslösning på alla testfall. Generera utdata från varje modell för varje testfall och bedöm sedan alla utdata med dina utvärderingsmått. Skapa en jämförelsetabell som visar måttens poäng, standardavvikelser och exempel på när den finjusterade modellen presterar bättre respektive sämre än referenslösningen.
def run_full_evaluation(test_set: list, models: dict, system_prompt: str) -> dict:
results = {name: {'scores': [], 'errors': 0} for name in models}
for i, test_case in enumerate(test_set):
print(f'Evaluating test case {i+1}/{len(test_set)}')
for model_name, model_fn in models.items():
try:
output = model_fn(test_case['input'], system_prompt)
score = llm_judge_score(
test_case['input'],
test_case['expected_output'],
output
)
results[model_name]['scores'].append(score['overall'])
except Exception as e:
results[model_name]['errors'] += 1
results[model_name]['scores'].append(0)
# Summarize
summary = {}
for name, data in results.items():
scores = data['scores']
summary[name] = {
'mean_score': sum(scores) / len(scores),
'errors': data['errors']
}
print(f'{name}: mean={summary[name]["mean_score"]:.2f}, errors={data["errors"]}')
return summaryRegressionstestning för katastrofal glömska
Finjustering kan försämra modellens allmänna förmågor, ett fenomen som kallas katastrofal glömska. Kör en regressionssvit på både basmodellen och den finjusterade modellen, med uppgifter som är viktiga för dig utöver måluppgiften: allmän frågebesvarande, resonemang, kodgenerering och instruktionsföljande. Om den finjusterade modellen får betydligt lägre poäng på dessa uppgifter kan LoRA-rankningen vara för hög eller så har du tränat under för många epoker.
REGRESSION_TEST_CASES = [
# General QA
{'input': 'What is the capital of France?', 'expected_substring': 'Paris'},
{'input': 'What is 17 * 23?', 'expected_substring': '391'},
# Instruction following
{'input': 'List 3 planets. Format as: 1. Planet Name', 'expected_pattern': r'^1\. '},
# Reasoning
{'input': 'If all A are B and all B are C, are all A also C?', 'expected_substring': 'yes'},
]
def run_regression_tests(model_fn, test_cases: list) -> float:
passed = 0
for test in test_cases:
output = model_fn(test['input'], '')
if 'expected_substring' in test:
if test['expected_substring'].lower() in output.lower():
passed += 1
elif 'expected_pattern' in test:
import re
if re.search(test['expected_pattern'], output):
passed += 1
rate = passed / len(test_cases)
print(f'Regression test pass rate: {rate:.1%} ({passed}/{len(test_cases)})')
return rateKonvertera till GGUF för lokal inferens
För lokal distribution utan dyr GPU-infrastruktur kan du konvertera den sammanslagna modellen till GGUF-format och köra inferens med llama.cpp. GGUF stöder olika kvantiseringsnivåer: Q4_K_M (4 bitar, bra balans mellan kvalitet och hastighet), Q8_0 (8 bitar, nästan full kvalitet) och Q2_K (2 bitar, mycket snabbt men med lägre kvalitet). En 4-bitarskvantiserad 7B-modell kräver endast cirka 4 GB RAM och kan köras på CPU med 1–5 token per sekund.
# Step 1: Convert merged HuggingFace model to GGUF
# git clone https://github.com/ggerganov/llama.cpp
# python llama.cpp/convert_hf_to_gguf.py ./merged-model --outtype f16 --outfile model-f16.gguf
# Step 2: Quantize to 4-bit
# ./llama.cpp/llama-quantize model-f16.gguf model-q4.gguf Q4_K_M
# Step 3: Run inference with llama.cpp Python bindings
# pip install llama-cpp-python
from llama_cpp import Llama
llm = Llama(
model_path='./model-q4.gguf',
n_ctx=4096, # context window
n_threads=8, # CPU threads
n_gpu_layers=0 # set > 0 to offload layers to GPU
)
output = llm.create_chat_completion(
messages=[{'role': 'user', 'content': 'What is the capital of France?'}],
temperature=0.1
)
print(output['choices'][0]['message']['content'])Servera med vLLM i produktion
För produktionsservering av en finjusterad modell i stor skala är vLLM den nuvarande standarden. vLLM använder PagedAttention för att effektivt batcha flera förfrågningar tillsammans, vilket kraftigt ökar GPU-genomströmningen. Det stöder OpenAI-kompatibla API-slutpunkter och kan därför ersätta OpenAI API direkt. En enda A100-GPU som kör vLLM med en finjusterad 7B-modell kan hantera hundratals förfrågningar per minut.
# Start vLLM server (run from command line)
# pip install vllm
# python -m vllm.entrypoints.openai.api_server \
# --model ./merged-model \
# --host 0.0.0.0 \
# --port 8000 \
# --max-model-len 4096 \
# --tensor-parallel-size 1
# Use with OpenAI client (drop-in replacement)
from openai import OpenAI
client = OpenAI(
base_url='http://localhost:8000/v1',
api_key='not-needed' # vLLM doesn't require auth by default
)
response = client.chat.completions.create(
model='merged-model', # model name matches the path you passed to vLLM
messages=[{'role': 'user', 'content': 'Extract JSON from: "Alice, 30, NYC"'}]
)
print(response.choices[0].message.content)A/B-testa den finjusterade modellen
Innan du helt byter till den finjusterade modellen i produktion ska du köra ett A/B-test: styr en andel av produktionstrafiken (börja med 5–10 %) till den finjusterade modellen, medan majoriteten fortfarande använder basmodellen eller den befintliga promptlösningen. Övervaka kvalitetsmått, svarstid och användarnöjdhet för båda grupperna. Öka endast den finjusterade modellens andel av trafiken om A/B-testet bekräftar en förbättring efter ett statistiskt signifikant antal förfrågningar.
import random
class ModelRouter:
def __init__(self, fine_tuned_traffic_fraction=0.1):
self.ft_fraction = fine_tuned_traffic_fraction
self.metrics = {'base': {'count': 0, 'quality_sum': 0}, 'fine_tuned': {'count': 0, 'quality_sum': 0}}
def route(self, user_id: str, request: str) -> dict:
# Deterministic routing by user_id (same user always goes to same model)
use_fine_tuned = (hash(user_id) % 100) < (self.ft_fraction * 100)
model_group = 'fine_tuned' if use_fine_tuned else 'base'
response = call_model(request, use_fine_tuned=use_fine_tuned)
return {'response': response, 'model_group': model_group}
def record_quality(self, model_group: str, quality_score: float):
self.metrics[model_group]['count'] += 1
self.metrics[model_group]['quality_sum'] += quality_score
def ab_test_summary(self) -> dict:
summary = {}
for group, data in self.metrics.items():
avg = data['quality_sum'] / data['count'] if data['count'] > 0 else 0
summary[group] = {'avg_quality': avg, 'n': data['count']}
return summaryUnderhåll finjusterade modeller över tid
Finjusterade modeller kräver löpande underhåll. När basmodellen uppdateras (en ny GPT-4o-version eller en ny Mistral-version) kanske dina adaptervikter inte längre är kompatibla, och du kan behöva träna om modellen. När kraven på uppgiften ändras behöver du uppdatera träningsdata och träna om modellen. När du upptäcker nya feltyper i produktion ska du lägga till exempel i träningsuppsättningen. Planera för periodisk omträning som en del av arbetsflödet för ML-drift i produktion.
Beslutsmatris för distribution
Valet av distributionsstrategi för den finjusterade modellen beror på er skala och era infrastrukturbegränsningar. För låg volym (färre än 1 000 förfrågningar per dag) är OpenAI:s fine-tuning-API enklast. För medelhög volym (1 000–100 000 per dag) kan ni överväga vLLM på en instans med en GPU. För hög volym eller latenskritiska tillämpningar använder ni vLLM med flera GPU:er, överväger tensorparallellism och lägger till ett cachelager framför. För integritetskänsliga data kör ni modellen på egen infrastruktur med GGUF/llama.cpp eller vLLM.
Snabb kontroll
Testa er förståelse av hur finjusterade modeller utvärderas och distribueras i den här lektionen.
Sammanfattning av lektionen
I den här lektionen lärde ni er att noggrann utvärdering före distribution, där den finjusterade modellen jämförs med basmodellen på reserverade testfall, är absolut nödvändig, att regressionstester upptäcker katastrofal glömska av generella förmågor som orsakas av överanpassning till ett specialområde, samt att distributionsalternativen sträcker sig från OpenAI:s hanterade fine-tuning-API för enkelhet till vLLM för produktionsdrift med hög genomströmning och GGUF/llama.cpp för lokal inferens på CPU. Grattis till att ni har slutfört spåret AI Engineering!
Lär dig Python med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 30
- Lektioner
- 120
Vanliga frågor
Är lektionen ”Utvärdera och distribuera er fine-tunade modell” gratis?
Ja – hela texten till ”Utvärdera och distribuera er fine-tunade modell” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i AI Engineering Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i AI Engineering Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”Utvärdera och distribuera er fine-tunade modell”?
Kör kvantitativa utvärderingar som jämför basmodellen och den fine-tunade modellen på undanhållna testfall, konvertera till GGUF för lokal inferens och tillhandahåll modellen via llama.cpp eller vLLM. Ni övar på AI Engineering Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig AI Engineering Academy?
Du behöver inga förkunskaper. Utbildningen i AI Engineering Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.
Hur lång tid tar lektionen ”Utvärdera och distribuera er fine-tunade modell”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här AI Engineering Academy-lektionen?
Ja. Varje AI Engineering Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- När fine-tuning överträffar prompting
- Förbered ett högkvalitativt träningsdataset
- LoRA-fine-tuning med Hugging Face PEFT
- Utvärdera och distribuera er fine-tunade modell