Files
ai-skill-chat/src/lib/skill-node-quality.ts
2026-07-29 11:42:41 +08:00

109 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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("")}`;
}