mcpField
O
openai-assistants

openai-assistants

github.com/jackspace开发1635 次安装12 周前更新
代码仓库

关于 openai-assistants

openai-assistants 是面向开发者的技能,用于维护基于 OpenAI Assistants API v2 的应用或迁移至 Responses API。内容涵盖 Assistant、持久化线程、运行任务、流式处理和内置工具;该 API 计划于 2026 年上半年停止服务。

主要功能

  1. 01Assistant 和线程生命周期管理
  2. 02异步运行任务与流式处理
  3. 03Code Interpreter、File Search 和函数
  4. 04向量存储与文件上传
  5. 05迁移至 Responses API 的指南

适用场景

  1. 01维护现有 Assistants API 应用
  2. 02实现持久化的助手对话
  3. 03流式获取运行进度和响应
  4. 04规划从 Assistants 迁移至 Responses API

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jackspace/claudeskillz --skill openai-assistants

安装后在 Claude Code 中输入/openai-assistants确认已加载。

附带文件README.mdSKILL.json

详细介绍

OpenAI Assistants API v2

状态:已可用于生产环境(计划于 2026 年上半年弃用) 软件包:[email protected] 最后更新:2025-10-25 v1 弃用时间:2024 年 12 月 18 日 v2 计划结束时间:2026 年上半年(迁移至 Responses API)


⚠️ 重要:弃用通知

OpenAI 宣布,Assistants API 将弃用,并由 Responses API 取代。

时间表:

  • ✅ 2024 年 12 月 18 日:Assistants API v1 弃用
  • ⏳ 2026 年上半年:计划停止支持 Assistants API v2
  • ✅ 现在:Responses API 已推出(新项目推荐使用)

你仍应使用此技能吗?

  • ✅ 是,如果:你已有 Assistants API 代码(有 12–18 个月的迁移窗口)
  • ✅ 是,如果:你需要维护旧版应用
  • ✅ 是,如果:你正计划从 Assistants 迁移至 Responses
  • ❌ 否,如果:你正开始一个新项目(请改用 openai-responses 技能)

迁移路径: 完整迁移指南请参阅 references/migration-to-responses.md。


目录

  1. 快速开始
  2. 核心概念
  3. Assistants
  4. Threads
  5. Messages
  6. Runs
  7. 流式 Runs
  8. 工具
  9. 向量存储
  10. 文件上传
  11. Thread 生命周期管理
  12. 错误处理
  13. 生产环境最佳实践
  14. 与其他技能的关系

快速开始

安装
npm install [email protected]
环境设置
export OPENAI_API_KEY="sk-..."
基础 Assistant(Node.js SDK)
import OpenAI from 'openai';

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

// 1. Create an assistant
const assistant = await openai.beta.assistants.create({
  name: "Math Tutor",
  instructions: "You are a personal math tutor. Write and run code to answer math questions.",
  tools: [{ type: "code_interpreter" }],
  model: "gpt-4o",
});

// 2. Create a thread
const thread = await openai.beta.threads.create();

// 3. Add a message to the thread
await openai.beta.threads.messages.create(thread.id, {
  role: "user",
  content: "I need to solve the equation `3x + 11 = 14`. Can you help me?",
});

// 4. Create a run
const run = await openai.beta.threads.runs.create(thread.id, {
  assistant_id: assistant.id,
});

// 5. Poll for completion
let runStatus = await openai.beta.threads.runs.retrieve(thread.id, run.id);

while (runStatus.status !== 'completed') {
  await new Promise(resolve => setTimeout(resolve, 1000));
  runStatus = await openai.beta.threads.runs.retrieve(thread.id, run.id);
}

// 6. Retrieve messages
const messages = await openai.beta.threads.messages.list(thread.id);
console.log(messages.data[0].content[0].text.value);
基础 Assistant(Fetch - Cloudflare Workers)
// 1. Create assistant
const assistant = await fetch('https://api.openai.com/v1/assistants', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${env.OPENAI_API_KEY}`,
    'Content-Type': 'application/json',
    'OpenAI-Beta': 'assistants=v2',
  },
  body: JSON.stringify({
    name: "Math Tutor",
    instructions: "You are a helpful math tutor.",
    model: "gpt-4o",
  }),
});

const assistantData = await assistant.json();

// 2. Create thread
const thread = await fetch('https://api.openai.com/v1/threads', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${env.OPENAI_API_KEY}`,
    'Content-Type': 'application/json',
    'OpenAI-Beta': 'assistants=v2',
  },
});

const threadData = await thread.json();

// 3. Add message and create run
const run = await fetch(`https://api.openai.com/v1/threads/${threadData.id}/runs`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${env.OPENAI_API_KEY}`,
    'Content-Type': 'application/json',
    'OpenAI-Beta': 'assistants=v2',
  },
  body: JSON.stringify({
    assistant_id: assistantData.id,
    additional_messages: [{
      role: "user",
      content: "What is 3x + 11 = 14?",
    }],
  }),
});

// Poll for completion...

核心概念

Assistants API 使用四种主要对象:

1. Assistants

经过配置的 AI 实体,包含:

  • 指令(系统提示词,最多 256k 个字符)
  • 模型(gpt-4o、gpt-5 等)
  • 工具(Code Interpreter、File Search、Functions)
  • 文件附件
  • 元数据
2. Threads

对话容器,具有以下特点:

  • 存储消息历史
  • 在多次运行之间持久保存
  • 可包含元数据
  • 最多支持 100,000 条消息
3. Messages

Thread 中的单条消息:

  • 用户消息(输入)
  • Assistant 消息(输出)
  • 可包含文件附件
  • 支持文本和图像内容
4. Runs

在 Thread 上执行 Assistant:

  • 异步处理
  • 有多种状态(queued、in_progress、completed、failed 等)
  • 可流式传输结果
  • 自动处理工具调用

Assistants

创建 Assistant
const assistant = await openai.beta.assistants.create({
  name: "Data Analyst",
  instructions: "You are a data analyst. Use code interpreter to analyze data and create visualizations.",
  model: "gpt-4o",
  tools: [
    { type: "code_interpreter" },
    { type: "file_search" },
  ],
  tool_resources: {
    file_search: {
      vector_store_ids: ["vs_abc123"],
    },
  },
  metadata: {
    department: "analytics",
    version: "1.0",
  },
});

参数:

  • model(必填):模型 ID(gpt-4o、gpt-5、gpt-4-turbo)
  • instructions:系统提示词(v2 中最多 256k 个字符;v1 中为 32k)
  • name:Assistant 名称(最多 256 个字符)
  • description:描述(最多 512 个字符)
  • tools:工具数组(最多 128 个工具)
  • tool_resources:工具所需资源(向量存储、文件)
  • temperature:0–2(默认值为 1)
  • top_p:0–1(默认值为 1)
  • response_format:"auto"、"json_object" 或 JSON Schema
  • metadata:键值对(最多 16 对)
获取 Assistant
const assistant = await openai.beta.assistants.retrieve("asst_abc123");
更新 Assistant
const updatedAssistant = await openai.beta.assistants.update("asst_abc123", {
  instructions: "Updated instructions",
  tools: [{ type: "code_interpreter" }, { type: "file_search" }],
});
删除 Assistant
await openai.beta.assistants.del("asst_abc123");
列出 Assistants
const assistants = await openai.beta.assistants.list({
  limit: 20,
  order: "desc",
});

Threads

Threads 用于存储对话历史,并在多次运行之间持久保存。

创建 Thread
// Empty thread
const thread = await openai.beta.threads.create();

// Thread with initial messages
const thread = await openai.beta.threads.create({
  messages: [
    {
      role: "user",
      content: "Hello! I need help with Python.",
      metadata: { source: "web" },
    },
  ],
  metadata: {
    user_id: "user_123",
    session_id: "session_456",
  },
});
获取 Thread
const thread = await openai.beta.threads.retrieve("thread_abc123");
更新 Thread 元数据
const thread = await openai.beta.threads.update("thread_abc123", {
  metadata: {
    user_id: "user_123",
    last_active: new Date().toISOString(),
  },
});
删除 Thread
await openai.beta.threads.del("thread_abc123");

⚠️ 警告:删除 Thread 也会删除其中的所有消息和 Runs。此操作无法撤销。


Messages

向 Thread 添加消息
const message = await openai.beta.threads.messages.create("thread_abc123", {
  role: "user",
  content: "Can you analyze this data?",
  attachments: [
    {
      file_id: "file_abc123",
      tools: [{ type: "code_interpreter" }],
    },
  ],
  metadata: {
    timestamp: new Date().toISOString(),
  },
});

参数:

  • role:仅限 "user"(Assistant 消息由 Runs 创建)
  • content:文本或内容块数组
  • attachments:包含关联工具的文件
  • metadata:键值对
获取 Message
const message = await openai.beta.threads.messages.retrieve(
  "thread_abc123",
  "msg_abc123"
);
列出 Messages
const messages = await openai.beta.threads.messages.list("thread_abc123", {
  limit: 20,
  order: "desc", // "asc" or "desc"
});

// Iterate through messages
for (const message of messages.data) {
  console.log(`${message.role}: ${message.content[0].text.value}`);
}
更新消息元数据
const message = await openai.beta.threads.messages.update(
  "thread_abc123",
  "msg_abc123",
  {
    metadata: {
      edited: "true",
      edit_timestamp: new Date().toISOString(),
    },
  }
);
删除消息
await openai.beta.threads.messages.del("thread_abc123", "msg_abc123");

运行

运行会在一个线程上执行助手。

创建运行
const run = await openai.beta.threads.runs.create("thread_abc123", {
  assistant_id: "asst_abc123",
  instructions: "Please address the user as Jane Doe.",
  additional_messages: [
    {
      role: "user",
      content: "Can you help me with this?",
    },
  ],
});

参数:

  • assistant_id(必填):要使用的助手
  • instructions:覆盖助手指令
  • additional_messages:在运行前添加消息
  • tools:覆盖助手工具
  • metadata:键值对
  • temperature:覆盖 temperature
  • top_p:覆盖 top_p
  • max_prompt_tokens:限制输入 token 数量
  • max_completion_tokens:限制输出 token 数量
获取运行
const run = await openai.beta.threads.runs.retrieve(
  "thread_abc123",
  "run_abc123"
);

console.log(run.status); // queued, in_progress, requires_action, completed, failed, etc.
运行状态
状态描述
queued运行正在等待启动
in_progress运行正在执行
requires_action函数调用需要你的输入
cancelling正在取消
cancelled运行已取消
failed运行失败(检查 last_error)
completed运行已成功完成
expired运行已过期(最长 10 分钟)
轮询模式
async function pollRunCompletion(threadId: string, runId: string) {
  let run = await openai.beta.threads.runs.retrieve(threadId, runId);

  while (['queued', 'in_progress', 'cancelling'].includes(run.status)) {
    await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second
    run = await openai.beta.threads.runs.retrieve(threadId, runId);
  }

  if (run.status === 'failed') {
    throw new Error(`Run failed: ${run.last_error?.message}`);
  }

  if (run.status === 'requires_action') {
    // Handle function calling (see Function Calling section)
    return run;
  }

  return run; // completed
}

const run = await openai.beta.threads.runs.create(threadId, { assistant_id: assistantId });
const completedRun = await pollRunCompletion(threadId, run.id);
取消运行
const run = await openai.beta.threads.runs.cancel("thread_abc123", "run_abc123");

⚠️ 重要:取消操作是异步的。请检查 status 是否变为 cancelled。

列出运行
const runs = await openai.beta.threads.runs.list("thread_abc123", {
  limit: 10,
  order: "desc",
});

流式运行

使用服务器发送事件(SSE)实时传输运行事件。

基本流式传输
const stream = await openai.beta.threads.runs.stream("thread_abc123", {
  assistant_id: "asst_abc123",
});

for await (const event of stream) {
  if (event.event === 'thread.message.delta') {
    const delta = event.data.delta.content?.[0]?.text?.value;
    if (delta) {
      process.stdout.write(delta);
    }
  }
}
流式事件类型
事件描述
thread.run.created运行已创建
thread.run.in_progress运行已开始
thread.run.step.created步骤已创建(工具调用、消息创建)
thread.run.step.delta步骤进度更新
thread.message.created消息已创建
thread.message.delta消息内容正在流式传输
thread.message.completed消息已完成
thread.run.completed运行已完成
thread.run.failed运行失败
thread.run.requires_action需要进行函数调用
完整流式传输示例
async function streamAssistantResponse(threadId: string, assistantId: string) {
  const stream = await openai.beta.threads.runs.stream(threadId, {
    assistant_id: assistantId,
  });

  for await (const event of stream) {
    switch (event.event) {
      case 'thread.run.created':
        console.log('\\nRun started...');
        break;

      case 'thread.message.delta':
        const delta = event.data.delta.content?.[0];
        if (delta?.type === 'text' && delta.text?.value) {
          process.stdout.write(delta.text.value);
        }
        break;

      case 'thread.run.step.delta':
        const toolCall = event.data.delta.step_details;
        if (toolCall?.type === 'tool_calls') {
          const codeInterpreter = toolCall.tool_calls?.[0]?.code_interpreter;
          if (codeInterpreter?.input) {
            console.log('\\nExecuting code:', codeInterpreter.input);
          }
        }
        break;

      case 'thread.run.completed':
        console.log('\\n\\nRun completed!');
        break;

      case 'thread.run.failed':
        console.error('\\nRun failed:', event.data.last_error);
        break;

      case 'thread.run.requires_action':
        // Handle function calling
        console.log('\\nFunction calling required');
        break;
    }
  }
}

工具

Assistants API 支持三种类型的工具:

代码解释器

在沙盒环境中执行 Python 代码。

功能:

  • 运行 Python 代码
  • 生成图表
  • 处理文件(CSV、JSON、文本、图像等)
  • 返回文件输出(图像、数据文件)
  • 安装软件包(可用软件包有限)

示例:

const assistant = await openai.beta.assistants.create({
  name: "Data Analyst",
  instructions: "You are a data analyst. Use Python to analyze data and create visualizations.",
  model: "gpt-4o",
  tools: [{ type: "code_interpreter" }],
});

// Upload a file
const file = await openai.files.create({
  file: fs.createReadStream("sales_data.csv"),
  purpose: "assistants",
});

// Create thread with file
const thread = await openai.beta.threads.create({
  messages: [{
    role: "user",
    content: "Analyze this sales data and create a visualization.",
    attachments: [{
      file_id: file.id,
      tools: [{ type: "code_interpreter" }],
    }],
  }],
});

// Run
const run = await openai.beta.threads.runs.create(thread.id, {
  assistant_id: assistant.id,
});

// Poll for completion and retrieve outputs

输出文件:

代码解释器可以生成文件(图像、CSV 等)。通过以下方式访问:

const messages = await openai.beta.threads.messages.list(thread.id);
const message = messages.data[0];

for (const content of message.content) {
  if (content.type === 'image_file') {
    const fileId = content.image_file.file_id;
    const fileContent = await openai.files.content(fileId);
    // Save or process file
  }
}
文件搜索

使用向量存储对已上传的文档进行语义搜索。

主要功能:

  • 每个助手最多支持 10,000 个文件(是 v1 的 500 倍)
  • 自动分块和嵌入
  • 向量 + 关键词搜索
  • 支持多线程并行查询
  • 高级重排序

定价:

  • 向量存储费用为 $0.10/GB/天
  • 前 1GB 免费

示例:

// 1. Create vector store
const vectorStore = await openai.beta.vectorStores.create({
  name: "Product Documentation",
  metadata: { category: "docs" },
});

// 2. Upload files to vector store
const file = await openai.files.create({
  file: fs.createReadStream("product_guide.pdf"),
  purpose: "assistants",
});

await openai.beta.vectorStores.files.create(vectorStore.id, {
  file_id: file.id,
});

// 3. Create assistant with file search
const assistant = await openai.beta.assistants.create({
  name: "Product Support",
  instructions: "Use file search to answer questions about our products.",
  model: "gpt-4o",
  tools: [{ type: "file_search" }],
  tool_resources: {
    file_search: {
      vector_store_ids: [vectorStore.id],
    },
  },
});

// 4. Create thread and run
const thread = await openai.beta.threads.create({
  messages: [{
    role: "user",
    content: "How do I install the product?",
  }],
});

const run = await openai.beta.threads.runs.create(thread.id, {
  assistant_id: assistant.id,
});

最佳实践:

  • 使用前等待向量存储状态变为 completed
  • 使用元数据进行筛选(即将推出)
  • 适当拆分较大的文档
  • 监控存储费用
函数调用

定义供助手调用的自定义函数。

示例:

const assistant = await openai.beta.assistants.create({
  name: "Weather Assistant",
  instructions: "You help users get weather information.",
  model: "gpt-4o",
  tools: [{
    type: "function",
    function: {
      name: "get_weather",
      description: "Get the current weather for a location",
      parameters: {
        type: "object",
        properties: {
          location: {
            type: "string",
            description: "City name, e.g., 'San Francisco'",
          },
          unit: {
            type: "string",
            enum: ["celsius", "fahrenheit"],
            description: "Temperature unit",
          },
        },
        required: ["location"],
      },
    },
  }],
});

// Create thread and run
const thread = await openai.beta.threads.create({
  messages: [{
    role: "user",
    content: "What's the weather in San Francisco?",
  }],
});

let run = await openai.beta.threads.runs.create(thread.id, {
  assistant_id: assistant.id,
});

// Poll until requires_action
while (run.status === 'in_progress' || run.status === 'queued') {
  await new Promise(resolve => setTimeout(resolve, 1000));
  run = await openai.beta.threads.runs.retrieve(thread.id, run.id);
}

if (run.status === 'requires_action') {
  const toolCalls = run.required_action.submit_tool_outputs.tool_calls;

  const toolOutputs = [];
  for (const toolCall of toolCalls) {
    if (toolCall.function.name === 'get_weather') {
      const args = JSON.parse(toolCall.function.arguments);
      // Call your actual weather API
      const weather = await getWeatherAPI(args.location, args.unit);

      toolOutputs.push({
        tool_call_id: toolCall.id,
        output: JSON.stringify(weather),
      });
    }
  }

  // Submit tool outputs
  run = await openai.beta.threads.runs.submitToolOutputs(thread.id, run.id, {
    tool_outputs: toolOutputs,
  });

  // Continue polling...
}

向量存储

向量存储可对大量文档集合进行高效的语义搜索。

创建向量存储
const vectorStore = await openai.beta.vectorStores.create({
  name: "Legal Documents",
  metadata: {
    department: "legal",
    category: "contracts",
  },
  expires_after: {
    anchor: "last_active_at",
    days: 7, // Auto-delete 7 days after last use
  },
});
向向量存储添加文件

单个文件:

const file = await openai.files.create({
  file: fs.createReadStream("contract.pdf"),
  purpose: "assistants",
});

await openai.beta.vectorStores.files.create(vectorStore.id, {
  file_id: file.id,
});

批量上传:

const fileBatch = await openai.beta.vectorStores.fileBatches.create(vectorStore.id, {
  file_ids: ["file_abc123", "file_def456", "file_ghi789"],
});

// Poll for batch completion
let batch = await openai.beta.vectorStores.fileBatches.retrieve(vectorStore.id, fileBatch.id);
while (batch.status === 'in_progress') {
  await new Promise(resolve => setTimeout(resolve, 1000));
  batch = await openai.beta.vectorStores.fileBatches.retrieve(vectorStore.id, fileBatch.id);
}
检查向量存储状态
const vectorStore = await openai.beta.vectorStores.retrieve("vs_abc123");

console.log(vectorStore.status); // "in_progress", "completed", "failed"
console.log(vectorStore.file_counts); // { in_progress: 0, completed: 50, failed: 0 }

⚠️ 重要:与文件搜索搭配使用前,请等待 status: "completed"。

列出向量存储
const stores = await openai.beta.vectorStores.list({
  limit: 20,
  order: "desc",
});
更新向量存储
const vectorStore = await openai.beta.vectorStores.update("vs_abc123", {
  name: "Updated Name",
  metadata: { updated: "true" },
});
删除向量存储
await openai.beta.vectorStores.del("vs_abc123");

文件上传

上传文件以供代码解释器或文件搜索使用。

上传文件
import fs from 'fs';

const file = await openai.files.create({
  file: fs.createReadStream("document.pdf"),
  purpose: "assistants",
});

console.log(file.id); // file_abc123

支持的格式:

  • Code Interpreter:.c、.cpp、.csv、.docx、.html、.java、.json、.md、.pdf、.php、.pptx、.py、.rb、.tex、.txt、.css、.jpeg、.jpg、.js、.gif、.png、.tar、.ts、.xlsx、.xml、.zip
  • File Search:.c、.cpp、.docx、.html、.java、.json、.md、.pdf、.php、.pptx、.py、.rb、.tex、.txt、.css、.js、.ts、.go

大小限制:

  • Code Interpreter:每个文件最大 512 MB
  • File Search:每个文件最大 512 MB
  • Vector Store:最多 10,000 个文件
获取文件信息
const file = await openai.files.retrieve("file_abc123");
下载文件内容
const content = await openai.files.content("file_abc123");
// Returns binary content
删除文件
await openai.files.del("file_abc123");
列出文件
const files = await openai.files.list({
  purpose: "assistants",
});

线程生命周期管理

妥善管理线程生命周期可避免常见错误。

模式 1:每个用户使用一个线程
async function getOrCreateUserThread(userId: string): Promise<string> {
  // Check if thread exists in your database
  let threadId = await db.getThreadIdForUser(userId);

  if (!threadId) {
    // Create new thread
    const thread = await openai.beta.threads.create({
      metadata: { user_id: userId },
    });
    threadId = thread.id;
    await db.saveThreadIdForUser(userId, threadId);
  }

  return threadId;
}
模式 2:检查活跃运行
async function ensureNoActiveRun(threadId: string) {
  const runs = await openai.beta.threads.runs.list(threadId, {
    limit: 1,
    order: "desc",
  });

  const latestRun = runs.data[0];
  if (latestRun && ['queued', 'in_progress', 'cancelling'].includes(latestRun.status)) {
    throw new Error('Thread already has an active run. Wait or cancel first.');
  }
}

// Before creating new run
await ensureNoActiveRun(threadId);
const run = await openai.beta.threads.runs.create(threadId, { assistant_id });
模式 3:清理线程
async function cleanupOldThreads(maxAgeHours = 24) {
  const threads = await openai.beta.threads.list({ limit: 100 });

  for (const thread of threads.data) {
    const createdAt = new Date(thread.created_at * 1000);
    const ageHours = (Date.now() - createdAt.getTime()) / (1000 * 60 * 60);

    if (ageHours > maxAgeHours) {
      await openai.beta.threads.del(thread.id);
    }
  }
}

错误处理

常见错误与解决方案

1. 线程已有活跃运行

Error: 400 Can't add messages to thread_xxx while a run run_xxx is active.

解决方案:

// Wait for run to complete or cancel it
const run = await openai.beta.threads.runs.retrieve(threadId, runId);
if (['queued', 'in_progress'].includes(run.status)) {
  await openai.beta.threads.runs.cancel(threadId, runId);
  // Wait for cancellation
  while (run.status !== 'cancelled') {
    await new Promise(resolve => setTimeout(resolve, 500));
    run = await openai.beta.threads.runs.retrieve(threadId, runId);
  }
}

2. 运行轮询超时

长时间运行的任务可能会超过合理的轮询时限。

解决方案:

async function pollWithTimeout(threadId: string, runId: string, maxSeconds = 300) {
  const startTime = Date.now();

  while (true) {
    const run = await openai.beta.threads.runs.retrieve(threadId, runId);

    if (!['queued', 'in_progress'].includes(run.status)) {
      return run;
    }

    const elapsed = (Date.now() - startTime) / 1000;
    if (elapsed > maxSeconds) {
      await openai.beta.threads.runs.cancel(threadId, runId);
      throw new Error('Run exceeded timeout');
    }

    await new Promise(resolve => setTimeout(resolve, 1000));
  }
}

3. Vector Store 尚未就绪

在索引完成前使用 Vector Store。

解决方案:

async function waitForVectorStore(vectorStoreId: string) {
  let store = await openai.beta.vectorStores.retrieve(vectorStoreId);

  while (store.status === 'in_progress') {
    await new Promise(resolve => setTimeout(resolve, 2000));
    store = await openai.beta.vectorStores.retrieve(vectorStoreId);
  }

  if (store.status === 'failed') {
    throw new Error('Vector store indexing failed');
  }

  return store;
}

4. 文件上传格式问题

不支持的文件格式会导致错误。

解决方案:

const SUPPORTED_FORMATS = {
  code_interpreter: ['.csv', '.json', '.pdf', '.txt', '.py', '.js', '.xlsx'],
  file_search: ['.pdf', '.docx', '.txt', '.md', '.html'],
};

function validateFile(filename: string, tool: string) {
  const ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
  if (!SUPPORTED_FORMATS[tool].includes(ext)) {
    throw new Error(`Unsupported file format for ${tool}: ${ext}`);
  }
}

完整的错误目录请参阅 references/top-errors.md。


生产环境最佳实践

1. 使用 Assistant ID(不要重新创建)

❌ 不好:

// Creates new assistant on every request!
const assistant = await openai.beta.assistants.create({ ... });

✅ 好:

// Create once, store ID, reuse
const ASSISTANT_ID = process.env.ASSISTANT_ID || await createAssistant();

async function createAssistant() {
  const assistant = await openai.beta.assistants.create({ ... });
  console.log('Save this ID:', assistant.id);
  return assistant.id;
}
2. 实施完善的错误处理
async function createRunWithRetry(threadId: string, assistantId: string, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await openai.beta.threads.runs.create(threadId, {
        assistant_id: assistantId,
      });
    } catch (error) {
      if (error.status === 429) {
        // Rate limit - wait and retry
        await new Promise(resolve => setTimeout(resolve, 2000 * (i + 1)));
        continue;
      }

      if (error.message?.includes('active run')) {
        // Wait for active run to complete
        await new Promise(resolve => setTimeout(resolve, 5000));
        continue;
      }

      throw error; // Other errors
    }
  }

  throw new Error('Max retries exceeded');
}
3. 监控成本
// Track usage
const run = await openai.beta.threads.runs.retrieve(threadId, runId);
console.log('Tokens used:', run.usage);
// { prompt_tokens: 150, completion_tokens: 200, total_tokens: 350 }

// Set limits
const run = await openai.beta.threads.runs.create(threadId, {
  assistant_id: assistantId,
  max_prompt_tokens: 1000,
  max_completion_tokens: 500,
});
4. 清理资源
// Delete old threads
async function cleanupUserThread(userId: string) {
  const threadId = await db.getThreadIdForUser(userId);
  if (threadId) {
    await openai.beta.threads.del(threadId);
    await db.deleteThreadIdForUser(userId);
  }
}

// Delete unused vector stores
async function cleanupVectorStores(keepDays = 30) {
  const stores = await openai.beta.vectorStores.list({ limit: 100 });

  for (const store of stores.data) {
    const ageSeconds = Date.now() / 1000 - store.created_at;
    const ageDays = ageSeconds / (60 * 60 * 24);

    if (ageDays > keepDays) {
      await openai.beta.vectorStores.del(store.id);
    }
  }
}
5. 使用流式传输提升用户体验
// Show progress in real-time
async function streamToUser(threadId: string, assistantId: string) {
  const stream = await openai.beta.threads.runs.stream(threadId, {
    assistant_id: assistantId,
  });

  for await (const event of stream) {
    if (event.event === 'thread.message.delta') {
      const delta = event.data.delta.content?.[0]?.text?.value;
      if (delta) {
        // Send to user immediately
        sendToClient(delta);
      }
    }
  }
}

与其他技能的关系

与 openai-api 技能的比较

openai-api(Chat Completions):

  • 无状态请求
  • 手动管理历史记录
  • 直接返回响应
  • 适用于:简单文本生成、函数调用

openai-assistants:

  • 有状态对话(线程)
  • 自动管理历史记录
  • 内置工具(Code Interpreter、File Search)
  • 适用于:聊天机器人、数据分析、RAG
与 openai-responses 技能的比较

openai-responses(Responses API):

  • ✅ 新项目推荐使用
  • 更好地保留推理过程
  • 现代 MCP 集成
  • 积极开发中

openai-assistants:

  • ⚠️ 将于 2026 年上半年弃用
  • 适用于旧版应用
  • 提供迁移路径

**迁移:**请参阅 references/migration-to-responses.md


从 v1 迁移到 v2

v1 已弃用:2024 年 12 月 18 日

主要变更:

  1. Retrieval → File Search:retrieval 工具已替换为 file_search
  2. Vector Stores:文件现在按 Vector Store 组织(上限为 10,000 个文件)
  3. Instructions 限制:从 32k 增至 256k 个字符
  4. 文件附件:现在属于消息级,而非助手级

完整指南请参阅 references/migration-from-v1.md。


后续步骤

模板:

  • templates/basic-assistant.ts - 简易数学辅导
  • templates/code-interpreter-assistant.ts - 数据分析
  • templates/file-search-assistant.ts - 使用 Vector Store 的 RAG
  • templates/function-calling-assistant.ts - 自定义工具
  • templates/streaming-assistant.ts - 实时流式传输

参考资料:

  • references/top-errors.md - 12 个常见错误及解决方案
  • references/thread-lifecycle.md - 线程管理模式
  • references/vector-stores.md - Vector Store 深入介绍

相关技能:

  • openai-responses - 现代替代方案(推荐)
  • openai-api - Chat Completions(无状态)

最后更新:2025-10-25 软件包版本:[email protected] 状态:可用于生产环境(将于 2026 年上半年弃用)

评论

支持 Markdown