AI 기반 코드 편집기 만들기: (part 2) LLM 같은 인터프리터

발행: (2025년 12월 30일 오전 07:42 GMT+9)
14 min read
원문: Dev.to

Source: Dev.to

인사이트

LLM CodeForge를 구축하면서, LLM이 코드를 자율적으로 읽고, 수정하고, 테스트할 수 있게 하는 에이전트 편집기를 만들고 있었는데, 5 000 토큰에 달하는 지시문을 작성한 뒤에 나는 다음을 깨달았습니다:

나는 프롬프트를 작성하고 있던 것이 아니라, 자연어에 내장된 도메인‑특정 언어(DSL)를 만들고 있었다.

이 글에서는 이 구분이 왜 근본적인지, 그리고 여러분이 자체 에이전트 시스템에 대해 무엇을 배울 수 있는지를 분석합니다.

모델이 CodeForge에서 행동하는 방식

측면모델이 하는 일모델이 하지 않는 일
의사결정프로토콜의 어느 분기를 따를지 선택합니다결정하지 않습니다
문제 해결자연어로 설명된 절차를 실행합니다창의적으로 문제를 해결하지 않습니다
특성바이트코드 인터프리터, 텍스트 기반 유한 상태 머신, 혹은 닫힌 행동을 가진 플래너처럼 동작합니다결정론적 제어 흐름에 의존하며, 개방형 추론에 의존하지 않습니다
신뢰성LLM이 근본적으로 신뢰할 수 없음을 인정하기 때문에 작동합니다해당 없음

DSL 제어 흐름

모든 요청은 단계로 진행됩니다:

[UNDERSTAND] → [GATHER] → [EXECUTE] → [RESPOND]

단계 1 – UNDERSTAND

요청 유형 분류

유형키워드다음 단계
설명“what is”, “explain”[RESPOND] (text)
수정“add”, “change”[GATHER] → [EXECUTE]
분석“analyze”, “show”[GATHER] → [RESPOND]

이는 고전적인 체인‑오브‑생각이 아닙니다. 이는 결정적 작업 라우팅—입력 → 워크플로를 매핑하는 결정표입니다. 모델은 “생각”하지 않고 조건 점프를 실행합니다.

불변 규칙

🚨 중요 규칙: 이 대화에서 아직 읽지 않은 파일에 대해 update_file사용할 수 없습니다.

update_file을 사용하기 전 자체 점검

  • 시스템으로부터 내용을 받았나요?
  • 현재 정확한 상태를 알고 있나요?
  • 실제 코드를 기반으로 수정하고 있나요?

어느 하나라도 아니오라면 → read_file 동작출력하고, 중단하세요.

이것은 자연어로 전제 조건을 정의하려는 시도입니다. 다음과 유사합니다:

def update_file(path, content):
    assert path in conversation_state.read_files
    # ... actual update

타입 시스템이나 자동 런타임 강제 적용이 없기 때문에, 이 규칙은 파일을 먼저 읽지 않고 수정하는 가능성을 줄이지만 완전히 없애지는 못합니다. 테스트에서는 ~85‑90 % 안정성을 관찰했지만, 중요한 경우에는 서버 측 검증이 여전히 필수입니다.

Source:

Multi‑File Tasks: Prompt Regeneration

제가 구현한 가장 효과적인 기법은 프롬프트를 동적으로 재생성하여 LLM이 다단계 계획을 따르도록 강제하는 것입니다.

구체적인 시나리오

사용자 요청: “프로젝트에 인증을 추가해 주세요.”

  1. 계획 수립 – LLM이 계획을 생성합니다:
{
  "plan": "I will modify these files in order:",
  "files_to_modify": ["Auth.js", "Login.jsx", "App.jsx"]
}
  1. 첫 번째 파일 – LLM이 Auth.js를 작업하고 완료합니다.

  2. 트릭 – LLM에게 “계획을 기억하라”고 요청하는 대신, 프롬프트를 재생성하면서 명시적인 “다음‑작업” 블록을 삽입합니다:

### ⚠️ MULTI‑FILE TASK IN PROGRESS

You completed: Auth.js  
Remaining files: Login.jsx, App.jsx

### 🚨 REQUIRED ACTION
Your next output MUST be:
{"action":"continue_multi_file","next_file":{"path":"Login.jsx"}}

Do NOT do anything else. Do NOT deviate from the plan.

LLM은 더 이상 “계획을 기억”할 필요가 없습니다. 가능한 행동은 프롬프트에 이미 고정되어 있습니다.

왜 강력한가

  • 상태(완료된 파일, 남은 파일)는 외부 JavaScript에 저장되며, LLM의 메모리에 의존하지 않습니다.
  • 각 단계마다 업데이트된 상태를 포함해 프롬프트를 재생성합니다.
  • LLM은 항상 단일하고 명확한 지시만을 받습니다.

구현 스케치

// In the code
function buildPrompt(multiFileState) {
  let prompt = BASE_PROMPT;

  if (multiFileState) {
    prompt += `
### TASK IN PROGRESS
Completed: ${multiFileState.completed.join(', ')}
Next: ${multiFileState.next}
Your ONLY valid action: continue_multi_file with ${multiFileState.next}
`;
  }

  return prompt;
}

이는 **상태 주입(state injection)**이며, 외부 상태가 LLM이 다음에 수행할 수 있는 작업을 완전히 제어합니다.

혼합 콘텐츠를 위한 사용자 정의 구분자

다양한 “형식”(JSON, 코드, 메타데이터)을 처리하기 위해 DSL은 사용자 정의 구분자를 사용합니다:

#[json-data]
{"action":"create_file","file":{"path":"App.jsx"}}
#[end-json-data]

#[file-message]
This file implements the main app component.
#[end-file-message]

#[content-file]
export default function App() {
  return Hello World;
}
#[end-content-file]

일반 JSON이나 XML을 사용하지 않는 이유

  • 내용에 {}, <> 등과 같은 문자가 포함될 수 있어 복잡한 이스케이프가 필요합니다.
  • #[tag]…#[end-tag]구문적으로 고유하며 정규식으로 쉽게 파싱할 수 있고, 삽입된 언어와 무관합니다.
  • 이는 문맥 자유 문법처럼 동작하여 의미 계층을 분리합니다.

오류‑예시 가이드

DSL에 “오류 예시”를 직접 삽입하면 모델에게 일반적인 실패 모드를 가르치는 인라인 단위 테스트와 같은 효과가 있습니다.

❌ 잘못된 예✅ 올바른 예
{"action":"start_multi_file","plan":{},"first_file":{...}}{"action":"start_multi_file","plan":{},"first_file":{...}}
#[json-data]{...}#[file-message]...#[json-data]{...}#[end-json-data]#[file-message]...

자연어 DSL의 트레이드오프

제한결과
❌ 검증 가능한 타입 없음정적 타입 검사가 이루어지지 않음
❌ 자동 구문 검증 없음오류는 런타임에 잡혀야 함
❌ 변환을 위한 AST 없음컴파일 타임 최적화가 없음

보완책

  • 방대한 검증 체크리스트 (8+ 항목)
  • 의미 중복 – 동일한 규칙을 여러 방식으로 표현
  • 광범위한 안티패턴 문서화

자연어로 DSL을 구축할 때 이러한 트레이드오프는 불가피하지만, 결과 시스템은 여전히 견고하고, 투명하며, 제어 가능합니다.

개요

파서는 결정론적 컴파일러가 아니라 확률적 LLM입니다.
앞으로 CodeForge를 발전시킨다면, 진정한 미니‑DSL (JSON Schema + codegen)이 프롬프트 크기를 30‑40 % 줄일 수 있습니다. 그러나 브라우저 샌드박스에서는 현재 선택이 정당합니다.

Pre‑Send Checklist

EVERY 응답 전에 다음을 확인하십시오:

#체크 항목실패 시 수정 방법
1JSON 유효성구조 수정
2태그 완전성누락된 #[end-*] 태그 추가

단독으로는 40‑60 % 신뢰성을 제공합니다. 내 시스템에서는 **80‑90 %**에 도달하는데, 이는 다음과 같은 경우 안정성 승수 역할을 하기 때문입니다:

  • 모델이 이미 채널링되어 있을 때 (결정 프로토콜)
  • 형식이 경직되어 있을 때 (맞춤 구분자)
  • 다음 동작이 결정론적일 때 (상태 주입)

Meta‑validation은 주된 기능이 아니라, 이미 제한된 시스템에서 최종 안전망 역할을 합니다.

모델 호환성

✅ Works well with Claude 3.5, GPT‑4  
❌ Smaller models will fail  
❌ Less‑aligned models will ignore sections

나는 암묵적으로 말하고 있다: 이 시스템은 “진지한” 모델을 필요로 한다.
이는 내가 받아들인 아키텍처 제약이며 — “이 라이브러리는 Python 3.10+을 필요로 합니다.” 라고 말하는 것과 같다.

맥락 재정렬

“읽고‑쓰기 전” 규칙을 적용합니다:

  • Decision Protocol(계획 단계)에서 나타남
  • Available Actions(실행 단계)에서 나타남
  • Pre‑Send Validation(검증 단계)에서 나타남
  • Golden Rules(일반 원칙)에서 나타남

이는 전략적 반복이며, 무작위 중복이 아닙니다. 안전‑중요 시스템을 닮았습니다:

  • 동일한 불변식
  • 여러 수준에서 검증됨
  • 각 상황에 맞는 구체적인 문구 사용

Pattern Examples

Bad vs. Good Patterns

// BAD: Relying on the model's "memory"
"Remember that you have already read these files..."

// GOOD: Injecting explicit state
prompt += `Files already read: ${readFiles.join(', ')}`

// BAD: Giving open choices
"Decide which operation to perform"

// GOOD: Forcing the only legal move
"Your NEXT action MUST be: continue_multi_file"

Input → Action → Next State

입력 패턴동작다음 상태
"add X"GATHEREXECUTE
"explain Y"RESPONDEND

“think what to do” 대신 “if X then Y” 를 사용하세요.

Embedding Arbitrary Content

  • Don’t use JSON – escaping nightmare
  • Don’t use XML – conflicts with HTML/JSX
  • Use unique tags: #[content]…#[end-content]

Pattern #5 – Redundancy = Coverage, Not Noise

  • 핵심 규칙을 반복
    • 다른 표현 방식으로 (semantic reinforcement)
    • 다른 맥락에서 (contextual re‑anchoring)
    • 다른 근거와 함께 (why, not just what)

5 000 토큰과 수개월에 걸친 반복 후, 가장 중요한 교훈은 다음과 같습니다:

This prompt is not “beautiful.” It is effective.

Optimization Shift

❌ 찾던 것을 중단함✅ 최적화 시작
가능한 가장 짧은 프롬프트극한 상황에서의 견고함
가장 우아한 표현실패 모드 커버리지
가장 일반적인 추상화실패 시 디버깅 명확성

Result:

  • Redundant? Yes. → * 중복? .
  • Verbose? Absolutely. → * 장황? 절대적으로.
  • Works? Consistently. → * 작동? 일관되게.

Future Directions: Where I Could Go

If I were to evolve CodeForge 2.0, I would explore a two‑agent architecture instead of a single 5 000‑token agent:

AgentToken BudgetRole
Planner Agent2 000Decides strategy
Executor Agent2 000Implements actions

Benefits

  • Separation of concerns
  • Less context per agent
  • Parallel execution possible

핵심 기술

RatingTechnique
⭐⭐⭐⭐⭐상태 주입 + 강제 다음 행동
⭐⭐⭐⭐⭐작업 라우팅을 위한 의사결정 테이블
⭐⭐⭐⭐⭐구조화된 출력용 사용자 정의 구분자
⭐⭐⭐⭐⭐불변식의 맥락적 재정착
⭐⭐⭐⭐안전망으로서의 메타‑검증
⭐⭐⭐시각적 계층 구조(유용하지만 필수는 아님)

근본 원칙:
LLM에게 “이해”하도록 요구하지 말고 “실행”하도록 강제하라.

프로토콜을 DSL로 취급하고, 대화가 아니라 DSL로 다루어라. 외부 상태가 가능한 행동을 제한해야 하며, 검증은 항상 서버‑ 또는 클라이언트‑측에서, 예외 없이 이루어져야 한다. 중복성은 버그가 아니라 기능이 될 수 있다.

행동 요청

CodeForge 사용해 보기:

이 프로젝트는 오픈 소스이며, 전체 프롬프트와 검증 시스템 구현이 저장소에 공개되어 있습니다.

커뮤니티 질문

  1. 자연어로 임베디드 DSL을 구축해 본 적이 있나요?
  2. 프롬프트에서 “인지적 오버헤드”의 비용은 얼마나 되나요?
  3. 두 에이전트 아키텍처와 단일 에이전트: 경험은 어떠했나요?

댓글로 공유해주세요 — 아직 대부분 미탐색 영역입니다.

Back to Blog

관련 글

더 보기 »