블로그 AI / Agent

AI Coding Agent 대전 2026: Claude Code, Codex, OpenCode, DeepSeek Agent는 무엇을 겨루는가? JSON Tool Calling으로 보는 Agent Harness 아키텍처

순위표는 아직 누가 점수가 더 높은지를 묻는다. 터미널을 열면, 파일을 고치고, 테스트를 돌리고, MCP를 잇는 것은 그 자연어 답이 아니다.

Claude Code, Codex, OpenCode, DeepSeek Agent는 겉으로 「일하는 Coding Agent」를 판다. 진짜 간극은 Agent Harness다. 한 번의 JSON Tool Calling을 arguments에서 부작용까지 누가 쥐는가.

이 글에서는:

이것만 기억하라: 2026년의 대전은 「누가 다음 한 줄을 더 정확히 완성하는가」가 아니다. 모델은 tool call을 내고, 파라미터는 JSON이다. harness는 parse할 수 있는지, 승인할지, 어떤 샌드박스에서 실행할지, 결과를 어떻게 되돌려 쓸지를 정한다. Claude Code는 훅을 매 호출 앞뒤에 박는다. Codex는 샌드박스와 승인을 기본 경계로 만든다. OpenCode는 모델과 권한을 바꿀 수 있는 설정으로 만든다. DeepSeek Agent는 파이프 전체를 플러그인으로 쪼갠다.

진짜로 겨루는 것은 완성이 아니다

완성이 푸는 문제는 「다음 줄을 무엇으로 쓸까」다. Coding Agent가 푸는 문제는 「이 목표를 실제 저장소에서 어떻게 끝낼까」다: 컨텍스트를 읽고, 도구를 고르고, 코드를 고치고, 명령을 돌리고, 결과를 보고, 다시 결정한다.

네 곳의 화면은 모두 채팅처럼 보인다. 밑의 루프는 거의 같다:

네 곳이 공유하는 Agent 루프
User goal
  → Agent loop
  → LLM emits tool_call (JSON arguments)
  → Harness parses / validates / gates / executes
  → Tool result returns to context
  → Agent decides again

모델은 추론과 「다음에 누구를 부를까」를 맡는다. harness는 모델이 어떤 도구를 보는지, 파라미터가 합법인지, 고위험 동작에 사람을 물을지, 도구가 실제로 무엇을 하는지, 세션을 어떻게 남기는지, 무엇을 끝으로 볼지를 맡는다.

기능 목록은 점점 닮아 간다. Skills, MCP, 하위 Agent, 권한 스위치는 모두 있다. 차이는 제어권이 어느 층에 앉는가다. 제품 포지션은 AI Coding Agent는 더 이상 코드 완성이 아니다: Codex, Claude Code, OpenCode, DeepSeek Harness는 무엇을 겨루는가?를 보라. 루프가 어떻게 도는지는 AI Coding Agent는 어떻게 동작하는가?를 보라. 이 글은 한 가지만 가른다. JSON Tool Calling이 모델을 떠난 뒤, harness가 어떻게 이어받는가.

Agent Harness란 무엇인가

2026년, 이 층에는 이미 학문 이름이 있다. 프로덕션 Coding Agent 열한 곳의 소스를 해부한 논문은 이를 Harness Engineering이라 부른다. Agent는 모델 더하기 harness다. LLM을 실제 세계에 잇는 런타임이며, 루프, 도구, 컨텍스트, 안전 제어, 오케스트레이션, 확장 면을 포함한다.

다른 대조 실험은 더 직설적이다. harness를 바꾸면 같은 모델이 문제를 더 푸는가? 평균 점수는 자주 비슷하다. 저장소 과제와 대회 과제는 반대 방향으로 움직이기도 하고, 비용과 취소율도 바뀐다. 결론은 「네이티브 harness가 반드시 더 세다」가 아니다. 「사는 것은 완료 경로이지, 순위표의 한 점이 아니다」다.

그래서 네 곳은 버튼을 누가 하나 더 달았나를 겨루지 않는다. 도구 계약, 실행 경계, 사람의 거부권을 누가 더 분명히 조직하는지를 겨룬다.

맡는 것 맡지 않는 것
모델 도구를 고르고, JSON 파라미터를 채우고, 결과를 읽고 다시 결정한다 디스크에 쓰고, shell을 돌리고, 네트워크에 닿고, 인가한다
JSON 계약 파라미터와 결과가 어떻게 생겼는지 이번 호출이 일어나야 하는지
Agent Harness 보이는 도구, 검증, 승인, 샌드박스, 되돌려 쓰기, 세션 업무 목표를 대신 생각해 주는 것

기술 스택 층은 2026 AI Agent 기술 스택: LLM, MCP, Function Calling, JSON Schema를 보라.

공통 전선: JSON Tool Calling

Tool Calling(Function Calling이라고도 한다)은 「모델이 코드를 쓸 줄 안다」의 다른 이름이 아니다. 구조화된 호출이다. 모델이 당신이 선언한 도구 목록에서 이름을 고르고, 파라미터 계약에 맞는 JSON을 만든다.

OpenAI 호환 인터페이스에서 도구 정의의 parameters 필드 자체가 JSON Schema다:

도구 정의(parameters = JSON Schema)
{
  "type": "function",
  "function": {
    "name": "run_tests",
    "description": "Run the project test suite and return a structured summary.",
    "parameters": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "suite": { "type": "string", "enum": ["unit", "integration", "e2e"] },
        "path": { "type": "string", "minLength": 1 }
      },
      "required": ["suite"]
    }
  }
}

모델이 반환할 때 arguments는 이미 parse된 객체가 아니라, 문자열인 경우가 많다:

모델이 돌려준 tool_call(arguments는 문자열)
{
  "id": "call_7f21",
  "type": "function",
  "function": {
    "name": "run_tests",
    "arguments": "{\"suite\":\"e2e\",\"path\":\"tests/checkout.spec.ts\"}"
  }
}

그래서 harness는 적어도 두 가지를 한다. 먼저 문자열을 합법 JSON으로 파싱하고, 선언한 schema로 필드, 타입, 열거를 검증한다. 따옴표 누락, 쉼표 추가, 선언하지 않은 키는 모두 이 홉에서 일어난다.

MCP는 같은 전선을 외부 Server에 잇는다. inputSchema / outputSchema는 여전히 JSON Schema이고, tools/call은 여전히 한 번의 구조화 호출이다. Server가 늘수록 모델이 보는 description과 schema도 늘고, harness가 지켜야 할 문도 는다. 안전 책임을 어떻게 나누는지는 MCP 보안 취약점 전면 해설을 보라.

전장: tool call 한 번의 일곱 홉

네 제품을 펴 놓으면 기능 이름은 다르다. 파이프 모양은 같다. 겨루는 것은 각 홉을 누가 정하는가다:

  1. 1
    제시

    어떤 도구, 어느 조각의 schema가 이번 요청에 들어가는가. 보이지 않는 도구는 모델이 부르지 못한다.

  2. 2
    발행

    모델이 이름을 고르고 arguments 문자열을 만든다. 그 홉은 「호출하겠다」는 뜻일 뿐이다.

  3. 3
    파싱

    문자열이 객체가 된다. 불법 JSON은 실행 층에 들어가기 전에 실패해야 한다.

  4. 4
    검증

    JSON Schema로 필수, 타입, 열거, additionalProperties를 검사한다.

  5. 5

    allow / deny / ask. 모양이 합법한 것이 인가된 것은 아니다.

  6. 6
    실행

    샌드박스, 워크스페이스, 또는 호스트 전체 권한에서 실제로 돈다. 부작용은 여기서 시작한다.

  7. 7
    되돌려 쓰기

    결과는 텍스트 또는 JSON이 되어 세션에 남고, 다음 턴에 들어간다. 실패에도 구조가 있어야 한다. 「오류가 났다」한 줄로 끝내면 안 된다.

네 곳 모두 이 일곱 홉을 걷는다. 차이는 훅을 어디에 꽂는지, 기본 샌드박스가 얼마나 조이는지, 모델을 바꿀 수 있는지, 파이프 자체를 교체할 수 있는지다.

Claude Code: 훅을 호출 앞뒤에 박는다

Claude Code는 주 Agent를 강하게 만든다. Skills, MCP, 하위 Agent, CLAUDE.md는 모두 같은 Claude Agent를 감싼다. JSON Tool Calling과 실제로 맞물리는 것은, 매 호출 앞뒤의 결정적 훅이다.

공식 생명주기에서, 루프의 매 도구 호출은 PreToolUsePostToolUse를 지난다. 권한 프롬프트가 뜰 때 막을 수도 있고(PermissionRequest), 실패 뒤에 재시도할지를 정할 수도 있다(PermissionDenied / PostToolUseFailure).

훅이 읽는 것은 이벤트 JSON이지, 산문이 아니다. 입력을 고치고, 호출을 거절하고, 확인을 요구하거나, 성공 뒤에 로그를 보태고, 포맷터를 돌리고, 새 컨텍스트를 다시 넣을 수 있다. 이미 일어난 부작용은 되돌리지 못한다—PostToolUse는 너무 늦다.

권한 규칙은 deny → ask → allow 순으로 맞추고, deny가 이긴다. 훅이 allow를 반환해도 대화 프롬프트만 건너뛴다. 기업이 관리하는 deny 목록은 막지 못한다. bypassPermissions를 켜도 deny를 반환하는 PreToolUse는 호출을 막는다.

엔지니어링 함의는 분명하다. 확률적 Agent에 결정적 문을 더한다. 고친 뒤 테스트를 돌리고, 위험 명령을 막고, 보호 경로는 승인을 받게 하는 일은 모델이 「매번 기억하기」를 기대하면 안 된다.

적합한 경우: 워크플로가 안정적이고, 주 루프에 Skills / 하위 Agent / 훅을 박아 경험을 재사용 가능한 패키지로 만들고 싶을 때.

Codex: 샌드박스와 승인이 실행보다 먼저다

Codex(Codex CLI 포함)는 문제를 실행 층으로 민다. Agent가 파일을 고치고, shell을 돌리고, 의존성을 설치하고, 네트워크와 자격 증명에 닿는 순간, 서로 다른 두 가지에 동시에 답해야 한다. 능력 경계, 그리고 지금 이 일을 해도 되는가.

메커니즘 답하는 질문 전형 스위치
Sandbox 기술적으로 무엇을 만지고 고칠 수 있는가? read-only / workspace-write / danger-full-access
Approval 지금 이 동작을 해도 되는가? untrusted / on-request / never

기본 서사는 최소 권한이다. 먼저 환경을 조이고, 필요할 때 연다. 신뢰하지 않는 디렉터리는 read-only에서 시작한다. 워크스페이스를 신뢰한 뒤의 흔한 프리셋은 workspace-write 더하기 on-request다. 워크스페이스 안 읽기·쓰기와 일상 명령은 자동으로 돌고, 워크스페이스 밖이나 네트워크는 승인이 필요하다. 네트워크는 기본이 꺼져 있고, 명시적으로 켜야 한다.

새 버전은 파일시스템과 네트워크를 permission profile로 적는다. 옛 sandbox_mode와 섞지 마라. 이름은 바뀐다. 가름은 그대로다. 한쪽은 「무엇을 만질 수 있는가」, 한쪽은 「지금 해도 되는가」다.

적합한 경우: 부작용이 크고, 감사 가능한 실행 궤적이 필요하며, 격리와 승인을 일등 시민으로 둔다. 오픈소스 저장소: openai/codex.

OpenCode: 모델은 바꿀 수 있고, 권한은 설정이다

OpenCode의 차별점은 「Skills 문법을 하나 더」가 아니다. 기본 입장은 이렇다. 모델을 바꿀 수 있다. MIT 오픈소스, 터미널 우선, 여러 제공자와 로컬 모델을 잇는다. 유연성은 주로 설정에 있다: provider, model, permission, agent. harness 커널을 플러그인 버스로 쪼개지는 않는다.

권한은 초기의 불리언 tools에서 permission으로 들어갔다. 각 동작은 allow, ask, deny다. 도구 이름, 명령 패턴, 워크스페이스 밖인지(external_directory)로 규칙을 쓸 수 있다. 마지막 매칭이 이긴다. 하위 Agent는 주 Agent보다 더 엄할 수 있다. 예: review 역할이 edit를 바로 deny한다.

OpenCode는 문을 JSON 설정으로 쓴다
{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "bash": {
      "*": "ask",
      "git *": "allow",
      "git push *": "deny"
    },
    "edit": "allow",
    "external_directory": "deny"
  }
}

보통 이기는 지점: 다중 모델이 기본 능력이고 벤더 덤이 아니라는 것, 오픈소스 라이선스와 커뮤니티 생태계, 「모델 바꾸기」가 일등 조작이라는 것. 대가도 분명하다. 실행 경계와 플러그인 깊이가 반드시 1순위 셀링 포인트는 아니다. 사는 것은 모델을 바꿀 수 있는 harness이지, 가장 무거운 샌드박스 제품도, 「Everything is a plugin」 플랫폼 커널도 아니다.

적합한 경우: 단일 공급자를 믿지 않거나, 같은 루프 안에서 모델을 바꾸고, 로컬 가중치까지 쓰고 싶을 때.

DeepSeek Agent: 파이프 자체가 플러그인이다

DeepSeek는 이 문제를 한 층 더 아래로 민다. 공개 프리뷰 제품은 DeepSeek Harness(dsh)다. 바깥 계약은 Agent 인터페이스이고, 기본 구현은 교체 가능한 agent-loop다. 슬로건은 「Everything is a plugin」이다. 모델, 도구, Skills, 세션, 샌드박스, 저장, loop, 스케줄링, UI를 모두 바꿀 수 있다.

Tool Calling과 맞닿는 것은 도구 파이프이지, 채팅 창이 아니다. 레지스트리의 ToolDefinition은 타입 있는 파라미터와 출력을 가진다. 모델에 투영되는 것은 name, description, parameters뿐이다. execute, 타임아웃, 동시성 플래그, UI 전시는 요청에 새면 안 된다.

매 호출은 고정된 폭포를 걷는다:

DeepSeek Harness의 도구 파이프
tools/pre-execute   → allow / deny / ask
monotonic guards    → 只收紧,不能再放行
tools/execute       → 真正派发(可包超时 / 重试)
tools/post-execute  → 检查或替换结果
finalizeContent     → 定义自己的收尾
tools/result        → 冻结后的权威结果

네이티브 Function Calling을 쓸 수도 있고, PTC를 쓸 수도 있다(예약된 run_code를 전송으로 쓰고, 하위 호출은 같은 파이프에 들어간다). 동시성은 호출마다 나눈다. 독점은 장벽이 되고, 병렬 가능한 것은 상한 있는 풀에 들어간다. 이벤트는 여전히 모델 순서로 세션에 쓴다.

적합한 경우: 더 센 조수만 사는 것이 아니라, 런타임 자체를 플랫폼으로 쓰고 싶을 때. 모델 층은 DeepSeek V4-Pro 완전 해설을 보라.

같은 JSON, 네 벌의 문

같은 tool call JSON이라도, 네 곳은 문을 다른 자리에 단다:

이 홉 Claude Code Codex OpenCode DeepSeek Agent
모델에 보이는 도구 면 내장 도구 + Skills + MCP. schema는 지연 로드할 수 있다 세션 도구 상자 + 프로젝트 설명(AGENTS.md) 내장 + MCP + agent별 재단 스코프 레지스트리가 allowlist로 ToolSchema를 투영한다
파라미터가 실행 층에 들어가기 전 훅이 완전한 tool 이벤트 JSON을 읽을 수 있다 먼저 샌드박스 능력, 그다음 승인 정책 permission 규칙이 도구 이름과 입력을 맞춘다 parse 뒤 pre-execute 폭포와 단조 가드
사람이 어떻게 거부하는가 PermissionRequest. deny는 훅의 allow보다 앞선다 on-request / untrusted. reviewer에게 넘길 수 있다 ask. 하위 Agent는 더 엄할 수 있다 ask 결정은 파이프의 일등 결과다
부작용이 일어나는 곳 로컬 도구 + 훅 후처리 OS 수준 샌드박스. 기본은 네트워크 없음, 워크스페이스 쓰기 가능 로컬 실행, git 스냅샷으로 undo 교체 가능한 sandbox 플러그인
결과를 어떻게 되돌려 쓰는가 PostToolUse / 실패 훅이 컨텍스트를 보탠다 JSONL 이벤트. CI 감사가 쉽다 LSP 진단을 루프에 다시 넣을 수 있다 tools/result가 고정된 뒤 세션 로그에 쓴다

마지막 줄은 순위가 아니다. 사는 것은 「쓰기 좋은 주 Agent」인지, 「더 통제 가능한 실행 환경」인지, 「모델을 바꿀 수 있는 설정 층」인지, 「조립할 수 있는 런타임」인지다.

제어권 지도의 제품 시각은 여전히 네 곳 아키텍처 중심 대조를 보라. MCP가 도구 면을 키운 뒤 누가 안전을 맡는지는 AI Agent가 「스스로 인터넷을 공격하기 시작」: JSON이 어떻게 보안 경계가 되는가를 보라.

왜 직접 JSON Schema를 봐야 하는가

네 곳 harness가 아무리 강해도, 더러운 파라미터가 실행 층에 들어가면 사고가 된다. 모델이 채운 파라미터는 느슨한 제약이다. arguments는 깨진 JSON일 수 있고, 필드가 빠질 수 있고, 선언하지 않은 키가 더해질 수 있다.

Schema로 합법한 것이 인가된 것은 아니다. 아래 두 조각은 「sql 필드가 있다」는 느슨한 schema를 모두 통과한다. 오른쪽만 동작을 열거로 묶고, 식별자를 pattern으로 쓴다.

느슨한 계약 vs 조인 계약
{
  "loose": {
    "type": "object",
    "properties": { "sql": { "type": "string" } },
    "required": ["sql"]
  },
  "tight": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "op": { "type": "string", "enum": ["get_user_by_id"] },
      "user_id": { "type": "string", "pattern": "^[a-z0-9-]{8,36}$" }
    },
    "required": ["op", "user_id"]
  }
}

계약을 어떻게 쓸지, JSON Mode와 Strict Schema가 어디서 다른지는 AI에 JSON Schema가 필요한 이유AI Agent에 JSON Schema가 필요한 이유를 보라.

JSONNote로 tool call 한 번을 분해하기

harness를 디버깅할 때 가장 쓸모 있는 재료는 대개 JSON 한 토막이다. 도구 정의, 모델 arguments, 훅 이벤트, 거절 이유. 모두 브라우저 로컬에서 분해할 수 있다. 저장소를 올릴 필요는 없다.

  1. 1
    먼저 arguments가 합법 JSON인지 본다

    문자열의 이스케이프를 풀고 JSON 포맷터에 넣는다. 쉼표 누락, 끝 쉼표, 작은따옴표는 여기서 터진다.

  2. 2
    선언한 schema로 검증한다

    도구의 parameters / inputSchema와 파싱한 객체를 JSON Schema에 넣는다. 필드 누락인지, 타입이 틀린지, 있으면 안 되는 키가 더해졌는지 본다.

  3. 3
    「승인할 때」와 「지금」을 비교한다

    지난주 저장한 도구 목록과 오늘의 목록을 JSON Diff에 넣고, description과 schema의 조용한 변경만 찾는다.

  4. 4
    동료에게 보여줄 때는 Hash 공유

    데이터는 URL fragment에 남고 서버를 지나지 않는다. URL Hash로 JSON 공유하기를 보라.

자주 묻는 질문

Claude Code, Codex, OpenCode, DeepSeek Agent는 무엇을 겨루는가?

기능 목록이 아니고, 누가 다음 한 줄을 더 정확히 완성하는지도 아니다. 겨루는 것은 Agent Harness다. 한 번의 JSON Tool Calling을 파라미터 파싱, 계약 검증, 승인, 샌드박스 실행, 결과 되돌려 쓰기까지 누가 쥐는가.

Agent Harness와 모델, 무엇이 더 중요한가?

모델은 추론과 다음 단계를 맡는다. harness는 도구가 보이는 범위, 파라미터가 합법인지, 고위험 동작에 사람을 물을지, 부작용이 어디서 일어나는지를 맡는다. harness를 바꿔도 평균 점수가 반드시 오르지는 않는다. 다만 완료 경로, 비용, 취소율은 바뀐다. 제품을 고르는 것은 제어권을 고르는 것이지, 점수만 고르는 것이 아니다.

네 곳 중 어디를 고를까?

통일된 우승자는 없다. 주 Agent에 결정적 훅과 권한을 박으려면 Claude Code. 샌드박스와 승인을 기본 실행 경계로 두려면 Codex. 모델을 바꾸고 락인을 피하려면 OpenCode. loop, 도구 파이프, 샌드박스를 모두 교체 가능한 플러그인으로 만들려면 DeepSeek Agent(DeepSeek Harness).

JSON Tool Calling 자체에 권한 제어가 있는가?

없다. 모델이 도구 이름을 고르고 arguments를 채운다. 그 홉은 「호출하겠다」는 뜻일 뿐이다. 막을지, 어떤 샌드박스에서 돌릴지, 결과를 모델에 되돌릴지는 harness의 일이다. 도구가 없거나, 권한이 거절되거나, JSON 검증이 실패하면 디스크에서는 아무 일도 없다.

왜 직접 JSON Schema를 검증하는가?

모델이 채운 파라미터는 느슨한 제약이다. arguments는 자주 문자열이고, 필드가 빠지거나, 타입이 틀리거나, 선언하지 않은 키가 더해질 수 있다. Schema로 합법한 것이 인가된 것은 아니다. 프로덕션 경로는 여전히 parse와 검증을 한 뒤 권한과 샌드박스에 넘긴다. 네 곳 harness가 아무리 강해도, 더러운 파라미터가 실행 층에 들어가면 사고가 된다.

요약

2026년 Coding Agent 대전은 모델 전쟁처럼 보인다. 저장소 안에서는 harness 전쟁이다.

모델은 JSON을 낸다. Harness는 그 JSON이 부작용이 될 수 있는지를 정한다. 네 곳은 같은 파이프 위의 제어권을 겨룬다. Claude Code는 훅을 박고, Codex는 실행 경계를 조이며, OpenCode는 모델 락인을 풀고, DeepSeek Agent는 런타임 자체를 플러그인으로 만든다.

기능은 계속 닮아 갈 것이다. 진짜로 봐야 하는 것은, tool call이 모델을 떠난 뒤 누가 정하는가다.

다음: tool call 한 번의 arguments를 JSONNote에 붙인다

← 블로그로