← 에세이 /Post · 20 of 21 · Edge AI

LLM에 하드웨어 문서 주입: grep vs RAG

RAG는 하드웨어 문서의 교차 참조를 파괴합니다. 파이프라인 없이 LLM에 SVD와 PDF를 파일 도구로 직접 주세요.

·7 min read · · · #rag#ai-agents#embedded-systems#stm32#datasheets
LLM에 하드웨어 문서 주입: grep vs RAG
On this page

Claude한테 STM32F407에서 USART2를 9600 보드로 잡아달라고 했다. 코드는 잘 컴파일됐다. 그런데 시리얼 터미널엔 쓰레기만 찍혔다.

문제는 LLM 추론이 아니었다. 검색이었다. USART 보드 레이트 공식은 주변 클록 주파수를 참조하는데, 정작 그 값은 USART 레지스터와 완전히 동떨어진 챕터에 있다. RAG 파이프라인은 한쪽 챕터만 집어오고 나머지를 놓쳤다. 비어버린 자리는 LLM이 클록 주파수를 지어내서 메꿨다.

RM0090 하나 잡겠다고 RAG 시스템을 2주나 붙들었다. Docling으로 PDF 파싱하고, ChromaDB로 하이브리드 검색 짜고, 라우팅 레이어까지 얹었다. 그러다 허무하게 깨달았다. 그냥 LLM한테 파일 경로만 던져주고 grep 시키면 될 일이었다.

grep이 이기는 자리, RAG가 이기는 자리

이 글의 나머지는 하드웨어 문서에 RAG를 쓰지 말라는 논거다. 그 전에 경계부터 그어두자. “RAG는 나쁘다”보다는 좁은 이야기다.

상황쓸 것
문서 몇 개, 클라우드 LLM, 넉넉한 컨텍스트grep과 read를 파일 도구로
망 분리 환경이거나 컨텍스트가 좁은 로컬 모델문서 구조에 맞춰 다시 짠 검색
데이터시트 수십 개, “어느 MCU가 X를 지원하나” 류 질의인덱스. 꼭 RAG일 필요는 없다

첫 줄이 대부분의 펌웨어 작업이고, 이 글은 그 얘기다. 둘째 줄은 나중에 망 분리된 공장 네트워크에서 실제로 부딪힌 제약이고, 거기선 검색 파이프라인을 데이터시트에 맞게 다시 짜야 했다. 가르는 변수는 문서 종류가 아니다. 페이지를 모델 앞에 올려놓을 수 있느냐다.

RAG가 하드웨어 문서에서 깨지는 이유

RAG 연구 대부분은 애초에 엉뚱한 문서로 테스트한다. LaRA(2025년 2월, 2,326개 테스트 케이스)가 다룬 건 소설, 학술 논문, 재무제표다. Self-Route(2024년 7월)는 NLP 논문에 다분야 문서, 다중 홉 QA 벤치마크를 붙였다. Databricks 연구는 제품 문서와 금융, 일반 QA 데이터셋으로 2,000개 실험을 돌렸다. 하드웨어 문서를 물린 연구는 하나도 없다. 그런데 여기선 실패 모드가 구조부터 다르다.

청킹이 교차 참조를 끊어놓는다. RM0090 Section 30.3.4에 보드 레이트 공식이 있다. 그런데 이 공식이 요구하는 클록 주파수는 수백 페이지 건너뛴 Section 7.2에 따로 있다. 일반 RAG는 청크를 서로 독립적으로 검색한다. Late Chunking 논문(2024년 9월)이 딱 이 문제를 짚었다. 앞 문맥을 받아 쓰는 구문은 청킹을 거치면 임베딩 품질이 뚝 떨어진다. 하드웨어 문서에선 “이 레지스터”가 3챕터 전 정의를 가리키는 게 예삿일이다.

임베딩 모델은 레지스터 테이블을 인덱싱하지 못한다. RCC_CFGR[SWS]: bits 3:2, read-only 같은 설명은 15 토큰 안에 어마어마한 정보를 욱여넣는다. 자연어로 학습된 임베딩 모델은 이런 항목에 유사도를 박하게 매긴다. “MCU가 어떤 클록 소스를 쓰지?”로 질의해도, 코사인 유사도로는 SWS 필드가 안 걸린다.

비트 위치가 틀리면 “얼추 맞다” 같은 건 없다. 시스템이 bit 12여야 할 자리에 bit 13을 돌려주면, 코드는 엉뚱한 레지스터 필드에 값을 쓰고 주변 장치는 그냥 죽어 있다. RespCode(2026)가 LLM 4개를 놓고 이걸 기록했다. Gemini는 LPC55S69의 SYSCON_BASE0x50000000이라고 환각했다(정답은 0x40000000). 4개 중 3개 모델은 CTIMER2 클록 활성화 비트를 틀렸다. 코드는 넷 다 arm-none-eabi-gcc로 멀쩡하게 컴파일됐다. 그리고 실제 하드웨어에선 하나도 안 돌았다.

LlamaIndex 벤치마크가 이 격차를 대놓고 측정했다. 소규모 연구 논문 묶음(문서 5개, 22에서 52페이지)에서 파일시스템 에이전트(grep + read)가 정확도 8.4/10을 찍었고, RAG는 6.4/10에 그쳤다. 이들 설명은 이렇다. “RAG는 청킹과 비최적 검색 호출로 인한 컨텍스트 손실에 묶여 있어, 최종 답변을 생성하는 LLM이 제한적이고 때로는 부정확한 컨텍스트에 접근합니다.”

하드웨어 문서는 이 모든 걸 한층 더 악화시킨다. 정보 밀도는 빽빽하고, 교차 참조가 문서 구조 자체를 떠받치고, 오류 허용 범위는 0이다.

USART 보드 레이트 버그

이 예제 하나에 하드웨어 문서에서 RAG가 틀어지는 방식이 전부 담겨 있다.

168MHz STM32F407에서 USART2를 9600 보드, 8N1, RX 인터럽트로 설정해 달라고 했다. RAG는 RM0090 Section 30.3.4에서 USARTDIV 공식이 붙은 보드 레이트 레지스터 설명을 가져왔다. 정작 Section 7.2에 있는 RCC 설정, 그러니까 USART2가 APB1에 걸려 있고 SYSCLK/4 = 42MHz라는 부분은 놓쳤다. LLM은 공식에서 f_CK를 보긴 했는데, USART2의 f_CK가 얼마인지 짚어주는 청크가 없으니 그냥 찍었다.

// What RAG generated (WRONG - assumes f_CK = 168MHz)
USART2->BRR = 168000000 / 9600;  // BRR = 17500

// Correct (f_CK = 42MHz for APB1 peripherals)
USART2->BRR = 42000000 / 9600;   // BRR = 4375
// Simplified formula for 16x oversampling (OVER8=0, default).
// Full: Baud = f_CK / (8 * (2 - OVER8) * USARTDIV). RM0090 Section 30.3.4.

컴파일 된다. 실행도 된다. 그런데 9600 보드로 물리면 쓰레기가 쏟아진다. 코드가 멀쩡해 보여서 몇 시간씩 잡아먹는, 딱 그런 부류의 버그다.

청크 크기를 아무리 만져봐도 안 고쳐진다. 보드 레이트 공식과 클록 트리가 서로 다른 챕터에 흩어져 있어서다. 코사인 유사도는 “USART 보드 레이트”와 “RCC APB1 프리스케일러”를 같이 끌어오지 못한다. 두 텍스트가 의미적으로 남남이어서다. 이건 튜닝 문제가 아니라 구조 문제다.

RAG가 필요 없다. 파일 접근이 필요하다.

답은 더 정교한 RAG 파이프라인에 있지 않다. LLM한테 문서 파일을 직접 만지게 열어주고, 필요할 때 알아서 검색하게 두면 된다.

도구 기반 MCU 문서 접근 아키텍처: 프로젝트 파일과 로컬 문서(SVD, PDF)가 도구 호출(grep, read)을 통해 LLM 에이전트에 연결되어 검증된 레지스터 코드를 생성

아키텍처: 에이전트가 사전 청킹된 임베딩을 검색하는 대신 SVD와 PDF 파일을 필요할 때 grep한다.

펌웨어 엔지니어한테 필요한 건 사실상 두 파일이면 거의 다 된다.

SVD (System View Description): ARM Cortex-M 실리콘 벤더라면 어디든 내놓는 XML 파일이다. 특정 MCU의 주변 장치 레지스터, 베이스 주소, 비트 필드, 리셋 값, 열거형 값이 전부 들어 있다. STM32F407 SVD만 봐도 58개 주변 장치에 걸쳐 레지스터 정의가 1,000개를 넘는다. cmsis-svd-data 리포지토리가 여러 벤더 SVD를 한데 모아뒀다. RespCode는 SVD 파일을 2,177개 파싱했는데, SVD를 주입하자 테스트한 필드에서 LLM의 레지스터 값 정확도가 ~25% 기준선에서 100%까지 뛰었다.

PDF 레퍼런스 매뉴얼: STM32F407용 RM0090은 1,700페이지가 넘고, 클록 트리부터 주변 장치 동작, 타이밍 다이어그램, 초기화 시퀀스, 전기적 특성까지 다 담고 있다. 절차적 지식은 여기 다 있다. DMA를 어떻게 세우는지, 프리스케일러를 건드리면 무슨 일이 터지는지, 어떤 GPIO 대체 기능이 어떤 주변 장치로 이어지는지.

이 파일들을 통째로 컨텍스트 윈도우에 밀어 넣을 이유는 없다. 필요한 건 도구 접근이다. grep으로 뒤지고 read로 해당 섹션만 불러오면 된다. Claude Code(임베디드 리눅스 워크플로우는 임베디드 리눅스 AI 에이전트 포스트에서 다뤘다)나 Cursor 같은 도구가 이미 이 기능을 갖추고 있다. 파일 위치만 짚어주면 끝이다.

도구 접근이 전체 컨텍스트보다 나은 이유

레퍼런스 매뉴얼 전체를 컨텍스트 윈도우에 넣는 것도 방법이긴 한데, 비용이 감당이 안 된다. RM0090이 약 1.5M 토큰이다. Gemini 2.5 Pro 가격(장문 컨텍스트 $2.50/M 입력 토큰)이면 쿼리 한 번에 약 $3.75가 나간다. Gemini 2.5 Flash-Lite($0.10/M)로 낮춰도 쿼리당 $0.15이고, O(n^2) 어텐션 계산 탓에 30초에서 60초를 기다려야 한다.

도구 기반 접근은 필요한 만큼만 읽는다. 보통 쿼리 하나는 SVD 데이터와 PDF 섹션에서 20에서 50K 토큰 정도 쓴다. 쿼리당 토큰이 30배에서 75배 적은 셈이다. 하나의 거대한 컨텍스트를 통째로 삼키는 대신, LLM이 작은 읽기를 여러 번 하고, 그 읽기 하나하나를 LLM 자신의 검색 로직이 조준한다.

아래 표는 Claude Sonnet 4.6 가격($3/M 입력, 2026년 3월 기준)으로 맞춰 비교한 것이다. 실제로 전체 컨텍스트 로딩을 하려면 Gemini의 1M에서 2M 컨텍스트 윈도우가 있어야 한다.

접근법쿼리당 토큰추정 비용레이턴시정확도
RAG (청킹)~3K~$0.011~2s주변 장치 간 낮음
전체 컨텍스트~1,500K~$4.5030~60s높지만 비쌈
도구 접근 (grep+read)2050K$0.060.1510~20s높음

비용 추정치는 공개 API 가격과 대략적인 토큰 수를 바탕으로 잡았다. 도구 접근 수치는 쿼리 하나당 read/grep 라운드를 3회에서 5회 돈다고 가정한 값이다.

LlamaIndex 벤치마크도 같은 쪽을 가리킨다. 소규모 문서에서는 에이전트형 파일 검색이 RAG보다 정확도가 2점 높았다(8.4 vs 6.4). 연구 논문으로 낸 수치라 하드웨어 문서는 아니지만, 방향은 그대로고 교차 참조가 촘촘한 하드웨어 문서라면 격차는 오히려 더 벌어질 것이다.

에이전트가 보드 레이트 버그를 해결하는 방법

도구 접근이면 아까 그 USART2 쿼리가 전혀 다르게 흘러간다. 에이전트가 SVD에서 USART2BRR을 grep한다.

<!-- grep result from STM32F407.svd -->
<peripheral>
  <name>USART2</name>
  <baseAddress>0x40004400</baseAddress>
  ...
  <register>
    <name>BRR</name>
    <addressOffset>0x08</addressOffset>
    <size>0x20</size>
    <fields>
      <field><name>DIV_Mantissa</name><bitOffset>4</bitOffset><bitWidth>12</bitWidth></field>
      <field><name>DIV_Fraction</name><bitOffset>0</bitOffset><bitWidth>4</bitWidth></field>
    </fields>
  </register>
</peripheral>

이제 정확한 레지스터 주소와 필드 레이아웃이 손에 들어왔다. 에이전트는 PDF의 USART 보드 레이트 섹션을 읽고 공식에서 f_CK를 본다. 여기서 찍는 게 아니라, PDF에서 “APB1”과 “USART2”를 grep해서 Section 7.2의 APB1 = SYSCLK/4 = 42MHz를 찾아낸다. 도구 호출 3번. 정답이다.

RAG는 이걸 못 한다. 코사인 유사도가 교차 참조를 따라가질 못해서다. 반면 에이전트는 방금 찾은 걸 근거로 다음에 뭘 뒤질지 추론하기 때문에, 그 참조를 끝까지 따라간다.

설정 방법

기본 설정

cmsis-svd-data에서 쓰는 MCU의 SVD 파일을 내려받고, 레퍼런스 매뉴얼 PDF는 벤더 사이트에서 받는다. 둘 다 프로젝트의 docs/ 폴더에 넣는다. 그다음 CLAUDE.md(또는 그에 준하는 프로젝트 컨텍스트 파일)에 이렇게 적어둔다.

## Hardware Reference
- Target: STM32F407VG (Cortex-M4, 168MHz)
- SVD: docs/STM32F407.svd (register definitions, bit fields, addresses)
- Reference Manual: docs/RM0090.pdf (peripheral behavior, clock tree, init sequences)
- Datasheet: docs/DS8626.pdf (pinout, electrical characteristics, absolute max ratings)

When writing register-level code, always grep the SVD file for exact
register addresses and bit field definitions. Do not guess register values.
For clock configuration, read RM0090 Section 7 (RCC).

이게 전부다. 이제 에이전트는 PDF 뷰어에 띄워놓고 보던 그 문서를 똑같이 열람하되, 프로그래밍 방식으로 검색까지 한다.

에이전트가 여전히 틀리는 것

STM32, ESP32, nRF52처럼 인기 있는 MCU라면, LLM은 학습 데이터에서 이미 관련 문서를 거의 다 본 상태다. 문서를 안 줘도 레지스터 설정을 맞히는 경우가 흔하다. 이럴 때 SVD 파일은 주 소스라기보다 검증 레이어에 가깝다.

문서 접근이 진짜 결정적인 경우는 따로 있다. LLM이 본 적 없는 마이너하거나 틈새인 MCU, 레지스터 레이아웃이 갈아엎인 최신 실리콘 리비전, 벤더마다 다른 에라타. 이런 상황이라면 RAG도 결국 문서를 인제스트해야 한다. 도구 접근은 전처리 파이프라인 없이 그냥 처리한다.

다루지 않는 것

대규모 다중 문서 검색. 데이터시트 50개를 늘어놓고 “메시지 버퍼가 64개 넘는 CAN-FD 주변 장치를 가진 MCU가 뭐냐”고 물으면, 도구 기반 grep은 확실히 굼떠진다. 이럴 땐 가벼운 인덱스(꼭 RAG일 필요는 없다)가 도움이 된다. 그런데 이건 MCU 선정 쿼리다. 펌웨어 개발과는 결이 다른 문제고.

다이어그램과 회로도. 도구 기반 PDF 접근이 예상보다 이걸 잘 해낸다. Claude와 Gemini가 PDF 페이지를 이미지로 처리하기 때문이다. 그래서 에이전트가 특정 페이지를 읽고 블록 다이어그램이나 클록 트리 그림, 핀 배치 테이블을 눈으로 보듯 해석한다. 도구 패턴은 똑같다. PDF에서 “Figure 23”을 grep하고, 그 페이지를 읽고, 필요한 정보를 뽑아낸다.

타이밍 다이어그램은 얘기가 다르다. 범용 VLM은 아직도 다중 신호 파형 해석에서 헤맨다. GPT-4o는 신호를 잘못 짚고, AHB 대기 상태 같은 프로토콜 고유의 전환을 놓치기 일쑤다. TD-Interpreter(2025년 7월)는 타이밍 다이어그램만 노리고 비전-LLM을 파인튜닝해서 전문가 수준 정확도를 냈고 GPT-4o도 앞섰다. 대신 합성한 타이밍 다이어그램 데이터로 커스텀 학습을 시켜야 한다. 과목 30개를 아우르는 MMMU 멀티모달 벤치마크(엔지니어링 다이어그램 포함)에서, 이전 세대 VLM은 60에서 70%, 인간 전문가는 ~89%를 찍었다. 최신 모델이 간격을 좁히곤 있지만 타이밍 다이어그램에선 여전히 밀린다. 난이도를 올린 MMMU-Pro 변형에서는 점수가 더 주저앉는다. setup/hold 시간이나 프로토콜 타이밍은 아직도 데이터시트에서 직접 숫자를 읽는 수밖에 없다.

검증. 올바른 문서를 넣어준다고 올바른 코드가 나오는 건 아니다. RespCode처럼 생성이 끝난 뒤 SVD 데이터베이스랑 대조해 검증하면, 완벽한 컨텍스트에서도 LLM이 저지르는 오류를 잡아낸다. 이건 검색과는 별개의 문제다.

RAG를 건너뛰고 파일을 쓴다

RAG는 근사 검색만으로도 충분한 자연어 문서를 겨냥해 만들어졌다. 하드웨어 문서는 거기서 벗어난다. 레지스터 주소, 비트 필드, 클록 트리, 주변 장치 사이 의존성은 전체 컨텍스트를 온전히 지킨 정확한 검색을 요구한다.

제일 단순한 해법이 제일 낫다. SVD와 PDF 파일을 프로젝트에 넣고, LLM한테 위치만 알려준 다음, grep하게 두면 된다. 임베딩 파이프라인도, 벡터 데이터베이스도, 청크 크기 튜닝도 다 필요 없다. 파일이 곧 ground truth다. 에이전트한테 읽으라고 하면 된다.

ecro
글쓴이 ecro

LLM 펌웨어 벤치마크를 만들었습니다. EmbedEval →

프로젝트에 맞는 Claude Code / Cursor / Codex 하네스를 생성하는 도구를 만듭니다. harness-maker →

Datasheet을 읽는 터미널을 만들고 있습니다. NeuroTerm →

댓글

댓글 불러오는 중...