← 에세이 /Post · 12 of 21 · Embedded Dev

AI가 짠 펌웨어: AI가 펌웨어를 망가뜨리지 못하게 막는 법

3-Tier Trust로 PR을 분류하고, 머지까지 검증 게이트(spec, TDD, RAG, HIL, 결정론적 분석기 등)를 거친다. 단계마다 잡는 결함 클래스가 다르다.

·4 min read · · · #llm#embedded-dev#firmware#ai-agents#code-review
AI가 짠 펌웨어: AI가 펌웨어를 망가뜨리지 못하게 막는 법
On this page

3편 벤치마크 포스트를 올리자 “그래서 어쩌라는 거냐”가 바로 따라왔다. 답은 하나로 안 떨어진다. 카테고리마다 다르다. EmbedEval n=3 데이터로 보면 LLM 출력은 세 갈래로 갈린다. 단독 승인 가능, 리뷰 필수, 그리고 사람이 처음부터 쓰는 영역. 재밌는 건 이 경계가 토큰을 아무리 부어도 안 움직인다는 점이다. 데이터시트와 보드 식별이 애초에 모델 context 밖에 있어서다.

3-Tier Trust

Tier카테고리SonnetHaikuPR 규칙
1. 단독 승인 가능device-tree, pwm, boot, kconfig90% 이상90% 이상syntax 리뷰 후 머지
2. 전문가 리뷰 필수gpio, linux-driver, yocto, ota, power-mgmt, spi-i2c, ble67%에서 90%45%에서 83%error path + 사이드이펙트 확인
3. 전문가가 처음부터 쓴다DMA, ISR, threading, storage55% 미만55% 미만LLM draft는 참고만

수치는 3편의 n=3 측정값(233 TCs)에서 왔다. 임계 정의는 간단하다. 두 모델 다 60% 미만이고 n=3 안정도가 80% 미만이면 Tier 3. 왜 하필 60%와 80%냐면, “사람이 처음부터 쓰는 시간 ≤ LLM 초안을 다듬어 통과시키는 시간”이라는 부등식이 깨지는 자리가 거기였다. 다음 모델 세대가 나오면 다시 재볼 값이다.

1편에서 eMMC를 죽인 CAN 로깅 데몬, 그게 Tier 3 storage(flash wear leveling, NVS 라이프사이클)에 속한다. 2편에서 추린 6가지 failure pattern도 마찬가지다. ISR(volatile), DMA cache coherency, error path cleanup처럼 죄다 Tier 3 언저리에 몰려 있다. 3편이 그 경계를 숫자로 찍었다면, 이번 편은 그 숫자를 팀 운영 룰로 옮긴다.

토큰을 더 써도 안 움직이는 이유

일반 SW라면 토큰을 부을수록 품질이 로그 곡선으로 따라 올라온다. 임베디드는 어느 지점에서 곡선이 평평해진다. 그 평평해지는 자리엔 공통점이 있다. 데이터시트, 레퍼런스 매뉴얼, 실시간 타이밍, “지금 내가 어느 보드 위에 있는지”. 이게 전부 context에서 빠진 자리라는 것.

EmbedAgent(ICSE 2026) 측정에서 datasheet RAG가 ESP-IDF를 29.4%에서 65.1%로 끌어올렸다. 35.7%p가 돌아온 셈이다. 그런데 이 숫자가 말하는 건 context engineering이 ceiling을 올려준다는 뜻이다. ceiling을 없애준다는 얘기가 아니고. RAG로 데이터시트 페이지를 통째로 밀어넣어도, “내 보드는 i.MX8M Mini의 어느 마스크 셋이고 SDMA 채널 N이 어느 PHY에 묶여 있다” 같은 사실까진 자동으로 안 넘어간다.

Tier 3가 회색이 아니라 빨간색

DMA 카테고리는 Sonnet 31%, Haiku 8%(3편 n=3). 이 숫자가 어디서 나오는지, 실제 사례 하나로 풀어본다.

i.MX8M Mini SDMA를 Linux dma_alloc_coherent API 안 쓰고 kmalloc()으로 잡아 넘기면, A53 L1 캐시에 갇힌 데이터를 SDMA가 못 본다. i.MX8M Mini 레퍼런스 매뉴얼에 SDMA는 Cortex-A53 캐시 코히런시 도메인 밖이라고 대놓고 적혀 있다. 고치는 건 한 줄이다.

/* SDMA on i.MX8M Mini is outside the A53 cache coherency domain.
 * Use coherent allocation instead of kmalloc.
 * dev = &pdev->dev (struct device *) from platform_driver probe.
 * dma_handle: dma_addr_t, dma_buf: void *. */
dma_buf = dma_alloc_coherent(dev, DMA_BUF_SIZE, &dma_handle, GFP_KERNEL);

LLM이 이 한 줄을 못 짜는 이유는 둘이다. 레퍼런스 매뉴얼의 그 페이지가 context에 없고, “내가 i.MX8M Mini 위에 있다”는 사실부터가 프롬프트 밖이다. 이터레이션을 백날 돌려도 모르는 상태만 반복된다. 게다가 LLM 출력에 dma_alloc_coherent 대신 kmalloc이 박혀 있을 때 “이거 안 된다”고 짚어내려면, 리뷰어가 이미 non-coherent SDMA의 존재를 알고 있어야 한다. 리뷰어가 답을 모르면 리뷰는 rubber stamp가 된다. 1편의 eMMC 사망이 딱 이 꼴이었다. 주니어가 LLM이 짠 로깅 데몬을 머지했고, 리뷰 라인 어디에도 write amplification을 의심한 사람이 없었다.

막는 법

CODEOWNERS로 자동 머지 차단. .github/CODEOWNERS나 브랜치 보호 규칙에 Tier 3 디렉터리를 박아둔다.

# Tier 3: expert review mandatory, no LLM auto-merge
drivers/dma/            @firmware-leads
kernel/threading/       @firmware-leads
drivers/storage/        @firmware-leads

모델은 Tier 2에만 Sonnet. Sonnet 68%와 Haiku 57%, 이 11점 차이는 Tier 2에서만 값을 한다. Tier 1은 Haiku로 충분하고, Tier 3는 Sonnet을 붙여봤자 어차피 사람이 처음부터 쓴다. 그러니 Sonnet 호출을 Tier 2 PR로만 라우팅하면 비용이 눈에 띄게 빠진다. 정확한 절감률이야 자기 팀 Tier 분포(PR 수, 토큰량)에 달렸다.

Tier 2 리뷰는 error path랑 사이드이펙트만 본다. LLM이 작업 시간을 반으로 줄여주는 구간인데, 딱 두 군데가 빈다. 하나는 error path 분기랑 reverse-order resource cleanup. 다른 하나는 recipe·DTS·Kconfig 변경의 사이드이펙트. 두 번째는 우리 팀도 한 번 데였다. Yocto recipe 하나 바꿨는데 그게 kernel DTB를 건드려서, 부팅 후 SPI flash 쓰기 지연이 50ms에서 800ms로 튀었다. recipe diff만 들여다본 리뷰는 이걸 절대 못 잡는다.

경계는 계속 움직인다. 6주쯤 굴리면 절반 넘게 재분류된다. BLE GATT는 타이밍 민감도가 드러나면서 Tier 2에서 Tier 3로 올라갔고, i2c bring-up은 datasheet RAG를 붙이고 나서 Tier 3에서 Tier 2로 내려왔다. 그러니 이 분류 표는 한 번 정하고 끝나는 게 아니다. 분기마다 다시 재는 운영 산물이다.

머지까지 검증 게이트, 세 층

위 네 개는 더 큰 파이프라인의 일부다. Tier 3까지 통과해서 머지되는 코드는 단계마다 서로 다른 결함 클래스를 잡는 검증 게이트를 지난다. 크게 세 층이다. Implicit Context(생성 시점에 사실 주입), Review(머지 전 정적 검증), Test(실행 검증).

1. Implicit Context. 생성하는 그 순간에 사실(facts)을 LLM 컨텍스트에 밀어넣는다.

  • Spec 기반 생성. 요구사항을 contract YAML로 먼저 박고, LLM이랑 reviewer가 같은 contract를 본다.
  • Datasheet RAG 주입. 보드 reference manual, errata, SDK 예제를 chunk해서 생성 시점 context로 넣는다. EmbedAgent ICSE 2026의 +35.7%p 회복이 이 층의 정량 데이터다.

2. Review. 생성된 코드를 머지 전에 정적으로 검증한다.

  • Multi-agent 리뷰. 한 모델 출력을 다른 모델, 다른 prompt로 cross-check. 단일 모델 stability(3편 n=3 기준 Sonnet 87%, Haiku 73%)에 기대지 않는다.
  • 정적 분석. 룰 기반 패턴 검출. volatile 누락, ISR blocking, error path cleanup, 49일 wrap처럼 grep으로 잡히는 안티패턴.
  • 결정론적 분석기. 보드, errata, contract, requirement를 git YAML facts로 두고, LLM 생성 시점과 CI 게이트에 같은 사실을 먹인다. 정적 분석이 보드 컨텍스트 없이 못 잡던 결함이 여기서 걸린다. eMMC wear 누적 패턴, board-specific contract 위반, “이 카운터가 32-bit이라 wrap 난다” 같은 board-fact 기반 검증이 그 예다. 이 층이 잘 붙으면 SDMA 같은 카테고리도 Tier 2로 내려온다.
  • 휴먼 전문가 리뷰. 마지막 게이트. 앞의 자동 단계를 깔아두면, 전문가 시간이 시스템 레벨 판단(아키텍처 적합성, novel 결함, 도메인 trade-off)에 쏠린다.

3. Test. 실행으로 동작을 검증한다.

  • TDD. 테스트 케이스가 코드보다 먼저. LLM이 환각으로 메우는 자리를 줄여준다.
  • On-board 테스트. 실 보드 1대를 CI에 물린 HIL. QEMU가 못 보는 DMA 캐시 일관성, 인터럽트 latency, 클락 지터를 잡는다.

각 단계의 도구 선택, 층별로 얼마나 깊게 넣을지, 층 사이 정보 흐름은 다음 편에서 푼다.

한계

3-Tier Trust는 결국 분류다. 분류만으로는 결함을 못 잡는다. 위 검증 게이트랑 같이 굴러야 한다. Board Profile, datasheet RAG, HIL farm 같은 context engineering 영역이 이 게이트들의 인프라다.

EmbedEval은 90% 넘게 Zephyr다. ESP-IDF나 STM32 HAL로 가면 Tier 경계가 달라질 수 있다. 자기 플랫폼 숫자는 자기가 재야 한다.

마지막 한계가 제일 무겁다. Tier 분류는 전문가 없는 팀엔 해법이 못 된다. Tier 3에서 처음부터 쓸 사람이 없으면 LLM 출력을 감별할 수조차 없어서다. 이러면 LLM 도입은 생산성이 아니라 위험을 키운다. 1편의 eMMC 사망이 그 증거다. Tier 분류는 사고를 막은 게 아니라, 뒤늦게 라벨만 붙였을 뿐이다.

정리

1편은 LLM이 짠 코드가 eMMC를 죽인 사례. 2편은 그 실패가 6가지 패턴으로, Tier 3에 몰린다는 분류. 3편은 경계가 어디쯤인지 숫자로 측정. 4편인 이번 글은 그 측정을 운영 룰의 큰 그림으로 옮긴 거고, 검증 게이트 파이프라인의 overview다. 다음 편에서 게이트 하나하나를 도구·구성·trade-off로 뜯는다.

i.MX8M의 SDMA 수정은 dma_alloc_coherent() 한 줄이다. 하지만 그 한 줄을 쓸 판단은 레퍼런스 매뉴얼과 오실로스코프에서 나왔다. 토큰에서 나온 게 아니다. 시리즈 전체가 이 한 문장으로 요약된다.

ecro
글쓴이 ecro

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

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

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

댓글

댓글 불러오는 중...