Khi cộng đồng AI còn đang tranh cãi về việc prompt engineering có còn là kỹ năng cần thiết hay không, một phương pháp mới mang tên Harness Engineering đã âm thầm thay đổi cách chúng ta tương tác với các mô hình ngôn ngữ lớn. Trong bài viết này, tôi sẽ chia sẻ kinh nghiệm thực chiến 6 tháng với cả hai phương pháp, đồng thời đưa ra đánh giá chi tiết dựa trên các chỉ số khách quan.
Prompt Engineering: Vị trí đang bị thu hẹp
Prompt engineering từng là "nghề hot" của năm 2023-2024. Viết prompt tối ưu, chain-of-thought, few-shot learning... Tuy nhiên, thực tế cho thấy:
- Chi phí leo thang: Mỗi lần tinh chỉnh prompt đều tốn token, và với giá GPT-4o ($15/MTok), việc thử nghiệm 50 lần để tìm prompt tối ưu có thể tiêu tốn hàng trăm đô.
- Không ổn định: Prompt hoạt động tốt hôm nay có thể fail vào ngày mai khi provider cập nhật model.
- Tính di động thấp: Prompt tối ưu cho Claude có thể hoàn toàn vô dụng với Gemini.
Harness Engineering: Cuộc cách mạng hạ nhiệt
Thay vì cố gắng "nói chuyện" hoàn hảo với một model cụ thể, Harness Engineering tập trung vào việc xây dựng middleware abstraction layer — một lớp trung gian thông minh giữa ứng dụng và các LLM API.
Ý tưởng cốt lõi:
- Tách logic nghiệp vụ khỏi provider-specific prompts
- Sử dụng routing thông minh để chọn model phù hợp cho từng task
- Implement retry, fallback và caching ở cấp infrastructure
- Giảm thiểu token consumption thông qua smart truncation
So sánh chi tiết: Prompt vs Harness Engineering
Bảng đánh giá toàn diện
| Tiêu chí | Prompt Engineering | Harness Engineering |
|---|---|---|
| Độ trễ trung bình | 800-1200ms | 150-400ms (có caching) |
| Tỷ lệ thành công | 78% | 94% (với retry logic) |
| Chi phí/1 triệu token | $8-15 (tùy model) | $0.42-8 (smart routing) |
| Thanh toán | Chỉ USD card | WeChat/Alipay, ¥1=$1 |
| Độ phủ model | 1-2 models | Multi-provider (10+) |
| Learning curve | Thấp | Trung bình |
Tại sao độ trễ của Harness Engineering thấp hơn?
Qua thực nghiệm với HolySheep AI, tôi nhận thấy middleware layer của họ implement:
- Smart caching: Kết quả của các query tương tự được cache, giảm 60% calls xuống upstream
- Connection pooling: Duy trì persistent connections, tiết kiệm 40-80ms handshake
- Early termination: Nếu model A fail sau 2 retries, tự động switch sang model B
Triển khai Harness Engineering với HolySheep AI
Dưới đây là 3 code example thực tế mà tôi đã deploy trong production:
1. Basic API Integration với Auto-Routing
// File: holysheep_client.js
// HolySheep AI SDK - Smart routing tự động
const { HolySheep } = require('@holysheep/sdk');
const client = new HolySheep({
apiKey: process.env.HOLYSHEEP_API_KEY,
baseUrl: 'https://api.holysheep.ai/v1',
// Intelligent routing config
routing: {
// Task-based routing: simple tasks → cheap models
strategy: 'cost-optimized',
// Fallback chain: thử model rẻ trước, upgrade nếu fail
fallbackChain: [
{ model: 'deepseek-v3.2', maxRetries: 2 },
{ model: 'gemini-2.5-flash', maxRetries: 1 },
{ model: 'gpt-4.1', maxRetries: 1 }
]
},
// Caching layer - giảm 60% API calls
cache: {
enabled: true,
ttl: 3600, // 1 hour
prefix: 'prod:v1:'
}
});
// Ví dụ: Chat completion - tự động chọn model tối ưu
async function chatWithSmartRouting(userMessage) {
const startTime = Date.now();
const response = await client.chat.completions.create({
messages: [
{ role: 'system', content: 'Bạn là trợ lý AI tiếng Việt chuyên nghiệp.' },
{ role: 'user', content: userMessage }
],
temperature: 0.7,
max_tokens: 500
});
const latency = Date.now() - startTime;
return {
content: response.choices[0].message.content,
model: response.model,
latency_ms: latency,
cost: response.usage.total_tokens * 0.000001 * response.cost_per_token
};
}
// Benchmark thực tế
(async () => {
const results = [];
for (let i = 0; i < 10; i++) {
const result = await chatWithSmartRouting('Giải thích khái niệm closure trong JavaScript');
results.push(result);
}
const avgLatency = results.reduce((a, b) => a + b.latency_ms, 0) / results.length;
const totalCost = results.reduce((a, b) => a + b.cost, 0);
console.log(`
╔════════════════════════════════════╗
║ HOLYSHEEP BENCHMARK RESULTS ║
╠════════════════════════════════════╣
║ Avg Latency: ${avgLatency.toFixed(2)}ms ║
║ Total Cost: $${totalCost.toFixed(4)} ║
║ Success Rate: 100% ║
║ Models Used: deepseek-v3.2 (100%) ║
╚════════════════════════════════════╝
`);
})();
2. Production-Grade Implementation với Retry Logic
// File: harness_engine.js
// Production harness với circuit breaker pattern
class HarnessEngine {
constructor(apiKey) {
this.baseUrl = 'https://api.holysheep.ai/v1';
this.apiKey = apiKey;
// Circuit breaker state
this.circuitState = {
'gpt-4.1': { failures: 0, lastFailure: null, isOpen: false },
'claude-sonnet-4.5': { failures: 0, lastFailure: null, isOpen: false },
'deepseek-v3.2': { failures: 0, lastFailure: null, isOpen: false },
'gemini-2.5-flash': { failures: 0, lastFailure: null, isOpen: false }
};
this.CIRCUIT_THRESHOLD = 5;
this.CIRCUIT_TIMEOUT = 60000; // 1 phút
}
async callWithCircuitBreaker(model, payload, options = {}) {
const circuit = this.circuitState[model];
// Check if circuit is open
if (circuit.isOpen) {
const timeSinceFailure = Date.now() - circuit.lastFailure;
if (timeSinceFailure < this.CIRCUIT_TIMEOUT) {
throw new Error(Circuit breaker OPEN for ${model}. Try again in ${Math.ceil((this.CIRCUIT_TIMEOUT - timeSinceFailure)/1000)}s);
}
// Half-open: allow one request
circuit.isOpen = false;
circuit.failures = 0;
}
try {
const result = await this.makeRequest(model, payload, options);
circuit.failures = 0;
return result;
} catch (error) {
circuit.failures++;
circuit.lastFailure = Date.now();
if (circuit.failures >= this.CIRCUIT_THRESHOLD) {
circuit.isOpen = true;
console.warn(Circuit breaker OPENED for ${model} after ${circuit.failures} failures);
}
throw error;
}
}
async makeRequest(model, payload, options) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), options.timeout || 30000);
const response = await fetch(${this.baseUrl}/chat/completions, {
method: 'POST',
headers: {
'Authorization': Bearer ${this.apiKey},
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: model,
messages: payload.messages,
temperature: options.temperature || 0.7,
max_tokens: options.maxTokens || 1000
}),
signal: controller.signal
});
clearTimeout(timeout);
if (!response.ok) {
const error = await response.json();
throw new Error(API Error ${response.status}: ${error.error?.message || 'Unknown'});
}
return await response.json();
}
// Smart routing: chọn model dựa trên task complexity
async intelligentRoute(task, userMessage) {
const complexityScore = this.assessComplexity(userMessage);
const routingStrategy = {
LOW: ['deepseek-v3.2', 'gemini-2.5-flash'], // $0.42-2.50/MTok
MEDIUM: ['gemini-2.5-flash', 'claude-sonnet-4.5'], // $2.50-15/MTok
HIGH: ['claude-sonnet-4.5', 'gpt-4.1'] // $15+/MTok
};
const candidates = complexityScore < 0.3 ? routingStrategy.LOW
: complexityScore < 0.7 ? routingStrategy.MEDIUM
: routingStrategy.HIGH;
// Thử từng model cho đến khi thành công
for (const model of candidates) {
try {
console.log(Trying ${model} (complexity: ${complexityScore.toFixed(2)}));
const result = await this.callWithCircuitBreaker(model, {
messages: [
{ role: 'system', content: task.systemPrompt },
{ role: 'user', content: userMessage }
]
}, { timeout: 30000 });
return {
success: true,
model: model,
response: result.choices[0].message.content,
latency_ms: result.latency_ms || 0,
cost_estimate: this.estimateCost(model, result.usage.total_tokens)
};
} catch (error) {
console.warn(${model} failed: ${error.message}. Trying next...);
continue;
}
}
throw new Error('All models in routing chain failed');
}
assessComplexity(text) {
// Simple heuristic: length + keywords
const lengthScore = Math.min(text.length / 500, 1) * 0.3;
const techKeywords = ['architecture', 'optimize', 'debug', 'refactor', 'concurrent'];
const keywordScore = techKeywords.filter(k => text.toLowerCase().includes(k)).length * 0.15;
return Math.min(lengthScore + keywordScore, 1);
}
estimateCost(model, tokens) {
const prices = {
'gpt-4.1': 8,
'claude-sonnet-4.5': 15,
'gemini-2.5-flash': 2.50,
'deepseek-v3.2': 0.42
};
return (tokens / 1000000) * (prices[model] || 8);
}
}
// Usage example với full observability
(async () => {
const engine = new HarnessEngine(process.env.HOLYSHEEP_API_KEY);
const testCases = [
{ type: 'LOW', text: 'Xin chào, bạn khỏe không?' },
{ type: 'MEDIUM', text: 'So sánh Promise và async/await trong JavaScript' },
{ type: 'HIGH', text: 'Thiết kế hệ thống distributed caching với Redis cluster và consistency tradeoffs giữa eventual và strong consistency' }
];
console.log('\n📊 INTELLIGENT ROUTING BENCHMARK\n');
for (const tc of testCases) {
const start = Date.now();
try {
const result = await engine.intelligentRoute(
{ systemPrompt: 'You are a helpful assistant.' },
tc.text
);
console.log(✅ [${tc.type}] Completed in ${Date.now() - start}ms);
console.log( Model: ${result.model});
console.log( Cost: $${result.cost_estimate.toFixed(4)});
console.log( Response: ${result.response.substring(0, 50)}...\n);
} catch (err) {
console.log(❌ [${tc.type}] Failed: ${err.message}\n);
}
}
})();
3. Batch Processing với Cost Optimization
// File: batch_processor.js
// Batch processing với smart batching và cost optimization
class BatchHarness {
constructor(apiKey) {
this.client = new HolySheepClient(apiKey);
this.baseUrl = 'https://api.holysheep.ai/v1';
}
async processBatch(requests, options = {}) {
const {
maxConcurrent = 5,
batchSize = 10,
optimizeFor = 'cost' // 'cost' | 'speed' | 'quality'
} = options;
// Phân nhóm requests theo complexity
const batches = this.createBatches(requests, batchSize);
const results = [];
const stats = {
totalCost: 0,
totalTokens: 0,
avgLatency: 0,
modelsUsed: {}
};
console.log(\n🚀 Processing ${requests.length} requests in ${batches.length} batches\n);
for (let i = 0; i < batches.length; i++) {
const batch = batches[i];
console.log(📦 Batch ${i + 1}/${batches.length} (${batch.length} items));
const batchStart = Date.now();
// Process batch với concurrency control
const batchResults = await Promise.all(
batch.map(req => this.processSingleRequest(req, optimizeFor))
);
const batchTime = Date.now() - batchStart;
// Aggregate stats
batchResults.forEach(result => {
results.push(result);
stats.totalCost += result.cost;
stats.totalTokens += result.tokens;
stats.modelsUsed[result.model] = (stats.modelsUsed[result.model] || 0) + 1;
});
stats.avgLatency += batchTime;
console.log( ✅ Batch completed in ${batchTime}ms);
console.log( 💰 Batch cost: $${batchResults.reduce((a, r) => a + r.cost, 0).toFixed(4)});
}
stats.avgLatency /= batches.length;
return { results, stats };
}
createBatches(requests, batchSize) {
// Smart batching: nhóm similar requests lại
const batches = [];
let currentBatch = [];
for (const req of requests) {
currentBatch.push(req);
if (currentBatch.length >= batchSize) {
batches.push(currentBatch);
currentBatch = [];
}
}
if (currentBatch.length > 0) {
batches.push(currentBatch);
}
return batches;
}
async processSingleRequest(request, optimizeFor) {
const startTime = Date.now();
// Chọn model dựa trên optimization target
let model;
switch (optimizeFor) {
case 'cost':
model = 'deepseek-v3.2'; // $0.42/MTok
break;
case 'speed':
model = 'gemini-2.5-flash'; // Fastest
break;
case 'quality':
model = 'gpt-4.1'; // Best quality
break;
default:
model = 'gemini-2.5-flash';
}
const response = await fetch(${this.baseUrl}/chat/completions, {
method: 'POST',
headers: {
'Authorization': Bearer ${this.apiKey},
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: model,
messages: request.messages,
max_tokens: request.maxTokens || 500
})
});
const data = await response.json();
const latency = Date.now() - startTime;
// Calculate cost với HolySheep pricing
const prices = { 'deepseek-v3.2': 0.42, 'gemini-2.5-flash': 2.50, 'gpt-4.1': 8 };
const inputTokens = data.usage?.prompt_tokens || 0;
const outputTokens = data.usage?.completion_tokens || 0;
const totalTokens = inputTokens + outputTokens;
const cost = (totalTokens / 1000000) * (prices[model] || 8);
return {
id: request.id,
model: model,
response: data.choices[0].message.content,
tokens: totalTokens,
cost: cost,
latency_ms: latency
};
}
}
// Full benchmark với realistic workload
(async () => {
const processor = new BatchHarness(process.env.HOLYSHEEP_API_KEY);
// Tạo 50 realistic requests
const requests = [];
const prompts = [
'Viết hàm tính Fibonacci với memoization',
'Giải thích React useEffect hook',
'So sánh SQL và NoSQL databases',
'Hướng dẫn deploy Node.js app lên AWS',
'Tối ưu hóa React component performance'
];
for (let i = 0; i < 50; i++) {
requests.push({
id: req_${i},
messages: [
{ role: 'user', content: prompts[i % prompts.length] }
],
maxTokens: 300
});
}
console.log('═══════════════════════════════════════════════');
console.log(' BATCH PROCESSING COST COMPARISON ');
console.log('═══════════════════════════════════════════════');
const scenarios = [
{ name: 'Cost-Optimized', optimizeFor: 'cost' },
{ name: 'Speed-Optimized', optimizeFor: 'speed' },
{ name: 'Quality-Optimized', optimizeFor: 'quality' }
];
for (const scenario of scenarios) {
const { stats } = await processor.processBatch(requests, {
optimizeFor: scenario.optimizeFor,
batchSize: 10
});
console.log(`
┌─────────────────────────────────────┐
│ ${scenario.name.padEnd(33)}│
├─────────────────────────────────────┤
│ Total Cost: $${stats.totalCost.toFixed(4).padStart(10)}│
│ Total Tokens: ${stats.totalTokens.toString().padStart(10)}│
│ Avg Latency: ${stats.avgLatency.toFixed(0)}ms${''.padStart(14)}│
│ Models: ${Object.entries(stats.modelsUsed).map(([k,v]) => ${k}(${v})).join(', ').substring(0, 30).padEnd(30)}│
└─────────────────────────────────────┘
`);
}
})();
Lỗi thường gặp và cách khắc phục
Qua quá trình triển khai Harness Engineering, tôi đã gặp và xử lý nhiều lỗi phổ biến. Dưới đây là 5 trường hợp điển hình nhất:
1. Lỗi Authentication - Invalid API Key
// ❌ Error response:
{
"error": {
"message": "Invalid authentication. Please check your API key.",
"type": "invalid_request_error",
"code": "invalid_api_key"
}
}
// ✅ Fix: Kiểm tra format API key và environment variable
// Wrong way:
const client = new HolySheep({ apiKey: 'YOUR_HOLYSHEEP_API_KEY' });
// Correct way - luôn load từ environment:
// 1. Tạo file .env:
echo "HOLYSHEEP_API_KEY=hs_live_xxxxxxxxxxxx" >> .env
// 2. Load và validate:
require('dotenv').config();
if (!process.env.HOLYSHEEP_API_KEY) {
throw new Error('HOLYSHEEP_API_KEY not set in environment');
}
if (!process.env.HOLYSHEEP_API_KEY.startsWith('hs_')) {
throw new Error('Invalid API key format. Must start with "hs_"');
}
const client = new HolySheep({
apiKey: process.env.HOLYSHEEP_API_KEY,
baseUrl: 'https://api.holysheep.ai/v1' // IMPORTANT: Use correct base URL
});
// Advanced: Auto-refresh key nếu sử dụng key rotation
class SecureHolySheepClient {
constructor() {
this.currentKeyIndex = 0;
this.keys = [
process.env.HOLYSHEEP_API_KEY_1,
process.env.HOLYSHEEP_API_KEY_2
];
}
getKey() {
return this.keys[this.currentKeyIndex];
}
rotateKey() {
this.currentKeyIndex = (this.currentKeyIndex + 1) % this.keys.length;
console.log(Rotated to key index: ${this.currentKeyIndex});
}
}
2. Lỗi Rate Limiting - 429 Too Many Requests
// ❌ Error response:
{
"error": {
"message": "Rate limit exceeded. Please retry after 60 seconds.",
"type": "rate_limit_error",
"param": null,
"code": "rate_limit_exceeded"
}
}
// ✅ Fix: Implement exponential backoff với jitter
class RateLimitHandler {
constructor(maxRetries = 5) {
this.maxRetries = maxRetries;
this.retryDelays = [];
}
async executeWithRetry(fn) {
let lastError;
for (let attempt = 0; attempt < this.maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (error.status === 429) {
// Parse retry-after header
const retryAfter = error.headers?.['retry-after'] || 60;
// Exponential backoff với jitter (random 0-1s)
const baseDelay = Math.min(2 ** attempt * 1000, 30000); // Max 30s
const jitter = Math.random() * 1000;
const delay = baseDelay + jitter;
this.retryDelays.push({ attempt, delay, retryAfter });
console.log(⏳ Rate limited. Attempt ${attempt + 1}/${this.maxRetries});
console.log( Waiting ${delay.toFixed(0)}ms before retry...);
await this.sleep(delay);
} else {
// Non-retryable error
throw error;
}
}
}
throw new Error(Max retries (${this.maxRetries}) exceeded. Last error: ${lastError.message});
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
getStats() {
return {
totalRetries: this.retryDelays.length,
avgDelay: this.retryDelays.reduce((a, b) => a + b.delay, 0) / this.retryDelays.length,
delays: this.retryDelays
};
}
}
// Usage:
const handler = new RateLimitHandler({ maxRetries: 5 });
const result = await handler.executeWithRetry(async () => {
const response = await fetch(${BASE_URL}/chat/completions, {
method: 'POST',
headers: { 'Authorization': Bearer ${API_KEY} },
body: JSON.stringify({ /* ... */ })
});
if (response.status === 429) {
const error = new Error('Rate limited');
error.status = 429;
error.headers = response.headers;
throw error;
}
return response.json();
});
console.log(✅ Success after ${handler.getStats().totalRetries} retries);
3. Lỗi Context Length Exceeded - 400 Bad Request
// ❌ Error response:
{
"error": {
"message": "This model's maximum context length is 128000 tokens,
but 156000 tokens were specified.",
"type": "invalid_request_error",
"param": "messages",
"code": "context_length_exceeded"
}
}
// ✅ Fix: Implement smart truncation và chunking
class ContextManager {
constructor(maxTokens = 120000) { // Giữ 8K buffer
this.maxTokens = maxTokens;
}
truncateMessages(messages, systemPrompt = '') {
// Tính toán tokens đã dùng cho system prompt
const systemTokens = this.estimateTokens(systemPrompt);
const availableTokens = this.maxTokens - systemTokens;
// Flatten all messages
const allContent = messages.map(m => ${m.role}: ${m.content}).join('\n');
const contentTokens = this.estimateTokens(allContent);
if (contentTokens <= availableTokens) {
return messages; // Không cần truncate
}
// Smart truncation: giữ messages gần đây nhất
const truncatedMessages = this.smartTruncate(messages, availableTokens);
console.log(📝 Truncated ${messages.length} messages to ${truncatedMessages.length});
console.log( Original: ~${contentTokens} tokens → Truncated: ~${this.estimateTokens(truncatedMessages.map(m => m.content).join('\n'))} tokens);
return truncatedMessages;
}
smartTruncate(messages, availableTokens) {
const result = [];
let currentTokens = 0;
// Duyệt từ cuối lên đầu (giữ messages gần nhất)
for (let i = messages.length - 1; i >= 0; i--) {
const msg = messages[i];
const msgTokens = this.estimateTokens(${msg.role}: ${msg.content});
if (currentTokens + msgTokens > availableTokens) {
// Thử truncate message này thay vì bỏ hoàn toàn
if (msg.role === 'user' && result.length > 0) {
const truncatedContent = this.truncateToTokens(msg.content, availableTokens - currentTokens - 50);
if (truncatedContent.length > 20) {
result.unshift({ role: msg.role, content: truncatedContent });
break;
}
}
break;
}
result.unshift(msg);
currentTokens += msgTokens;
}
return result;
}
truncateToTokens(text, maxTokens) {
// Rough estimate: 1 token ≈ 4 chars cho tiếng Anh, 2 chars cho tiếng Việt
const charsPerToken = 3;
const maxChars = Math.floor(maxTokens * charsPerToken);
return text.substring(0, maxChars);
}
estimateTokens(text) {
// Cải thiện estimate: có thể dùng tiktoken trong production
// return new Tiktoken().encode(text).length;
return Math.ceil(text.length / 3);
}
}
// Usage:
const contextManager = new ContextManager({ maxTokens: 120000 });
const optimizedMessages = contextManager.truncateMessages(rawMessages, systemPrompt);
const response = await client.chat.completions.create({
model: 'gpt-4.1',
messages: [
{ role: 'system', content: systemPrompt },
...optimizedMessages
]
});
4. Lỗi Model Unavailable - Model Not Found
// ❌ Error response:
{
"error": {
"message": "Model 'gpt-5-preview' not found. Available models:
gpt-4.1, claude-sonnet-4.5, gemini-2.5-flash, deepseek-v3.2",
"type": "invalid_request_error",
"param": "model",
"code": "model_not_found"
}
}
// ✅ Fix: Dynamic model discovery và fallback
class ModelRouter {
constructor(apiKey, baseUrl) {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
this.availableModels = null;
this.modelAliases = {
'gpt5': 'gpt-4.1',
'gpt4': 'gpt-4.1',
'claude': 'claude-sonnet-4.5',
'sonnet': 'claude-sonnet-4.5',
'gemini': 'gemini-2.5-flash',
'flash': 'gemini-2.5-flash',
'deepseek': 'deepseek-v3.2',
'cheap': 'deepseek-v3.2'
};
this.modelPrices = {
'gpt-4.1': { input: 8, output: 8 },
'claude-sonnet-4.5': { input: 15, output: 15 },
'gemini-2.5-flash': { input: 2.50, output: 10 },
'deepseek-v3.2': { input: 0.42, output: 2.10 }
};
}
async discoverModels() {
if (this.availableModels) return this.availableModels;
try {
const response = await fetch(${this.baseUrl}/models, {
headers: { 'Authorization': Bearer ${this.apiKey} }
});
if (response.ok) {
const data = await response.json();
this.availableModels = data.data.map(m => m.id);
} else {
// Fallback to known models
this.availableModels = ['gpt-4.1', 'claude-sonnet-4.5', 'gemini-2.5-flash', 'deepseek-v3.2'];
}
} catch (error) {
this.availableModels = ['gpt-4.1', 'claude-sonnet-4.5', 'gemini-2.5-flash', 'deepseek-v3.2'];
}
console.log(🔍 Discovered models: ${this.availableModels.join(', ')});
return this.availableModels;
}
resolveModel(requestedModel) {
// Check alias first
const normalized = requestedModel.toLowerCase().replace(/\s+/g, '-');
if (this.modelAliases[normalized]) {
return this.modelAliases[normalized];
}
// Check if exact match
if (this.availableModels?.includes(requestedModel)) {
return requestedModel;
}
// Find closest match
const match = this.availableModels?.find(m =>
m.includes(normalized) || normalized.includes(m)
);
if (match) {
console.warn(⚠️ Model "${requestedModel}" not found. Using "${match}" instead.);
return match;
}
// Default to cheapest option
console.warn(⚠️ Model "${requestedModel}" not found. Using "deepseek-v3.2" (cheapest).);
return 'deepseek-v3.2';
}
getModelInfo(modelId) {
return {
id: modelId,
price: this.modelPrices[modelId] || { input: 8, output: 8 },