에이전트 실행
에이전트는 스스로 아무것도 하지 않습니다. Runner 클래스나 run() 유틸리티로 이를 실행합니다.
import { Agent, run } from '@openai/agents';
const agent = new Agent({ name: 'Assistant', instructions: 'You are a helpful assistant',});
const result = await run( agent, 'Write a haiku about recursion in programming.',);console.log(result.finalOutput);
// Code within the code,// Functions calling themselves,// Infinite loop's dance.커스텀 러너가 필요하지 않다면 싱글톤 기본 Runner 인스턴스를 실행하는 run() 유틸리티를 사용할 수 있습니다.
또는 자체 러너 인스턴스를 만들 수도 있습니다:
import { Agent, Runner } from '@openai/agents';
const agent = new Agent({ name: 'Assistant', instructions: 'You are a helpful assistant',});
// You can pass custom configuration to the runnerconst runner = new Runner();
const result = await runner.run( agent, 'Write a haiku about recursion in programming.',);console.log(result.finalOutput);
// Code within the code,// Functions calling themselves,// Infinite loop's dance.에이전트를 실행한 후에는 최종 출력과 실행 전체 이력을 포함하는 실행 결과 객체를 받게 됩니다.
에이전트 루프
섹션 제목: “에이전트 루프”Runner에서 run 메서드를 사용할 때 시작 에이전트와 입력을 전달합니다. 입력은 문자열(사용자 메시지로 간주) 또는 OpenAI Responses API의 항목인 입력 아이템 목록일 수 있습니다.
러너는 다음과 같은 루프를 실행합니다:
- 현재 입력으로 현재 에이전트의 모델을 호출합니다.
- LLM 응답을 검사합니다.
- 최종 출력 → 반환
- 핸드오프 → 새로운 에이전트로 전환, 누적된 대화 기록 유지, 1로 이동
- 도구 호출 → 도구를 실행하고 결과를 대화에 추가, 1로 이동
maxTurns에 도달하면MaxTurnsExceededError를 던집니다.
Runner 수명 주기
섹션 제목: “Runner 수명 주기”앱이 시작될 때 Runner를 생성하고 요청 간에 재사용하세요. 이 인스턴스는 모델 제공자, 트레이싱 옵션 같은 전역 구성을 저장합니다. 완전히 다른 설정이 필요할 때만 다른 Runner를 생성하세요. 단순한 스크립트의 경우 내부적으로 기본 러너를 사용하는 run()을 호출할 수도 있습니다.
실행 인수
섹션 제목: “실행 인수”run() 메서드의 입력은 실행을 시작할 초기 에이전트, 실행 입력, 그리고 옵션 집합입니다.
입력은 문자열(사용자 메시지로 간주), input items 목록, 또는 휴먼 인 더 루프 (HITL) 에이전트를 구축하는 경우 RunState 객체일 수 있습니다.
추가 옵션은 다음과 같습니다:
| Option | Default | Description |
|---|---|---|
stream | false | true이면 호출은 StreamedRunResult를 반환하고 모델에서 도착하는 대로 이벤트를 내보냅니다. |
context | – | 모든 도구 / 가드레일 / 핸드오프로 전달되는 컨텍스트 객체입니다. 자세한 내용은 컨텍스트 관리 가이드를 참고하세요. |
maxTurns | 10 | 안전 한도 – 도달 시 MaxTurnsExceededError를 던집니다. |
signal | – | 취소를 위한 AbortSignal |
스트리밍
섹션 제목: “스트리밍”스트리밍을 사용하면 LLM이 실행되는 동안 추가로 스트리밍 이벤트를 받을 수 있습니다. 스트림이 시작되면 StreamedRunResult에는 새로 생성된 모든 출력을 포함해 실행에 대한 완전한 정보가 담깁니다. for await 루프로 스트리밍 이벤트를 순회할 수 있습니다. 자세한 내용은 스트리밍 가이드를 참고하세요.
실행 구성
섹션 제목: “실행 구성”자체 Runner 인스턴스를 만드는 경우 RunConfig 객체를 전달해 러너를 구성할 수 있습니다.
| Field | Type | Purpose |
|---|---|---|
model | string | Model | 실행의 모든 에이전트에 대해 특정 모델을 강제합니다. |
modelProvider | ModelProvider | 모델 이름을 확인합니다. 기본은 OpenAI 제공자입니다. |
modelSettings | ModelSettings | 에이전트별 설정을 재정의하는 전역 튜닝 매개변수입니다. |
handoffInputFilter | HandoffInputFilter | 핸드오프를 수행할 때 입력 아이템을 변환합니다(핸드오프 자체에 이미 정의되어 있지 않은 경우). |
inputGuardrails | InputGuardrail[] | 초기 사용자 입력에 적용되는 가드레일입니다. |
outputGuardrails | OutputGuardrail[] | 최종 출력에 적용되는 가드레일입니다. |
tracingDisabled | boolean | OpenAI Tracing을 완전히 비활성화합니다. |
traceIncludeSensitiveData | boolean | 스팬은 유지하면서 트레이스에서 LLM/도구 입력 및 출력을 제외합니다. |
workflowName | string | Traces 대시보드에 표시됩니다. 관련 실행을 그룹화하는 데 도움이 됩니다. |
traceId / groupId | string | SDK가 생성하도록 두는 대신 트레이스 또는 그룹 ID를 수동으로 지정합니다. |
traceMetadata | Record<string, any> | 모든 스팬에 첨부할 임의의 메타데이터입니다. |
대화 / 채팅 스레드
섹션 제목: “대화 / 채팅 스레드”runner.run() 호출(또는 run() 유틸리티)마다 애플리케이션 수준 대화의 한 번의 턴을 나타냅니다. 최종 사용자에게 RunResult를 얼마나 보여줄지 선택할 수 있습니다. 때로는 finalOutput만, 때로는 생성된 모든 아이템을 보여줍니다.
import { Agent, run } from '@openai/agents';import type { AgentInputItem } from '@openai/agents';
let thread: AgentInputItem[] = [];
const agent = new Agent({ name: 'Assistant',});
async function userSays(text: string) { const result = await run( agent, thread.concat({ role: 'user', content: text }), );
thread = result.history; // Carry over history + newly generated items return result.finalOutput;}
await userSays('What city is the Golden Gate Bridge in?');// -> "San Francisco"
await userSays('What state is it in?');// -> "California"대화형 버전은 채팅 코드 예제를 참고하세요.
서버 관리형 대화
섹션 제목: “서버 관리형 대화”매번 전체 로컬 대화 내역을 전송하는 대신 OpenAI Responses API가 대화 기록을 지속(persist)하도록 할 수 있습니다. 긴 대화나 여러 서비스를 조율할 때 유용합니다. 자세한 내용은 Conversation state guide를 참고하세요.
OpenAI는 서버 측 상태를 재사용하는 두 가지 방법을 제공합니다:
1. 전체 대화를 위한 conversationId
섹션 제목: “1. 전체 대화를 위한 conversationId”Conversations API로 한 번 대화를 생성한 다음, 각 턴에서 해당 ID를 재사용할 수 있습니다. SDK는 자동으로 새로 생성된 아이템만 포함합니다.
import { Agent, run } from '@openai/agents';import { OpenAI } from 'openai';
const agent = new Agent({ name: 'Assistant', instructions: 'Reply very concisely.',});
async function main() { // Create a server-managed conversation: const client = new OpenAI(); const { id: conversationId } = await client.conversations.create({});
const first = await run(agent, 'What city is the Golden Gate Bridge in?', { conversationId, }); console.log(first.finalOutput); // -> "San Francisco"
const second = await run(agent, 'What state is it in?', { conversationId }); console.log(second.finalOutput); // -> "California"}
main().catch(console.error);2. 마지막 턴에서 계속하기 위한 previousResponseId
섹션 제목: “2. 마지막 턴에서 계속하기 위한 previousResponseId”어차피 Responses API만으로 시작하려는 경우, 이전 응답에서 반환된 ID를 사용해 각 요청을 연결할 수 있습니다. 전체 대화 리소스를 만들지 않고도 턴 간 컨텍스트를 유지합니다.
import { Agent, run } from '@openai/agents';
const agent = new Agent({ name: 'Assistant', instructions: 'Reply very concisely.',});
async function main() { const first = await run(agent, 'What city is the Golden Gate Bridge in?'); console.log(first.finalOutput); // -> "San Francisco"
const previousResponseId = first.lastResponseId; const second = await run(agent, 'What state is it in?', { previousResponseId, }); console.log(second.finalOutput); // -> "California"}
main().catch(console.error);SDK는 다음과 같은 소수의 오류를 던지며, 이를 캐치할 수 있습니다:
MaxTurnsExceededError–maxTurns에 도달함ModelBehaviorError– 모델이 잘못된 출력 생성(예: 잘못된 JSON, 알 수 없는 도구)InputGuardrailTripwireTriggered/OutputGuardrailTripwireTriggered– 가드레일 위반GuardrailExecutionError– 가드레일 실행 실패ToolCallError– 함수 도구 호출 실패UserError– 구성 또는 사용자 입력을 기반으로 발생한 오류
모두 기본 AgentsError 클래스를 확장하며, 현재 실행 상태에 접근할 수 있는 state 속성을 제공할 수 있습니다.
다음은 GuardrailExecutionError를 처리하는 예시 코드입니다:
import { Agent, run, GuardrailExecutionError, InputGuardrail, InputGuardrailTripwireTriggered,} from '@openai/agents';import { z } from 'zod';
const guardrailAgent = new Agent({ name: 'Guardrail check', instructions: 'Check if the user is asking you to do their math homework.', outputType: z.object({ isMathHomework: z.boolean(), reasoning: z.string(), }),});
const unstableGuardrail: InputGuardrail = { name: 'Math Homework Guardrail (unstable)', execute: async () => { throw new Error('Something is wrong!'); },};
const fallbackGuardrail: InputGuardrail = { name: 'Math Homework Guardrail (fallback)', execute: async ({ input, context }) => { const result = await run(guardrailAgent, input, { context }); return { outputInfo: result.finalOutput, tripwireTriggered: result.finalOutput?.isMathHomework ?? false, }; },};
const agent = new Agent({ name: 'Customer support agent', instructions: 'You are a customer support agent. You help customers with their questions.', inputGuardrails: [unstableGuardrail],});
async function main() { try { const input = 'Hello, can you help me solve for x: 2x + 3 = 11?'; const result = await run(agent, input); console.log(result.finalOutput); } catch (e) { if (e instanceof GuardrailExecutionError) { console.error(`Guardrail execution failed: ${e}`); // If you want to retry the execution with different settings, // you can reuse the runner's latest state this way: if (e.state) { try { agent.inputGuardrails = [fallbackGuardrail]; // fallback const result = await run(agent, e.state); console.log(result.finalOutput); } catch (ee) { if (ee instanceof InputGuardrailTripwireTriggered) { console.log('Math homework guardrail tripped'); } } } } else { throw e; } }}
main().catch(console.error);위 예시를 실행하면 다음과 같은 출력이 표시됩니다:
Guardrail execution failed: Error: Input guardrail failed to complete: Error: Something is wrong!Math homework guardrail tripped