휴먼 인 더 루프 (HITL)
이 가이드는 SDK 의 내장된 휴먼인더루프 (HITL) 지원을 사용하여 사람의 개입에 따라 에이전트 실행을 일시 중지하고 재개하는 방법을 보여줍니다.
현재 주요 사용 사례는 민감한 도구 실행에 대한 승인을 요청하는 것입니다.
승인 요청
섹션 제목: “승인 요청”needsApproval 옵션을 true 또는 boolean 을 반환하는 async 함수로 설정하여 승인이 필요한 도구를 정의할 수 있습니다.
import { tool } from '@openai/agents';import z from 'zod';
const sensitiveTool = tool({ name: 'cancelOrder', description: 'Cancel order', parameters: z.object({ orderId: z.number(), }), // always requires approval needsApproval: true, execute: async ({ orderId }, args) => { // prepare order return },});
const sendEmail = tool({ name: 'sendEmail', description: 'Send an email', parameters: z.object({ to: z.string(), subject: z.string(), body: z.string(), }), needsApproval: async (_context, { subject }) => { // check if the email is spam return subject.includes('spam'); }, execute: async ({ to, subject, body }, args) => { // send email },});- 에이전트가 도구(하나 이상)를 호출하기로 결정하면
needsApproval을 평가하여 이 도구가 승인이 필요한지 확인합니다 - 승인이 필요한 경우, 에이전트는 승인이 이미 허용되었는지 또는 거부되었는지 확인합니다
- 승인이 허용되거나 거부되지 않은 경우, 도구 호출을 실행할 수 없다는 정적 메시지를 에이전트에 반환합니다
- 승인/거부가 누락된 경우 도구 승인 요청을 트리거합니다
- 에이전트는 모든 도구 승인 요청을 수집하고 실행을 인터럽트합니다
- 인터럽션이 있으면 실행 결과 에 보류 중인 단계를 설명하는
interruptions배열이 포함됩니다. 도구 호출에 확인이 필요한 경우type: "tool_approval_item"인ToolApprovalItem이 나타납니다 - 도구 호출을 승인하거나 거부하려면
result.state.approve(interruption)또는result.state.reject(interruption)를 호출할 수 있습니다 - 모든 인터럽션을 처리한 후
result.state를runner.run(agent, state)에 전달하여 실행을 재개할 수 있습니다. 여기서agent는 전체 실행을 트리거한 원래 에이전트입니다 - 흐름은 1단계부터 다시 시작됩니다
아래는 터미널에서 승인을 요청하고 상태를 파일에 임시 저장하는 휴먼인더루프 흐름의 더 완전한 예시입니다.
import { z } from 'zod';import readline from 'node:readline/promises';import fs from 'node:fs/promises';import { Agent, run, tool, RunState, RunResult } from '@openai/agents';
const getWeatherTool = tool({ name: 'get_weather', description: 'Get the weather for a given city', parameters: z.object({ location: z.string(), }), needsApproval: async (_context, { location }) => { // forces approval to look up the weather in San Francisco return location === 'San Francisco'; }, execute: async ({ location }) => { return `The weather in ${location} is sunny`; },});
const dataAgentTwo = new Agent({ name: 'Data agent', instructions: 'You are a data agent', handoffDescription: 'You know everything about the weather', tools: [getWeatherTool],});
const agent = new Agent({ name: 'Basic test agent', instructions: 'You are a basic agent', handoffs: [dataAgentTwo],});
async function confirm(question: string) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, });
const answer = await rl.question(`${question} (y/n): `); const normalizedAnswer = answer.toLowerCase(); rl.close(); return normalizedAnswer === 'y' || normalizedAnswer === 'yes';}
async function main() { let result: RunResult<unknown, Agent<unknown, any>> = await run( agent, 'What is the weather in Oakland and San Francisco?', ); let hasInterruptions = result.interruptions?.length > 0; while (hasInterruptions) { // storing await fs.writeFile( 'result.json', JSON.stringify(result.state, null, 2), 'utf-8', );
// from here on you could run things on a different thread/process
// reading later on const storedState = await fs.readFile('result.json', 'utf-8'); const state = await RunState.fromString(agent, storedState);
for (const interruption of result.interruptions) { const confirmed = await confirm( `Agent ${interruption.agent.name} would like to use the tool ${interruption.name} with "${interruption.arguments}". Do you approve?`, );
if (confirmed) { state.approve(interruption); } else { state.reject(interruption); } }
// resume execution of the current state result = await run(agent, state); hasInterruptions = result.interruptions?.length > 0; }
console.log(result.finalOutput);}
main().catch((error) => { console.dir(error, { depth: null });});완전한 엔드 투 엔드 버전은 전체 예제 스크립트 를 참고하세요.
긴 승인 시간 처리
섹션 제목: “긴 승인 시간 처리”휴먼인더루프 흐름은 서버를 계속 실행하지 않고도 오랜 기간 동안 인터럽트 가능하도록 설계되었습니다. 요청을 종료하고 나중에 계속해야 하는 경우 상태를 직렬화하여 이후에 재개할 수 있습니다.
JSON.stringify(result.state) 를 사용해 상태를 직렬화하고, 직렬화된 상태를 RunState.fromString(agent, serializedState) 에 전달하여 나중에 재개할 수 있습니다. 여기서 agent 는 전체 실행을 트리거한 에이전트 인스턴스입니다.
이렇게 하면 직렬화된 상태를 데이터베이스나 요청과 함께 저장할 수 있습니다.
보류 작업의 버전 관리
섹션 제목: “보류 작업의 버전 관리”승인 요청에 시간이 오래 걸리고 에이전트 정의를 의미 있게 버전 관리하거나 Agents SDK 버전을 올릴 계획이라면, 패키지 별칭을 사용해 두 버전의 Agents SDK 를 병행 설치하고 자체 브랜칭 로직을 구현하는 것을 권장합니다.
실무적으로는 자체 코드에 버전 번호를 부여하고 이를 직렬화된 상태와 함께 저장하여, 역직렬화 시 코드의 올바른 버전으로 안내하는 방식을 의미합니다.