在 OpenAI Assistants API 中,client.beta.assistants.createinstructionsclient.beta.threads.createmessages 是两个核心参数,二者定位、作用和生命周期完全不同,前者是助手的“系统级行为准则”,后者是对话的“上下文内容载体”

一、核心维度对比表

对比维度 instructions(助手创建参数) messages(线程创建参数)
核心定位 定义助手的角色、能力边界、行为规则,是助手的“底层逻辑” 承载用户与助手的对话内容,是助手生成回复的“直接依据”
作用对象 作用于整个 Assistant 实例,所有使用该助手的线程都会遵循 作用于单个 Thread 实例,仅影响当前线程的对话流程
生命周期 与 Assistant 绑定,修改前永久生效 与 Thread 绑定,随线程的对话轮次动态追加/更新
内容性质 偏向指令性、规则性、全局性,无时效性 偏向交互性、场景性、时效性,是对话上下文
修改方式 需调用 assistants.update 接口修改 需调用 threads.messages.create 接口追加新消息
是否必填 非必填(但不填的话助手行为无约束) 非必填(线程可先创建,后续再添加消息)

二、具体解释与场景举例

假设你要开发一个 Scratch 少儿编程教学助手,分别看两个参数的用法:

1. instructions:助手的“教学手册”

instructions 是给助手的全局指令,告诉它“你是谁、该做什么、不能做什么”,贯穿这个助手的所有对话。

import openai

client = openai.OpenAI()

# 创建 Scratch 教学助手时的 instructions
assistant = client.beta.assistants.create(
    name="Scratch少儿编程导师",
    instructions="""你是一个面向小学高年级学生的Scratch编程老师,需要做到:
1. 用通俗的语言解释编程概念,避免专业术语;
2. 回答问题时必须附带简单的Scratch积木示例;
3. 遇到学生问非编程问题时,引导回到Scratch学习;
4. 鼓励学生动手尝试,拒绝直接给出完整项目代码。""",
    model="gpt-4o"
)

关键点

  • 这个指令对所有使用该助手的线程都生效,比如学生A问“怎么移动角色”、学生B问“怎么加音效”,助手都会遵循同一个教学规则。
  • 修改指令需要调用 assistants.update,比如你想新增“允许给低年级学生提供分步代码”,修改后所有后续对话都会按新规则执行。
2. messages:线程的“对话记录”

messages单个对话线程的内容,包含用户的提问、助手的回复,是助手生成下一轮回复的上下文。
一个线程对应一个学生的单次对话会话,你可以先创建空线程,再添加消息:

# 1. 创建一个空线程(对应学生小明的对话)
thread = client.beta.threads.create()

# 2. 给线程添加第一条用户消息(小明的问题)
message = client.beta.threads.messages.create(
    thread_id=thread.id,
    role="user",
    content="怎么让小猫在Scratch里走直线?"
)

# 3. 运行助手,生成回复(助手会结合 instructions + 这条 message 输出内容)
run = client.beta.threads.runs.create(
    thread_id=thread.id,
    assistant_id=assistant.id
)

关键点

  • 这条 message 只属于小明的这个线程,不会影响其他学生的对话。
  • 后续小明继续问“怎么让小猫碰到边缘就反弹”,你需要调用 threads.messages.create 追加新消息,助手会基于历史所有 messages + instructions 生成回复。

三、要点

  1. 关联逻辑instructions 是助手的“行为框架”,messages 是助手的“对话素材”;助手生成回复时,会先遵循 instructions 的规则,再基于 messages 的上下文输出内容
  2. 使用建议
    • instructions 时要明确、可落地,避免模糊表述(比如不要写“做一个好老师”,要写“用小学生能懂的话解释”)。
    • 管理 messages 时要控制上下文长度,如果对话轮次太多,可清理无关历史消息,避免超出模型上下文窗口。
一句话总结 类比
instructions助手的“出厂设置” 老师的教学大纲
messages单次对话的“聊天记录” 老师和一个学生的课堂对话

四、线程(Thread)中的 messages

  1. 线程 ID(thread_id):一旦创建永久不变,多次 run 同一个线程只会生成新的 run_id,不会改变 thread_id
  2. Messages 特性:同一线程内的 messages追加式存储(包含用户发送的消息 + 助手返回的回复),再次 run 时会自动衔接所有历史 messages
  3. Messages 可修改:在再次 run 线程前,你可以追加新消息、甚至修改/删除已有消息,修改后 run 会基于最新的 messages 上下文生成回复。
完整代码示例

以下代码会完整演示:创建线程 → 第一次 run → 查看追加的 messages → 第二次追加消息并 run → 验证线程 ID 不变、messages 衔接 → 演示修改已有 messages 后再次 run。

import openai
import time

# 1. 初始化客户端(替换为你的 API Key)
client = openai.OpenAI(api_key="你的 OpenAI API Key")

# 2. 创建一个简单的助手(用于测试)
assistant = client.beta.assistants.create(
    name="测试助手",
    instructions="你是一个数学老师,回答问题时要简洁明了,基于上下文衔接回答。",
    model="gpt-4o"
)
print(f"创建的助手 ID:{assistant.id}\n")

# 3. 创建一个线程(核心:这个 thread_id 全程不变)
thread = client.beta.threads.create()
THREAD_ID = thread.id  # 保存线程 ID,后续所有操作都用这个
print(f"创建的线程 ID:{THREAD_ID}\n")

# ---------------------- 第一步:第一次 run 线程 ----------------------
# 3.1 给线程添加第一条用户消息
message_1 = client.beta.threads.messages.create(
    thread_id=THREAD_ID,
    role="user",
    content="请问 1+1 等于多少?"
)
print(f"第一条用户消息 ID:{message_1.id}")

# 3.2 第一次运行助手(生成 run_id,每次 run 都会生成新的)
run_1 = client.beta.threads.runs.create(
    thread_id=THREAD_ID,
    assistant_id=assistant.id
)
print(f"第一次 run ID:{run_1.id}\n")

# 3.3 等待 run 完成(必须等待,否则获取不到助手回复)
def wait_for_run_completion(client, thread_id, run_id):
    while True:
        run = client.beta.threads.runs.retrieve(thread_id=thread_id, run_id=run_id)
        if run.status == "completed":
            return run
        time.sleep(1)

wait_for_run_completion(client, THREAD_ID, run_1.id)

# 3.4 获取第一次 run 后的所有 messages(验证:包含用户消息 + 助手回复)
messages_after_run1 = client.beta.threads.messages.list(thread_id=THREAD_ID)
print("===== 第一次 run 后的 messages 列表 =====")
for msg in messages_after_run1.data:
    print(f"角色:{msg.role} | 内容:{msg.content[0].text.value}")
print("\n")

# ---------------------- 第二步:再次 run 线程(追加消息) ----------------------
# 4.1 追加第二条用户消息(衔接上下文提问)
message_2 = client.beta.threads.messages.create(
    thread_id=THREAD_ID,
    role="user",
    content="那这个结果乘以 3 是多少?"  # 助手会知道“这个结果”指的是 1+1=2
)
print(f"第二条用户消息 ID:{message_2.id}")

# 4.2 第二次运行助手(run_id 新生成,thread_id 不变)
run_2 = client.beta.threads.runs.create(
    thread_id=THREAD_ID,
    assistant_id=assistant.id
)
print(f"第二次 run ID:{run_2.id}(与第一次 run ID 不同)")
print(f"线程 ID 仍为:{THREAD_ID}(与之前一致)\n")

# 4.3 等待第二次 run 完成
wait_for_run_completion(client, THREAD_ID, run_2.id)

# 4.4 获取第二次 run 后的所有 messages(验证:追加了第二条用户消息 + 新的助手回复)
messages_after_run2 = client.beta.threads.messages.list(thread_id=THREAD_ID)
print("===== 第二次 run 后的 messages 列表(追加式) =====")
for msg in messages_after_run2.data:
    print(f"角色:{msg.role} | 内容:{msg.content[0].text.value}")
print("\n")

# ---------------------- 第三步:演示修改 messages 后再次 run ----------------------
# 5.1 修改第一条用户消息(比如修正问题)
# 先找到第一条消息的 ID(就是 message_1.id)
updated_message = client.beta.threads.messages.update(
    thread_id=THREAD_ID,
    message_id=message_1.id,
    content="请问 2+2 等于多少?"  # 把原来的 1+1 改成 2+2
)
print(f"修改后的第一条消息内容:{updated_message.content[0].text.value}\n")

# 5.2 第三次运行助手(基于修改后的 messages 重新回答)
run_3 = client.beta.threads.runs.create(
    thread_id=THREAD_ID,
    assistant_id=assistant.id
)
print(f"第三次 run ID:{run_3.id}")
wait_for_run_completion(client, THREAD_ID, run_3.id)

# 5.3 获取修改后 run 的 messages(验证:助手会基于修改后的问题重新回答)
messages_after_run3 = client.beta.threads.messages.list(thread_id=THREAD_ID)
print("===== 修改消息后第三次 run 的 messages 列表 =====")
for msg in messages_after_run3.data:
    print(f"角色:{msg.role} | 内容:{msg.content[0].text.value}")

# 清理测试资源(可选)
# client.beta.assistants.delete(assistant.id)
# client.beta.threads.delete(THREAD_ID)
代码运行结果说明

假设你运行代码后,会看到以下核心结果(示例):

  1. 线程 ID 不变:全程 THREAD_ID 都是同一个值,三次 run 的 run_id 各不相同;
  2. Messages 追加存储
    • 第一次 run 后:messages 包含「用户:1+1等于多少?」+「助手:1+1等于2」;
    • 第二次 run 后:messages 追加了「用户:那这个结果乘以3是多少?」+「助手:2×3=6」;
  3. 修改 messages 生效
    • 第三次 run 后,助手会基于修改后的「2+2等于多少?」重新回答(结果为4),且后续的「乘以3」会变成 4×3=12。
细节解释
  1. run_id vs thread_id
    • thread_id:线程的唯一标识,代表一个“对话会话”,创建后永不改变;
    • run_id:每次调用 threads.runs.create 都会生成新的 ID,代表“一次助手的执行过程”,用于查询执行状态、取消执行等。
  2. Messages 排序threads.messages.list 返回的消息默认是倒序(最新的在前),但助手生成回复时会按正序读取所有历史消息;
  3. 修改/删除 Messages:除了 update,你也可以用 client.beta.threads.messages.delete(message_id) 删除某条消息,修改/删除后再次 run,助手会基于最新的消息列表生成回复。
要点
  1. 线程 ID 固定thread_id 一旦创建不会变化,多次 run 仅生成新的 run_id
  2. Messages 追加式存储:同一线程内的 messages 会保留所有用户/助手消息,再次 run 会自动衔接上下文;
  3. Messages 可灵活修改:在 run 之前可以更新/删除已有消息,修改后的内容会影响后续 run 的回复结果。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐