모델 제공자(클라우드)
ADK-Rust는 adk-model crate를 통해 여러 클라우드 LLM 제공자를 지원합니다. 모든 제공자는 Llm trait를 구현하므로, 에이전트에서 서로 교체하여 사용할 수 있습니다.
개요
┌─────────────────────────────────────────────────────────────────────┐
│ Cloud Model Providers │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ • Gemini (Google) ⭐ Default - Multimodal, large context │
│ • OpenAI (GPT-5) 🔥 Popular - Best ecosystem │
│ • Anthropic (Claude) 🧠 Smart - Best reasoning │
│ • DeepSeek 💭 Thinking - Chain-of-thought, cheap │
│ • Groq ⚡ Ultra-Fast - Fastest inference │
│ │
│ For local/offline models, see: │
│ • Ollama → ollama.md │
│ • mistral.rs → mistralrs.md │
│ │
└─────────────────────────────────────────────────────────────────────┘
빠른 비교
| 제공자 | 적합한 용도 | 속도 | 비용 | 주요 기능 |
|---|---|---|---|---|
| Gemini | 일반 사용 | ⚡⚡⚡ | 💰 | 멀티모달, 큰 컨텍스트, thinking |
| OpenAI | 신뢰성 | ⚡⚡ | 💰💰 | 최고의 생태계 |
| Anthropic | 복잡한 추론 | ⚡⚡ | 💰💰 | 가장 안전하고, 가장 신중함 |
| DeepSeek | Chain-of-thought | ⚡⚡ | 💰 | 생각 모드, 저렴함 |
| Groq | 속도 중요한 | ⚡⚡⚡⚡ | 💰 | 가장 빠른 추론 |
1단계: 설치
필요한 provider를 Cargo.toml에 추가하세요:
[dependencies]
# Pick one or more providers:
adk-model = { version = "2.0.0", features = ["gemini"] } # Google Gemini (default)
adk-model = { version = "2.0.0", features = ["openai"] } # OpenAI GPT-5
adk-model = { version = "2.0.0", features = ["anthropic"] } # Anthropic Claude
adk-model = { version = "2.0.0", features = ["deepseek"] } # DeepSeek
adk-model = { version = "2.0.0", features = ["groq"] } # Groq (ultra-fast)
# Or all cloud providers at once:
adk-model = { version = "2.0.0", features = ["all-providers"] }
2단계: API 키 설정
export GOOGLE_API_KEY="your-key" # Gemini
export OPENAI_API_KEY="your-key" # OpenAI
export ANTHROPIC_API_KEY="your-key" # Anthropic
export DEEPSEEK_API_KEY="your-key" # DeepSeek
export GROQ_API_KEY="your-key" # Groq
스키마 정규화
각 provider는 요청 시점에 MCP tool schema를 자동으로 정규화합니다. 별도로 할 일은 없습니다 — 투명하게 작동합니다. 하지만 내부에서 일어나는 일은 다음과 같습니다:
| 제공자 | 스키마 어댑터 | 동작 |
|---|---|---|
| Gemini | GeminiSchemaAdapter | 공격적: $ref를 해석하고, 결합기를 축소하며, 지원되지 않는 키워드를 제거함 |
| OpenAI (엄격) | OpenAiStrictSchemaAdapter | 구조를 보존하고, additionalProperties: false를 추가함 |
| OpenAI | OpenAiSchemaAdapter | 최소한의 안전 수정 |
| Anthropic | AnthropicSchemaAdapter | 거의 그대로 통과 |
| DeepSeek | GenericSchemaAdapter | 보수적인 안전 변환 |
| Ollama | GenericSchemaAdapter | 보수적인 안전 변환 |
어댑터는 Llm trait를 통해 프로그램적으로 접근할 수 있습니다:
use adk_core::{Llm, SchemaAdapter};
let adapter = model.schema_adapter();
let normalized = adapter.normalize_schema(raw_schema);
전체 문서는 Schema Normalization를 참조하세요.
Gemini (Google) ⭐ 기본
적합한 용도: 범용, 멀티모달 작업, 대용량 문서
주요 특징:
- 🖼️ 네이티브 멀티모달(이미지, 비디오, 오디오, PDF)
- 📚 최대 2M 토큰 컨텍스트 윈도우
- 🧠 Thinking mode: 레벨 기반(Gemini 3) 및 예산 기반(Gemini 2.5), thought signatures 포함
- 💰 경쟁력 있는 가격
- ⚡ 빠른 추론
완전한 동작 예제
use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
let api_key = std::env::var("GOOGLE_API_KEY")?;
let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;
let agent = LlmAgentBuilder::new("gemini_assistant")
.description("Gemini-powered assistant")
.instruction("You are a helpful assistant powered by Google Gemini. Be concise.")
.model(Arc::new(model))
.build()?;
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
사용 가능한 모델
| 모델 | 설명 | 컨텍스트 |
|---|---|---|
gemini-3.1-pro-preview | 복잡한 에이전트 워크플로를 위한 가장 강력한 추론 | 2M tokens |
gemini-3-flash-preview | 코드와 에이전트를 위해 빠르고 효율적임 | 1M tokens |
gemini-3.1-flash-lite-preview | 가장 저렴하고 가장 빠른 라우팅과 대량 작업 | 1M tokens |
gemini-2.5-pro | 고급 추론 및 멀티모달 | 1M tokens |
gemini-2.5-flash | 속도와 성능의 균형 (권장) | 1M tokens |
사고 모드
Gemini 3 모델은 수준 기반 사고를 지원하는 반면, Gemini 2.5는 예산 기반 사고를 사용합니다. 함수 호출과 함께 사고 모드를 사용할 때, Gemini 2.5+ 및 3.x 모델은 thoughtSignature 값을 반환하며, 이는 추론 컨텍스트를 보존하기 위해 이후 턴에서 그대로 되돌려 보내야 합니다. ADK-Rust는 이를 자동으로 처리합니다 — 서명은 존재할 때 직렬화되고, None일 때는 생략됩니다.
use adk_gemini::{Gemini, ThinkingLevel};
// Gemini 3: level-based thinking
let response = client.generate_content()
.with_user_message("Solve this step by step")
.with_thinking_level(ThinkingLevel::High)
.with_thoughts_included(true)
.execute().await?;
// Gemini 2.5: budget-based thinking
let response = client.generate_content()
.with_user_message("Solve this step by step")
.with_thinking_budget(2048)
.with_thoughts_included(true)
.execute().await?;
예제 출력
👤 User: What's in this image? [uploads photo of a cat]
🤖 Gemini: I can see a fluffy orange tabby cat sitting on a windowsill.
The cat appears to be looking outside, with sunlight illuminating its fur.
It has green eyes and distinctive striped markings typical of tabby cats.
OpenAI (GPT-5) 🔥 인기
최적 용도: 프로덕션 앱, 안정적인 성능, 폭넓은 기능
주요 특징:
- 🏆 업계 표준
- 🔧 뛰어난 도구/함수 호출
- 📖 최고의 문서 & 생태계
- 🎯 일관되고 예측 가능한 출력
- 📋 JSON 스키마 강제 적용이 있는 구조화된 출력
- 🧠 o1/o3 추론 모델을 위한 Reasoning effort 제어
- 🆕 Responses API — 추론 요약, 내장 도구, 서버 측 상태를 갖춘
/v1/responses전용 클라이언트
완전한 동작 예제
use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
let api_key = std::env::var("OPENAI_API_KEY")?;
let model = OpenAIClient::new(OpenAIConfig::new(&api_key, "gpt-5-mini"))?;
let agent = LlmAgentBuilder::new("openai_assistant")
.description("OpenAI-powered assistant")
.instruction("You are a helpful assistant powered by OpenAI GPT-5. Be concise.")
.model(Arc::new(model))
.build()?;
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
구조화된 출력 (JSON 스키마)
OpenAI는 output_schema를 통해 보장된 JSON 출력을 지원합니다. ADK-Rust는 이를 OpenAI의 response_format API에 자동으로 연결합니다:
use adk_rust::prelude::*;
use serde_json::json;
use std::sync::Arc;
let model = OpenAIClient::new(OpenAIConfig::new(&api_key, "gpt-5-mini"))?;
let agent = LlmAgentBuilder::new("data_extractor")
.model(Arc::new(model))
.instruction("Extract person information from the text.")
.output_schema(json!({
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "number" },
"email": { "type": "string" }
},
"required": ["name", "age"]
}))
.build()?;
// Response is guaranteed to be valid JSON matching the schema
중첩 객체에 대한 엄격 모드에서는 각 수준에 additionalProperties: false를 포함하세요:
.output_schema(json!({
"type": "object",
"properties": {
"title": { "type": "string" },
"metadata": {
"type": "object",
"properties": {
"author": { "type": "string" },
"tags": { "type": "array", "items": { "type": "string" } }
},
"required": ["author"],
"additionalProperties": false // Required for nested objects
}
},
"required": ["title", "metadata"],
"additionalProperties": false // Auto-injected at root level
}))
Reasoning Effort (o1, o3 모델)
OpenAI 추론 모델의 경우, 모델이 적용하는 추론 노력을 제어합니다:
use adk_model::openai::{OpenAIClient, OpenAIConfig, ReasoningEffort};
let config = OpenAIConfig::new(&api_key, "o3-mini")
.with_reasoning_effort(ReasoningEffort::High);
let model = OpenAIClient::new(config)?;
사용 가능한 수준: Low, Medium, High. 더 높은 노력은 지연 시간과 토큰 비용을 늘리는 대신 더 철저한 추론을 생성합니다.
OpenAI 호환 로컬 APIs
로컬 서버(Ollama, vLLM, LM Studio)에 연결하려면 OpenAIConfig::compatible()를 사용하세요:
// Ollama exposes OpenAI-compatible API at /v1
let config = OpenAIConfig::compatible(
"not-needed", // API key (ignored by Ollama)
"http://localhost:11434/v1", // Base URL
"llama3.2" // Model name
);
let model = OpenAIClient::new(config)?;
참고: 구조화된 출력(
output_schema)에는 백엔드 지원이 필요합니다. 네이티브 OpenAI는 이를 완전히 지원하지만, 로컬 서버는 지원이 제한될 수 있습니다.
OpenAI 호환 엔드포인트를 통한 Gemini
Gemini 모델은 다음 위치의 OpenAI Chat Completions 와이어 형식을 통해 접근할 수 있습니다:
https://generativelanguage.googleapis.com/v1beta/openai. openai 기능 아래의 OpenAICompatibleConfig::gemini(...) 프리셋과
GEMINI_API_KEY을 사용하여 다른 모든 제공자에 사용하는 것과 동일한 OpenAI 호환 클라이언트로 Gemini를 실행하세요:
use adk_model::openai_compatible::{OpenAICompatible, OpenAICompatibleConfig};
let api_key = std::env::var("GEMINI_API_KEY")?;
let model = OpenAICompatible::new(
OpenAICompatibleConfig::gemini(api_key, "gemini-3.5-flash"),
)?;
이 경로는 채팅, 스트리밍, 함수 호출, 구조화된 출력, 그리고
reasoning effort(OpenAI의 reasoning_effort는 Gemini 사고
수준/예산에 매핑됨)를 지원합니다. Gemini 전용 옵션 — 예를 들어 thinking_config와
include_thoughts, 또는 cached_content — 은 요청의
extensions["openai"]["extra_body"]["google"] 맵을 통해 전달되며, 클라이언트는 이를 요청 본문에
그대로 병합합니다.
이것을
GeminiModel대신 언제 사용할까: 서버 측 도구, Interactions API, 네이티브ThinkingConfig, 멀티모달 우선 사용성 같은 네이티브 Gemini 기능이 필요하다면GeminiModel를 사용하세요. 제공자 전반에 걸쳐 단일한 통일된 클라이언트를 원할 때는 OpenAI 호환 프리셋을 사용하세요.
예제 (GEMINI_API_KEY 또는 GOOGLE_API_KEY 필요):
# Direct client: chat, reasoning effort, extra_body thinking, streaming,
# function calling, structured output.
cargo run -p adk-model --features openai --example gemini_openai_compat
# The same compat client driving a normal LlmAgent in a Runner.
# (Lives in adk-agent: it exercises the agent layer, which sits above adk-model.)
cargo run -p adk-agent --example gemini_openai_compat_agent
Reasoning Effort (o1, o3 모델)
ReasoningEffort으로 모델이 적용하는 추론 노력을 제어합니다:
use adk_model::openai::{OpenAIClient, OpenAIConfig, ReasoningEffort};
let config = OpenAIConfig::new(&api_key, "o3-mini")
.with_reasoning_effort(ReasoningEffort::High);
let model = OpenAIClient::new(config)?;
사용 가능한 수준: Low(가장 빠름), Medium(균형형), High(가장 철저함).
사용 가능한 모델
| 모델 | 설명 | 컨텍스트 |
|---|---|---|
gpt-5 | 적응형 사고를 갖춘 최첨단 통합 모델 | 256K 토큰 |
gpt-5-mini | 대부분의 작업에 적합한 효율적인 버전(권장) | 128K 토큰 |
gpt-5-nano | 최저 비용 라우팅 및 분류 | 128K 토큰 |
gpt-4.1 | 레거시 GPT-4.1 배포를 위한 안정적인 프로덕션 모델 | 1M 토큰 |
예시 출력
👤 User: Write a haiku about Rust programming
🤖 GPT-5: Memory so safe,
Ownership guards every byte—
Compiler, my friend.
Anthropic (Claude) 🧠 스마트
최적 용도: 복잡한 추론, 안전이 중요한 앱, 긴 문서
주요 특징:
- 🧠 뛰어난 추론 능력
- 🛡️ 가장 안전성에 중점
- 📚 200K 토큰 컨텍스트
- ✍️ 뛰어난 글쓰기 품질
완전한 동작 예제
use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
let api_key = std::env::var("ANTHROPIC_API_KEY")?;
let model = AnthropicClient::new(AnthropicConfig::new(&api_key, "claude-sonnet-4-6"))?;
let agent = LlmAgentBuilder::new("anthropic_assistant")
.description("Anthropic-powered assistant")
.instruction("You are a helpful assistant powered by Anthropic Claude. Be concise and thoughtful.")
.model(Arc::new(model))
.build()?;
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
사용 가능한 모델
| 모델 | 설명 | 컨텍스트 |
|---|---|---|
claude-opus-4-7 | 가장 성능이 뛰어난 GA 모델, 적응형 사고만 지원 | 100만 토큰 |
claude-opus-4-6 | 복잡한 자율 작업을 위한 이전 플래그십 | 100만 토큰 |
claude-sonnet-4-6 | 균형 잡힌 지능과 비용(권장) | 1M 토큰 |
claude-haiku-4-5-20251001 | 대규모 작업 부하에 매우 효율적 | 200K 토큰 |
claude-opus-4-20250514 | 확장된 사고를 갖춘 하이브리드 모델 | 200K 토큰 |
claude-sonnet-4-20250514 | 확장된 사고를 갖춘 균형형 모델 | 1M 토큰 |
예제 출력
👤 User: Explain quantum entanglement to a 10-year-old
🤖 Claude: Imagine you have two magic coins. When you flip them, they always
land the same way - both heads or both tails - even if one coin is on Earth
and the other is on the Moon! Scientists call this "entanglement." The coins
are connected in a special way that we can't see, like invisible best friends
who always make the same choice at the exact same time.
DeepSeek 💭 사고
적합한 용도: 복잡한 문제 해결, 수학, 코딩, 추론 작업
주요 특징:
- 💭 사고 모드 - chain-of-thought 추론을 표시
- 💰 매우 비용 효율적임 (GPT-4보다 10배 저렴)
- 🔄 반복되는 접두사에 대한 컨텍스트 캐싱
- 🧮 수학과 코딩에 강함
완전한 동작 예제
use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
let api_key = std::env::var("DEEPSEEK_API_KEY")?;
// Standard chat model
let model = DeepSeekClient::chat(&api_key)?;
// OR: Reasoning model with thinking mode
// let model = DeepSeekClient::reasoner(&api_key)?;
let agent = LlmAgentBuilder::new("deepseek_assistant")
.description("DeepSeek-powered assistant")
.instruction("You are a helpful assistant powered by DeepSeek. Be concise.")
.model(Arc::new(model))
.build()?;
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
사용 가능한 모델
| 모델 | 설명 | 특수 기능 |
|---|---|---|
deepseek-r1-0528 | 최신 추론 모델 | 향상된 사고 깊이 |
deepseek-r1 | 고급 추론 | o1과 동등함 |
deepseek-v3.1 | 최신 671B MoE 모델 | 일반 작업 |
deepseek-chat | 671B MoE 모델 (V3) | 범용, 저렴함 |
deepseek-vl2 | 비전-언어 모델 | 멀티모달 |
예제 출력(Reasoner with Thinking Mode)
👤 User: What's 17 × 23?
🤖 DeepSeek: <thinking>
Let me break this down:
17 × 23 = 17 × (20 + 3)
= 17 × 20 + 17 × 3
= 340 + 51
= 391
</thinking>
The answer is 391.
Groq ⚡ 초고속
추천 용도: 실시간 애플리케이션, 챗봇, 속도 중심 작업
주요 특징:
- ⚡ 가장 빠른 추론 - 경쟁사보다 10배 더 빠름
- 🔧 LPU(Language Processing Unit) 기술
- 💰 경쟁력 있는 가격
- 🦙 LLaMA, Mixtral, Gemma 모델 실행
전체 동작 예제
use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
let api_key = std::env::var("GROQ_API_KEY")?;
let model = GroqClient::llama70b(&api_key)?;
let agent = LlmAgentBuilder::new("groq_assistant")
.description("Groq-powered assistant")
.instruction("You are a helpful assistant powered by Groq. Be concise and fast.")
.model(Arc::new(model))
.build()?;
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
사용 가능한 모델
| 모델 | 메서드 | 설명 |
|---|---|---|
llama-4-scout | GroqClient::new(GroqConfig::new(key, "llama-4-scout")) | Llama 4 Scout (17Bx16E) |
llama-3.2-90b-text-preview | GroqClient::new(GroqConfig::new(key, "llama-3.2-90b-text-preview")) | 대형 텍스트 모델 |
llama-3.1-70b-versatile | GroqClient::llama70b() | 다목적 대형 모델 |
llama-3.1-8b-instant | GroqClient::llama8b() | 가장 빠름 |
mixtral-8x7b-32768 | GroqClient::mixtral() | 균형이 좋음 |
| 모든 모델 | GroqClient::new(GroqConfig::new(key, "model")) | 사용자 정의 모델 |
예제 출력
👤 User: Quick! Name 5 programming languages
🤖 Groq (in 0.2 seconds):
1. Rust
2. Python
3. JavaScript
4. Go
5. TypeScript
제공자 전환
모든 제공자는 동일한 Llm trait를 구현하므로, 전환은 쉽습니다:
use adk_agent::LlmAgentBuilder;
use std::sync::Arc;
// Just change the model - everything else stays the same!
let model: Arc<dyn adk_core::Llm> = Arc::new(
// Pick one:
// GeminiModel::new(&api_key, "gemini-2.5-flash")?
// OpenAIClient::new(OpenAIConfig::new(&api_key, "gpt-5-mini"))?
// AnthropicClient::new(AnthropicConfig::new(&api_key, "claude-sonnet-4-6"))?
// DeepSeekClient::chat(&api_key)?
// GroqClient::llama70b(&api_key)?
);
let agent = LlmAgentBuilder::new("assistant")
.instruction("You are a helpful assistant.")
.model(model)
.build()?;
예제
검증된 0.8 의존성을 사용하는 제공자별 프로젝트를 생성하려면 cargo-adk를 사용하세요:
cargo adk new gemini_agent --provider gemini
cargo adk new openai_agent --template openai
cargo adk new anthropic_agent --provider anthropic
생성된 프로젝트는 CI에서 scripts/check-cargo-adk-templates.sh에 의해 컴파일됩니다. 전체 예제 갤러리는 이 사이트에 포함된 ADK-Rust Playground에서 탐색하고 실행할 수 있습니다.
관련 항목
- Ollama (Local) - Ollama로 모델을 로컬에서 실행하기
- Local Models (mistral.rs) - 네이티브 Rust 추론
- LlmAgent - agent와 함께 모델 사용하기
- Function Tools - agent에 tool 추가하기
이전: ← Realtime Agents | 다음: Ollama (Local) →
제공자가 전달할 수 없는 content는 어떻게 되나
Content는 단일 provider transport가 허용하는 것보다 더 많은 것을 표현할 수 있으므로, 각 adapter는 나머지를 어떻게 처리할지 결정해야 합니다. 이러한 결정은 이제 보이지 않게 적용되는 대신 기록됩니다. 모든 부분은 다음과 같이 분류됩니다:
| 배치 | 의미 |
|---|---|
Converted | 제공자에게 동등한 네이티브 형식으로 전달됨 |
Downgraded | 더 손실이 큰 형식으로 전달됨 — 모델이 읽을 수는 있지만 가져올 수는 없는 설명 텍스트로 렌더링된 파일 참조 |
Omitted | 전혀 전달되지 않음 |
다운그레이드와 누락은 기록될 때 tracing 경고를 발생시키며, part 종류, MIME type, 그리고 이유를 명시하므로 어느 쪽도 조용히 넘어가지 않습니다.
요청을 전송하기 전에 결과를 확인하려면:
use adk_core::{Content, Part};
use adk_model::bedrock::convert::report_for_contents;
let content = Content {
role: "user".to_string(),
parts: vec![Part::inline_data("audio/wav", vec![0u8; 16])],
};
let report = report_for_contents(std::slice::from_ref(&content));
for omission in report.omitted_parts() {
println!("{} was dropped: {}", omission.kind, omission.detail);
}
모델이 보지 못한 자료에 대한 답변을 받는 대신, 불완전한 상태로 모델에 도달할 요청을 거부하려면:
use adk_core::{Content, Part};
use adk_model::bedrock::convert::report_for_contents;
let content = Content {
role: "user".to_string(),
parts: vec![Part::inline_data("video/mp4", vec![0u8; 16])],
};
if let Some(error) = report_for_contents(std::slice::from_ref(&content)).into_error() {
return Err(error);
}
into_error는 누락만 다룹니다. 다운그레이드는 여전히 모델에 도달하며, 이를 거부하면 문서화된 텍스트 대체 경로를 거부하게 됩니다.
참고: ledger는 구성상 완전합니다. 어댑터를 떠날 때 기록된 운명이 없는 모든 part — 미래의 변경으로 추가된 것까지 포함해 — 는 명시적인 "기록된 이유 없음"과 함께 누락으로 기록되며,
adk-model/tests/part_conversion_matrix_tests.rs가 이를 실패로 처리합니다.
Bedrock Converse 범위
| 부분 | 처리 상태 |
|---|---|
| 텍스트, FunctionCall, FunctionResponse, Thinking | Converted |
InlineData with JPEG, PNG, GIF, WebP | Converted as an image block |
InlineData 지원되는 문서 유형(PDF 등)과 함께 | 문서 블록으로서 Converted |
InlineData 오디오, 비디오 또는 임의의 바이너리와 함께 | Omitted |
이미지 또는 지원되는 문서에 대해 FileData | 텍스트로 Downgraded — Converse는 임의의 URLs가 아니라 S3 URIs를 사용함 |
다른 모든 유형에 대해 FileData | Omitted |
ServerToolCall, ServerToolResponse | Omitted — Gemini 전용 |
EmbeddedResource 텍스트, 또는 지원되는 유형의 blob | Converted |
EmbeddedResource 지원되지 않는 유형의 blob | Omitted |