온체인 AI 에이전트 아키텍처: 다섯 가지 빌드 패턴
작성자 Uttam Singh

온체인 상태를 읽고 쓰는 AI 에이전트는 데모 단계를 지나 프로덕션 단계로 넘어갔습니다. 모델은 추론할 수 있고, 에이전트 지갑은 범위가 지정된 권한 하에서 서명할 수 있으며, 인프라는 이벤트가 온체인에 기록된 지 몇 초 만에 에이전트에 푸시할 수 있습니다. 아키텍처는 여전히 빌드가 잘못되는 지점입니다. 에이전트가 구독할 수 있는 이벤트를 폴링하거나, 신뢰할 수 없는 입력을 읽는 프로세스와 같은 프로세스에서 서명 권한을 보유하거나, 실제 자금으로 메인넷에서 학습하는 경우가 그렇습니다.
온체인 에이전트는 하나의 루프입니다: 관찰, 판단, 실행. 프로덕션 에이전트는 이 루프를 다섯 가지 반복되는 형태로 배치하며, 각각에 대해 아래에 실제 예제가 있습니다. 온체인 에이전트 구축 가이드에서는 이 모든 형태의 기반이 되는 요소들(지갑, 결제 레일, 데이터 피드)을 다룹니다. 이 페이지에서는 이러한 요소들을 어떻게 배치하는지를 다룹니다.
실시간 지갑 감시 에이전트는 어떻게 구축하나요?
관심 있는 주소를 웹훅에 등록하고 체인이 여러분에게 오도록 하세요. 잔액을 루프로 폴링하면 연산 자원을 소모하면서도 여전히 그 순간을 놓칠 수 있습니다. 푸시 파이프라인은 전송이 기록된 지 몇 초 만에 전달하며, 이것이 바로 감시자의 본연의 역할입니다.
에이전트가 펀드의 카운터파티 지갑을 추적하고 대규모 USDC 이동을 감지한다고 가정해 보겠습니다. Alchemy에서는 단일 Address Activity webhook으로 최대 100,000개 주소에 대한 네이티브, ERC-20, ERC-721, ERC-1155 전송을 모두 다룰 수 있으므로, 웹훅 하나로 전체 카운터파티 목록을 감시할 수 있습니다. 에이전트가 장기 실행 프로세스로 동작하고 공개 URL을 노출하고 싶지 않다면, WebSocket 구독이 프로세스 내부에서 동일한 역할을 합니다. alchemy_minedTransactions으로 구독하면 이미 여러분의 주소로 필터링된 확인된 트랜잭션을 받을 수 있으며, 로그 파싱이 필요 없습니다. Solana에서는 Yellowstone gRPC 스트리밍이 TB당 $75로 동일한 역할을 하며, 재연결 시에도 데이터 누락이 없습니다. 어떤 전송 방식이 적합한지 확신이 서지 않을 때는, webhooks vs WebSockets vs gRPC 비교에서 상세히 구분해 드립니다.
핸들러 자체는 거의 아무 일도 하지 않아야 합니다. 전달이 Alchemy에서 온 것임을 증명하고, 중복을 제거하고, 이벤트를 에이전트의 판단 단계로 넘긴 다음, 그때서야 확인 응답을 보내세요:
import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";
const SIGNING_KEY = process.env.ALCHEMY_WEBHOOK_SIGNING_KEY!; // from the webhook's dashboard settings
const USDC = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"; // canonical USDC contract on Ethereum mainnet
const seen = new Set<string>();
function remember(key: string) {
seen.add(key);
if (seen.size > 10_000) seen.delete(seen.values().next().value!); // bound the set; only recent deliveries repeat
}
function wake(signal: unknown) {
// The agent's decide step starts here. Queue the signal;
// don't run model reasoning inside the request handler.
}
const app = express();
app.use(
express.json({
verify: (req, _res, buf) => {
(req as { rawBody?: Buffer }).rawBody = buf; // keep the raw bytes for the HMAC check
},
})
);
app.post("/hooks/address-activity", (req, res) => {
const sig = Buffer.from(String(req.headers["x-alchemy-signature"] ?? ""), "hex");
const expected = createHmac("sha256", SIGNING_KEY)
.update((req as { rawBody?: Buffer }).rawBody ?? Buffer.alloc(0))
.digest();
if (sig.length !== expected.length || !timingSafeEqual(sig, expected)) {
return res.sendStatus(401); // not signed with our key; never process it
}
for (const transfer of req.body.event.activity) {
const key = `${transfer.hash}:${transfer.log?.logIndex ?? "native"}`; // one tx can carry several transfers
if (seen.has(key)) continue; // repeat delivery, already handled
if (transfer.rawContract?.address?.toLowerCase() === USDC && transfer.value > 50_000) {
wake({ kind: "large-transfer", ...transfer }); // if this throws, the key stays unmarked and the retry redelivers
}
remember(key); // mark handled only after the handoff succeeded
}
res.sendStatus(200); // ack only after queueing: a crash above gets retried, not lost
});
app.listen(8080);세 가지 습관이 이 패턴을 프로덕션에서 신뢰할 수 있게 만듭니다. 전달을 신뢰하기 전에 HMAC 서명을 검증해야 합니다. 그렇지 않으면 엔드포인트 URL을 알아낸 누구든 가짜 전송을 POST로 보내 여러분의 에이전트를 조종할 수 있습니다. 토큰은 심볼이 아니라 컨트랙트 주소로 매칭해야 합니다. 누구든 자신을 USDC라고 부르는 토큰을 배포해서 감시 중인 주소로 보낼 수 있기 때문입니다. 그리고 전달은 최소 한 번(at-least-once) 방식이므로 중복 제거 기록은 선택 사항이 아닙니다. 인메모리 집합은 하나의 장기 실행 프로세스에서는 작동하지만, 재시작되거나 복제본으로 실행되는 서비스는 Redis 키나 데이터베이스 행처럼 공유되고 지속되는 곳에 그 기록을 두어야 합니다. 트레이딩 에이전트에게 중복된 웨이크업은 곧 중복된 트랜잭션이기 때문입니다. 기계적인 필터링은 핸들러에 두고 모델은 여기서 배제해야 합니다. 전송 하나당 LLM 호출을 하는 비용이 그 전송을 전달한 인프라 비용보다 더 크기 때문입니다.
AI 에이전트가 스마트 컨트랙트 이벤트를 모니터링하고 자동으로 반응하게 하려면 어떻게 해야 하나요?
컨트랙트의 로그를 구독하고, 중요한 이벤트 한두 개로 필터링한 다음, 핸들러를 멱등하게 만드세요. 컨트랙트 이벤트는 에이전트가 얻을 수 있는 가장 깔끔한 트리거입니다. 컨트랙트가 무슨 일이 일어났는지, 어떤 순서로 일어났는지를 정확히 명시하기 때문입니다.
Alchemy에서는 두 가지 표면이 이를 다룹니다. Custom webhooks는 GraphQL 필터를 받으므로, 컨트랙트 주소와 이벤트 토픽으로 매칭해서 요청한 로그만 받을 수 있습니다. 이는 서버리스 리액터에 적합합니다. 장기 실행되는 에이전트라면, WebSocket 로그 구독이 모든 것을 하나의 프로세스 안에 유지합니다. 다음은 Uniswap v3 풀을 감시하는 리액터로, 트레이딩 에이전트가 단일 스왑으로 가격이 움직이는 것을 감지하는 데 사용하는 종류의 피드입니다:
import { createPublicClient, webSocket, parseAbiItem } from "viem";
import { mainnet } from "viem/chains";
function react(args: unknown) {
// Decide step: is this swap big enough to act on?
}
const client = createPublicClient({
chain: mainnet,
transport: webSocket("wss://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"),
});
client.watchEvent({
address: "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640", // USDC/WETH 0.05% pool
event: parseAbiItem(
"event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)"
),
onLogs: (logs) => {
for (const log of logs) {
if (log.removed) continue; // reorg removal notice; irreversible actions also need the confirmation-depth rule below
react(log.args);
}
},
});log.removed 검사는 보이는 것보다 더 중요합니다. 체인은 재구성될 수 있으며, 에이전트가 이미 처리한 로그가 몇 블록 뒤에 정식 체인에서 사라질 수 있습니다. 멱등한 핸들러와 확인 깊이 규칙(비가역적 조치를 취하기 전 몇 블록 대기)을 함께 사용하는 것이 표준적인 방어 방법입니다. 리액터의 또 다른 원칙은 감시자와 동일합니다. 구독 필터가 저비용의 제거 작업을 수행하고, 모델은 그 필터를 통과한 이벤트만 보게 됩니다.
DeFi 포트폴리오 리밸런싱 에이전트를 구축하려면 무엇이 필요한가요?
네 가지 요소가 필요합니다: 현재 잔액, 현재 가격, 드리프트 규칙, 그리고 스왑 경로. 에이전트는 처음 두 가지를 읽고, 세 번째를 확인하며, 규칙이 트리거될 때만 네 번째를 사용합니다.
WETH, USDC, WBTC를 50/30/20 비율로 보유한 트레저리 에이전트를 예로 들어보겠습니다. 잔액은 Portfolio API에서 가져오며, 이 API는 여러 체인에 걸친 지갑의 토큰을 체인별 호출을 여러 번 부채꼴로 보내는 대신 한 번의 요청으로 반환합니다. 가치는 Prices API에서 가져옵니다. 드리프트 규칙은 산술적입니다. 흔한 출발점은 각 목표 비중을 중심으로 5퍼센트 포인트 밴드를 두는 것입니다. 드리프트는 대체로 토큰이 움직여서가 아니라 가격이 움직여서 발생하며, 가격 변동은 반응할 온체인 이벤트를 만들어내지 않으므로 타이머로 확인하세요. 감시자(패턴 1)가 보고하는 전송은 입금과 출금을 그 즉시 포착하는 보조 트리거입니다.
const TARGET = { WETH: 0.5, USDC: 0.3, WBTC: 0.2 } as const;
const BAND = 0.05; // rebalance when a weight drifts 5 points from target
const WALLET = "0xYourTreasuryWallet"; // the wallet the agent manages
const res = await fetch(
`https://api.g.alchemy.com/data/v1/${process.env.ALCHEMY_API_KEY}/assets/tokens/by-address`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
addresses: [{ address: WALLET, networks: ["eth-mainnet"] }],
}),
}
);
const { data } = await res.json();
// Price each balance with the Prices API, sum to a total, then:
for (const [symbol, target] of Object.entries(TARGET)) {
const drift = weightOf(symbol, data) - target; // weightOf: your portfolio math
if (Math.abs(drift) > BAND) {
propose({ symbol, drift }); // propose: log it and request approval; never swap directly
}
}실행 측은 원시 개인 키를 보유해서는 안 됩니다. 범위가 지정된 에이전트 지갑을 사용하면 키는 커스터디에 남아 있고, 세션은 여러분이 부여한 기능만 갖게 됩니다. ERC-20을 지출하려면 스왑 전에 라우터에 대한 허용량(allowance)이 필요합니다. 매번 정확한 금액만 승인하면 트랜잭션이 하나 더 들지만, 공격자가 유출할 수 있는 상시 허용량을 남기지 않습니다:
# before each swap: let the router from your quote spend exactly this swap's WETH
alchemy evm approve 0xRouterFromQuote --token-address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 --amount 0.4 -n eth-mainnet
# swap WETH into USDC (Ethereum mainnet contract addresses)
alchemy evm swap execute \
--from 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 \
--to 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
--amount 0.4 --slippage 0.5 -n eth-mainnet \
--signer session --json --no-interactive이 루프의 형태에 주목하세요. 에이전트는 제안하고, 다른 무언가가 승인합니다. 초기에는 그 무언가가 바로 여러분입니다. 나중에는 크기, 슬리피지, 자산 허용 목록에 대한 정책 검사가 될 수 있습니다. DeFi AI 에이전트 개요에서는 이러한 분리가 왜 프로덕션 DeFi 에이전트에서 표준이 되는지를 다루며, 가스 스폰서십은 여러분이 제어하는 정책 하에서 수수료를 대신 지불함으로써 마지막 운영상의 번거로움을 없애줍니다. 그러면 에이전트는 가스 잔액을 관리할 필요가 없습니다.
탐지 후 실행(detect-then-execute) 방식의 멀티 에이전트 시스템에 가장 적합한 아키텍처는 무엇인가요?
에이전트를 작업량이 아니라 권한에 따라 나누세요. 탐지자(detector)는 모든 것을 읽지만 아무것도 서명할 수 없습니다. 실행자(executor)는 트랜잭션에 서명하지만 자신이 재검증하지 않은 것은 아무것도 믿지 않습니다.
이를 애널리스트와 트레이더로 생각해 보세요. 애널리스트는 하루 종일 시장을 지켜보며 누구와도 대화할 수 있습니다. 트레이더는 애널리스트의 판단을 받아 검토한 다음, 계정에 접근 권한을 가진 유일한 사람으로서 실행합니다.
이 패턴에서 흔히 쓰이는 표현은 일반적인 에이전트 도구에서 나온 것으로, 플래너 모델이 단계를 생성하고 실행 에이전트가 도구를 실행하는 구조입니다. 그 표현은 오케스트레이션에 관한 것입니다. 온체인에서는 이 분리가 더 어려운 이유, 즉 커스터디 때문에 그 복잡성을 감수할 가치가 있습니다. 탐지자는 하루 종일 신뢰할 수 없는 입력을 소비합니다: 멤풀 노이즈, 서드파티 API, 이벤트 스트림, 때로는 소셜 피드까지. 이 중 어떤 것이든 프롬프트 인젝션을 담고 있을 수 있습니다. 적대적인 입력을 읽는 프로세스가 서명 권한도 함께 보유하고 있다면, 오염된 메시지 하나가 서명된 트랜잭션이 될 수 있습니다. 이를 분리하면, 탈취된 탐지자가 할 수 있는 최악의 일은 실행자가 버리게 될 나쁜 제안을 하는 것뿐입니다.
탐지자는 패턴 1과 2로 구성되며, 폴링 루프가 아닌 푸시 인프라에 연결됩니다. 큐를 통해 신호를 내보내며, 이 큐는 동시에 감사 로그 역할도 합니다. 신호 계약(contract)은 작고 검증 가능하게 유지하세요:
{
"kind": "arb-opportunity",
"pair": "WETH/USDC",
"evidence": { "txHash": "0x…", "block": 23411005 },
"proposal": { "action": "swap", "from": "WETH", "to": "USDC", "amount": "0.4" },
"observedAt": "2026-09-05T09:14:03Z",
"expiresAt": "2026-09-05T09:14:33Z"
}실행자는 어떤 신호에 대해 행동하기 전에 세 가지 규칙을 강제합니다:
- 증거를 온체인에서 재검증하세요. 탐지자의 요약을 믿는 대신 참조된 트랜잭션을 직접 읽으세요. 탐지자의 역할은 알아차리는 것이었고, 증명하는 것은 실행자의 역할입니다.
- 만료 시간을 강제하세요. 오래된 기회에 행동하는 것은 공격자가 루프에 없어도 탐지 후 실행 시스템이 손실을 보는 방식입니다.
- 지갑 레이어에서 지출 한도를 설정하세요. 신호당, 일당 예산은 범위가 지정된 세션에 존재하며, 행동이 이상해 보이는 순간 대시보드에서 취소할 수 있습니다.
도구 측면에서 실행자에게 필요한 것은 딱 두 가지입니다: 검증을 위한 RPC 연결과 서명 표면입니다. 탐지자는 더 많은 자원을 필요로 하는 쪽이며, 이를 인덱싱된 데이터(Transfers API로 이력을, Portfolio API로 상태를)와 함께 사용하면 원시 체인 데이터를 디코딩하는 대신 추론에 토큰 지출을 집중할 수 있습니다. 자율 에이전트를 위한 블록체인 API 비교에서 이 선택의 인프라 측면을 다룹니다.
메인넷으로 가기 전에 AI 에이전트 트랜잭션을 안전하게 테스트하려면 어떻게 해야 하나요?
에이전트와 실제 자산 사이에 네 개의 게이트를 두세요: 모든 트랜잭션을 드라이런하고, 키가 지출할 수 있는 범위를 제한하고, 전체 루프를 테스트넷에서 리허설하고, 자금을 이동하는 모든 작업에 사람의 승인을 유지하세요.
- 먼저 드라이런하세요. Alchemy CLI는 서명하거나 브로드캐스트하지 않고 모든 전송을 미리 볼 수 있게 해줍니다(
alchemy evm send 0xRecipient 0.4 --dry-run). 코드에서는 viem의simulateContract이 실제 트랜잭션을 제출하지 않고도 라이브 메인넷 상태에 대해 컨트랙트 호출을 검증하므로, 오래된 픽스처가 아닌 실제 가격과 실제 풀 깊이로 리허설할 수 있습니다. - 키를 제한하세요. 범위가 지정된 세션 지갑은 여러분이 설정한 일정에 따라 만료되며, 승인된 작업만 수행할 수 있습니다. 또한 가스 스폰서십 정책은 수수료 레이어에 허용 목록과 지출 한도를 추가합니다. 키를 제한하면 최악의 버그가 계정 유출에서 한정된 손실로 바뀝니다.
- 테스트넷에서 리허설하세요. 동일한 코드를 Sepolia나 Base Sepolia 엔드포인트로 향하게 하고, 테스트넷 파우셋에서 에이전트에 자금을 지원하세요. 리허설과 프로덕션 사이에서 코드가 바뀐다면 실행 결과는 무의미해지므로, 네트워크 이름은 구성(configuration)에 두고 그 외에는 아무것도 바꾸지 마세요.
- 자금 이동 작업을 게이트하세요. 에이전트가 아직 검증되지 않은 초기 단계에서는 모든 전송, 스왑, 승인이 명시적인 승인을 기다려야 합니다. 대부분의 팀은 감사 로그가 에이전트의 정상 동작을 입증함에 따라 한 번에 하나의 작업 유형씩 의도적으로 게이트를 완화합니다.
이를 잘 운영하는 팀들은 승격을 스위치가 아니라 순서로 다룹니다: 먼저 메인넷에 대한 읽기 전용, 그다음 테스트넷 쓰기, 그다음 한도가 설정된 메인넷 쓰기, 마지막으로 전체 예산 순입니다. 각 단계는 다음 단계를 정당화하는 로그를 만들어냅니다.
이미 존재하는 요소들로 시작하세요
이 페이지에 나온 모든 패턴은 오늘 바로 사용할 수 있는 인프라에서 동작합니다. Alchemy CLI는 지갑, 전송, 스왑, 웹훅 관리를 하나의 바이너리에서 처리하며 에이전트는 --json --no-interactive로 이를 구동할 수 있습니다. 호스팅된 MCP server는 RPC, 시뮬레이션, 데이터에 걸쳐 168개의 도구를 제공하며, Claude Code용 Alchemy 플러그인은 명령 하나로 전체 표면을 설치합니다. 계약도 필요 없고 최소 약정도 없는 무료 티어로 시작할 수 있으며, 에이전트가 자신의 지갑으로 직접 가입하고 USDC로 결제하는 것도 가능합니다. 어떤 패턴으로 시작하든, 루프는 동일하게 유지됩니다: 관찰, 판단, 실행.
자주 묻는 질문
하나의 에이전트가 기회를 탐지하고 다른 에이전트가 실행하는 멀티 에이전트 시스템에 가장 적합한 아키텍처는 무엇인가요?
권한에 따라 분리하세요: 이벤트 스트림을 읽지만 키를 보유하지 않는 탐지자, 소규모의 서명되지 않은 신호를 전달하는 큐, 그리고 행동에 옮기기 전 각 신호를 온체인에서 재검증하는 실행자로 구성합니다. Alchemy에서는 탐지자가 webhooks나 WebSocket 구독으로 동작하고, 실행자는 지출 한도와 즉시 취소가 가능한 범위가 지정된 에이전트 지갑을 통해 서명합니다.
실시간 지갑 감시 에이전트에 가장 적합한 인프라는 무엇인가요?
폴링이 아닌 푸시 기반 이벤트 전달입니다. Alchemy의 Address Activity webhooks는 웹훅당 최대 100,000개 주소에 걸친 전송을 추적하고, WebSocket 구독은 여러분의 주소로 필터링된 채굴된 트랜잭션을 스트리밍하며, Yellowstone gRPC는 Solana를 다룹니다. 푸시 파이프라인은 폴링 루프의 지연 시간과 연산 비용 없이 전송이 기록된 지 몇 초 만에 에이전트를 깨웁니다.
AI 코딩 에이전트가 지갑 활동을 모니터링하는 데 어떤 도구를 사용해야 하나요?
Alchemy MCP server는 코딩 에이전트에게 RPC, 트랜잭션 이력, 포트폴리오 데이터를 다루는 168개의 도구를 제공하며, Alchemy CLI는 명령줄에서 웹훅을 생성하고 관리합니다. 런타임 자체는 Address Activity webhook이나 alchemy_minedTransactions 구독이 지갑 이벤트를 전달하며, Transfers API가 이력을 소급 채워줍니다.
DeFi 포트폴리오 리밸런싱 에이전트를 구축하려면 무엇이 필요한가요?
잔액, 가격, 드리프트 규칙, 스왑 경로가 필요합니다. Alchemy의 Portfolio API는 한 번의 호출로 여러 체인의 잔액을 반환하고, Prices API는 그 가치를 매기며, 드리프트 검사(일반적으로 목표 비중을 중심으로 한 5포인트 밴드)는 언제 행동할지를 결정합니다. 범위가 지정된 에이전트 지갑을 통해 실행함으로써 에이전트는 제안만 하고 정책이나 사람이 승인하도록 하세요.
AI 에이전트가 스마트 컨트랙트 이벤트를 모니터링하고 자동으로 반응하게 하려면 어떻게 해야 하나요?
컨트랙트의 로그를 구독하고 매칭되는 이벤트를 에이전트에 전달하세요. Alchemy의 custom webhooks는 전달 전에 GraphQL로 컨트랙트 주소와 이벤트 토픽으로 필터링하며, WebSocket 로그 구독도 프로세스 내부에서 동일한 역할을 합니다. 핸들러를 멱등하게 만들고, 재구성된 로그는 건너뛰며, 모델은 기계적인 필터를 통과한 이벤트에 대해서만 추론하도록 하세요.
메인넷으로 가기 전에 AI 에이전트 트랜잭션을 안전하게 테스트하려면 어떻게 해야 하나요?
게이트를 층층이 쌓으세요: Alchemy CLI의 드라이런 플래그로 트랜잭션을 미리 보고, eth_call 기반 시뮬레이션으로 라이브 상태에 대해 컨트랙트 호출을 검증하고, 범위가 지정된 세션과 가스 정책 지출 한도로 에이전트의 지갑을 제한하고, Alchemy의 파우셋에서 받은 자금으로 Sepolia나 Base Sepolia에서 리허설하며, 감사 로그가 더 느슨한 게이트를 얻을 자격을 입증할 때까지 자금을 이동하는 모든 작업에 사람의 승인을 유지하세요.
관련 개요
인프라2026년 4월 23일
자율 온체인 에이전트 구축을 위한 최고의 블록체인 API
자율 온체인 에이전트를 위한 주요 블록체인 API 제공업체를 비교합니다. 에이전트 네이티브 기능, 체인 커버리지, 그리고 사용자가 머신일 때 중요한 기능들을 다룹니다.
DeFi2026년 6월 12일
DeFi AI 에이전트란? 사용 사례, 리스크, 아키텍처
DeFi AI 에이전트, 일명 DeFAI 에이전트는 정책 통제 하에 온체인에서 추론, 서명, 정산을 수행하는 자율 시스템입니다.
기술2026년 5월 19일
Webhooks 대 WebSockets 대 gRPC
실시간 데이터 전달을 지배하는 세 가지 프로토콜이 있습니다. webhooks, WebSockets, gRPC가 어떻게 다른지, 각각 언제 한계에 부딪히는지, 그리고 이들 중 어떻게 선택해야 하는지 설명합니다.

블록체인 매직을 만드세요
Alchemy는 가장 강력한 Web3 개발자 제품 및 도구를 리소스, 커뮤니티, 그리고 전설적인 지원과 결합합니다.