AI 에이전트가 읽지 않는 HTML에 토큰을 낭비한다 — 7배 토큰 비용 측정

발행: (2026년 6월 9일 PM 04:58 GMT+9)
10 분 소요
원문: Dev.to

출처: Dev.to

나는 에이전트에게 fetch_page 도구를 주고, 위키피디아 기사 하나를 읽게 했으며, 모델이 단어를 출력하기 전에 해당 페이지가 48,703 토큰을 소모하는 것을 보았다. 그 페이지의 실제 텍스트는 약 7,300 토큰에 불과했다. 나는 “, 인라인 CSS, 그리고 모델이 답을 도출하는 데 전혀 도움이 되지 않는 분석 스크립트에 대해 약 41,000 토큰을 지불하고 있었다.

이것이 에이전트 웹 접근에 대한 토큰 세금이며, 거의 아무도 이를 측정하지 않는다. 여기 숫자, 40줄 해결책, 그리고 솔직한 부분—그것이 의미가 없을 때가 있다.


짧게 말하면

에이전트가 “페이지를 읽는다”고 할 때, 보통 원시 HTML이 프롬프트에 그대로 붙여진다. 내가 테스트한 세 페이지에서 **85~86%**의 토큰이 모델이 의미를 파악하는 데 필요 없는 마크업이었다. 페이지를 먼저 텍스트만 남기면 토큰 비용이 약 7배 줄어든다. 해결책은 표준 라이브러리와 토크나이저만 있으면 된다—API도, 유료 서비스도 필요 없다.


측정 방법

o200k_base(GPT‑4o가 사용하는 토크나이저)로 세 개의 실시간 페이지를 크기별로 비교했다. 원시 HTML vs 텍스트 전용. 2026‑06‑09 측정—실시간 페이지이므로 정확한 숫자는 다를 수 있다.

페이지원시 HTML에이전트용 텍스트감소율
Wikipedia: Web scraping (165 KB)48,703 tok7,280 tok6.7× (85 % 감소)
Wikipedia: Large language model (686 KB)221,622 tok30,988 tok7.2× (86 % 감소)
example.com (528 B, 대조)152 tok22 tok6.9× (86 % 감소)

세 페이지는 작은 샘플이며 벤치마크는 아니다. 하지만 528 바이트 페이지와 686 KB 페이지 사이에서도 비율이 거의 변하지 않았다. 마크업 오버헤드가 대략 비례하기 때문에, 내가 테스트한 페이지들에서는 세금이 큰 페이지에만 국한되지 않고 어디서든 나타난다.

GPT‑4o 입력 가격($2.50 / 1M 토큰, OpenAI, 2026‑06 기준)으로 보면, 순수 HTML 페이지는 $0.55, 정제된 텍스트는 $0.078 정도다. 한 번 읽는 데만 해도 차이가 난다. 에이전트가 루프 안에서 200 페이지를 크롤링하면 실제 비용이 발생하고, 더 나아가 컨텍스트 창을 잡음으로 채워 모델이 실제로 reasoning 해야 할 토큰을 밀어낸다.


해결책 (stdlib + tiktoken)

import sys, ssl, urllib.request
from html.parser import HTMLParser
import tiktoken

UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/148.0.0.0 Safari/537.36"
SKIP = {"script", "style", "head", "noscript", "svg", "template"}

class TextOnly(HTMLParser):
    def __init__(self):
        super().__init__(); self.parts = []; self.skipping = 0
    def handle_starttag(self, tag, attrs):
        if tag in SKIP: self.skipping += 1
    def handle_endtag(self, tag):
        if tag in SKIP and self.skipping: self.skipping -= 1
    def handle_data(self, data):
        if not self.skipping and data.strip(): self.parts.append(data.strip())

raw = urllib.request.urlopen(
    urllib.request.Request(sys.argv[1], headers={"User-Agent": UA}), timeout=30
).read().decode("utf-8", "replace")

p = TextOnly(); p.feed(raw); text = "\n".join(p.parts)
enc = tiktoken.encoding_for_model("gpt-4o")          # o200k_base
raw_tok, clean_tok = len(enc.encode(raw)), len(enc.encode(text))
assert clean_tok  0        # 작업이 수행됐음을 증명
print(f"{raw_tok:,} -> {clean_tok:,} tokens  ({raw_tok/clean_tok:.1f}x less)")

Enter fullscreen mode
Exit fullscreen mode

이 코드는 로컬에서 실행 가능한 예시다. pip install -U tiktoken( o200k_base를 지원하는 최신 버전 필요) 후 python clean.py https://en.wikipedia.org/wiki/Web_scraping 를 실행한다. 내 머신에서 출력:

48,703 -> 7,280 tokens  (6.7x less)

Enter fullscreen mode
Exit fullscreen mode

전체 스크립트(TLS 처리와 아래 sanity check 포함)는 레포에 있다. HTMLParser가 담당하는 작업을 표준 라이브러리만으로 수행하고, tiktoken을 써서 모델 단위(토큰)로 셈한다. requests, 가독성 라이브러리, 외부 서비스는 전혀 사용하지 않는다.

sanity print에서 확인한 솔직한 점: 추출된 텍스트는 Jump to content Main menu Main menu ... Navigation 로 시작한다. 이는 메인 콘텐츠 전용 리더가 아니라 정제기이며, 네비게이션과 푸터 텍스트를 그대로 남긴다(아래에서 더 설명).


10분을 잡아먹은 함정

나는 VPN 뒤에서 작업했는데, 첫 번째 fetch가 CERTIFICATE_VERIFY_FAILED 로 실패했다. VPN이 TLS를 가로채면서 신뢰할 수 있는 루트 인증서 체인을 찾지 못한 것이다. urllib은 이를 숨긴다: ssl.SSLErrorurllib.error.URLError 안에 감싸기 때문에, 단순히 except ssl.SSLError 로는 잡히지 않는다. 대신 URLError를 잡고 e.reason을 확인한다:

except urllib.error.URLError as e:
    if not isinstance(e.reason, ssl.SSLError):
        raise
    sys.exit("TLS failed. If you trust this proxy, re-run with --insecure.")

Enter fullscreen mode
Exit fullscreen mode

스크립트는 닫힌 상태로 실패한다—검증을 조용히 비활성화하지 않는다. 신뢰할 수 없는 MITM 프록시를 통해 페이지를 측정하면 프록시가 삽입한 내용까지 토큰화하게 되므로 의미가 없으며, TLS를 끄는 경우는 명시적인 --insecure 플래그가 필요하다.


이것이 가치가 없는 경우

“항상 HTML을 정제한다”고 말한다면 거짓말이다. 비용이 들지 않는다:

  • 구조를 잃는다. 테이블, 링크 대상, alt/title, 그리고 “ 경계가 텍스트로 평탄화된다. 에이전트가 “이 테이블의 모든 행을 추출한다”거나 “이 링크들을 따라간다”는 작업을 해야 한다면 텍스트 전용은 신호를 날려버린다. 이런 경우에는 Markdown을 제공하라.
  • html.parser는 브라우저가 아니다. JS‑렌더링 페이지는 거의 빈 쉘을 반환한다—이는 서버가 보낸 HTML을 정제할 뿐, 브라우저가 실제로 그리는 내용을 반영하지 않는다. SPA는 먼저 헤드리스 브라우저가 필요하다.
  • 정제기는 읽기 도구가 아니다. 위에서 본 것처럼 메뉴와 푸터 텍스트를 남긴다. 가독성 라이브러리를 추가하면 더 많이 줄일 수 있지만, 의존성이 생기고 가끔 실제 콘텐츠를 먹어버릴 위험도 있다. 에이전트에게 “텍스트가 너무 많다”는 비용은 저렴하지만, “답을 조용히 놓쳤다”는 비용은 비싸다—그래서 나는 가능한 한 많이 보존한다.
  • 7× 감소는 원시 HTML 대비이며, 기본값인 HTML이 아니라 Markdown이나 가독성 정제 후와 비교한 것이 아니다. 이미 Markdown을 공급하고 있다면 절감 효과는 작아진다.
    • 숫자는 실시간 페이지, User‑Agent, 로케일에 따라 달라진다. 직접 목표 페이지에서 다시 측정하라.

따라서 솔직한 규칙은: 에이전트가 의미를 이해하기 위해 읽는 경우(예: RAG 인제션, 요약, Q&A) 텍스트로 정제한다. 특정 필드를 추출해야 할 경우에는 구조를 유지한다.


왜 이 글을 썼는가

나는 프로덕션 스크래퍼를 운영하고 있는데, 데이터 파이프라인에서 배운 교훈이 에이전트에도 그대로 적용된다: 비용은 요청 자체가 아니라

0 조회
Back to Blog

관련 글

더 보기 »

Eidentic 소개

Today we're releasing Eidentic, an open-source TypeScript SDK for building AI agents with self-improving memory and the production fundamentals built in — not b...

Typescript의 타입

Introdução Tipos são uma forma de definir a “forma” ou o contrato dos dados que estamos usando no código. Pensando em Javascript puro, ele é dinâmico: você pode...