THINK 판단 단계

하네스 엔지니어링이란? LLM 엔진을 '탈 수 있는 자동차'로 만드는 기술

하네스 엔지니어링이란? LLM 엔진을 '탈 수 있는 자동차'로 만드는 기술

하네스 엔지니어링(harness engineering)은 대규모 언어 모델(LLM, 방대한 글을 읽고 배워 문장을 이어 쓰는 AI 모델)을 실제 제품·서비스로 잇기 위해, 모델을 둘러싼 입력·출력·검증·실행·안전 장치를 하나의 시스템으로 설계하는 일입니다. 모델이 강력한 엔진이라면, 하네스 엔지니어링은 그 엔진에 차체와 브레이크를 달아 사람이 탈 수 있는 자동차로 완성하는 일에 해당합니다.

한눈에 보기

  • 하네스 엔지니어링은 AI 모델은 그대로 두고, 그 둘레에 검사·재시도·사람 확인 같은 장치를 짜서 실제 업무에 안전하게 쓰게 만드는 일입니다.
  • AI의 답은 늘 '그럴듯한 글'이라 형식이 어긋나거나 사실이 틀릴 수 있으므로, 정해진 틀로 받고 프로그램으로 검사한 뒤에야 다음 단계로 넘깁니다.
  • 결제·삭제·발송처럼 되돌릴 수 없는 일 앞에는 사람이 승인하는 관문을 두고, 기록을 남겨 계속 고쳐 갑니다.

엔진이 아니라 자동차를 만든다는 발상

'하네스(harness)'는 본래 말에 채워 수레와 잇고 부리는 마구를 가리키는 말입니다. 소프트웨어에서는 프로그램을 붙들어 놓고 시험하는 뼈대를 '테스트 하네스'라 불러 왔고, 공사장에서 작업자를 붙들어 주는 안전대도 영어로 하네스라 합니다. 공통점은 하나입니다. 강력하지만 그대로 두면 위험하거나 제구실을 못 하는 것을, 붙들고 이어서 안전하게 쓸 수 있게 만든다는 점입니다. 언어 모델도 마찬가지입니다. 모델 자체는 강력한 엔진이지만, 엔진만으로는 자동차가 아닙니다. 차체와 조향장치, 브레이크, 계기판, 안전벨트가 갖춰져야 비로소 사람이 탈 수 있는 자동차가 됩니다.

이런 상황을 떠올려 보세요. 작은 회사의 회계 담당자가 매달 수백 장씩 쌓이는 영수증 사진을 AI에 넣어 날짜·가게 이름·금액을 뽑아 엑셀에 옮기게 했습니다. 대부분은 잘 되는데, 가끔 날짜가 '9월 3일'과 '2026-09-03'으로 뒤섞여 들어오고, 흐릿한 영수증에서는 있지도 않은 금액이 자신 있게 적힙니다. 사람이 한 장씩 다시 보면 자동화한 의미가 없습니다. 그래서 날짜는 정해진 형식만 받도록 틀을 정하고, 합계가 품목 금액의 합과 맞는지 프로그램이 검사하고, 어긋난 영수증만 담당자에게 넘기게 짭니다. AI는 그대로인데 둘레에 장치를 두른 것입니다. 이 둘레 장치를 설계하는 일이 하네스 엔지니어링입니다.

핵심부터 짚어 두겠습니다. 하네스 엔지니어링은 '더 똑똑한 모델을 만드는 일'이 아닙니다. 모델 자체는 그대로 두고, 그 주변을 짜는 일입니다. 모델의 가중치(모델이 학습으로 익힌 지식을 담은 숫자들)에 손대는 파인튜닝(fine-tuning, 미세조정)이나 학습과는 층위가 다릅니다. 파인튜닝이 엔진 자체의 성능을 끌어올리는 일이라면, 하네스 엔지니어링은 그 엔진을 차체에 얹어 사람이 안전하게 몰 수 있는 자동차로 완성하는 일에 가깝습니다.

이 개념은 최근 에이전트(agent, 목표를 받으면 스스로 여러 단계를 계획하고 도구를 써 가며 일을 끝내는 AI 프로그램)와 LLM 애플리케이션이 늘어나면서 부쩍 중요해졌습니다. 시연에서는 근사하게 돌아가던 프롬프트가 정작 운영 환경에 올리면 무너지는 경험을 흔히 겪습니다. 그 간극을 메우는 공학이 하네스 엔지니어링입니다. '프롬프트만 잘 쓰면 된다'는 인식에서 '프롬프트를 감싼 시스템을 잘 지어야 한다'는 인식으로 넘어가는 지점이라고 봐도 좋습니다. '하네스 엔지니어링'이라는 말은 OpenAI가 2026년 2월 이 이름을 제목으로 한 글을 내는 등 쓰임이 늘었지만, 뜻은 쓰는 사람마다 조금씩 다릅니다. 비슷한 일을 스캐폴딩(scaffolding, 공사장에서 작업 발판으로 세우는 임시 구조물인 비계를 가리키는 말)이나 LLM 애플리케이션 엔지니어링이라고 부르기도 합니다.

왜 모델만으로는 제품이 되지 않는가

하네스 엔지니어링의 출발점은 언어 모델의 작동 방식입니다. 언어 모델은 이해하는 기계가 아니라 확률로 그럴듯한 다음 토큰(token, AI가 글을 읽고 쓰는 조각 단위로, 보통 단어 하나보다 조금 작은 단위)을 고르는 기계입니다. 입력이 주어지면 다음에 올 단어의 확률 분포를 계산하고, 그 분포에서 하나를 뽑습니다. 이 과정을 되풀이해 문장을 만듭니다. 그럴듯한 글을 빠르게 대량으로 만드는 데는 뛰어나지만, 그 결과가 사실인지, 정확한지, 형식에 맞는지는 스스로 보장하지 못합니다. 자신 있게 틀리기도 합니다.

제품은 다릅니다. 결제 시스템에 넘길 값은 정확한 숫자여야 하고, 데이터베이스에 넣을 결과는 정해진 형식이어야 하며, 사용자에게 나가는 답변은 되돌릴 수 없는 사고를 내지 않아야 합니다. 그런데 모델의 출력은 본질적으로 '그럴듯한 텍스트'입니다. 이 텍스트를 그대로 시스템의 다음 부품에 흘려보내면 언젠가 어긋나기 쉽습니다. 영수증 장면에서 형식이 뒤섞인 날짜가 그대로 엑셀에 들어가면 월말 집계가 틀어집니다.

그래서 모델과 제품 사이에 완충 장치가 필요합니다. 모델이 내놓은 그럴듯한 결과를 받아서 형식을 강제하고, 틀린 것을 걸러 내고, 실패하면 다시 시도하고, 위험한 행동은 사람에게 넘기는 층입니다. 이 층 전체를 설계하는 일이 하네스 엔지니어링입니다. 정리하면, 모델의 능력을 '쓸 수 있는 능력'으로 바꾸는 작업입니다.

AI 활용에서 흔히 쓰는 '초안은 기계, 판단은 사람'이라는 원칙을 시스템 수준으로 넓힌 것이라고 봐도 좋습니다. 사람이 매번 눈으로 검토할 수 없을 만큼 자동화가 늘어나면, 그 검토의 일부를 코드로 짜 넣어야 합니다. 그 코드가 하네스입니다.

모델과 제품을 잇는 파이프라인의 골격

하네스를 하나의 흐름으로 그려 보면 대략 이렇습니다. 사용자 요청이 들어오면 먼저 입력을 다듬고 필요한 맥락을 붙입니다. 답하기 전에 관련 문서를 먼저 찾아 붙여 주는 검색 증강 생성(RAG)이 이 단계에 들어갑니다. 그다음 정돈된 프롬프트를 모델에 보내 출력을 받습니다. 받은 출력은 곧바로 쓰지 않고 검증기를 거칩니다. 형식이 맞는지, 값이 유효한지 확인합니다. 통과하면 실제 행동(도구 호출, 저장, 응답)으로 넘어가고, 실패하면 재시도하거나 대체 경로(폴백)로 빠집니다.

모델을 제품으로 잇는 데이터 파이프라인: 입력 정리, 모델 호출, 검증, 실행 또는 재시도로 이어지는 흐름

여기서 눈여겨볼 점은 모델 호출이 파이프라인 전체에서 한 부품에 불과하다는 사실입니다. 처음에는 '프롬프트 → 답변'이 전부처럼 보이지만, 운영 시스템에서는 앞뒤로 전처리와 후처리가 훨씬 길게 붙습니다. 실제로 손이 많이 가는 곳도 모델 호출 한 줄이 아니라 그 앞뒤입니다.

이 파이프라인은 대부분 같은 입력에 늘 같은 결과를 내는 평범한 코드로 짭니다. 모델만 확률적이고, 그것을 감싼 차체는 예측 가능하게 움직여야 합니다. 확률적인 엔진과 예측 가능한 차체를 어떻게 맞물리느냐가 하네스 설계의 핵심 감각입니다.

구조화 출력: 자유 텍스트를 검증 가능한 데이터로

구조화 출력: 자유 텍스트 응답을 읽어 들여(파싱) 정해진 틀에 맞는지 검사할 수 있는 데이터로 바꾸는 과정

하네스의 첫 번째 기둥은 구조화 출력(structured output)입니다. 모델이 자유로운 문장으로 답하게 두는 대신, 정해진 형식(대개 JSON, 항목 이름과 값을 짝지어 적는 데이터 표기법)으로 답하도록 강제합니다. 예를 들어 회의록에서 할 일을 뽑는 기능이라면, 모델에게 {"tasks": [{"title": "...", "due": "...", "owner": "..."}]} 같은 스키마(어떤 항목에 어떤 종류의 값이 와야 하는지 적은 양식)를 따르라고 지시합니다. 그러면 프로그램이 출력을 곧바로 읽어 들여(파싱) 쓸 수 있습니다.

이것이 왜 결정적일까요. 자유 텍스트는 사람이 읽기 좋지만 기계가 검증하기 어렵습니다. 반면 스키마가 정해진 JSON은 형식 위반을 바로 잡아낼 수 있습니다. due 필드가 날짜 형식이 아니거나, 필수 항목이 비어 있거나, 값이 허용 범위를 벗어나면 검증기가 그 자리에서 거부합니다. 그럴듯하게 틀린 출력을 다음 단계로 넘기기 전에 걸러 내는 그물이 생기는 셈입니다. 영수증 장면의 뒤섞인 날짜도 이 그물에 걸립니다.

구조화 출력(JSON 스키마)으로 결과를 검증 가능하게 만드는 예시

요즘 주요 모델 API(프로그램끼리 정해진 방식으로 요청과 답을 주고받는 창구)는 이 요구를 더 강하게 뒷받침합니다. 응답 형식을 JSON으로 못 박거나, 미리 정의한 도구 호출 양식에 맞춰 인자를 채우게 하는 기능입니다. 이렇게 하면 모델이 형식을 어길 확률 자체가 크게 줄어듭니다. 다만 형식이 맞다고 내용까지 맞는 것은 아니라는 점을 늘 기억해야 합니다. 형식 검증은 첫 그물일 뿐이고, 내용의 사실성은 별도의 장치로 따져야 합니다.

디코딩 설정: 용도에 맞춰 조절하기

하네스 엔지니어링은 모델이 토큰을 뽑는 방식에도 개입합니다. 모델이 만든 확률 분포에서 어떻게 하나를 고를지 정하는 규칙이 디코딩 파라미터이고, 대표적인 것이 온도(temperature)입니다. 값이 낮으면 확률이 높은 토큰에 몰려 보수적이고 일관된 출력이 나오고, 값이 높으면 다양하고 창의적이지만 엉뚱해지기 쉽습니다. 하네스 관점에서는 이 값을 작업 성격에 맞춰 정해 두어야 합니다. 영수증 정보 추출이나 분류처럼 정확성이 중요한 작업에서는 온도를 낮게 두어 출력을 안정시키고, 카피 초안이나 아이디어 발산처럼 다양성이 필요한 작업에서는 조금 올립니다. top-k, top-p 같은 다른 설정과 작업별 권장값은 프롬프트 엔지니어링 글에서 다룹니다.

한 가지 주의할 점이 있습니다. 온도를 0에 가깝게 둔다고 출력이 완전히 똑같아지지는 않습니다. 서버가 여러 요청을 묶어 계산하는 방식 같은 요인으로 미세한 변동이 남을 수 있습니다. 그래서 '온도를 낮췄으니 검증은 생략해도 된다'는 판단은 위험합니다. 디코딩 조정은 어긋날 확률을 줄이는 완화책이지, 검증을 대신하는 보장책이 아닙니다.

실패를 전제로 설계하기: 재시도와 폴백

잘 만든 하네스는 성공을 가정하지 않습니다. 실패를 기본값으로 놓고 설계합니다. 모델이 형식을 어긴 JSON을 내놓거나, API가 응답 시간을 넘기거나, 검증기가 결과를 거부하는 일은 드물지 않게 일어납니다. 이때 시스템 전체가 멈추면 제품이 될 수 없습니다.

실패 시 폴백·재시도 전략: 검증에 실패하면 오류를 알려 다시 시도하고, 그래도 안 되면 다른 경로나 사람에게 넘기는 흐름

재시도(retry)는 가장 기본적인 대응입니다. 형식 검증에 실패하면, 오류 내용을 다시 프롬프트에 담아 '이 부분이 스키마에 맞지 않았으니 고쳐 달라'고 되돌려 보냅니다. 이 자기 교정 루프는 외부 검증 신호를 되먹인다는 점에서 Reflexion, 그리고 자기 출력을 스스로 다듬는 Self-Refine 계열 연구가 보여 준 아이디어와 통합니다. 모델이 자기 출력에 붙은 지적을 받아 다듬는 방식입니다. 다만 끝없이 되풀이하면 비용과 지연이 쌓이므로, 시도 횟수에 상한을 두어야 합니다.

폴백(fallback)은 재시도로도 안 될 때의 대비책입니다. 더 강한 모델로 올려 다시 시도하거나, 규칙 기반의 단순한 처리로 우회하거나, 마지막에는 사람에게 넘깁니다. 중요한 것은 '실패했을 때 무엇을 할지'가 코드에 미리 정해져 있어야 한다는 점입니다. 폴백 경로가 없는 파이프라인은 예외 상황이 오는 순간 사용자에게 아무 대답도 못 하고 무너집니다. 영수증 장면에서 합계가 맞지 않는 영수증을 담당자에게 넘기는 것도 폴백입니다.

이 사고방식은 에이전트에서 특히 중요합니다. 에이전트는 사고-행동-관찰(ReAct) 루프를 스스로 여러 번 돕니다. 한 단계의 작은 오차가 다음 단계의 전제가 되어 어긋남이 쌓입니다. 단계마다 검증과 재시도, 폴백을 심어 두지 않으면 길어진 사슬의 끝에서 결과가 크게 빗나갑니다.

도구 호출과 에이전트 루프: 하네스가 손발을 갖출 때

구조화 출력이 모델의 말을 데이터로 바꾸는 장치라면, 도구 호출(tool calling, 함수 호출)은 모델에게 손발을 달아 주는 장치입니다. 모델 자체는 계산기를 두드리거나 데이터베이스를 조회하지 못합니다. 그저 '지금 이 기능을 이런 값으로 부르고 싶다'는 의사를 정해진 형식으로 표현할 뿐입니다. 실제 실행은 하네스가 맡습니다. 모델이 도구 호출 요청을 내놓으면, 하네스가 그것을 읽어 진짜 기능을 실행하고, 결과를 다시 모델에게 돌려줍니다. 이 왕복이 에이전트 루프의 기본 골격입니다.

루프의 흐름을 구체적으로 그려 보면 이렇습니다. 사용자 질문이 들어옵니다. 모델이 '날씨 조회 도구를 서울 값으로 부르겠다'고 응답합니다. 하네스가 날씨 서비스를 호출해 결과를 얻습니다. 그 결과를 대화 이력에 도구 응답으로 추가하고 모델을 다시 부릅니다. 모델은 이제 실제 데이터를 손에 쥐고 최종 답변을 만듭니다. 도구가 여러 개 필요하면 이 순환이 여러 바퀴 돕니다. 문제는 이 순환에 자연스러운 종료 조건이 없다는 점입니다. 모델이 같은 도구를 끝없이 부르며 맴도는 상황을 반드시 막아야 합니다.

그래서 에이전트 루프에는 반드시 상한을 겁니다. 최대 반복 횟수를 정하고, 같은 도구를 같은 값으로 연속 호출하면 차단하며, 누적 토큰이나 누적 비용에도 천장을 둡니다. 실무에서 흔히 겪는 사고가 바로 이 안전장치가 없어 비용이 불어나는 일입니다. 시험할 때는 몇 바퀴로 끝나던 루프가, 예상하지 못한 입력에서 수십 바퀴를 돌며 요금을 낭비합니다. 반복마다 지금 몇 번째인지, 어떤 도구를 왜 불렀는지 로그로 남겨 두면 나중에 루프가 어디서 꼬였는지 추적할 수 있습니다.

도구 호출의 신뢰성은 도구 설명을 얼마나 정확히 적었느냐에 크게 좌우됩니다. 각 도구의 이름, 목적, 입력값의 의미를 모델이 읽을 양식으로 명료하게 적어야 합니다. 설명이 모호하면 모델은 엉뚱한 값을 채워 넣습니다. 여기서 자주 나오는 오해가 '도구를 많이 주면 똑똑해진다'는 생각입니다. 오히려 반대인 경우가 많습니다. 선택지가 늘수록 모델은 도구를 잘못 고르고, 필요 없는 호출을 남발합니다. 한 번의 판단에 보여 주는 도구는 정말 필요한 것으로 추려 두는 편이 정확도와 비용 양쪽에 이롭습니다.

되돌릴 수 없는 행동 앞의 사람 확인

하네스의 또 다른 기둥은 안전장치입니다. 모든 행동을 자동으로 흘려보내서는 안 됩니다. 파일을 지우거나, 결제를 실행하거나, 외부로 메일을 보내는 행동은 되돌릴 수 없습니다. 이런 행동 앞에는 사람이 확인하고 승인하는 관문을 세웁니다. 이것을 사람 개입(human-in-the-loop)이라고 부릅니다.

위험한 행동은 사람에게 넘기는 안전장치: 행동의 위험도를 가려 위험한 것만 승인 관문을 거치게 하는 흐름

설계 요령은 행동을 위험도에 따라 등급으로 나누는 것입니다. 조회나 요약처럼 되돌릴 수 있고 영향이 작은 행동은 자동으로 통과시킵니다. 데이터 변경이나 외부 발송처럼 되돌리기 어려운 행동은 승인 관문을 거치게 합니다. 이렇게 나누면 자동화의 효율과 안전을 함께 챙길 수 있습니다. 모든 것을 사람이 확인하면 자동화의 의미가 없고, 아무것도 확인하지 않으면 사고가 납니다.

에이전트가 강력한 실행기이면서도 아직 감독이 필요한 실행기인 이유가 여기에 있습니다. 오히려 여러 단계를 자동으로 처리할수록 사람의 감독은 더 중요해집니다. 하네스 엔지니어링은 그 감독을 '매번 사람이 지켜보는' 방식이 아니라 '중요한 길목에만 사람을 세우는' 방식으로 짭니다. Anthropic이 2024년 12월에 낸 에이전트 설계 지침 Building effective agents도 같은 점을 강조합니다. 자율성을 높이되 통제 가능성을 함께 설계하라는 것입니다.

믿을 수 없는 입력: 프롬프트 인젝션

하네스가 외부 데이터를 문맥에 끌어들이는 순간 새로운 공격 통로가 열립니다. 대표적인 위협이 프롬프트 인젝션(prompt injection)입니다. 모델은 시스템 프롬프트(모든 대화 앞에 붙는 기본 지침)와 검색해 온 문서를 구분하는 확실한 경계를 갖고 있지 않습니다. 그래서 웹페이지나 사용자가 올린 문서 안에 '이전 지시를 모두 무시하고 다음을 실행하라' 같은 문구가 숨어 있으면, 모델이 그 지시를 진짜 명령으로 착각해 따라갈 수 있습니다.

특히 위험한 경우는 도구 호출과 결합될 때입니다. 모델이 외부 문서를 읽고, 그 문서에 심긴 지시에 따라 이메일 발송 도구나 데이터 삭제 도구를 부른다고 생각해 보세요. 믿을 수 없는 입력이 곧바로 실제 행동으로 이어집니다. 그래서 하네스 설계의 원칙은 분명합니다. 외부에서 들어온 텍스트는 절대 믿지 않습니다. 검색된 문맥은 '데이터'로만 다루고, 그 안의 어떤 문장도 시스템의 명령으로 올려 주지 않도록 지시를 분명히 못 박습니다.

여기서 흔한 오해 하나를 짚겠습니다. '시스템 프롬프트에 절대 규칙을 강하게 적으면 인젝션을 막을 수 있다'는 믿음입니다. 지시를 아무리 단호하게 써도 모델은 확률적으로 움직입니다. 충분히 교묘한 입력 앞에서는 규칙이 무너질 수 있습니다. 그러니 프롬프트 차원의 방어는 첫 겹일 뿐이고, 진짜 안전선은 하네스 쪽의 권한 통제와 검증에 두어야 합니다. 모델을 믿는 대신 모델이 무엇을 할 수 있는지 그 경계를 코드로 강제하는 것, 이것이 하네스 보안의 핵심입니다. 방어 장치를 겹겹이 두는 구체적인 방법은 글 끝 심화 절에 모았습니다.

평가와 관측: 눈에 보이지 않는 시스템을 재는 법

하네스가 잘 작동하는지 어떻게 알 수 있을까요. 여기서 평가(evaluation)와 관측 가능성(observability, 시스템 안에서 무슨 일이 일어났는지 기록으로 들여다볼 수 있게 하는 것)이 필요합니다. 모델 출력은 정답이 하나로 딱 떨어지지 않는 경우가 많아, 기능 하나하나를 정답과 맞춰 보는 전통적인 시험만으로는 품질을 재기 어렵습니다. 그래서 대표적인 입력들을 모아 놓은 평가 세트를 만들고, 시스템을 바꿀 때마다 그 세트에 돌려 성능이 나아졌는지 나빠졌는지 비교합니다. 영수증 장면이라면 정답을 적어 둔 영수증 50장이 좋은 평가 세트가 됩니다.

평가 항목은 형식 준수율, 사실성, 거부해야 할 요청을 잘 거부하는지, 지연과 비용 같은 운영 지표까지 폭넓게 잡습니다. HELM처럼 언어 모델을 여러 축에서 종합적으로 평가하려는 연구 흐름이 이런 다면 평가의 필요성을 잘 보여 줍니다. 정확도 하나만 보면 놓치는 것이 너무 많습니다.

관측은 운영 중인 시스템의 내부를 들여다보는 장치입니다. 어떤 프롬프트가 들어갔고, 모델이 무엇을 돌려주었으며, 어느 단계에서 재시도가 났고, 어떤 도구가 호출됐는지를 기록으로 남깁니다. 이 기록(트레이스)이 있어야 문제가 생겼을 때 원인을 추적하고, 실패 사례를 모아 평가 세트에 다시 반영할 수 있습니다. 하네스 엔지니어링은 이렇게 만들고, 재고, 고치는 순환으로 굴러갑니다.

흔한 오해와 넘기 힘든 벽

가장 흔한 오해는 '프롬프트를 잘 쓰면 하네스가 필요 없다'는 생각입니다. 프롬프트 엔지니어링은 모델에게 무엇을 어떻게 지시할지 다루는 기술이고, 하네스 엔지니어링은 그 지시의 결과를 받아 시스템으로 엮는 기술입니다. 둘은 서로를 대신하는 관계가 아니라 층이 다른 보완 관계입니다. 아무리 정교한 프롬프트라도 확률적 출력이라는 본질은 바뀌지 않으니, 그 결과를 검증하고 감싸는 층은 여전히 필요합니다.

'검증을 촘촘히 하면 모델의 오류를 완전히 없앨 수 있다'는 기대도 지나칩니다. 하네스는 어긋날 확률을 줄이고, 어긋났을 때의 피해를 줄이는 장치입니다. 오류를 0으로 만드는 마법이 아닙니다. 특히 형식 검증은 겉모습만 봅니다. JSON 형식은 완벽한데 그 안의 날짜가 사실과 다를 수 있습니다. 형식과 내용은 다른 문제라는 점을 늘 붙들어야 합니다.

복잡성의 벽도 실재합니다. 재시도, 폴백, 승인 관문, 평가 파이프라인을 다 붙이면 시스템이 무거워지고 비용과 지연이 늘어납니다. 그래서 하네스는 처음부터 다 짓기보다, 위험이 큰 길목부터 최소한으로 시작해 필요에 따라 늘려 가는 편이 현명합니다. 앞의 Anthropic 지침이 '가장 단순한 구조로 시작하라'고 조언하는 이유도 여기에 있습니다. 과잉 설계는 그 자체로 새로운 실패 지점을 만듭니다.

더 깊이 파고들려면

하네스 엔지니어링을 제대로 이해하려면 먼저 그 안쪽의 원리를 단단히 다져야 합니다. 다음 토큰을 확률로 예측하는 언어 모델의 작동, 트랜스포머와 자기어텐션(self-attention), 토큰화와 임베딩, 그리고 temperature·top-k·top-p 같은 디코딩 파라미터의 감각이 바탕이 됩니다. 이 기초가 없으면 하네스의 각 장치가 왜 필요한지 잘 와닿지 않습니다.

그다음은 하네스를 이루는 개별 기법들입니다. 자기 교정 루프의 원리는 Self-Refine 연구에서, 생각과 행동을 엮는 에이전트 루프는 ReAct 논문에서 출발점을 찾을 수 있습니다. 추론 단계를 드러내는 사고 사슬(chain-of-thought) 프롬프팅, 모델이 스스로 규범을 따르게 하는 Constitutional AI, 언어 모델을 다면적으로 재는 HELM 평가 프레임워크도 함께 보면 하네스의 각 기둥이 어떤 연구 배경에서 나왔는지 이어집니다.

실무 감각을 잡는 데는 앞에서 소개한 Anthropic의 'Building effective agents'가 좋은 출발점입니다. 언제 단순한 워크플로로 충분하고 언제 자율 에이전트가 필요한지, 어디에 사람을 세워야 하는지를 현장의 언어로 정리해 두었습니다. 결국 하네스 엔지니어링의 핵심 태도는 하나로 모입니다. 모델은 확률로 그럴듯한 것을 만드는 강력한 엔진이고, 그 엔진을 안전한 제품으로 잇는 차체를 짓는 것은 사람의 몫입니다. 원리를 아는 사람이 그 차체를 잘 짓습니다.

실전에 적용하려면

하네스를 실제 업무에 맞게 설계하려면 도구 연동·오류 복구·컨텍스트 관리를 함께 다뤄야 합니다. 젠아이랩스(GenAI Labs)의 MCP Agent 솔루션이 이 하네스를 기업 환경에 맞게 구축해 드립니다.

개발자를 위한 심화

이 부분은 직접 구현하는 개발자를 위한 내용입니다.

디코딩 파라미터 대비표

top-k는 확률 상위 k개 후보만 남기고 나머지를 잘라 내는 방식이고, top-p(뉴클리어스 샘플링)는 확률을 큰 순서로 더해 누적이 p에 이를 때까지의 후보만 남깁니다. 예를 들어 top-p를 0.9로 두면, 누적 확률 90%를 채우는 만큼의 후보 안에서만 다음 토큰을 뽑습니다. 꼬리 쪽의 이상한 후보를 자연스럽게 배제하는 장치입니다. 아래 표는 감각을 잡는 데 참고할 만한 대략적인 대비입니다.

파라미터 하는 일 낮게·좁게 둘 때 높게·넓게 둘 때
temperature 분포의 뾰족함 조절 일관·보수적 다양·엉뚱해지기 쉬움
top-k 상위 k개 후보만 남김 안정적 후보 폭 넓음
top-p 누적확률 p까지 후보 유지 꼬리 제거 강함 다양성 허용

낮게·좁게 두는 설정은 추출·분류·JSON 생성에, 높게·넓게 두는 설정은 창작·브레인스토밍에 맞습니다.

프롬프트를 코드처럼 다루기: 하네스 안의 버전 관리

하네스 엔지니어링에서 가장 자주 방치되는 자산이 프롬프트입니다. 많은 팀이 프롬프트를 소스 코드가 아니라 설정값 정도로 여깁니다. 문자열 하나를 슬쩍 고치고 배포한 뒤, 며칠이 지나 품질이 떨어졌다는 제보를 받고서야 무엇이 바뀌었는지 뒤늦게 추적합니다. 하지만 대규모 언어 모델(LLM) 시스템에서 프롬프트는 사실상 프로그램의 논리 그 자체입니다. 한 줄의 지시문이 바뀌면 출력 분포 전체가 흔들립니다. 그러므로 프롬프트는 코드와 같은 규율로 관리해야 합니다. 버전 관리 저장소(Git 등)에 넣고, 변경 이력을 남기고, 리뷰를 거쳐 병합합니다.

실무에서는 프롬프트를 소스 파일과 뒤섞지 않고 별도의 템플릿 파일로 분리하는 방식이 잘 통합니다. 예를 들어 지시문 본문과 변수 자리를 나눠 system.md, user.jinja 같은 파일로 두고, 코드에서는 렌더링만 맡게 합니다. 이렇게 나눠 두면 프롬프트 변경분만 따로 비교(diff)해 볼 수 있어 리뷰가 깔끔해집니다. 더 중요한 점은 프롬프트마다 버전 번호를 붙여 로그에 함께 기록하는 것입니다. 어떤 응답이 프롬프트 v3.2에서 나왔는지, v4.0에서 나왔는지를 나중에 구분할 수 있어야 품질이 뒷걸음친 지점(회귀)을 잡아낼 수 있습니다.

프롬프트 변경은 코드 변경보다 위험한 구석이 있습니다. 컴파일러가 잡아 주는 오류가 없기 때문입니다. 세미콜론을 빠뜨리면 빌드가 깨지지만, 지시문에서 '반드시 JSON으로만 답하라'는 문장을 실수로 지워도 시스템은 아무 불평 없이 돌아갑니다. 출력 품질만 조용히 무너질 뿐입니다. 그래서 프롬프트 변경에는 반드시 자동 평가를 붙입니다. 대표 입력 수십 건을 고정해 두고, 프롬프트를 고칠 때마다 그 묶음을 다시 돌려 결과 차이를 봅니다. 이 회귀 검사가 없으면 프롬프트 개선은 도박이 됩니다.

한 가지 더 짚을 함정은 프롬프트와 모델 버전의 결합입니다. 같은 프롬프트라도 모델 공급자가 백엔드를 조용히 업데이트하면 출력이 달라집니다. 특정 프롬프트는 특정 모델 버전(스냅샷)에 맞춰 튜닝된 상태라고 보는 편이 안전합니다. 그래서 모델 식별자를 프롬프트 버전과 함께 고정하고, 공급자가 모델을 바꾼다는 공지가 뜨면 그것을 하나의 배포로 다룹니다. 모델과 프롬프트를 짝으로 묶어 관리하는 습관이 재현성을 지키는 핵심입니다.

컨텍스트 창이라는 예산: 토큰 회계의 기술

하네스를 설계하다 보면 결국 부딪히는 물리적 한계가 컨텍스트 창(context window)입니다. 모델이 한 번에 받아들이는 토큰 수에는 상한이 있고, 이 상한은 단순한 용량 제한이 아니라 비용과 지연 시간, 품질을 함께 결정하는 예산입니다. RAG 파이프라인에서 검색된 문서를 무작정 다 밀어 넣으면 안 되는 이유가 여기 있습니다. 토큰이 늘수록 요금이 비례해 오르고, 응답 지연도 길어지며, 무엇보다 정작 중요한 지시가 방대한 배경 텍스트에 묻혀 버립니다.

토큰 회계를 제대로 하려면 먼저 입력을 구성 요소로 나눠 각 몫을 정해야 합니다. 시스템 프롬프트에 얼마, 대화 이력에 얼마, 검색 문맥에 얼마, 그리고 모델이 생성할 응답 여유분에 얼마를 배정할지 미리 정합니다. 예컨대 12만 8천 토큰짜리 창을 쓴다고 해도, 실제로는 시스템 프롬프트 2천, 이력 1만, 검색 문맥 3만, 출력 여유 4천처럼 나눠 쓰고 나머지는 안전 완충으로 남깁니다. 이 배분을 고정 상수로만 두지 말고, 실제 토큰 수를 측정해 초과하면 오래된 이력부터 잘라 내는 정책을 붙여야 운영 중 폭주를 막을 수 있습니다.

긴 문맥을 넣으면 모델은 맨 앞과 맨 뒤에 놓인 정보는 잘 활용하지만 가운데에 묻힌 정보는 놓치는 경향(lost in the middle)을 보입니다. 그래서 검색 문맥을 배치할 때 관련도가 가장 높은 문서를 앞이나 뒤 끝자락에 두는 재배치가 효과를 냅니다. 원리는 컨텍스트 엔지니어링 글에서 자세히 다룹니다.

긴 문맥을 다룰 때 쓰는 또 다른 절약 기법이 프롬프트 캐싱입니다. 여러 요청에서 되풀이되는 앞부분, 이를테면 고정된 시스템 프롬프트나 대용량 참조 문서를 공급자 쪽에서 캐시해 두면 재계산을 건너뜁니다. 여러 상용 API가 이 기능을 제공하며, 캐시된 토큰은 일반 입력 토큰보다 훨씬 싸게 과금됩니다. 하네스 설계 단계에서 프롬프트의 고정부와 가변부를 분명히 나눠 두면 이런 캐싱 이점을 그대로 챙길 수 있습니다. 토큰 회계는 인색해서 하는 일이 아니라, 예산을 알아야 품질을 설계할 수 있기 때문에 하는 일입니다.

지연 시간과 비용 줄이기: 스트리밍, 배치, 모델 라우팅

사용자가 체감하는 품질에서 지연 시간은 정확도만큼 중요합니다. LLM 응답에는 두 개의 시계가 있습니다. 첫 토큰이 나오기까지 걸리는 시간(time to first token)과, 그 뒤로 토큰이 흘러나오는 속도(tokens per second)입니다. 챗봇처럼 사람이 실시간으로 읽는 화면이라면 첫 토큰까지의 지연이 특히 결정적입니다. 3초 동안 빈 화면을 보여 주면 사용자는 시스템이 멈춘 줄 압니다. 그래서 스트리밍이 사실상 필수입니다. 완성된 답을 기다렸다 한꺼번에 보여 주는 대신, 생성되는 대로 토큰을 흘려보내면 체감 지연이 크게 줄어듭니다.

다만 스트리밍은 구조화 출력이나 도구 호출과 부딪힙니다. JSON을 스트리밍하면 중간 단계에서는 문법이 깨진 불완전한 조각이 나옵니다. 이 조각을 그대로 파싱하려 들면 오류가 납니다. 그래서 사람이 읽을 자유 텍스트는 스트리밍하되, 기계가 쓸 구조화 데이터는 완결된 뒤에 검증하는 식으로 경로를 나눠 설계합니다. 두 요구를 한 응답에 억지로 섞으면 어느 쪽도 만족스럽지 않습니다.

비용 최적화의 큰 축은 모델 라우팅입니다. 모든 요청을 가장 크고 비싼 모델에 보낼 이유가 없습니다. 간단한 분류나 형식 변환은 작고 빠른 모델로 충분하고, 복잡한 추론이 필요할 때만 큰 모델을 부릅니다. 실무에서는 요청의 난이도를 먼저 가늠하는 가벼운 라우터를 앞단에 두고, 판단에 따라 서로 다른 모델로 흘려보냅니다. 이 계층화만 잘해도 전체 비용이 크게 줄어듭니다. 실시간이 필요 없는 대량 작업이라면 배치 API를 쓰는 선택지도 있습니다. 여러 공급자가 배치 처리에 상당한 할인율을 적용합니다.

아래 표는 하네스에서 자주 조율하는 성능·비용 지표와 대표적인 대응 수단을 정리한 것입니다. 이 지표들은 서로 맞물려 있어서 하나를 조이면 다른 하나가 헐거워집니다. 예컨대 응답 품질을 위해 큰 모델을 쓰면 지연과 비용이 오릅니다. 하네스 엔지니어링은 결국 이 상충 관계를 제품의 요구에 맞게 저울질하는 일입니다.

관심 지표 무엇을 재나 주요 대응 수단
첫 토큰 지연 요청 후 첫 응답까지 시간 스트리밍, 프롬프트 캐싱, 작은 모델
처리 비용 요청당 토큰 요금 모델 라우팅, 배치 API, 문맥 절삭
처리량 초당 소화 요청 수 동시성 제어, 큐잉, 재시도 백오프
응답 품질 정확도·형식 준수율 큰 모델, 구조화 출력, 회귀 평가

표의 동시성 제어는 한꺼번에 보내는 요청 수를 조절하는 것, 큐잉은 요청을 줄 세워 차례로 처리하는 것, 재시도 백오프는 실패한 요청을 점점 간격을 늘려 가며 다시 보내는 것을 말합니다.

보안 경계를 겹겹이 두기

프롬프트 인젝션은 데이터베이스에 악성 명령을 끼워 넣는 SQL 인젝션과 성격이 비슷하지만, 방어가 훨씬 까다롭습니다. 코드에는 특수 문자를 무력화하는 이스케이프 같은 깔끔한 경계 처리가 있지만, 자연어에는 그런 경계가 없기 때문입니다.

완벽한 방어는 없지만 위험을 낮추는 겹겹의 장치는 있습니다. 우선 신뢰 경계를 분명히 구분해, 시스템 프롬프트와 사용자 데이터를 서로 다른 역할로 나눠 전달합니다. 되돌릴 수 없는 도구는 꼭 필요한 권한만 주는 최소 권한 원칙으로 묶고, 위험한 작업일수록 승인 단계를 끼워 넣습니다. 출력에도 검사를 겁니다. 모델이 생성한 텍스트를 그대로 브라우저에 그리면 악성 스크립트가 끼어들 위험이 생기므로, 출력에서 위험한 코드를 걸러 내는 정화(sanitization)를 잊지 말아야 합니다. 입력 필터링만으로는 부족하고, 입력·행동·출력 세 지점에 모두 방어를 두어야 합니다.

보완 · 한눈에 보기와 영수증 정리 장면을 더하고, 용어 풀이를 채우고, 개발자용 내용을 심화 절로 옮겼다.

작성: AI (Claude Opus 4.8)

출처

  1. ReAct: Synergizing Reasoning and Acting
  2. Chain-of-Thought Prompting
  3. Self-Refine: Iterative Refinement with Self-Feedback
  4. Constitutional AI: Harmlessness from AI Feedback
  5. Holistic Evaluation of Language Models (HELM)
  6. Building effective agents
  7. Building effective agents · 2024-12-19
  8. Harness engineering: leveraging Codex in an agent-first world · 2026-02-11
뉴스레터로 매주 받아보기 기술 블로그 목록