作为一个每天都在和OpenAI API打交道的开发者,我深深体会到一个好的提示(Prompt)对API调用效果的重要性。今天就来分享一下我在实际项目中总结的一些经验和技巧。
提示工程的艺术
在我看来,写好提示词就像写好代码一样,是一门艺术。以下是我总结的几个关键原则:
1. 明确角色和上下文
// ❌ 模糊的提示
const prompt = `总结这段文字:${text}`
// ✅ 明确的角色和上下文
const prompt = {
role: 'system',
content: '你是一位专业的技术文档编辑,擅长将复杂的技术内容转化为清晰、简洁的总结。'
}
const userPrompt = {
role: 'user',
content: `请用专业的技术视角总结以下内容,重点突出核心技术概念和实现方法:\n\n${text}`
}
2. 结构化输出
// ❌ 自由格式输出
const prompt = '分析这段代码的问题'
// ✅ 结构化输出
const prompt = `分析以下代码,并按照这个格式输出:
{
"issues": [
{
"type": "性能" | "安全" | "可维护性",
"severity": "高" | "中" | "低",
"description": "具体问题描述",
"solution": "建议解决方案"
}
]
}
代码:${code}`
3. 迭代优化
// 第一版:基础功能
async function generateCode(description: string) {
const completion = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
messages: [
{
role: 'user',
content: `生成代码:${description}`
}
]
})
return completion.data.choices[0].message?.content
}
// 优化版:更精确的控制
async function generateCode(description: string, context: CodeContext) {
const completion = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
messages: [
{
role: 'system',
content: `你是一个专业的${context.language}开发者,精通${context.framework}框架。
请生成符合以下规范的代码:
- 遵循${context.language}最佳实践
- 使用${context.framework}的最新特性
- 包含适当的错误处理
- 添加必要的注释
- 考虑性能优化`
},
{
role: 'user',
content: `请生成一个${description}的实现,要求:
1. 代码简洁易懂
2. 包含类型定义
3. 包含示例用法
4. 考虑边界情况`
}
],
temperature: 0.3, // 降低随机性
max_tokens: 1500, // 控制输出长度
presence_penalty: 0.1, // 鼓励多样性
frequency_penalty: 0.1 // 避免重复
})
return completion.data.choices[0].message?.content
}
API调用优化
1. 错误处理和重试机制
// api/openai.ts
import { OpenAIApi, Configuration } from 'openai'
import { sleep } from '@/utils'
export class OpenAIService {
private openai: OpenAIApi
private maxRetries: number
private retryDelay: number
constructor(
apiKey: string,
maxRetries = 3,
retryDelay = 1000
) {
const configuration = new Configuration({ apiKey })
this.openai = new OpenAIApi(configuration)
this.maxRetries = maxRetries
this.retryDelay = retryDelay
}
async createCompletion(params: any) {
let lastError: Error | null = null
for (let i = 0; i < this.maxRetries; i++) {
try {
return await this.openai.createChatCompletion(params)
} catch (error: any) {
lastError = error
// 判断是否需要重试
if (this.shouldRetry(error)) {
const delay = this.calculateDelay(i)
console.log(`重试第${i + 1}次,等待${delay}ms...`)
await sleep(delay)
continue
}
throw error
}
}
throw lastError || new Error('达到最大重试次数')
}
private shouldRetry(error: any): boolean {
// 根据错误类型判断是否需要重试
const retryableErrors = [
'rate_limit_exceeded',
'timeout',
'service_unavailable'
]
return retryableErrors.includes(error.code)
}
private calculateDelay(retryCount: number): number {
// 指数退避策略
return this.retryDelay * Math.pow(2, retryCount)
}
}
2. 缓存机制
// utils/cache.ts
import { Redis } from 'ioredis'
export class Cache {
private redis: Redis
private ttl: number
constructor(redisUrl: string, ttl = 3600) {
this.redis = new Redis(redisUrl)
this.ttl = ttl
}
async get(key: string): Promise<any> {
const value = await this.redis.get(key)
return value ? JSON.parse(value) : null
}
async set(key: string, value: any): Promise<void> {
await this.redis.set(
key,
JSON.stringify(value),
'EX',
this.ttl
)
}
}
// api/completion.ts
export async function getCompletion(prompt: string) {
const cache = new Cache(process.env.REDIS_URL!)
const cacheKey = `completion:${hashString(prompt)}`
// 尝试从缓存获取
const cached = await cache.get(cacheKey)
if (cached) {
console.log('命中缓存')
return cached
}
// 调用API
const completion = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
messages: [{ role: 'user', content: prompt }]
})
// 存入缓存
await cache.set(cacheKey, completion.data)
return completion.data
}
3. 成本控制
// utils/cost.ts
export class CostTracker {
private costs: Record<string, number> = {
'gpt-3.5-turbo': 0.002, // 每1K tokens
'gpt-4': 0.03, // 每1K tokens
'text-embedding-ada-002': 0.0004 // 每1K tokens
}
calculateCost(
model: string,
tokens: number
): number {
const costPer1K = this.costs[model]
return (tokens / 1000) * costPer1K
}
async trackUsage(
model: string,
prompt: string
): Promise<void> {
const tokens = await this.countTokens(prompt)
const cost = this.calculateCost(model, tokens)
await this.logUsage({
timestamp: new Date(),
model,
tokens,
cost
})
}
}
// 使用示例
const costTracker = new CostTracker()
async function makeAPICall(prompt: string) {
// 1. 预估成本
const estimatedTokens = await costTracker.countTokens(prompt)
const estimatedCost = costTracker.calculateCost(
'gpt-3.5-turbo',
estimatedTokens
)
// 2. 检查预算
if (estimatedCost > dailyBudget) {
throw new Error('超出每日预算限制')
}
// 3. 调用API
const result = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
messages: [{ role: 'user', content: prompt }]
})
// 4. 记录实际使用情况
await costTracker.trackUsage(
'gpt-3.5-turbo',
prompt
)
return result
}
实战经验分享
1. 提示词模板化
在实际项目中,我会把常用的提示词模板化:
// templates/prompts.ts
export const prompts = {
codegen: {
typescript: (description: string) => ({
role: 'system',
content: '你是一个TypeScript专家,精通类型系统和最佳实践。'
}),
react: (description: string) => ({
role: 'system',
content: '你是一个React专家,精通hooks和性能优化。'
})
},
review: {
security: () => ({
role: 'system',
content: '你是一个安全专家,专注于代码安全审查。'
}),
performance: () => ({
role: 'system',
content: '你是一个性能优化专家,专注于代码性能审查。'
})
}
}
2. 动态调整参数
根据不同场景动态调整API参数:
type CompletionConfig = {
temperature: number
maxTokens: number
presencePenalty: number
frequencyPenalty: number
}
const configs: Record<string, CompletionConfig> = {
creative: {
temperature: 0.8,
maxTokens: 2000,
presencePenalty: 0.5,
frequencyPenalty: 0.5
},
precise: {
temperature: 0.2,
maxTokens: 1000,
presencePenalty: 0.1,
frequencyPenalty: 0.1
}
}
async function getCompletion(
prompt: string,
mode: 'creative' | 'precise'
) {
const config = configs[mode]
return await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
messages: [{ role: 'user', content: prompt }],
...config
})
}
3. 结果验证
对API返回的结果进行验证:
type ValidationResult = {
valid: boolean
errors: string[]
}
async function validateCompletion(
completion: string,
schema: any
): Promise<ValidationResult> {
try {
// 1. 格式验证
const parsed = JSON.parse(completion)
const validation = await schema.validate(parsed)
// 2. 业务规则验证
const businessRules = validateBusinessRules(parsed)
// 3. 安全检查
const securityCheck = validateSecurity(parsed)
return {
valid: validation && businessRules && securityCheck,
errors: []
}
} catch (error) {
return {
valid: false,
errors: [error.message]
}
}
}
// 使用示例
const result = await getCompletion(prompt)
const validation = await validateCompletion(
result.data.choices[0].message?.content,
schema
)
if (!validation.valid) {
console.error('验证失败:', validation.errors)
// 重试或降级处理
}
写在最后
OpenAI API的调用看似简单,但要用好它还是需要不少经验积累。希望这篇文章能帮助你更好地使用OpenAI API,如果你有什么好的实践经验,也欢迎在评论区分享!
如果觉得有帮助,别忘了点赞关注,我会继续分享更多实战经验~