强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

OpenAI API 接口对接完全教程 / 08 - Assistants API

第 08 章 · Assistants API(助手 API)

Assistants API 提供了一个更高层的抽象,内置了线程管理、文件检索和代码解释器,简化复杂 AI 应用的构建。


8.1 核心概念

对象关系模型

Assistant(助手)
    ├── 指令 (instructions)
    ├── 模型 (model)
    ├── 工具 (tools)
    └── 文件 (files)

Thread(线程)
    └── Messages(消息)
        ├── user 消息
        └── assistant 消息

Run(运行)
    ├── 状态机 (queued → in_progress → completed)
    ├── 工具调用 (function / retrieval / code_interpreter)
    └── 步骤 (steps)

内置工具

工具名称功能
代码解释器code_interpreter执行 Python 代码、生成图表
文件检索file_search搜索上传的文档
函数调用function调用自定义函数

8.2 创建助手

from openai import OpenAI

client = OpenAI()

# 创建助手
assistant = client.beta.assistants.create(
    name="数据分析助手",
    instructions="""你是一个专业的数据分析师。
    帮助用户分析数据、生成图表和报告。
    使用代码解释器处理数据文件。
    输出时使用中文,并提供清晰的分析结论。""",
    model="gpt-4o",
    tools=[
        {"type": "code_interpreter"},
        {"type": "file_search"},
    ],
)

print(f"助手 ID: {assistant.id}")

管理助手

# 列出所有助手
assistants = client.beta.assistants.list(limit=10)
for a in assistants.data:
    print(f"  {a.id}: {a.name}")

# 更新助手
client.beta.assistants.update(
    assistant_id=assistant.id,
    instructions="更新后的指令...",
    model="gpt-4o",
)

# 删除助手
client.beta.assistants.delete(assistant_id=assistant.id)

8.3 线程与消息

创建线程和发送消息

# 创建线程
thread = client.beta.threads.create()
print(f"线程 ID: {thread.id}")

# 添加消息
message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="请分析这份销售数据,找出趋势和异常。",
)

添加文件到消息

# 上传文件
file = client.files.create(
    file=open("sales_data.csv", "rb"),
    purpose="assistants",
)

# 带文件的消息
message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="分析这份销售数据",
    attachments=[{
        "file_id": file.id,
        "tools": [{"type": "file_search"}, {"type": "code_interpreter"}]
    }]
)

8.4 运行助手 (Run)

8.4.1 基础运行

import time

# 创建运行
run = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id,
)

# 轮询等待完成
while run.status in ["queued", "in_progress", "cancelling"]:
    time.sleep(1)
    run = client.beta.threads.runs.retrieve(
        thread_id=thread.id,
        run_id=run.id,
    )
    print(f"状态: {run.status}")

if run.status == "completed":
    # 获取回复
    messages = client.beta.threads.messages.list(
        thread_id=thread.id,
        order="desc",
        limit=1,
    )
    for msg in messages.data:
        print(msg.content[0].text.value)
elif run.status == "failed":
    print(f"运行失败: {run.last_error}")

8.4.2 使用 create_and_poll(推荐)

# 一步完成:创建运行并等待结果
run = client.beta.threads.runs.create_and_poll(
    thread_id=thread.id,
    assistant_id=assistant.id,
)

if run.status == "completed":
    messages = client.beta.threads.messages.list(thread_id=thread.id)
    for msg in messages.data:
        if msg.role == "assistant":
            print(msg.content[0].text.value)

8.4.3 流式运行

with client.beta.threads.runs.stream(
    thread_id=thread.id,
    assistant_id=assistant.id,
) as stream:
    for event in stream:
        if event.event == "thread.message.delta":
            delta = event.data.delta
            if delta.content:
                for block in delta.content:
                    if hasattr(block, 'text') and block.text:
                        print(block.text.value, end="", flush=True)
        elif event.event == "thread.run.failed":
            print(f"\n运行失败: {event.data.last_error}")

print()

8.5 代码解释器 (Code Interpreter)

# 上传文件用于代码解释器
file = client.files.create(
    file=open("data.csv", "rb"),
    purpose="assistants",
)

# 创建带代码解释器的助手
analyst = client.beta.assistants.create(
    name="数据分析专家",
    instructions="用 Python 分析数据并生成可视化图表。",
    model="gpt-4o",
    tools=[{"type": "code_interpreter"}],
    tool_resources={
        "code_interpreter": {
            "file_ids": [file.id]
        }
    }
)

# 运行分析
thread = client.beta.threads.create()
client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="请分析数据中的趋势,生成折线图和柱状图。",
)

run = client.beta.threads.runs.create_and_poll(
    thread_id=thread.id,
    assistant_id=analyst.id,
)

# 获取生成的文件(图表等)
if run.status == "completed":
    messages = client.beta.threads.messages.list(thread_id=thread.id)
    for msg in messages.data:
        for content in msg.content:
            if content.type == "image":
                print(f"生成图表: {content.image.file_id}")
            elif content.type == "text":
                print(content.text.value)

# 创建向量存储
vector_store = client.beta.vector_stores.create(
    name="产品文档",
)

# 上传文件到向量存储
files = ["manual.pdf", "faq.txt", "specs.docx"]
file_streams = [open(f, "rb") for f in files]

file_batch = client.beta.vector_stores.file_batches.upload_and_poll(
    vector_store_id=vector_store.id,
    files=file_streams,
)

print(f"文件状态: {file_batch.status}")
print(f"文件数量: {file_batch.file_counts}")

# 创建带检索功能的助手
doc_assistant = client.beta.assistants.create(
    name="文档问答助手",
    instructions="基于上传的文档回答用户问题,引用具体来源。",
    model="gpt-4o",
    tools=[{"type": "file_search"}],
    tool_resources={
        "file_search": {
            "vector_store_ids": [vector_store.id]
        }
    }
)

检索参数调优

run = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=doc_assistant.id,
    tool_choice={"type": "file_search"},
)

8.7 Function Calling 集成

import json

# 定义工具
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_user_info",
            "description": "获取用户信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "user_id": {"type": "string", "description": "用户ID"}
                },
                "required": ["user_id"]
            }
        }
    }
]

assistant = client.beta.assistants.create(
    name="客服助手",
    instructions="帮助用户查询订单和账户信息。",
    model="gpt-4o",
    tools=tools,
)

# 运行并处理工具调用
def run_with_tools(thread_id, assistant_id):
    run = client.beta.threads.runs.create_and_poll(
        thread_id=thread_id,
        assistant_id=assistant_id,
    )

    # 处理工具调用
    while run.status == "requires_action":
        tool_outputs = []
        for call in run.required_action.submit_tool_outputs.tool_calls:
            if call.function.name == "get_user_info":
                args = json.loads(call.function.arguments)
                result = json.dumps({"name": "张三", "tier": "VIP"})
                tool_outputs.append({
                    "tool_call_id": call.id,
                    "output": result,
                })

        run = client.beta.threads.runs.submit_tool_outputs_and_poll(
            thread_id=thread_id,
            run_id=run.id,
            tool_outputs=tool_outputs,
        )

    return run

8.8 完整对话应用

class AssistantApp:
    """基于 Assistants API 的对话应用"""

    def __init__(self, assistant_id: str):
        self.client = OpenAI()
        self.assistant_id = assistant_id
        self.thread = self.client.beta.threads.create()

    def chat(self, user_input: str) -> str:
        """发送消息并获取回复"""
        # 添加用户消息
        self.client.beta.threads.messages.create(
            thread_id=self.thread.id,
            role="user",
            content=user_input,
        )

        # 运行
        run = self.client.beta.threads.runs.create_and_poll(
            thread_id=self.thread.id,
            assistant_id=self.assistant_id,
        )

        if run.status == "completed":
            messages = self.client.beta.threads.messages.list(
                thread_id=self.thread.id,
                order="desc",
                limit=1,
            )
            return messages.data[0].content[0].text.value
        else:
            return f"运行状态: {run.status}"

    def get_history(self) -> list[dict]:
        """获取对话历史"""
        messages = self.client.beta.threads.messages.list(
            thread_id=self.thread.id,
            order="asc",
        )
        return [
            {"role": msg.role, "content": msg.content[0].text.value}
            for msg in messages.data
            if msg.content[0].type == "text"
        ]


# 使用
app = AssistantApp(assistant_id="asst_xxx")
print(app.chat("你好,请帮我分析数据"))
print(app.chat("按月份统计趋势"))

8.9 运行状态机

queued → in_progress → completed
                     → requires_action → in_progress → completed
                     → failed
                     → cancelled
                     → expired
状态含义下一步
queued排队中等待
in_progress运行中等待
completed完成读取结果
requires_action需要工具输出提交工具结果
failed失败检查错误
cancelled已取消-
expired超时过期重新运行

8.10 注意事项

  1. 线程持久化:线程和消息会持久保存,注意定期清理
  2. 运行超时:默认 10 分钟超时,可通过 expires_at 设置
  3. 并发限制:同一线程同时只能有一个 Run
  4. 文件大小:单文件最大 512MB,向量存储最大 10000 文件
  5. 成本:助手会消耗更多 token(系统指令 + 工具定义 + 上下文)
  6. 不适合简单场景:简单对话直接用 Chat Completions 更高效

8.11 扩展阅读


下一章09 - Whisper 语音转文字 — 音频转录、多语言、实时处理。