äžå¥è¯çè§£ HarnessïŒåé©¬å ·ïŒharnessïŒé©Ÿé©é©¬å¹äžæ ·ïŒçšç»æåæµæ°Žçº¿é©Ÿé©å€§æš¡åïŒè®©å®åš "çæ â è¯æµ â æ©äŒ" çéç¯äžèªåšäº§åºæŽé«èŽšéçç»æã
ð äžã䞺ä»ä¹éèŠ HarnessïŒ
倧暡åïŒLLMïŒæäž€äžªèçåžžè°çé®é¢ïŒ
| é®é¢ | è¡šç° |
|---|---|
| ð² äžç¡®å®æ§ | åäžäžª Prompt æ¯æ¬¡çæçç»æäžåïŒèŽšéåå·®äžéœ |
| ð€¥ å¹»è§ | æš¡åå¯èœäžæ¬æ£ç»å°è¡è¯Žå «éïŒèŸåºç䌌æ£ç¡®å®åæ Bug ç代ç |
忬¡è°çš LLM å°±å"åŒç²ç"ââäœ æ°žè¿äžç¥éè¿æ¬¡æ¿å°çæ¯æåè¿æ¯æåã
Harness çæè·¯åŸç®åïŒæ¢ç¶äžæ¬¡äžé è°±ïŒé£å°±å€çæå 次ïŒå让暡åèªå·±åœè¯å§ææå¥œçã
ð§ äºãæ žå¿ææ³ïŒäžæ¿æ§
Harness ç讟计ç±äžäžªå ³é®æš¡åŒç»åèæïŒ
âââââââââââââââââââââââââââââââââââââââââââââââââââ
â Harness æµæ°Žçº¿ â
â â
â â Best of N Sampling â¡ LLM as Judge â
â âââââââââââââââââ âââââââââââââââââ â
â â å¹¶è¡çæ N 䞪 ââââââââ¶â LLM èªåšè¯å â â
â â åéç»æ â â 0-10 æå â â
â âââââââââââââââââ âââââââââ¬ââââââââ â
â â â
â ⢠æ©äŒçé â â
â âââââââââââââŒââââââââ â
â â æåºåæé«å â â
â â è¿åæäŒç»æ â â
â âââââââââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââ
â Best of N SamplingïŒN é 1 éæ ·ïŒ
ð¯ æ žå¿ææ³ïŒå¹¶è¡è°çš LLM 倿¬¡ïŒå©çšéæºæ§èŠçæŽå€å¯èœæ§ã
æš¡åçèŸåºåžŠæéæºæ§ïŒtemperature > 0ïŒïŒè¿æå³çåäžäžª Prompt æ¯æ¬¡å¯èœåŸå°äžåççæ¡ãæ¢ç¶åŠæ€ïŒäžåŠå€è·å æ¬¡ïŒæ©å€§æçŽ¢ç©ºéŽïŒæ»æäžçæ¯å¥œçã
â¡ LLM as JudgeïŒå€§æš¡ååœè¯å§ïŒ
ð§ââïž æ žå¿ææ³ïŒçš LLM æ¿ä»£äººå·¥è¯æµïŒå®ç°éç¯èªåšåã
äººå·¥éæ¡æ£æ¥åéç»æå€ªçŽ¯äºãæ¢ç¶ LLM æä»£ç çè§£èœåïŒäžåŠè®©å®èªå·±åœè£å€ïŒå¯¹æ¯äžªåéç»ææåïŒå®ç°å šèªåšè¯å®¡ã
⢠Harness æœè±¡ïŒæµæ°Žçº¿çŒæïŒ
ð æ žå¿ææ³ïŒå°"çæ â è¯æµ â æ©äŒ"äžé¶æ®µè§£èŠäžºæµæ°Žçº¿ã
äžäžªé¶æ®µååžå ¶èïŒå¯ä»¥ç¬ç«æ¿æ¢ãåçº§ãæ¯åŠæ¢äžäžªæŽå¥œç Judge æš¡åïŒæè å¢å åéæ°éïŒéœäžåœ±åå ¶ä»ç¯èã
ð» äžã代ç å®ç°è¯Šè§£
äžé¢ä»¥"让 LLM å®ç°æ°ç»å»éåœæ°"䞺äŸåïŒå®æŽå±ç€º Harness çå®ç°ã
3.1 项ç®åå§å
# å建项ç®
mkdir q1 && cd q1 && pnpm init
# å®è£
äŸèµ
pnpm add openai dotenv
package.json å
³é®é
眮ïŒ
{
"type": "commonjs",
"dependencies": {
"dotenv": "^17.4.2",
"openai": "^7.8.0"
}
}
ð¡ 䜿çš
dotenv管ç API KeyïŒäœ¿çšopenai宿¹ SDK è°çšæš¡åã
3.2 åºç¡è°çšå°è£
import OpenAI from 'openai';
import { config } from 'dotenv';
config();
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
baseURL: process.env.OPENAI_BASE_URL,
});
// éçš LLM è°çšåœæ°
const askLLM = async (prompt) => {
const res = await client.chat.completions.create({
model: process.env.MODEL_NAME,
messages: [{ role: 'user', content: prompt }]
});
return res.choices[0].message.content;
};
ð éè¿
.envæä»¶é 眮 API KeyãBase URL åæš¡ååç§°ïŒæ¹äŸ¿åæ¢äžåæäŸåã
3.3 ç¬¬äžæ¥ïŒBest of N ââ å¹¶è¡çæåé
const generateCandidates = (prompt, n = 3) => {
const tasks = Array.from({ length: n }, () => askLLM(prompt));
return Promise.all(tasks); // å¹¶è¡åèµ· N 次请æ±
};
â¡
Promise.all让 N 次请æ±å¹¶è¡æ§è¡ïŒæ»èæ¶çºŠçäºå次è°çšçæ¶éŽãåŠæäž²è¡è°çšïŒèæ¶å°±æ¯ N åã
æ§è¡ææç€ºæïŒ
Prompt: "è¯·äœ¿çš javascript å®ç°äžäžªæ°ç»å»éåœæ°"
â
ââââ¶ Candidate 1: [...new Set(arr)]
ââââ¶ Candidate 2: arr.filter((v, i) => arr.indexOf(v) === i)
ââââ¶ Candidate 3: arr.reduce((acc, cur) => ...)
3.4 ç¬¬äºæ¥ïŒLLM as Judge ââ èªåšè¯å
async function judge(code) {
const prompt = `
äœ æ¯äžäžªäž¥æ Œç代ç è¯å®¡ïŒè¯·å€æäžé¢ä»£ç æ¯åŠæ£ç¡®å®ç°"æ°ç»å»éåœæ°"
èŠæ±ïŒ
- åªè¿åäžäžªæ°åè¯å(0-10)
- äžèŠè§£é
代ç ïŒ
${code}
`;
const res = await askLLM(prompt);
const score = parseFloat(res);
return isNaN(score) ? 0 : score;
}
// æ¹éè¯äŒ°ææåé
async function evaluateAll(candidates) {
const results = [];
for (const code of candidates) {
const score = await judge(code);
results.push({ code, score });
}
return results;
}
ð§ââïž å ³é® Prompt æå·§ïŒ
- æç¡®è§è²ïŒ"äœ æ¯äžäžªäž¥æ Œç代ç è¯å®¡"
- éå®èŸåºæ ŒåŒïŒ"åªè¿åäžäžªæ°åè¯å(0-10)"
- æå¶åºè¯ïŒ"äžèŠè§£é"
è¿æ ·
parseFloat()å°±èœçŽæ¥è§£æåºåæ°ïŒå®ç°ç»æåèŸåºã
3.5 ç¬¬äžæ¥ïŒæ©äŒçé
function pickBest(results) {
return results.sort((a, b) => b.score - a.score)[0];
}
ð æåæ°éåºæåïŒå第äžäžªå°±æ¯æäŒåéã
3.6 äž²èïŒHarness äž»æµçš
async function harness(prompt) {
// â çæåé
console.log('çæå€äžªåéè
....\n');
const candidates = await generateCandidates(prompt, 3);
console.log('åéç»æ:');
candidates.forEach((c, i) => {
console.log(`\n---- Candidate ${i + 1} ----\n${c}`);
});
// â¡ è¯å
console.log('\nEvaluate Candidates...\n');
const evaluated = await evaluateAll(candidates);
console.log('æåç»æ:');
evaluated.forEach((c, i) => {
console.log(`\n---- Candidate ${i + 1} ----\n${c.code}\n-> ${c.score}`);
});
// ⢠æ©äŒ
const best = pickBest(evaluated);
return best.code;
}
// å¯åš Harness
const bestCode = await harness("è¯·äœ¿çš javascript å®ç°äžäžªæ°ç»å»éåœæ°");
console.log('\nâ
æç»ç»æ:\n', bestCode);
宿޿§è¡æµçšïŒ
ð å¯åš Harness
â
âââ â generateCandidates(prompt, 3)
â âââ Candidate 1: const unique = [...new Set(arr)];
â âââ Candidate 2: arr.filter((v, i) => arr.indexOf(v) === i);
â âââ Candidate 3: arr.reduce((res, cur) => ...)
â
âââ â¡ evaluateAll(candidates)
â âââ Candidate 1 -> score: 9
â âââ Candidate 2 -> score: 8
â âââ Candidate 3 -> score: 7
â
âââ ⢠pickBest(evaluated)
âââ â
Winner: Candidate 1 (score: 9)
ðïž åãæ¶æå šæ¯
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Harness æ¶æåŸ â
â â
â âââââââââââ ââââââââââââââââââââââââââââââââââââ â
â â Prompt ââââââ¶â â Generator (çæåš) â â
â âââââââââââ â ââââââââââ ââââââââââ âââââââââââ â
â â â Gen 1 â â Gen 2 â â Gen 3 ââ â
â â âââââ¬âââââ âââââ¬âââââ âââââ¬ââââââ â
â ââââââââŒâââââââââââŒâââââââââââŒââââââ â
â â â â â
â ⌠⌠⌠â
â ââââââââââââââââââââââââââââââââââââ â
â â â¡ Judge (è¯å§) â â
â â ââââââââââ ââââââââââ âââââââââââ â
â â âScore: 9â âScore: 7â âScore: 8ââ â
â â âââââ¬âââââ âââââ¬âââââ âââââ¬ââââââ â
â ââââââââŒâââââââââââŒâââââââââââŒââââââ â
â â â â â
â ⌠⌠⌠â
â ââââââââââââââââââââââââââââââââââââ â
â â ⢠Selector (æ©äŒåš) â â
â â æåº â åæé«å â â
â âââââââââââââââââ¬âââââââââââââââââââ â
â â â
â ⌠â
â â
æäŒç»æèŸåº â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
ð äºã对æ¯ïŒææ Harness çåºå«
| 绎床 | â 忬¡è°çš | â Harness |
|---|---|---|
| 莚éä¿é | çè¿æ°ïŒå¯èœå¥œä¹å¯èœå·® | 倿¬¡çæ + è¯åçéïŒèŽšéäžéæŽé« |
| å¹»è§æ§å¶ | æ æ³èªæ£ | LLM åœè¯å§ïŒèªåšè¿æ»€äœèŽšéèŸåº |
| 坿©å±æ§ | æ | å¯è°èåéæ° NïŒå¯æŽæ¢ Judge æš¡å |
| ææ¬ | 1 次è°çš | N + N 次è°çšïŒçæ N 次 + è¯å N æ¬¡ïŒ |
| å»¶è¿ | 忬¡å»¶è¿ | 纊 2 å忬¡å»¶è¿ïŒå¹¶è¡çæ + äž²è¡è¯åïŒ |
âïž Trade-offïŒHarness çšæŽå€ç Token æ¶èæ¢åæŽé«çèŸåºèŽšéãåšå¯¹èŽšéèŠæ±é«ãå 讞äžå®ææ¬çåºæ¯äžéåžžåç®ã
ð å ãè¿é¶äŒåæ¹å
Harness çäžé¶æ®µè§£èŠè®Ÿè®¡è®©å®å€©ç¶æäºæ©å±ïŒ
6.1 çæé¶æ®µäŒå
- ð¡ïž è°é«
temperatureå¢å 倿 ·æ§ - ð 䜿çšäžåç Prompt åäœïŒå€è§åºŠæé®ïŒ
- ð åŒå ¥ Self-RefinementïŒè®©æš¡åèªææ¹è¿ïŒ
6.2 è¯æµé¶æ®µäŒå
- ð§ââïž äœ¿çšæŽåŒºçæš¡åå JudgeïŒåŠçš GPT-4 è¯å®¡ GPT-3.5 çèŸåºïŒ
- ð å€ç»ŽåºŠè¯åïŒæ£ç¡®æ§ãå¯è¯»æ§ãæ§èœå嫿åïŒ
- â ç»ååå æµè¯åèªåšåéªè¯ïŒä»£ç 坿§è¡æ¶ïŒ
6.3 æ©äŒé¶æ®µäŒå
- ð³ïž 倿°æç¥šïŒMajority VotingïŒæ¿ä»£ç®ååæé«å
- ð å æèåïŒå°å€äžªåéçäŒç¹åå¹¶ïŒ
- ð åžçޝæå沿ïŒå€ç®æ äŒåïŒ
ð¯ äžãéçšåºæ¯
| åºæ¯ | éå床 | 诎æ |
|---|---|---|
| 代ç çæ | âââââ | ææç¡®çæ£ç¡®æ§æ åïŒéåèªåšè¯å |
| ææ¡æ°å | ââââ | å¯ä»æµç 床ãåæç绎床è¯å |
| æ°æ®åæ | âââ | å¯è¯åäœéç»åäžå¡é»èŸ |
| é²èå¯¹è¯ | ââ | äž»è§æ§åŒºïŒèªåšè¯åå°éŸ |
ð¡ å «ãé¢è¯é«é¢è¿œé®
Q1ïŒHarness å RAG æä»ä¹åºå«ïŒ
RAG æ¯ä»å€éšç¥è¯åºæ£çŽ¢ä¿¡æ¯å¢åŒºèŸå ¥ïŒè§£å³"äžç¥é"çé®é¢ïŒïŒHarness æ¯å€æ¬¡çæ + è¯åçéå¢åŒºèŸåºïŒè§£å³"äžçš³å®"çé®é¢ïŒã䞀è å¯ä»¥ç»å䜿çšã
Q2ïŒäžºä»ä¹çš LLM åœ Judge èäžæ¯çšè§åïŒ
è§åïŒåŠåå æµè¯ïŒåªèœéªè¯åèœæ£ç¡®æ§ïŒæ æ³è¯äŒ°ä»£ç 飿 Œãå¯è¯»æ§çèœ¯ææ ãLLM äœäžº Judge èœåæŽå šé¢çè¯ä¹çº§è¯äŒ°ã
Q3ïŒN åå€å€§åéïŒ
éåžž 3-5 䞪å³å¯ãN è¶å€§èŽšéè¶é«ïŒäœææ¬çº¿æ§å¢é¿ãå®è·µäž 3 䞪æ§ä»·æ¯æé«ïŒå 䞺æå¥œç 1/3 éåžžå·²ç»è¿è¶ 忬¡è°çšç平忰Žå¹³ã
Q4ïŒåŠæ Judge æ¬èº«ä¹æå¹»è§æä¹åïŒ
è¿æ¯ Harness çäžäžªå±éãè§£å³æ¹æ¡ïŒ
- çšæŽåŒºçæš¡åå JudgeïŒåŠ GPT-4 è¯å®¡ GPT-3.5ïŒ
- å€äžª Judge æç¥š
- ç»å坿§è¡éªè¯ïŒä»£ç è·æµè¯çšäŸïŒ
ð æ»ç»
Harness å·¥çšçæ žå¿å¯ä»¥çšäžå¥è¯æŠæ¬ïŒ
"äžä¿¡ä»»å次 LLM èŸåºïŒçšçæ-è¯æµ-æ©äŒçéç¯æµæ°Žçº¿é©¯æäžç¡®å®æ§ã"
å®äœç°äºå·¥çšåæç»Žè§£å³ AI é®é¢çå žåèåŒââäžè¿œæ±åç¹å®çŸïŒèæ¯éè¿ç³»ç»è®Ÿè®¡æåæŽäœäº§åºèŽšéãè¿æ£æ¯ "Harness" è¿äžªååç粟é«ïŒäžæ¯è®©é©¬èªç±å¥è·ïŒèæ¯çšé©¬å ·åŒå¯Œå®èµ°åæ£ç¡®çæ¹åãðŽ