ai-content-generation

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AI Content Generation - Integration Guide

AI内容生成 - 集成指南

Purpose

目的

Comprehensive guide for AI content generation in the AIProDaily platform, covering OpenAI/Claude integration, prompt management, structured outputs, and content scoring systems.
AIProDaily平台中AI内容生成的综合指南,涵盖OpenAI/Claude集成、提示词管理、结构化输出及内容评分系统。

When to Use

适用场景

Automatically activates when:
  • Calling AI APIs (OpenAI, Claude)
  • Using
    callAIWithPrompt()
  • Creating or modifying prompts
  • Working with
    app_settings
    AI prompts
  • Implementing content generation
  • Building scoring systems
  • Handling AI responses

在以下场景自动触发:
  • 调用AI API(OpenAI、Claude)
  • 使用
    callAIWithPrompt()
  • 创建或修改提示词
  • 操作
    app_settings
    中的AI提示词
  • 实现内容生成功能
  • 构建评分系统
  • 处理AI响应

Core Pattern: callAIWithPrompt()

核心模式:callAIWithPrompt()

Standard Usage

标准用法

Location:
src/lib/openai.ts
typescript
import { callAIWithPrompt } from '@/lib/openai'

// Generate article title
const result = await callAIWithPrompt(
  'ai_prompt_primary_article_title',  // Prompt key in app_settings
  newsletterId,                        // Tenant context
  {
    // Variables for placeholder replacement
    title: post.title,
    description: post.description,
    content: post.full_article_text
  }
)

// result = { headline: "AI-Generated Title" }
位置
src/lib/openai.ts
typescript
import { callAIWithPrompt } from '@/lib/openai'

// 生成文章标题
const result = await callAIWithPrompt(
  'ai_prompt_primary_article_title',  // app_settings中的提示词键
  newsletterId,                        // 租户上下文
  {
    // 用于占位符替换的变量
    title: post.title,
    description: post.description,
    content: post.full_article_text
  }
)

// result = { headline: "AI生成的标题" }

How It Works

工作原理

  1. Loads prompt from
    app_settings
    table by key + newsletter_id
  2. Replaces placeholders like
    {{title}}
    ,
    {{content}}
    with provided variables
  3. Calls AI API (OpenAI or Claude) with complete request
  4. Parses response according to
    response_format
    schema
  5. Returns structured JSON object
  1. 加载提示词:通过键+newsletter_id从
    app_settings
    表中加载
  2. 替换占位符:将
    {{title}}
    {{content}}
    等占位符替换为提供的变量
  3. 调用AI API:向OpenAI或Claude发送完整请求
  4. 解析响应:根据
    response_format
    schema解析返回结果
  5. 返回结果:返回结构化JSON对象

Key Features

核心特性

Database-driven: All prompts stored in database, not hardcoded ✅ Tenant-scoped: Each newsletter can customize prompts ✅ Type-safe: JSON schema enforces response structure ✅ Flexible: Supports both OpenAI and Claude ✅ Reusable: Same function for all AI operations

数据库驱动:所有提示词存储在数据库中,而非硬编码 ✅ 租户隔离:每个新闻通讯可自定义提示词 ✅ 类型安全:JSON schema强制响应结构 ✅ 灵活兼容:同时支持OpenAI和Claude ✅ 可复用:同一函数适用于所有AI操作

Prompt Storage Format

提示词存储格式

Database Schema

数据库Schema

sql
-- app_settings table
CREATE TABLE app_settings (
  key TEXT PRIMARY KEY,
  value JSONB NOT NULL,
  description TEXT,
  newsletter_id UUID NOT NULL,
  ai_provider TEXT,  -- 'openai' or 'claude'
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
)
sql
-- app_settings表
CREATE TABLE app_settings (
  key TEXT PRIMARY KEY,
  value JSONB NOT NULL,
  description TEXT,
  newsletter_id UUID NOT NULL,
  ai_provider TEXT,  -- 'openai' 或 'claude'
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
)

Complete Prompt Structure

完整提示词结构

sql
INSERT INTO app_settings (key, value, newsletter_id, ai_provider, description)
VALUES (
  'ai_prompt_primary_article_title',
  '{
    "model": "gpt-4o",
    "temperature": 0.7,
    "max_output_tokens": 500,
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "article_title_response",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "headline": {
              "type": "string",
              "description": "The generated article headline"
            }
          },
          "required": ["headline"],
          "additionalProperties": false
        }
      }
    },
    "messages": [
      {
        "role": "system",
        "content": "You are an expert headline writer for accounting professionals..."
      },
      {
        "role": "user",
        "content": "Source Title: {{title}}\n\nSource Content: {{content}}\n\nWrite a compelling headline."
      }
    ]
  }'::jsonb,
  'newsletter-uuid-here',
  'openai',
  'Content Generation - Primary Article Title: Generates engaging headlines'
);
All parameters stored in database:
  • model
    - AI model to use
  • temperature
    - Creativity level (0-1)
  • max_output_tokens
    - Response length limit
  • response_format
    - JSON schema for structured output
  • messages
    - System and user prompts with placeholders

sql
INSERT INTO app_settings (key, value, newsletter_id, ai_provider, description)
VALUES (
  'ai_prompt_primary_article_title',
  '{
    "model": "gpt-4o",
    "temperature": 0.7,
    "max_output_tokens": 500,
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "article_title_response",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "headline": {
              "type": "string",
              "description": "生成的文章标题"
            }
          },
          "required": ["headline"],
          "additionalProperties": false
        }
      }
    },
    "messages": [
      {
        "role": "system",
        "content": "你是面向会计专业人士的资深标题撰写专家..."
      },
      {
        "role": "user",
        "content": "原文标题: {{title}}\n\n原文内容: {{content}}\n\n撰写一个引人注目的标题。"
      }
    ]
  }'::jsonb,
  'newsletter-uuid-here',
  'openai',
  '内容生成 - 主文章标题:生成有吸引力的标题'
);
所有参数存储在数据库中:
  • model
    - 使用的AI模型
  • temperature
    - 创意程度(0-1)
  • max_output_tokens
    - 响应长度限制
  • response_format
    - 用于结构化输出的JSON schema
  • messages
    - 包含占位符的系统提示词和用户提示词

Response Format Patterns

响应格式模式

Simple String Response

简单字符串响应

json
{
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "simple_response",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "result": { "type": "string" }
        },
        "required": ["result"],
        "additionalProperties": false
      }
    }
  }
}
json
{
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "simple_response",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "result": { "type": "string" }
        },
        "required": ["result"],
        "additionalProperties": false
      }
    }
  }
}

Complex Structured Response

复杂结构化响应

json
{
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "article_body_response",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "headline": { "type": "string" },
          "body": { "type": "string" },
          "summary": { "type": "string" },
          "key_points": {
            "type": "array",
            "items": { "type": "string" }
          }
        },
        "required": ["headline", "body"],
        "additionalProperties": false
      }
    }
  }
}
json
{
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "article_body_response",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "headline": { "type": "string" },
          "body": { "type": "string" },
          "summary": { "type": "string" },
          "key_points": {
            "type": "array",
            "items": { "type": "string" }
          }
        },
        "required": ["headline", "body"],
        "additionalProperties": false
      }
    }
  }
}

Scoring Response

评分响应

json
{
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "content_score_response",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "score": {
            "type": "number",
            "minimum": 0,
            "maximum": 10
          },
          "reasoning": { "type": "string" }
        },
        "required": ["score", "reasoning"],
        "additionalProperties": false
      }
    }
  }
}

json
{
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "content_score_response",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "score": {
            "type": "number",
            "minimum": 0,
            "maximum": 10
          },
          "reasoning": { "type": "string" }
        },
        "required": ["score", "reasoning"],
        "additionalProperties": false
      }
    }
  }
}

Multi-Criteria Scoring System

多标准评分系统

Overview

概述

Purpose: Evaluate RSS posts using multiple weighted criteria Location:
src/lib/rss-processor.ts
Storage:
post_ratings
table
目的:使用多个加权标准评估RSS文章 位置
src/lib/rss-processor.ts
存储
post_ratings

Configuration

配置

typescript
// Criteria settings in app_settings
{
  "criteria_enabled_count": 3,  // 1-5 criteria
  "criteria_1_name": "Interest Level",
  "criteria_1_weight": 1.5,
  "criteria_2_name": "Relevance",
  "criteria_2_weight": 1.5,
  "criteria_3_name": "Impact",
  "criteria_3_weight": 1.0
}
typescript
// app_settings中的标准配置
{
  "criteria_enabled_count": 3,  // 1-5个标准
  "criteria_1_name": "兴趣程度",
  "criteria_1_weight": 1.5,
  "criteria_2_name": "相关性",
  "criteria_2_weight": 1.5,
  "criteria_3_name": "影响力",
  "criteria_3_weight": 1.0
}

Scoring Process

评分流程

typescript
// Each criterion gets separate AI call
for (let i = 1; i <= criteriaCount; i++) {
  const promptKey = `ai_prompt_criteria_${i}`
  const weight = settings[`criteria_${i}_weight`]

  // Call AI for this criterion
  const result = await callAIWithPrompt(
    promptKey,
    newsletterId,
    {
      title: post.title,
      description: post.description,
      content: post.content
    }
  )

  // Store individual score
  await supabaseAdmin
    .from('post_ratings')
    .insert({
      post_id: post.id,
      newsletter_id: newsletterId,
      criterion_name: criteriaName,
      score: result.score,        // 0-10
      weighted_score: result.score * weight,
      reasoning: result.reasoning
    })
}

// Calculate total score (sum of weighted scores)
const totalScore = ratings.reduce((sum, r) => sum + r.weighted_score, 0)
typescript
// 每个标准单独调用AI
for (let i = 1; i <= criteriaCount; i++) {
  const promptKey = `ai_prompt_criteria_${i}`
  const weight = settings[`criteria_${i}_weight`]

  // 针对该标准调用AI
  const result = await callAIWithPrompt(
    promptKey,
    newsletterId,
    {
      title: post.title,
      description: post.description,
      content: post.content
    }
  )

  // 存储单个标准的评分
  await supabaseAdmin
    .from('post_ratings')
    .insert({
      post_id: post.id,
      newsletter_id: newsletterId,
      criterion_name: criteriaName,
      score: result.score,        // 0-10
      weighted_score: result.score * weight,
      reasoning: result.reasoning
    })
}

// 计算总评分(加权得分之和)
const totalScore = ratings.reduce((sum, r) => sum + r.weighted_score, 0)

Example Scoring

评分示例

Criterion 1: Interest Level (weight 1.5) → score 8 → weighted 12.0
Criterion 2: Relevance (weight 1.5)     → score 7 → weighted 10.5
Criterion 3: Impact (weight 1.0)        → score 6 → weighted 6.0
═══════════════════════════════════════════════════════════════
Total Score: 28.5

标准1:兴趣程度(权重1.5)→ 得分8 → 加权得分12.0
标准2:相关性(权重1.5)     → 得分7 → 加权得分10.5
标准3:影响力(权重1.0)        → 得分6 → 加权得分6.0
═══════════════════════════════════════════════════════════════
总评分:28.5

Prompt Design Best Practices

提示词设计最佳实践

System Message

系统提示词

typescript
{
  "role": "system",
  "content": `You are an expert content writer for accounting professionals.
Your audience is CPAs, accountants, and financial professionals.
Write in a professional yet engaging tone.
Focus on practical, actionable information.
Keep content concise and scannable.`
}
typescript
{
  "role": "system",
  "content": `你是面向会计专业人士的资深内容撰写者。
你的受众是注册会计师、会计和金融专业人士。
采用专业且有吸引力的语气撰写。
专注于实用、可操作的信息。
保持内容简洁易读。`
}

User Message with Placeholders

带占位符的用户提示词

typescript
{
  "role": "user",
  "content": `Source Article:
Title: {{title}}
Description: {{description}}
Full Content: {{content}}

Task: Write a 200-300 word article summary that:
1. Captures the key takeaways
2. Explains why this matters to accountants
3. Uses clear, professional language
4. Ends with a thought-provoking statement

Output the summary as a JSON object with a "body" field.`
}
typescript
{
  "role": "user",
  "content": `原文:
标题: {{title}}
描述: {{description}}
全文: {{content}}

任务:撰写一篇200-300词的文章摘要,要求:
1. 提炼核心要点
2. 解释对会计人员的重要性
3. 使用清晰、专业的语言
4. 以发人深省的语句结尾

将摘要作为包含"body"字段的JSON对象输出。`
}

Temperature Guidelines

Temperature参数指南

typescript
// Creative content (headlines, summaries)
"temperature": 0.7

// Factual content (analysis, scoring)
"temperature": 0.3

// Consistent output (classifications)
"temperature": 0.1

typescript
// 创意内容(标题、摘要)
"temperature": 0.7

// 事实性内容(分析、评分)
"temperature": 0.3

// 一致性输出(分类)
"temperature": 0.1

Model Selection

模型选择

OpenAI Models

OpenAI模型

typescript
// Fast, cost-effective (most common)
"model": "gpt-4o"

// Latest, most capable
"model": "gpt-4o-2024-11-20"

// Smaller, faster for simple tasks
"model": "gpt-4o-mini"
typescript
// 快速、经济高效(最常用)
"model": "gpt-4o"

// 最新、功能最强
"model": "gpt-4o-2024-11-20"

// 轻量、高速,适用于简单任务
"model": "gpt-4o-mini"

Claude Models

Claude模型

typescript
// Most capable
"model": "claude-3-5-sonnet-20241022"

// Fast, cost-effective
"model": "claude-3-5-haiku-20241022"

// Older, still powerful
"model": "claude-3-opus-20240229"

typescript
// 功能最强
"model": "claude-3-5-sonnet-20241022"

// 快速、经济高效
"model": "claude-3-5-haiku-20241022"

// 旧版本,但仍强大
"model": "claude-3-opus-20240229"

Error Handling

错误处理

Standard Pattern

标准模式

typescript
try {
  const result = await callAIWithPrompt(
    promptKey,
    newsletterId,
    variables
  )

  // Validate response
  if (!result || !result.headline) {
    throw new Error('Invalid AI response: missing required fields')
  }

  return result

} catch (error: any) {
  console.error('[AI] Error calling AI:', error.message)

  // Check for specific errors
  if (error.message.includes('rate_limit')) {
    console.error('[AI] Rate limit exceeded, implement backoff')
  }
  if (error.message.includes('context_length')) {
    console.error('[AI] Input too long, need to truncate')
  }

  throw error
}
typescript
try {
  const result = await callAIWithPrompt(
    promptKey,
    newsletterId,
    variables
  )

  // 验证响应
  if (!result || !result.headline) {
    throw new Error('无效AI响应:缺少必填字段')
  }

  return result

} catch (error: any) {
  console.error('[AI] 调用AI出错:', error.message)

  // 检查特定错误
  if (error.message.includes('rate_limit')) {
    console.error('[AI] 超出速率限制,需实现退避策略')
  }
  if (error.message.includes('context_length')) {
    console.error('[AI] 输入过长,需要截断')
  }

  throw error
}

Retry with Backoff

带退避的重试机制

typescript
async function callAIWithRetry(
  promptKey: string,
  newsletterId: string,
  variables: Record<string, any>,
  maxRetries = 2
) {
  let retryCount = 0

  while (retryCount <= maxRetries) {
    try {
      return await callAIWithPrompt(promptKey, newsletterId, variables)
    } catch (error: any) {
      retryCount++

      // Don't retry on validation errors
      if (error.message.includes('Invalid')) {
        throw error
      }

      if (retryCount > maxRetries) {
        throw error
      }

      console.log(`[AI] Retry ${retryCount}/${maxRetries} after error`)
      await new Promise(resolve => setTimeout(resolve, 2000 * retryCount))
    }
  }
}

typescript
async function callAIWithRetry(
  promptKey: string,
  newsletterId: string,
  variables: Record<string, any>,
  maxRetries = 2
) {
  let retryCount = 0

  while (retryCount <= maxRetries) {
    try {
      return await callAIWithPrompt(promptKey, newsletterId, variables)
    } catch (error: any) {
      retryCount++

      // 验证错误不重试
      if (error.message.includes('Invalid')) {
        throw error
      }

      if (retryCount > maxRetries) {
        throw error
      }

      console.log(`[AI] 出错后重试 ${retryCount}/${maxRetries}`)
      await new Promise(resolve => setTimeout(resolve, 2000 * retryCount))
    }
  }
}

Rate Limiting

速率限制

OpenAI Limits

OpenAI限制

Tier 1 (free/trial):
  • gpt-4o: 500 requests/day
  • gpt-4o-mini: 10,000 requests/day
Tier 2 (paid):
  • gpt-4o: 5,000 requests/min
  • gpt-4o-mini: 30,000 requests/min
Tier 1(免费/试用):
  • gpt-4o: 500请求/天
  • gpt-4o-mini: 10,000请求/天
Tier 2(付费):
  • gpt-4o: 5,000请求/分钟
  • gpt-4o-mini: 30,000请求/分钟

Batching Strategy

批量处理策略

typescript
// Process in batches to avoid rate limits
const BATCH_SIZE = 3
const BATCH_DELAY = 2000  // 2 seconds between batches

const batches = chunkArray(posts, BATCH_SIZE)

for (const batch of batches) {
  // Process batch in parallel
  await Promise.all(
    batch.map(post => generateArticle(post))
  )

  // Wait before next batch
  if (batches.indexOf(batch) < batches.length - 1) {
    await new Promise(resolve => setTimeout(resolve, BATCH_DELAY))
  }
}

console.log(`[AI] Processed ${posts.length} items in ${batches.length} batches`)

typescript
// 批量处理以避免超出速率限制
const BATCH_SIZE = 3
const BATCH_DELAY = 2000  // 批次间隔2秒

const batches = chunkArray(posts, BATCH_SIZE)

for (const batch of batches) {
  // 并行处理批次
  await Promise.all(
    batch.map(post => generateArticle(post))
  )

  // 下一批次前等待
  if (batches.indexOf(batch) < batches.length - 1) {
    await new Promise(resolve => setTimeout(resolve, BATCH_DELAY))
  }
}

console.log(`[AI] 分${batches.length}批处理了${posts.length}条内容`)

Content Generation Workflows

内容生成工作流

Article Title Generation

文章标题生成

typescript
const titleResult = await callAIWithPrompt(
  'ai_prompt_primary_article_title',
  newsletterId,
  {
    title: rssPost.title,
    description: rssPost.description,
    content: rssPost.full_article_text
  }
)

// Store generated title
await supabaseAdmin
  .from('articles')
  .insert({
    newsletter_id: newsletterId,
    campaign_id: campaignId,
    rss_post_id: rssPost.id,
    headline: titleResult.headline,
    article_text: null  // Body generated separately
  })
typescript
const titleResult = await callAIWithPrompt(
  'ai_prompt_primary_article_title',
  newsletterId,
  {
    title: rssPost.title,
    description: rssPost.description,
    content: rssPost.full_article_text
  }
)

// 存储生成的标题
await supabaseAdmin
  .from('articles')
  .insert({
    newsletter_id: newsletterId,
    campaign_id: campaignId,
    rss_post_id: rssPost.id,
    headline: titleResult.headline,
    article_text: null  // 正文单独生成
  })

Article Body Generation

文章正文生成

typescript
const bodyResult = await callAIWithPrompt(
  'ai_prompt_primary_article_body',
  newsletterId,
  {
    title: rssPost.title,
    headline: article.headline,  // Use AI-generated headline
    description: rssPost.description,
    content: rssPost.full_article_text
  }
)

// Update with generated body
await supabaseAdmin
  .from('articles')
  .update({
    article_text: bodyResult.body
  })
  .eq('id', article.id)
  .eq('newsletter_id', newsletterId)
typescript
const bodyResult = await callAIWithPrompt(
  'ai_prompt_primary_article_body',
  newsletterId,
  {
    title: rssPost.title,
    headline: article.headline,  // 使用AI生成的标题
    description: rssPost.description,
    content: rssPost.full_article_text
  }
)

// 更新生成的正文
await supabaseAdmin
  .from('articles')
  .update({
    article_text: bodyResult.body
  })
  .eq('id', article.id)
  .eq('newsletter_id', newsletterId)

Fact-Checking

事实核查

typescript
const factCheckResult = await callAIWithPrompt(
  'ai_prompt_fact_check',
  newsletterId,
  {
    headline: article.headline,
    body: article.article_text,
    source_content: article.rss_post.full_article_text
  }
)

// Store fact-check score
await supabaseAdmin
  .from('articles')
  .update({
    fact_check_score: factCheckResult.score,
    fact_check_reasoning: factCheckResult.reasoning
  })
  .eq('id', article.id)
  .eq('newsletter_id', newsletterId)

typescript
const factCheckResult = await callAIWithPrompt(
  'ai_prompt_fact_check',
  newsletterId,
  {
    headline: article.headline,
    body: article.article_text,
    source_content: article.rss_post.full_article_text
  }
)

// 存储事实核查评分
await supabaseAdmin
  .from('articles')
  .update({
    fact_check_score: factCheckResult.score,
    fact_check_reasoning: factCheckResult.reasoning
  })
  .eq('id', article.id)
  .eq('newsletter_id', newsletterId)

Testing Prompts

测试提示词

Test in Isolation

独立测试

typescript
// Create test route: app/api/test/prompt/route.ts
export async function POST(request: NextRequest) {
  const { promptKey, variables } = await request.json()

  try {
    const result = await callAIWithPrompt(
      promptKey,
      'test-newsletter-id',
      variables
    )

    return NextResponse.json({
      success: true,
      result
    })
  } catch (error: any) {
    return NextResponse.json({
      error: error.message
    }, { status: 500 })
  }
}

export const maxDuration = 60
typescript
// 创建测试路由: app/api/test/prompt/route.ts
export async function POST(request: NextRequest) {
  const { promptKey, variables } = await request.json()

  try {
    const result = await callAIWithPrompt(
      promptKey,
      'test-newsletter-id',
      variables
    )

    return NextResponse.json({
      success: true,
      result
    })
  } catch (error: any) {
    return NextResponse.json({
      error: error.message
    }, { status: 500 })
  }
}

export const maxDuration = 60

Validate Response Schema

验证响应Schema

typescript
function validateArticleResponse(result: any): boolean {
  if (!result) return false
  if (typeof result.headline !== 'string') return false
  if (typeof result.body !== 'string') return false
  if (result.headline.length < 10) return false
  if (result.body.length < 50) return false
  return true
}

typescript
function validateArticleResponse(result: any): boolean {
  if (!result) return false
  if (typeof result.headline !== 'string') return false
  if (typeof result.body !== 'string') return false
  if (result.headline.length < 10) return false
  if (result.body.length < 50) return false
  return true
}

Best Practices

最佳实践

✅ DO:

✅ 建议:

  • Store all prompts in
    app_settings
    database
  • Use JSON schema for response format validation
  • Include clear instructions in system message
  • Use placeholders for dynamic content
  • Implement retry logic for transient errors
  • Batch API calls to respect rate limits
  • Validate AI responses before using
  • Log AI calls for debugging
  • Use appropriate temperature for task
  • Test prompts thoroughly before production
  • 将所有提示词存储在
    app_settings
    数据库中
  • 使用JSON schema进行响应格式验证
  • 在系统提示词中包含清晰的指令
  • 为动态内容使用占位符
  • 为临时错误实现重试逻辑
  • 批量调用API以遵守速率限制
  • 使用AI响应前先验证
  • 记录AI调用以便调试
  • 根据任务设置合适的temperature参数
  • 生产环境前彻底测试提示词

❌ DON'T:

❌ 避免:

  • Hardcode prompts in code
  • Skip response validation
  • Ignore rate limits
  • Use overly complex prompts
  • Forget error handling
  • Expose API keys client-side
  • Use wrong model for task
  • Trust AI output blindly
  • Skip testing with real data
  • Make unbatched parallel calls

  • 在代码中硬编码提示词
  • 跳过响应验证
  • 忽略速率限制
  • 使用过于复杂的提示词
  • 忘记错误处理
  • 在客户端暴露API密钥
  • 为任务选择错误的模型
  • 盲目信任AI输出
  • 跳过真实数据测试
  • 发起无批量的并行调用

Troubleshooting

故障排除

AI Returns Invalid Format

AI返回无效格式

Check:
  1. JSON schema is correct
  2. strict: true
    is set
  3. Instructions are clear
  4. Model supports structured outputs
检查项:
  1. JSON schema是否正确
  2. 是否设置了
    strict: true
  3. 指令是否清晰
  4. 模型是否支持结构化输出

Rate Limit Errors

速率限制错误

Solutions:
  1. Implement batching (3-5 requests per batch)
  2. Add delays between batches (2-5 seconds)
  3. Use retry with exponential backoff
  4. Upgrade API tier if needed
解决方案:
  1. 实现批量处理(每批3-5个请求)
  2. 批次间添加延迟(2-5秒)
  3. 使用指数退避的重试机制
  4. 如有需要升级API tier

Content Quality Issues

内容质量问题

Improve:
  1. Refine system message instructions
  2. Adjust temperature (lower for consistency)
  3. Provide better examples in prompt
  4. Add validation rules
  5. Use more capable model
改进方法:
  1. 优化系统提示词的指令
  2. 调整temperature参数(降低以提升一致性)
  3. 在提示词中提供更好的示例
  4. 添加验证规则
  5. 使用功能更强的模型

Timeout Errors

超时错误

Fix:
  1. Reduce max_output_tokens
  2. Simplify prompt
  3. Use faster model (gpt-4o-mini, claude-haiku)
  4. Increase API route maxDuration

修复方案:
  1. 减少max_output_tokens
  2. 简化提示词
  3. 使用更快的模型(gpt-4o-mini, claude-haiku)
  4. 增加API路由的maxDuration

Reference

参考

Main Function:
src/lib/openai.ts
-
callAIWithPrompt()
Prompt Storage:
app_settings
table Response Storage:
articles
,
post_ratings
tables Scoring Logic:
src/lib/rss-processor.ts
Related Docs:
  • docs/AI_PROMPT_SYSTEM_GUIDE.md
  • docs/OPENAI_RESPONSES_API_GUIDE.md
  • docs/workflows/MULTI_CRITERIA_SCORING_GUIDE.md

Skill Status: ACTIVE ✅ Line Count: < 500 ✅ Integration: OpenAI + Claude ✅
核心函数
src/lib/openai.ts
-
callAIWithPrompt()
提示词存储
app_settings
响应存储
articles
,
post_ratings
评分逻辑
src/lib/rss-processor.ts
相关文档:
  • docs/AI_PROMPT_SYSTEM_GUIDE.md
  • docs/OPENAI_RESPONSES_API_GUIDE.md
  • docs/workflows/MULTI_CRITERIA_SCORING_GUIDE.md

技能状态:ACTIVE ✅ 代码行数:< 500 ✅ 集成情况:OpenAI + Claude ✅