
C#로 Claude Tool-Use 에이전트 구축하기: 단순한 챗봇 그 이상
요약
C#을 사용하여 Claude의 Tool-Use 기능을 활용한 AI 에이전트를 구축하는 방법을 설명합니다. HttpClient를 이용한 수동 구현 방식과 Anthropic .NET SDK를 사용하는 방식 두 가지를 통해 에이전트의 핵심 루프를 구현합니다.
핵심 포인트
- Tool-Use는 모델이 도구 호출을 요청하고 코드가 이를 실행하는 루프 구조임
- Claude는 직접 실행하지 않고 도구 사용을 요청(request)만 함
- C#과 Anthropic .NET SDK를 사용하여 약 60줄의 코드로 에이전트 구현 가능
- 보안 경계는 모델이 아닌 개발자의 실행 환경(harness)에 존재함
C#로 Claude Tool-Use 에이전트 구축하기: 단순한 챗봇 그 이상
이제 누구나 "AI 에이전트"를 출시합니다. 하지만 대부분의 내부를 들여다보면, 페르소나 프롬프트(personality prompt)와 희망 섞인 // TODO: 실제로 무언가를 하게 만들기가 포함된 챗봇을 발견하게 될 것입니다. 그것은 당신의 주문에 대해 이야기할 수는 있지만, 실제로 주문을 조회할 수는 없습니다.
진정한 에이전트는 그 간극을 메웁니다. 모델에게 도구(tools) 세트 — 즉, 코드베이스 내의 일반적인 메서드들 — 를 전달하면, 모델은 대화 도중에 그중 하나를 호출하기로 결정합니다. 당신의 코드가 실제 작업을 수행하고 결과를 다시 전달하면, 모델은 실제로 답변할 수 있을 때까지 과정을 계속합니다. 이 루프(loop)가 핵심이며, C#을 사용하여 약 60줄 정도면 이를 구축할 수 있습니다. 우리는 두 가지 방식으로 구현해 볼 것입니다. 하나는 와이어 프로토콜(wire protocol)을 확인할 수 있도록 HttpClient를 사용하여 수동으로 만드는 것이고, 다른 하나는 실제로 배포할 때 사용할 짧은 버전인 공식 Anthropic .NET SDK를 사용하는 것입니다.
"도구 사용(tool use)"의 실제 의미
도구 사용 (일명 함수 호출 (function calling))은 작고 엄격한 루프입니다:
- 도구를 선언합니다. 각 도구는
name(이름),description(설명), 그리고 입력값에 대한 JSON Schema(JSON 스키마)로 구성됩니다. 그게 전부입니다. Claude에게 코드가 전송되는 것이 아니라, 구조(shape)만 전달됩니다. - Claude는 텍스트 대신
tool_use블록으로 응답합니다. 이는 "{ "sku": "ETH-250" }를 사용하여check_stock을 실행하고 결과를 알려주세요"라고 말하는 것과 같습니다. - 당신의 코드가 이를 실행합니다. 사람들이 놓치는 부분이 바로 이것입니다: Claude는 아무것도 실행하지 않습니다. Claude는 _요청(requests)_할 뿐이며, 당신의 하네스(harness)가 _실행(executes)_합니다. 보안 경계는 항상 당신의 영역에 머뭅니다.
- 답변을
tool_result블록으로 다시 보냅니다. 이 블록은id를 통해 요청과 연결됩니다. - Claude가 계속 진행합니다. 더 많은 도구를 호출할 수도 있고, 답변을 할 수도 있습니다. Claude가 요청을 멈출 때까지 이 루프를 반복합니다.
Claude를 당신의 API를 읽을 수는 있지만 운영 환경(production)을 직접 건드릴 수는 없는, 매우 빠른 시니어 동료라고 생각하세요. Claude는 당신에게 정확히 어떤 버튼을 눌러야 하는지 알려주고, 당신은 그 버튼을 누른 뒤 결과를 보고합니다. 판단은 모델의 몫이며, 손은 당신의 것입니다.
우리가 구축할 에이전트
**Aurora Coffee Co.**를 만나보세요. 이 가상의 상점에는 _"제 주문이 발송되었나요? 그리고 에티오피아 원두가 아직 남아 있나요?"_와 같은 질문에 답하는 지원 에이전트가 있습니다. 이 에이전트는 인메모리 데이터(in-memory data)를 기반으로 하는 두 가지 도구를 가지고 있어, 별도의 외부 설정 없이 바로 실행됩니다.
get_order_status(order_id)— 주문 내역을 조회합니다.check_stock(sku)— 제품의 재고를 확인합니다.
여기 공통 부분인 데이터와 도구 실행기(tool executor)가 있습니다. 아래의 두 가지 접근 방식 모두 이 동일한 메서드를 재사용하며, Claude 관련 구현(plumbing) 부분만 달라집니다.
using System.Text.Json;
// Aurora Coffee Co.의 "데이터베이스" — 인메모리 방식이므로 별도의 설정 없이 실행됩니다.
...
RunTool이 도구 입력값을 JsonElement 딕셔너리로 받는다는 점에 주목하세요. 우리는 이를 **파싱(parse)**합니다. Claude가 보내는 가공되지 않은 JSON을 문자열 매칭(string-match)하지 않습니다. 이 점은 매우 중요하며, 나중에 다시 다루겠습니다.
접근 방식 1 — Raw HttpClient (프로토콜 확인)
SDK도, 의존성(dependencies)도 없습니다. 오직 HttpClient와 System.Net.Http.Json만 사용합니다. 이 버전은 네트워크상에서 실제로 어떤 일이 일어나고 있는지 알려줍니다.
먼저, 도구들을 JSON Schema로 정의합니다. 이것이 요청에 포함되어 전송되는 정확한 배열입니다.
var tools = new object[]
{
new
...
description 필드는 매우 중요합니다. Claude가 각 도구를 언제 사용할지 결정하는 근거가 되기 때문입니다. 변수 이름을 짓듯이 쓰지 말고, 주니어 개발자를 위한 독스트링(docstring)을 작성하듯 작성하세요.
이제 클라이언트와 에이전트 루프를 작성합니다. 메시지 목록을 계속 늘려가며, Claude가 더 이상 도구를 요청하지 않을 때까지 계속 호출합니다.
using System.Net.Http.Json;
var http = new HttpClient { BaseAddress = new Uri("https://api.anthropic.com") };
...
간과할 경우 문제가 될 수 있는 세 가지 세부 사항:
- 어시스턴트의 턴(assistant turn)을
tool_use블록을 포함하여 토씨 하나 틀리지 않고 그대로 다시 전달(Echo)하세요. 후속 요청에는 모든tool_result에 대해 원래의tool_use가 포함되어야 하며,tool_use_id로 매칭되어야 합니다. - 모든 결과를 단일 사용자 메시지(user message)에 담아 반환하세요. 만약 Claude가 두 개의 도구를 요청했는데 답변을 두 개의 메시지로 나누어 보낸다면, 모델은 병렬로 도구를 요청하는 것을 은연중에 멈추는 법을 배우게 됩니다.
- 루프 변수 이름을
args이외의 것으로 지정하세요. 최상위 문(Top-level statements)은 이미 암시적인args를 정의하고 있으며, 컴파일러는 이를 가차 없이 처리할 것입니다. 제가 어떻게 아는지 궁금하시다면 물어보세요.
이것으로 파일 하나로 구성된 완전한 에이전트가 완성되었습니다. 그리고 네트워크를 통해 오가는 모든 바이트를 직접 확인할 수 있습니다. 하지만 JSON을 직접 작성하는 방식은 금방 지루해지는데, 이것이 바로 SDK가 존재하는 이유입니다.
접근 방식 2 — Anthropic .NET SDK (요약 버전)
동일한 에이전트이지만, 훨씬 적은 배관 작업(plumbing)이 필요합니다. 패키지를 추가하세요:
dotnet add package Anthropic
도구 정의(Tool definitions)가 타입이 지정된 객체(typed objects)가 됩니다. InputSchema.Type은 자동으로 `
직접 루프(loop)를 작성하고 싶지 않다면, SDK에는 베타 버전의 **도구 실행기 (tool runner)**가 포함되어 있습니다. 각 도구에 스키마(schema)와 이를 실행할 코드(Run 콜백)를 제공하면, 실행기가 호출-실행-계속(call-execute-continue) 사이클 전체를 대신 처리해 줍니다.
using Anthropic;
using Anthropic.Helpers.Beta;
using Anthropic.Models.Beta.Messages;
...
수동 루프도, 블록 재구성(block reconstruction)도 필요 없습니다. 실행기가 사용자의 Run 콜백을 호출하며 Claude가 작업을 마칠 때까지 대화를 계속 이어갑니다. 어떤 버전을 실행하든 출력은 동일합니다.
> 주문 A-1001이 발송되었나요? 그리고 ETH-250 재고가 아직 있나요?
주문 A-1001은 발송되었으며 2026-07-26에 도착할 예정입니다. 그리고 네, 에티오피아 원두(ETH-250)는 재고가 있으며 42개가 남아 있습니다.
두 개의 도구와 하나의 질문만으로, Claude는 스스로 두 도구를 모두 호출해야 한다는 것을 알아냈습니다.
도구 사용(Tool use)을 언제 사용해야 하는가 — 그리고 언제 사용하지 말아야 하는가
도구 사용은 모델이 텍스트만으로는 얻을 수 없는 것이 필요할 때 적절한 선택입니다. 즉, 실시간 또는 비공개 데이터 (데이터베이스, 내부 API, 파일 시스템)나 동작을 수행하는 능력 (이메일 전송, 티켓 생성, 주문 환불)이 필요한 경우입니다. 만약 정답이 진정으로 귀사의 시스템 내부에 잠겨 있다면, 도구 사용은 모델이 그 정답에 도달하는 방법이 됩니다.
반면, 단일 프롬프트(prompt)로 해결될 수 있는 경우에는 잘못된 선택입니다. 단순히 텍스트 덩어리에서 JSON을 추출해야 하는 것이라면, 도구 루프가 아닌 구조화된 출력 (structured outputs)을 사용하세요. 그러면 불필요한 왕복(round trips) 과정을 생략할 수 있습니다. 모든 문제가 에이전트(agent)인 것은 아닙니다. 어떤 문제들은 그저 잘 설계된 프롬프트만으로도 해결됩니다.
두 가지 구현 방식 중에서 선택하자면: 프로토콜을 배우고 있거나, 의존성(dependencies)이 전혀 없기를 원하거나, 루프에 대한 완전한 제어권(도구 실행 전 승인 단계, 커스텀 로깅, 인간 참여형 검토(human-in-the-loop review) 등)이 필요한 경우에는 **순수 HttpClient**를 사용하세요. 실제로 배포할 모든 기능(타입이 지정된 모델, 적은 보일러플레이트(boilerplate), 그리고 루프 처리를 맡기고 싶을 때 사용하는 도구 실행기)을 위해서는 SDK를 사용하세요. 그리고 만약 순수 성능보다 비용이 더 중요하다면, claude-opus-4-8을 claude-sonnet-5로 교체하세요. 코드는 동일하지만 더 저렴하게 실행할 수 있습니다.
경험 법칙(Rule of thumb): 프롬프트(prompt)를 우선시하고, 모델이 당신의 세계에 접근해야 할 때 도구 사용(tool use)을 적용하며, 한 번 이상 접근해야 할 때만 에이전트 루프(agent loop)를 사용하세요.
핵심 요약 (Key Takeaways)
- 루프(loop)는 마법이 아니라 기술의 핵심입니다 — 도구를 선언하고, Claude가 요청하면, 이를 실행한 뒤 결과를 반환하며, 답변이 나올 때까지 반복합니다. 그 외의 모든 것은 배관(plumbing) 작업일 뿐입니다.
- 실행 권한은 당신에게 있으며, 그것이 핵심입니다 — Claude는 도구 실행을 _요청_할 뿐입니다. 실행 여부와 방식은 당신의 코드가 결정합니다. 보안 경계는 결코 당신의 측면을 벗어나지 않습니다.
- 도구 입력값은 파싱(parse)하세요, 절대 문자열 매칭(string-match)하지 마세요 — JSON을 타입이 지정된 값(
JsonElement/ 딕셔너리)으로 읽어들이세요. 가공되지 않은 직렬화된 문자열(raw serialized string)과 대조하는 방식은 유니코드 이스케이프(Unicode escape) 문제로 인해 버그가 발생하기 딱 좋습니다. - 네이티브(Native)는 프로토콜을 가르쳐주고, SDK는 이를 배포합니다 —
HttpClient는 모든 바이트를 보여주며 완전한 제어권을 제공합니다. 반면 Anthropic SDK는 타입이 지정된 블록(typed blocks)과 루프를 구동하는 도구 실행기(tool runner)를 제공합니다. - 단순하게 시작하세요 — 대부분의 작업에서는 일반적인 프롬프트가 에이전트보다 낫습니다. 모델이 실시간 데이터가 필요하거나 무언가를 _수행(do)_해야 할 때 도구 사용을 추가하고, 도구 호출 한 번으로 충분하지 않을 때만 에이전트 루프를 추가하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기

