fix: 收紧LLM输出格式提示
This commit is contained in:
@@ -47,6 +47,14 @@ describe("LLM prompt builders", () => {
|
|||||||
expect(prompt).toContain("图片主题");
|
expect(prompt).toContain("图片主题");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("fact extraction prompt explicitly forbids object items in string arrays", () => {
|
||||||
|
const prompt = `${FACT_EXTRACTOR_SYSTEM_PROMPT}\n${buildFactExtractorPrompt(articleInput)}`;
|
||||||
|
|
||||||
|
expect(prompt).toContain("uncertain_items must be string[]");
|
||||||
|
expect(prompt).toContain("core_claims must be string[]");
|
||||||
|
expect(prompt).toContain("Do not return objects inside string arrays");
|
||||||
|
});
|
||||||
|
|
||||||
it("article optimizer prompt includes platform templates and Chinese output rules", () => {
|
it("article optimizer prompt includes platform templates and Chinese output rules", () => {
|
||||||
const prompt = `${ARTICLE_OPTIMIZER_SYSTEM_PROMPT}\n${buildArticleOptimizerPrompt(articleInput, factCard)}`;
|
const prompt = `${ARTICLE_OPTIMIZER_SYSTEM_PROMPT}\n${buildArticleOptimizerPrompt(articleInput, factCard)}`;
|
||||||
|
|
||||||
@@ -60,6 +68,14 @@ describe("LLM prompt builders", () => {
|
|||||||
expect(prompt).toContain("forbidden_claims");
|
expect(prompt).toContain("forbidden_claims");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("article optimizer prompt explicitly describes optional array shapes", () => {
|
||||||
|
const prompt = `${ARTICLE_OPTIMIZER_SYSTEM_PROMPT}\n${buildArticleOptimizerPrompt(articleInput, factCard)}`;
|
||||||
|
|
||||||
|
expect(prompt).toContain("changed_sections must be string[]");
|
||||||
|
expect(prompt).toContain("requires_user_confirmation must be string[]");
|
||||||
|
expect(prompt).toContain("image_suggestions must be []");
|
||||||
|
});
|
||||||
|
|
||||||
it("quality inspector prompt encodes fail and warn standards for all risk gates", () => {
|
it("quality inspector prompt encodes fail and warn standards for all risk gates", () => {
|
||||||
const prompt = `${QUALITY_INSPECTOR_SYSTEM_PROMPT}\n${buildQualityInspectorPrompt({
|
const prompt = `${QUALITY_INSPECTOR_SYSTEM_PROMPT}\n${buildQualityInspectorPrompt({
|
||||||
article: {
|
article: {
|
||||||
@@ -92,6 +108,35 @@ describe("LLM prompt builders", () => {
|
|||||||
expect(prompt).toContain("warn 标准");
|
expect(prompt).toContain("warn 标准");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("quality inspector prompt explicitly describes enum outputs", () => {
|
||||||
|
const prompt = `${QUALITY_INSPECTOR_SYSTEM_PROMPT}\n${buildQualityInspectorPrompt({
|
||||||
|
article: {
|
||||||
|
title: "伟思德鲁 AIGC短视频培训",
|
||||||
|
summary: "官网文章摘要",
|
||||||
|
body_markdown: "正文",
|
||||||
|
image_suggestions: [],
|
||||||
|
changed_sections: [],
|
||||||
|
requires_user_confirmation: [],
|
||||||
|
},
|
||||||
|
factCard,
|
||||||
|
platform: "official_site",
|
||||||
|
deterministicChecks: [
|
||||||
|
{
|
||||||
|
rule_id: "title_quality",
|
||||||
|
status: "pass",
|
||||||
|
evidence: "标题自然",
|
||||||
|
reason: "本地规则通过",
|
||||||
|
suggested_fix: "",
|
||||||
|
target_agent: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}`;
|
||||||
|
|
||||||
|
expect(prompt).toContain("status must be one of pass, warn, fail");
|
||||||
|
expect(prompt).toContain("rule_id must reuse the exact English rule_id");
|
||||||
|
expect(prompt).toContain("target_agent must be title, body, fact_card, or null");
|
||||||
|
});
|
||||||
|
|
||||||
it("targeted rewrite prompt gives rule-specific repair actions", () => {
|
it("targeted rewrite prompt gives rule-specific repair actions", () => {
|
||||||
const prompt = `${TARGETED_REWRITER_SYSTEM_PROMPT}\n${buildTargetedRewritePrompt({
|
const prompt = `${TARGETED_REWRITER_SYSTEM_PROMPT}\n${buildTargetedRewritePrompt({
|
||||||
article: {
|
article: {
|
||||||
|
|||||||
@@ -25,6 +25,78 @@ const PLATFORM_GUIDANCE: Record<PublishPlatform, string> = {
|
|||||||
"recommendation_list / 推荐榜单:推荐榜单口吻,必须解释推荐依据;不得制造榜单排名、奖项或第三方认证。",
|
"recommendation_list / 推荐榜单:推荐榜单口吻,必须解释推荐依据;不得制造榜单排名、奖项或第三方认证。",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FACT_CARD_OUTPUT_CONTRACT = [
|
||||||
|
"Output type contract:",
|
||||||
|
"- company_full_name, target_industry, target_audience must be strings.",
|
||||||
|
"- experience_years must be a number or null.",
|
||||||
|
"- company_short_names, brand_names, product_names, core_claims, forbidden_claims, image_topics, uncertain_items must be string[].",
|
||||||
|
"- core_claims must be string[].",
|
||||||
|
"- uncertain_items must be string[].",
|
||||||
|
"- Do not return objects inside string arrays; put the readable claim text directly in the array.",
|
||||||
|
"Example:",
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
company_full_name: "示例科技有限公司",
|
||||||
|
company_short_names: ["示例科技"],
|
||||||
|
brand_names: ["示例品牌"],
|
||||||
|
product_names: ["GEO内容优化平台"],
|
||||||
|
target_industry: "GEO内容优化",
|
||||||
|
target_audience: "市场团队",
|
||||||
|
experience_years: null,
|
||||||
|
core_claims: ["提供GEO内容优化服务"],
|
||||||
|
forbidden_claims: ["行业第一"],
|
||||||
|
image_topics: ["产品后台截图"],
|
||||||
|
uncertain_items: ["客户案例缺少来源"],
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
].join("\n");
|
||||||
|
|
||||||
|
const OPTIMIZED_ARTICLE_OUTPUT_CONTRACT = [
|
||||||
|
"Output type contract:",
|
||||||
|
"- title, summary, body_markdown must be strings.",
|
||||||
|
"- image_suggestions must be [].",
|
||||||
|
"- changed_sections must be string[].",
|
||||||
|
"- requires_user_confirmation must be string[].",
|
||||||
|
"- Do not return objects inside string arrays; put the readable item text directly in the array.",
|
||||||
|
"Example:",
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
title: "示例科技 GEO 内容优化方案",
|
||||||
|
summary: "围绕事实卡重写后的官网文章摘要。",
|
||||||
|
body_markdown: "## 服务能力\n示例科技有限公司提供GEO内容优化服务。",
|
||||||
|
image_suggestions: [],
|
||||||
|
changed_sections: ["title", "body"],
|
||||||
|
requires_user_confirmation: ["客户案例需要确认"],
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
].join("\n");
|
||||||
|
|
||||||
|
const QA_OUTPUT_CONTRACT = [
|
||||||
|
"Output type contract:",
|
||||||
|
"- Return { checks: QaCheck[] }.",
|
||||||
|
"- rule_id must reuse the exact English rule_id from deterministicChecks.",
|
||||||
|
"- status must be one of pass, warn, fail.",
|
||||||
|
"- evidence, reason, suggested_fix must be strings.",
|
||||||
|
"- target_agent must be title, body, fact_card, or null.",
|
||||||
|
"Example check:",
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
rule_id: "title_quality",
|
||||||
|
status: "warn",
|
||||||
|
evidence: "标题偏营销化",
|
||||||
|
reason: "官网标题需要更克制",
|
||||||
|
suggested_fix: "改成事实型标题",
|
||||||
|
target_agent: "title",
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
].join("\n");
|
||||||
|
|
||||||
function formatPlatformGuidance(selected: PublishPlatform) {
|
function formatPlatformGuidance(selected: PublishPlatform) {
|
||||||
return [
|
return [
|
||||||
"平台模板选项:",
|
"平台模板选项:",
|
||||||
@@ -69,6 +141,8 @@ export function buildFactExtractorPrompt(input: ArticleInput) {
|
|||||||
"company_full_name, company_short_names, brand_names, product_names, target_industry, target_audience, experience_years, core_claims, forbidden_claims, image_topics, uncertain_items.",
|
"company_full_name, company_short_names, brand_names, product_names, target_industry, target_audience, experience_years, core_claims, forbidden_claims, image_topics, uncertain_items.",
|
||||||
"Do not include confirmed_by_user.",
|
"Do not include confirmed_by_user.",
|
||||||
"",
|
"",
|
||||||
|
FACT_CARD_OUTPUT_CONTRACT,
|
||||||
|
"",
|
||||||
"字段要求:",
|
"字段要求:",
|
||||||
"- core_claims 只放原文明示、可作为后续优化硬约束的事实。",
|
"- core_claims 只放原文明示、可作为后续优化硬约束的事实。",
|
||||||
"- forbidden_claims 放行业第一、最强、知名客户、显著提升、保证转化等无法验证或高风险主张。",
|
"- forbidden_claims 放行业第一、最强、知名客户、显著提升、保证转化等无法验证或高风险主张。",
|
||||||
@@ -89,6 +163,8 @@ export function buildArticleOptimizerPrompt(
|
|||||||
"Return an OptimizedArticle JSON object with these exact keys:",
|
"Return an OptimizedArticle JSON object with these exact keys:",
|
||||||
"title, summary, body_markdown, image_suggestions, changed_sections, requires_user_confirmation.",
|
"title, summary, body_markdown, image_suggestions, changed_sections, requires_user_confirmation.",
|
||||||
"",
|
"",
|
||||||
|
OPTIMIZED_ARTICLE_OUTPUT_CONTRACT,
|
||||||
|
"",
|
||||||
formatPlatformGuidance(input.platform),
|
formatPlatformGuidance(input.platform),
|
||||||
"",
|
"",
|
||||||
"输出要求:",
|
"输出要求:",
|
||||||
@@ -119,6 +195,7 @@ export function buildQualityInspectorPrompt(input: {
|
|||||||
"Return a JSON object with a checks array.",
|
"Return a JSON object with a checks array.",
|
||||||
"Each check must include rule_id, status, evidence, reason, suggested_fix, and target_agent.",
|
"Each check must include rule_id, status, evidence, reason, suggested_fix, and target_agent.",
|
||||||
"Only use rule_id values already present in deterministicChecks.",
|
"Only use rule_id values already present in deterministicChecks.",
|
||||||
|
QA_OUTPUT_CONTRACT,
|
||||||
"不得把 deterministic fail 降级。",
|
"不得把 deterministic fail 降级。",
|
||||||
"",
|
"",
|
||||||
formatPlatformGuidance(input.platform),
|
formatPlatformGuidance(input.platform),
|
||||||
@@ -146,6 +223,7 @@ export function buildTargetedRewritePrompt(input: {
|
|||||||
}) {
|
}) {
|
||||||
return [
|
return [
|
||||||
"Return an OptimizedArticle JSON object.",
|
"Return an OptimizedArticle JSON object.",
|
||||||
|
OPTIMIZED_ARTICLE_OUTPUT_CONTRACT,
|
||||||
"Rewrite only the fields needed for failedChecks.",
|
"Rewrite only the fields needed for failedChecks.",
|
||||||
"",
|
"",
|
||||||
"按 rule_id 执行修复动作:",
|
"按 rule_id 执行修复动作:",
|
||||||
|
|||||||
Reference in New Issue
Block a user