This commit is contained in:
2026-07-29 11:42:41 +08:00
commit 48b7391365
71 changed files with 28910 additions and 0 deletions

View File

@ -0,0 +1,108 @@
export type SkillQualityNodeKey =
| "trigger"
| "inputs"
| "steps"
| "output"
| "constraints";
export type SkillNodeQuality = {
complete: boolean;
missing: string[];
};
function normalizedContent(content: string) {
return content.replace(/\s+/g, " ").trim();
}
function hasOrderedSteps(content: string) {
const numberedSteps =
content.match(/(?:^|[\n;。])\s*(?:步骤\s*)?\d+[.、):]/g)?.length ?? 0;
const sequenceMarkers = ["先", "再", "然后", "接着", "最后", "最终"].filter(
(marker) => content.includes(marker),
).length;
const actionSegments = content
.split(/[\n;。]+/)
.filter((segment) =>
/(?:检查|识别|提取|分析|整理|比较|判断|生成|输出|复核|验证|标记)/.test(
segment,
),
).length;
return numberedSteps >= 2 || sequenceMarkers >= 2 || actionSegments >= 2;
}
export function evaluateSkillNodeQuality(
nodeKey: SkillQualityNodeKey,
content: string,
): SkillNodeQuality {
const normalized = normalizedContent(content);
const missing: string[] = [];
if (normalized.length < 8) {
missing.push("内容过短,尚未形成可执行规范");
return { complete: false, missing };
}
switch (nodeKey) {
case "trigger":
if (
!/(?:当|如果|遇到|用户|场景|适用|触发|不处理|不适用|请求)/.test(
normalized,
)
) {
missing.push("需要说明何时触发或适用场景");
}
break;
case "inputs":
if (
!/(?:必填|可选|输入|参数|提供|原文|材料|目标|字段|默认|缺失)/.test(
normalized,
)
) {
missing.push("需要列明执行所需的输入信息");
}
break;
case "steps":
if (!hasOrderedSteps(normalized)) {
missing.push("需要至少两个有明确顺序的执行动作");
}
break;
case "output":
if (
!/(?:输出|结果|格式|结构|标题|字段|表格|Markdown|JSON|列表|篇幅|语气|字数|包含)/i.test(
normalized,
)
) {
missing.push("需要明确结果结构、字段或格式");
}
break;
case "constraints":
if (
!/(?:不得|不能|禁止|必须|至少|至多|缺少|不足|失败|异常|验收|测试|反例|确保|待确认|质量)/.test(
normalized,
)
) {
missing.push("需要至少一条约束、质量标准或验收条件");
}
break;
}
return { complete: missing.length === 0, missing };
}
export function getSkillNodeQualityIssues(
nodes: Array<{
key: SkillQualityNodeKey;
title: string;
content: string;
}>,
) {
return nodes.flatMap((node) => {
const quality = evaluateSkillNodeQuality(node.key, node.content);
return quality.missing.map((missing) => `${node.title}${missing}`);
});
}
export function skillNodeQualityErrorMessage(issues: string[]) {
return `Skill 节点尚未达到可发布标准。需补充:${issues.join("")}`;
}