名称: llm-应用开发
描述: 使用大型语言模型构建应用程序 - 提示工程、RAG模式和LLM集成。用于AI驱动功能、聊天机器人或基于LLM的自动化。
来源: wshobson/agents
许可证: MIT
LLM应用开发
提示工程
结构化提示
const systemPrompt = `您是一个乐于助人的助手,回答关于我们产品的问题。
规则:
- 只回答关于我们产品的问题
- 如果不知道,就说“我不知道”
- 保持回答简洁(少于100字)
- 从不编造信息
上下文:
{context}`;
const userPrompt = `问题: {question}`;
少样本示例
const prompt = `分类客户反馈的情感。
示例:
输入: “爱这个产品!”
输出: 正面
输入: “最差的购买经历”
输出: 负面
输入: “它工作正常”
输出: 中性
输入: “${customerFeedback}”
输出:`;
思维链
const prompt = `逐步解决这个问题:
问题: ${question}
让我们思考:
1. 首先,识别关键信息
2. 然后,确定方法
3. 最后,计算答案
逐步解决方案:`;
API集成
OpenAI模式
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
async function chat(messages: Message[]): Promise<string> {
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages,
temperature: 0.7,
max_tokens: 500,
});
return response.choices[0].message.content ?? '';
}
Anthropic模式
import Anthropic from '@anthropic-ai/sdk';
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
async function chat(prompt: string): Promise<string> {
const response = await anthropic.messages.create({
model: 'claude-3-opus-20240229',
max_tokens: 1024,
messages: [{ role: 'user', content: prompt }],
});
return response.content[0].type === 'text'
? response.content[0].text
: '';
}
流式响应
async function* streamChat(prompt: string) {
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content) yield content;
}
}
RAG(检索增强生成)
基本RAG管道
async function ragQuery(question: string): Promise<string> {
// 1. 嵌入问题
const questionEmbedding = await embedText(question);
// 2. 搜索向量数据库
const relevantDocs = await vectorDb.search(questionEmbedding, { limit: 5 });
// 3. 构建上下文
const context = relevantDocs.map(d => d.content).join('
');
// 4. 生成答案
const prompt = `基于此上下文回答:
${context}
问题: ${question}`;
return await chat(prompt);
}
文档分块
function chunkDocument(text: string, options: ChunkOptions): string[] {
const { chunkSize = 1000, overlap = 200 } = options;
const chunks: string[] = [];
let start = 0;
while (start < text.length) {
const end = Math.min(start + chunkSize, text.length);
chunks.push(text.slice(start, end));
start += chunkSize - overlap;
}
return chunks;
}
嵌入存储
// 使用Supabase与pgvector
async function storeEmbeddings(docs: Document[]) {
for (const doc of docs) {
const embedding = await embedText(doc.content);
await supabase.from('documents').insert({
content: doc.content,
metadata: doc.metadata,
embedding: embedding, // 向量列
});
}
}
async function searchSimilar(query: string, limit = 5) {
const embedding = await embedText(query);
const { data } = await supabase.rpc('match_documents', {
query_embedding: embedding,
match_count: limit,
});
return data;
}
错误处理
async function safeLLMCall<T>(
fn: () => Promise<T>,
options: { retries?: number; fallback?: T }
): Promise<T> {
const { retries = 3, fallback } = options;
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429) {
// 速率限制 - 指数退避
await sleep(Math.pow(2, i) * 1000);
continue;
}
if (i === retries - 1) {
if (fallback !== undefined) return fallback;
throw error;
}
}
}
throw new Error('最大重试次数已超出');
}
最佳实践
- 令牌管理: 跟踪使用情况并设置限制
- 缓存: 缓存嵌入和常见查询
- 评估: 用多样化输入测试提示
- 护栏: 在使用前验证输出
- 日志记录: 记录提示和响应以便调试
- 成本控制: 对简单任务使用更便宜的模型
- 延迟: 流式响应以改善用户体验
- 隐私: 不要将个人身份信息发送到外部API