You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
aiserver/lib/evaluationDimensions.cjs

85 lines
3.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

const fs = require('fs');
const path = require('path');
/**
* 解析 config/evaluation-dimensions.yaml仅支持本仓库使用的扁平 dimensions 列表)
* @returns {{ id: string, name: string, weight: number, rubric: string }[]}
*/
function loadEvaluationDimensions(rootDir) {
const p = path.join(rootDir, 'config', 'evaluation-dimensions.yaml');
if (!fs.existsSync(p)) return [];
const raw = fs.readFileSync(p, 'utf8');
const dims = [];
let cur = null;
for (const line of raw.split('\n')) {
const t = line.trim();
if (t.startsWith('- id:')) {
if (cur && cur.id) dims.push(cur);
cur = { id: t.replace(/^-\s*id:\s*/, '').trim(), name: '', weight: 1, rubric: '' };
} else if (cur && t.startsWith('name:')) {
cur.name = t.replace(/^name:\s*/, '').trim();
} else if (cur && t.startsWith('weight:')) {
const w = parseFloat(t.replace(/^weight:\s*/, '').trim());
cur.weight = Number.isFinite(w) ? w : 1;
} else if (cur && t.startsWith('rubric:')) {
cur.rubric = t.replace(/^rubric:\s*/, '').trim();
}
}
if (cur && cur.id) dims.push(cur);
return dims;
}
/** 写入 Agent 提示词:教师可改 YAML 即改维度与 rubric */
function formatDimensionsForPrompt(dimensions) {
if (!dimensions.length) return '(未找到 evaluation-dimensions.yaml';
return dimensions
.map(
(d, i) =>
`${i + 1}. id=${d.id} name=${d.name} weight=${d.weight}\n rubric: ${d.rubric}`,
)
.join('\n');
}
/**
* 将大模型返回的 ability 与 YAML 维度对齐顺序、id、name 以 YAML 为准;缺项用启发式或占位。
*/
function alignEvaluationAbilityToDimensions(evaluation, dimensions, heuristicEvaluation) {
if (!evaluation || !dimensions.length) return;
const raw = evaluation.ability || evaluation.abilities || [];
const byId = new Map();
for (const a of raw) {
if (a && typeof a.id === 'string' && a.id.trim()) byId.set(a.id.trim(), a);
}
const fb = heuristicEvaluation?.ability || heuristicEvaluation?.abilities || [];
const fbMap = new Map();
for (const a of fb) {
if (a && a.id) fbMap.set(String(a.id).trim(), a);
}
evaluation.ability = dimensions.map((d) => {
const m = byId.get(d.id);
const h = fbMap.get(d.id);
const val = (() => {
if (m != null && m.value != null && !Number.isNaN(Number(m.value))) {
return Math.max(0, Math.min(100, Math.round(Number(m.value))));
}
if (h != null && h.value != null && !Number.isNaN(Number(h.value))) {
return Math.max(0, Math.min(100, Math.round(Number(h.value))));
}
return 32;
})();
const comment =
(typeof m?.comment === 'string' && m.comment.trim() && m.comment.trim()) ||
(typeof h?.comment === 'string' && h.comment.trim() && h.comment.trim()) ||
`请结合任务说明与本维度 rubric 核验:${d.rubric}`;
return { id: d.id, name: d.name, value: val, comment };
});
delete evaluation.abilities;
}
module.exports = {
loadEvaluationDimensions,
formatDimensionsForPrompt,
alignEvaluationAbilityToDimensions,
};