OpenAI 응답 API

ADK-Rust은 OpenAI의 응답 API(/v1/responses 엔드포인트)를 위한 전용 클라이언트를 제공합니다. 이는 Chat Completions API의 후속 기능입니다. 응답 API은 전체 추론 노력 범위를 포함한 최신 GPT-5.6 모델을 사용하는 데 권장되는 방식입니다.

개요

┌─────────────────────────────────────────────────────────────────────┐
│                  OpenAI Responses API Client                        │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   Endpoint:  POST /v1/responses                                     │
│   Client:    OpenAIResponsesClient                                  │
│   Config:    OpenAIResponsesConfig                                  │
│   Feature:   openai                                                 │
│                                                                     │
│   Capabilities:                                                     │
│   • Streaming and non-streaming                                     │
│   • Reasoning summaries                                             │
│   • Tool / function calling                                         │
│   • Multi-turn via previous_response_id                             │
│   • Built-in tools (web search, file search, code interpreter)      │
│   • System instructions                                             │
│   • Model-aware sampling controls and max_output_tokens             │
│   • Automatic retry with exponential backoff                        │
│                                                                     │
│   vs Chat Completions (OpenAIClient):                               │
│   • Stateful conversations (server-side context)                    │
│   • Native reasoning summaries                                      │
│   • Built-in tool hosting                                           │
│   • Simpler multi-turn (no manual message history)                  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

어떤 클라이언트를 사용할지 선택하는 방법

기능OpenAIClient (Chat Completions)OpenAIResponsesClient (Responses)
엔드포인트/v1/chat/completions/v1/responses
모델채팅 호환 모델현재 GPT 및 추론 모델
추론 요약사용 불가기본 지원
내장 도구사용 불가웹 검색, 파일 검색, 코드 인터프리터
서버 측 상태수동 메시지 기록previous_response_id
구조화된 출력response_formattext.format (예정)
성숙도안정적이며 널리 채택됨OpenAI에서 권장하는 최신 방식

OpenAIResponsesClient 요약 기능이 있는 추론 모델, 기본 제공 도구가 필요하거나 OpenAI의 최신 API을 사용하려는 경우 사용하세요. 기존 Chat Completions 워크플로와의 하위 호환성이 필요한 경우 OpenAIClient을 사용하세요.


설치

[dependencies]
adk-rust = { version = "2.1.0", features = ["openai"] }
adk-tool = "2.1.0"

또는 adk-model을 직접 사용하세요:

[dependencies]
adk-model = { version = "2.1.0", features = ["openai"] }

API 키를 설정하세요:

export OPENAI_API_KEY="sk-..."

빠른 시작

use adk_rust::prelude::*;
use adk_rust::session::{CreateRequest, SessionService};
use adk_rust::futures::StreamExt;
use adk_model::openai::{OpenAIResponsesClient, OpenAIResponsesConfig};
use std::collections::HashMap;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    let api_key = std::env::var("OPENAI_API_KEY")?;

    // 1. Create the Responses API client
    let config = OpenAIResponsesConfig::new(&api_key, "gpt-5.6-terra");
    let model = Arc::new(OpenAIResponsesClient::new(config)?);

    // 2. Build an agent
    let agent = Arc::new(
        LlmAgentBuilder::new("assistant")
            .instruction("You are a helpful assistant. Be concise.")
            .model(model)
            .build()?,
    );

    // 3. Create a session
    let sessions: Arc<dyn SessionService> = Arc::new(InMemorySessionService::new());
    sessions.create(CreateRequest {
        app_name: "my_app".into(),
        user_id: "user".into(),
        session_id: Some("s1".into()),
        state: HashMap::new(),
    }).await?;

    // 4. Run through the Runner
    let runner = Runner::builder()
        .app_name("my_app")
        .agent(agent)
        .session_service(sessions)
        .build()?;

    let message = Content::new("user").with_text("What is the capital of France?");
    let mut stream = runner.run(
        adk_rust::UserId::new("user")?,
        adk_rust::SessionId::new("s1")?,
        message,
    ).await?;

    while let Some(event) = stream.next().await {
        let event = event?;
        if let Some(content) = &event.llm_response.content {
            for part in &content.parts {
                if let Some(text) = part.text() {
                    print!("{text}");
                }
            }
        }
    }
    println!();
    Ok(())
}

구성

기본 구성

use adk_model::openai::OpenAIResponsesConfig;

// Minimal — just API key and model
let config = OpenAIResponsesConfig::new("sk-...", "gpt-5.6-luna");

// With organization and project
let config = OpenAIResponsesConfig::new("sk-...", "gpt-5.6-terra")
    .with_organization("org-...")
    .with_project("proj-...");

// Custom base URL (for proxies or compatible APIs)
let config = OpenAIResponsesConfig::new("sk-...", "gpt-5.6-terra")
    .with_base_url("https://my-proxy.example.com/v1");

추론 모델

GPT-5.6 추론 모델의 경우 추론 수준과 요약을 구성하세요:

use adk_model::openai::{
    OpenAIReasoningEffort, OpenAIResponsesClient,
    OpenAIResponsesConfig, ReasoningSummary,
};

let config = OpenAIResponsesConfig::new("sk-...", "gpt-5.6-terra")
    .with_reasoning_summary(ReasoningSummary::Detailed);

let model = OpenAIResponsesClient::new_with_reasoning_effort(
    config,
    OpenAIReasoningEffort::Max,
)?;
추론 수준설명
None가장 짧은 지연 시간을 위해 추론 비활성화
Minimal이를 지원하는 모델에서 레거시 최소 추론
Low낮은 추론 노력
Medium균형 잡힌 추론
High높은 추론 노력
XHigh매우 높은 추론 노력
Max지원되는 모델에서 최대 추론

GPT-5.6은 Responses API을 통해 None, Low, Medium, High, XHighMax을 지원합니다. Chat Completions는 최대 XHigh까지 지원합니다.

추론 요약설명
Auto모델이 요약을 포함할지 결정
Concise추론에 대한 간략한 요약
Detailed추론에 대한 철저한 요약

추론 요약은 응답 스트림에 Part::Thinking로 표시되므로, 모델의 사고 과정을 사용자에게 보여줄 수 있습니다.

재시도 구성

use adk_model::retry::RetryConfig;

let client = OpenAIResponsesClient::new(config)?
    .with_retry_config(RetryConfig {
        max_retries: 3,
        ..Default::default()
    });

속도 제한(429), 서버 오류(500/502/503/504) 및 네트워크 장애가 발생하면 자동으로 재시도합니다.


사용 가능한 모델

모델유형설명
gpt-5.6-terra추론프로덕션 에이전트를 위한 균형 잡힌 기본값
gpt-5.6-sol추론대표적인 추론 및 코딩
gpt-5.6-luna추론비용 효율적인 대규모 작업
gpt-5.6추론플래그십 별칭
gpt-5추론이전 세대 호환성
gpt-4.1 제품군채팅호환성 및 명시적 샘플링 제어
o3 / o4-mini추론이전 세대 추론 호환성

기능

도구 호출

함수 도구는 OpenAIClient와 동일하게 작동합니다. 에이전트에서 도구를 정의하면 runner가 도구 호출 루프를 처리합니다.

use adk_rust::prelude::*;
use adk_model::openai::{OpenAIResponsesClient, OpenAIResponsesConfig};
use adk_tool::FunctionTool;
use std::sync::Arc;

async fn get_weather(
    _ctx: Arc<dyn ToolContext>,
    args: serde_json::Value,
) -> Result<serde_json::Value> {
    let city = args["city"].as_str().unwrap_or("unknown");
    Ok(serde_json::json!({
        "city": city,
        "temperature_f": 72,
        "conditions": "Sunny"
    }))
}

let weather_tool = FunctionTool::new(
    "get_weather",
    "Get current weather for a city. Requires a 'city' string parameter.",
    get_weather,
);

let config = OpenAIResponsesConfig::new(&api_key, "gpt-5.6-terra");
let model = Arc::new(OpenAIResponsesClient::new(config)?);

let agent = LlmAgentBuilder::new("weather_agent")
    .instruction("Use the get_weather tool to answer weather questions.")
    .model(model)
    .tool(Arc::new(weather_tool))
    .build()?;

다중 턴 대화

Runner는 세션을 통해 대화 기록을 자동으로 관리합니다. 각 턴의 컨텍스트가 보존됩니다.

// Turn 1
let msg1 = Content::new("user").with_text("My name is Alice.");
let mut stream = runner.run(uid.clone(), sid.clone(), msg1).await?;
// ... consume stream ...

// Turn 2 — the model remembers the previous turn
let msg2 = Content::new("user").with_text("What is my name?");
let mut stream = runner.run(uid.clone(), sid.clone(), msg2).await?;
// Response: "Your name is Alice."

요청별 추론 재정의

LlmRequest 확장을 사용하여 요청별로 추론 설정을 재정의합니다.

use adk_rust::prelude::*;

let agent = LlmAgentBuilder::new("flexible_reasoner")
    .model(model)
    .generate_content_config(GenerateContentConfig {
        extensions: {
            let mut ext = std::collections::HashMap::new();
            ext.insert("openai".to_string(), serde_json::json!({
                "reasoning": {
                    "effort": "high",
                    "summary": "detailed"
                }
            }));
            ext
        },
        ..Default::default()
    })
    .build()?;

기본 제공 도구

Responses API은 OpenAI 호스팅 도구를 지원합니다. adk-tool의 타입이 지정된 래퍼를 우선 사용하세요.

use adk_tool::OpenAIWebSearchTool;
use std::sync::Arc;

let agent = LlmAgentBuilder::new("researcher")
    .model(model)
    .tool(Arc::new(OpenAIWebSearchTool::new().preview()))
    .build()?;

사용 가능한 래퍼에는 OpenAIWebSearchTool, OpenAIFileSearchTool, OpenAICodeInterpreterTool, OpenAIImageGenerationTool, OpenAIComputerUseTool, OpenAIMcpTool, OpenAILocalShellTool, OpenAIShellToolOpenAIApplyPatchTool가 포함됩니다.

이전 응답 ID

서버 측 대화 상태를 사용하려면(로컬 세션 기록 우회) previous_response_id를 전달합니다.

let agent = LlmAgentBuilder::new("stateful")
    .model(model)
    .generate_content_config(GenerateContentConfig {
        extensions: {
            let mut ext = std::collections::HashMap::new();
            ext.insert("openai".to_string(), serde_json::json!({
                "previous_response_id": "resp_abc123"
            }));
            ext
        },
        ..Default::default()
    })
    .build()?;

스트리밍 동작

Responses API 클라이언트는 텍스트 및 추론 델타를 실시간으로 스트리밍합니다.

  • 텍스트 델타는 Part::Text으로 partial: true과 함께 도착합니다.
  • 추론 요약 델타는 Part::Thinking으로 partial: true와 함께 도착합니다.
  • 함수 호출은 올바른 이름과 인수를 포함하여 최종 ResponseCompleted 이벤트에서 내보내집니다.
  • 최종 이벤트에는 사용량 메타데이터와 종료 사유가 포함된 turn_complete: true이 있습니다.

즉, 모델이 생성하는 동안 텍스트가 토큰 단위로 나타나는 것을 볼 수 있으며, 함수 호출은 실행할 수 있는 완전한 객체로 도착합니다.


공급자 메타데이터

모든 응답에는 response_id와 함께 공급자 메타데이터가 포함됩니다.

if let Some(meta) = &response.provider_metadata {
    let response_id = meta["openai"]["response_id"].as_str();
    // Use for previous_response_id, logging, debugging
}

추가 메타데이터에는 다음이 포함될 수 있습니다.

  • encrypted_content — 추론 모델에서 제공(컨텍스트 보존용)
  • built_in_tool_outputs — 웹 검색, 파일 검색, 코드 인터프리터의 결과

오류 처리

오류는 적절한 범주를 갖춘 구조화된 AdkError로 매핑됩니다.

HTTP 상태오류 범주재시도 가능
401Unauthorized아니요
429RateLimited
500, 502, 503, 504Unavailable
기타Internal아니요
match runner.run(uid, sid, message).await {
    Ok(stream) => { /* process stream */ }
    Err(e) if e.is_retryable() => { /* retry logic */ }
    Err(e) if e.is_unauthorized() => { /* check API key */ }
    Err(e) => { /* handle other errors */ }
}

백그라운드 모드 및 취소

장시간 실행되는 요청의 경우 background: true을 사용하여 제출하고 완료될 때까지 폴링합니다.

use adk_model::openai::{OpenAIResponsesClient, OpenAIResponsesConfig};

let client = OpenAIResponsesClient::new(config)?;

// Submit with background: true via extensions
let mut gen_config = GenerateContentConfig::default();
gen_config.extensions.insert("openai".into(), serde_json::json!({ "background": true }));

// ... send request, extract response_id from provider_metadata ...

// Poll until terminal status
let response = client.poll_response("resp_abc123").await?;
// Check provider_metadata["openai"]["status"]: "completed", "in_progress", "failed", "cancelled"

// Cancel a running background response
let cancelled = client.cancel_response("resp_abc123").await?;

심층 리서치 모델(o3-deep-research, o4-mini-deep-research)은 명시적인 background: true 없이도 백그라운드 모드를 자동으로 활성화합니다.


예제

완전한 7개 시나리오 예제는 examples/openai_responses/에서 확인할 수 있습니다.

export OPENAI_API_KEY=sk-...
cargo run --manifest-path examples/openai_responses/Cargo.toml

다음 시나리오를 다룹니다:

  1. 기본 비스트리밍 채팅
  2. 기본 스트리밍 채팅
  3. 요약 기능이 포함된 추론 모델(o4-mini 호환 경로)
  4. 함수 도구를 사용한 도구 호출
  5. 다중 턴 대화
  6. 시스템 지침
  7. 온도 및 생성 구성(gpt-4.1-nano 호환 경로)

추가 예제

독립 실행형 예제 crate 6개에서 특정 Responses API 기능을 보여 줍니다:

예시실행 명령기능
WebSocket 전송cargo run --manifest-path examples/openai_ws_minimal/Cargo.toml지연 시간이 짧은 영구 연결
백그라운드 모드cargo run --manifest-path examples/openai_background/Cargo.toml제출 및 폴링 워크플로
대화 APIcargo run --manifest-path examples/openai_conversations/Cargo.toml서버 관리 다중 턴
내장 도구cargo run --manifest-path examples/openai_builtin_tools/Cargo.toml이미지 생성, 웹 검색
심층 리서치cargo run --manifest-path examples/openai_deep_research/Cargo.toml자동 백그라운드 리서치
오픈 응답cargo run --manifest-path examples/openai_open_responses/Cargo.toml공급자 독립 엔드포인트


이전: ← 클라우드 제공업체 | 다음: Ollama(로컬) →