跳转到内容

会话

会话为 Agents SDK 提供了一个持久化内存层。向 Runner.run 提供任意实现了 Session 接口的对象,其余由 SDK 处理。当存在会话时,运行器将自动:

  1. 获取先前存储的对话项,并将其添加到下一轮对话的前面。
  2. 在每次运行完成后,持久化新的用户输入和助手输出。
  3. 保持该会话可用于未来的轮次,无论是用新的用户文本调用运行器,还是从中断的 RunState 恢复。

这无需再手动调用 toInputList() 或在轮次之间拼接历史。TypeScript SDK 自带两种实现:用于 Conversations API 的 OpenAIConversationsSession,以及用于本地开发的 MemorySession。由于它们共享 Session 接口,您可以插入自定义的存储后端。除 Conversations API 外的灵感可参考 examples/memory/ 下的示例会话后端(Prisma、文件存储等)。

提示:要运行本页中的 OpenAIConversationsSession 示例,请设置 OPENAI_API_KEY 环境变量(或在构造会话时提供 apiKey),以便 SDK 能调用 Conversations API。


使用 OpenAIConversationsSession 将内存与 Conversations API 同步,或替换为任意其他 Session 实现。

使用 Conversations API 作为会话内存
import { Agent, OpenAIConversationsSession, run } from '@openai/agents';
const agent = new Agent({
name: 'TourGuide',
instructions: 'Answer with compact travel facts.',
});
// Any object that implements the Session interface works here. This example uses
// the built-in OpenAIConversationsSession, but you can swap in a custom Session.
const session = new OpenAIConversationsSession();
const firstTurn = await run(agent, 'What city is the Golden Gate Bridge in?', {
session,
});
console.log(firstTurn.finalOutput); // "San Francisco"
const secondTurn = await run(agent, 'What state is it in?', { session });
console.log(secondTurn.finalOutput); // "California"

复用同一个会话实例可确保智能体在每一轮前都收到完整对话历史,并自动持久化新项目。切换到不同的 Session 实现无需更改其他代码。


  • 每次运行之前,它会检索会话历史,与新一轮输入合并,并将合并后的列表传递给您的智能体。
  • 对于非流式运行,通过一次 session.addItems() 调用即可同时持久化原始用户输入和最新一轮的模型输出。
  • 对于流式传输运行,它会先写入用户输入,并在该轮完成后追加流式输出。
  • RunResult.state 恢复时(如审批或其他中断),请继续传入同一个 session。恢复的这一轮将被加入内存,而无需重新准备输入。

会话提供简单的 CRUD 辅助方法,便于构建“撤销”“清空聊天”或审计等功能。

读取与编辑已存储的条目
import { OpenAIConversationsSession } from '@openai/agents';
import type { AgentInputItem } from '@openai/agents-core';
// Replace OpenAIConversationsSession with any other Session implementation that
// supports get/add/pop/clear if you store history elsewhere.
const session = new OpenAIConversationsSession({
conversationId: 'conv_123', // Resume an existing conversation if you have one.
});
const history = await session.getItems();
console.log(`Loaded ${history.length} prior items.`);
const followUp: AgentInputItem[] = [
{
type: 'message',
role: 'user',
content: [{ type: 'input_text', text: 'Let’s continue later.' }],
},
];
await session.addItems(followUp);
const undone = await session.popItem();
if (undone?.type === 'message') {
console.log(undone.role); // "user"
}
await session.clearSession();

session.getItems() 返回已存储的 AgentInputItem[]。调用 popItem() 可移除最后一项——在您重新运行智能体前,这对用户更正很有用。


实现 Session 接口,以使用 Redis、DynamoDB、SQLite 或其他数据存储为内存提供支持。只需实现五个异步方法。

自定义内存会话的实现
import { Agent, run } from '@openai/agents';
import { randomUUID } from '@openai/agents-core/_shims';
import { logger, Logger } from '@openai/agents-core/dist/logger';
import type { AgentInputItem, Session } from '@openai/agents-core';
/**
* Minimal example of a Session implementation; swap this class for any storage-backed version.
*/
export class CustomMemorySession implements Session {
private readonly sessionId: string;
private readonly logger: Logger;
private items: AgentInputItem[];
constructor(
options: {
sessionId?: string;
initialItems?: AgentInputItem[];
logger?: Logger;
} = {},
) {
this.sessionId = options.sessionId ?? randomUUID();
this.items = options.initialItems
? options.initialItems.map(cloneAgentItem)
: [];
this.logger = options.logger ?? logger;
}
async getSessionId(): Promise<string> {
return this.sessionId;
}
async getItems(limit?: number): Promise<AgentInputItem[]> {
if (limit === undefined) {
const cloned = this.items.map(cloneAgentItem);
this.logger.debug(
`Getting items from memory session (${this.sessionId}): ${JSON.stringify(cloned)}`,
);
return cloned;
}
if (limit <= 0) {
return [];
}
const start = Math.max(this.items.length - limit, 0);
const items = this.items.slice(start).map(cloneAgentItem);
this.logger.debug(
`Getting items from memory session (${this.sessionId}): ${JSON.stringify(items)}`,
);
return items;
}
async addItems(items: AgentInputItem[]): Promise<void> {
if (items.length === 0) {
return;
}
const cloned = items.map(cloneAgentItem);
this.logger.debug(
`Adding items to memory session (${this.sessionId}): ${JSON.stringify(cloned)}`,
);
this.items = [...this.items, ...cloned];
}
async popItem(): Promise<AgentInputItem | undefined> {
if (this.items.length === 0) {
return undefined;
}
const item = this.items[this.items.length - 1];
const cloned = cloneAgentItem(item);
this.logger.debug(
`Popping item from memory session (${this.sessionId}): ${JSON.stringify(cloned)}`,
);
this.items = this.items.slice(0, -1);
return cloned;
}
async clearSession(): Promise<void> {
this.logger.debug(`Clearing memory session (${this.sessionId})`);
this.items = [];
}
}
function cloneAgentItem<T extends AgentInputItem>(item: T): T {
return structuredClone(item);
}
const agent = new Agent({
name: 'MemoryDemo',
instructions: 'Remember the running total.',
});
// Using the above custom memory session implementation here
const session = new CustomMemorySession({
sessionId: 'session-123-4567',
});
const first = await run(agent, 'Add 3 to the total.', { session });
console.log(first.finalOutput);
const second = await run(agent, 'Add 4 more.', { session });
console.log(second.finalOutput);

自定义会话可让您实施保留策略、添加加密,或在持久化前为每轮对话附加元数据。


当您以 AgentInputItem 数组作为运行输入时,可提供 sessionInputCallback,以确定性地将它们与存储的历史合并。运行器会加载现有历史,在模型调用之前调用您的回调,并将回调返回的数组作为该轮的完整输入交给模型。此钩子非常适合裁剪旧项目、去重工具结果,或仅突出您希望模型看到的上下文。

使用 sessionInputCallback 截断历史
import { Agent, OpenAIConversationsSession, run } from '@openai/agents';
import type { AgentInputItem } from '@openai/agents-core';
const agent = new Agent({
name: 'Planner',
instructions: 'Track outstanding tasks before responding.',
});
// Any Session implementation can be passed here; customize storage as needed.
const session = new OpenAIConversationsSession();
const todoUpdate: AgentInputItem[] = [
{
type: 'message',
role: 'user',
content: [
{ type: 'input_text', text: 'Add booking a hotel to my todo list.' },
],
},
];
await run(agent, todoUpdate, {
session,
// function that combines session history with new input items before the model call
sessionInputCallback: (history, newItems) => {
const recentHistory = history.slice(-8);
return [...recentHistory, ...newItems];
},
});

对于字符串输入,运行器会自动合并历史,因此该回调为可选。


人工干预(Human in the loop)流程常会暂停一次运行以等待审批:

const result = await runner.run(agent, 'Search the itinerary', {
session,
stream: true,
});
if (result.requiresApproval) {
// ... collect user feedback, then resume the agent in a later turn
const continuation = await runner.run(agent, result.state, { session });
console.log(continuation.finalOutput);
}

当您从先前的 RunState 恢复时,新一轮会被追加到相同的内存记录中,以保留单一的对话历史。人工干预(HITL)流程保持完全兼容——审批检查点仍通过 RunState 往返,而会话则保持完整的对话记录。