教程演示如何构建一个确定性的 AI 答案质量 triage 流程,通过标注数据源角色(定义/证据/对比/实现等)找出模型回答中的信息缺口,不依赖黑盒评分。
一个可见性仪表盘可能看起来很精确,却隐藏了真正重要的问题:答案中缺少什么有用的来源?
本教程构建了一个小型、确定性的 AI 答案观察分类管道。它不会猜测模型如何工作、爬取私有接口、或将所有信号压缩成一个"可见性分数"。它接受一组冻结的 prompt 加上人工审查的来源角色,产生一个可审查的编辑队列。
示例均为合成数据,不代表实际排名或客户结果。
最小输入需要:
来源角色描述被引用页面承担的工作:
角色不是质量判断。支持状态需单独记录。
type Intent =
| "discovery"
| "diagnosis"
| "comparison"
| "implementation"
| "selection"
| "risk";
type SourceRole =
| "definition"
| "evidence"
| "comparison"
| "implementation"
| "identity"
| "selection"
| "context";
type SupportStatus =
| "supports"
| "partially_supports"
| "does_not_support"
| "unclear";
interface SourceObservation {
url: string;
role: SourceRole;
support: SupportStatus;
}
interface PromptObservation {
promptId: string;
promptVersion: string;
promptText: string;
intent: Intent;
answerSystem: string;
runTimestamp: string;
brandMentioned: boolean;
targetDomainCited: boolean;
sources: SourceObservation[];
evidenceArtifact: string;
isSynthetic: boolean;
}
interface TriageItem {
promptId: string;
intent: Intent;
missingRole: SourceRole;
priority: number;
reason: string;
}
保持答案系统和时间戳可见。重复运行是样本,不是永久排名。
该映射是一个编辑假设。它应该描述哪些角色会使答案更有用,而不是模型必须引用哪个发布方。
const expectedRoles: Record<Intent, SourceRole[]> = {
discovery: ["definition", "identity"],
diagnosis: ["evidence", "context"],
comparison: ["comparison", "evidence"],
implementation: ["implementation", "evidence"],
selection: ["selection", "comparison", "identity"],
risk: ["evidence", "context"],
};
对这个映射进行版本管理。如果在看到结果后更改它,你的新输出与旧输出无法直接比较。
有用的优先级不是关于模型概率的声明。它只是一个有序的工作队列。保持公式可见。
const intentWeight: Record<Intent, number> = {
discovery: 2,
diagnosis: 3,
comparison: 4,
implementation: 4,
selection: 5,
risk: 3,
};
const roleWeight: Record<SourceRole, number> = {
definition: 2,
evidence: 4,
comparison: 4,
implementation: 3,
identity: 2,
selection: 4,
context: 1,
};
这些值仅在本例中反映编辑紧急程度。不要将它们作为经过验证的行业基准来展示。
只有当审查者发现至少部分支持时,我们才将角色计为存在。不支持其附加声明的引用不应该让差距消失。
function supportedRoles(row: PromptObservation): Set<SourceRole> {
return new Set(
row.sources
.filter(
(source) =>
source.support === "supports" ||
source.support === "partially_supports"
)
.map((source) => source.role)
);
}
function triage(rows: PromptObservation[]): TriageItem[] {
const queue: TriageItem[] = [];
for (const row of rows) {
if (!row.promptId || !row.promptVersion) {
throw new Error("Every row needs a stable prompt ID and version");
}
if (!Number.isFinite(Date.parse(row.runTimestamp))) {
throw new Error("Invalid timestamp for " + row.promptId);
}
const present = supportedRoles(row);
for (const role of expectedRoles[row.intent]) {
if (present.has(role)) continue;
const citationGap = row.targetDomainCited ? 0 : 2;
const mentionGap = row.brandMentioned ? 0 : 1;
queue.push({
promptId: row.promptId,
intent: row.intent,
missingRole: role,
priority:
intentWeight[row.intent] +
roleWeight[role] +
citationGap +
mentionGap,
reason: [
"Expected " + role + " support for " + row.intent + " intent",
row.brandMentioned ? "brand mentioned" : "brand not mentioned",
row.targetDomainCited
? "target domain cited"
: "target domain not cited",
].join("; "),
});
}
}
return queue.sort(
(a, b) =>
b.priority - a.priority ||
a.promptId.localeCompare(b.promptId) ||
a.missingRole.localeCompare(b.missingRole)
);
}
确定性的平局打破机制很重要。两个使用相同输入的人应该得到相同的排序。
const observations: PromptObservation[] = [
{
promptId: "example-selection-01",
promptVersion: "1.0",
promptText:
"What should a mid-market team evaluate in an AI visibility platform?",
intent: "selection",
answerSystem: "Example Answer System",
runTimestamp: "2026-08-11T20:00:00Z",
brandMentioned: true,
targetDomainCited: false,
sources: [
{
url: "https://example.org/category-overview",
role: "identity",
support: "supports",
},
],
evidenceArtifact: "https://example.org/evidence/example-selection-01",
isSynthetic: true,
},
{
promptId: "example-implementation-01",
promptVersion: "1.0",
promptText:
"What evidence should an AI visibility audit preserve?",
intent: "implementation",
answerSystem: "Example Answer System",
runTimestamp: "2026-08-11T20:05:00Z",
brandMentioned: false,
targetDomainCited: false,
sources: [
{
url: "https://example.org/audit-method",
role: "evidence",
support: "partially_supports",
},
],
evidenceArtifact:
"https://example.org/evidence/example-implementation-01",
isSynthetic: true,
},
];
console.table(triage(observations));
对于 selection prompt,队列将保留缺失的 selection 和 comparison 角色。identity 页面确认了实体,但不独立为推荐提供依据。
对于 implementation prompt,evidence 存在,但可操作的 implementation 来源仍然缺失。
缺失的角色是研究线索,不是自动许可去发布另一篇文章。需确认 prompt 确实需要该角色。
function assetBrief(item: TriageItem): string {
const format: Record<SourceRole, string> = {
definition: "concise definition page with scope and exclusions",
evidence: "methodology or dataset with dates and limitations",
comparison: "criteria-led comparison with explicit tradeoffs",
implementation: "reproducible tutorial, template, or checklist",
identity: "canonical entity profile with consistent facts",
selection: "use-case matrix with qualification criteria",
context: "background explainer tied to the answer claim",
};
return [
"Prompt: " + item.promptId,
"Role gap: " + item.missingRole,
"Suggested format: " + format[item.missingRole],
"Priority: " + item.priority,
"Reason: " + item.reason,
].join("\n");
}
输出足够小,编辑可以审查。这就是重点。自动化应该让判断变得清晰,而不是隐藏它。
在将本方法用于报告工作流之前:
本方法无法揭示隐藏的检索、训练数据或因果归因。它无法保证发布一个缺失的资产会改变答案。在运行之间,接口、引用、个性化、地理和模型版本可能会发生变化。
它也不能替代编辑判断。definition 页面可能是 selection 问题的错误资产,而供应商撰写的 comparison 可能不够独立,无法支持推荐。
使用队列选择下一个证据问题。然后发布回答它所需的最小真实资产,将其分发到目标受众已经参与的地方,并用冻结的 prompt 组合重新测试。
如果你想在构建队列之前获得更广泛的基线,Corank 提供免费的 AI 可见性审计,覆盖主要答案引擎表面。