본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 04. 16:05

【#7】ds4.c 분석하기

요약

DeepSeek V4 Flash/Pro 전용 추론 엔진인 DwarfStar(ds4)의 네이티브 코딩 에이전트인 ds4-agent의 구조를 분석합니다. HTTP API 경계 없이 엔진과 직접 상호작용하여 KV 일관성 문제를 해결하고 수직 통합된 성능을 제공하는 설계 방식에 집중합니다.

핵심 포인트

  • API 경계 없는 네이티브 에이전트로 KV 일관성 문제 해결
  • DeepSeek V4 전용 DSML 기반의 최적화된 툴 디스패치
  • 온디스크 KV 캐시를 활용한 세션 관리 및 영속성 유지
  • 수직 통합을 통한 로컬 추론 에이전트의 실효성 검증

본 시리즈는 DeepSeek V4 Flash / Pro 전용 추론 엔진인 DwarfStar(ds4)의 코드를 분석하는 연재입니다.

제7회는 ds4-agent를 다룹니다. OpenAI/Anthropic 호환 서버가 아니라, 추론 엔진을 동일한 프로세스 내부에서 직접 조작하는 네이티브 코딩 에이전트(Native Coding Agent)입니다. 주요 참조 부분:

README.md, AGENT.md, ds4_agent.c, ds4_kvstore.c, ds4.h

관전 포인트: HTTP 경계를 벗어나면, 서버 편에서 고생했던 KV 일관성(Consistency) 문제가 "구조적으로 발생하지 않는" 상태가 됩니다. 그 트레이드오프(Trade-off)를 읽어봅니다.

  • ds4-agent는 HTTP API 경계를 가지지 않습니다. UI 스레드와 워커 스레드(Worker Thread)는 분리되어 있지만, 워커가 라이브(Live) ds4_session과 KV 상태를 직접 소유합니다. - README는 에이전트의 세션이 온디스크(On-disk) KV 캐시 그 자체로 표현된다고 설명하고 있습니다.
  • 서버 편에서 필요했던 OpenAI/Anthropic JSON과 DSML 간의 왕복 변환이 줄어듭니다. 에이전트의 툴 프롬프트(Tool Prompt)는 DeepSeek V4용 DSML을 전제로 만들어지며, 툴 실행도 네이티브 DSML 파서(Parser)에서 직접 디스패치(Dispatch)됩니다.
  • 세션은 ~/.ds4/kvcache에 저장되며, /save, /list, /switch, /del, /strip으로 조작할 수 있습니다. - 저장된 세션의 ID는 첫 번째 사용자 프롬프트 유래 타이틀과 생성 시각으로부터 SHA1을 통해 생성합니다. 다시 저장해도 동일한 동일성(Identity)을 유지합니다.
  • 툴은 read, more, write, edit, search, list, bash, bash_status, bash_stop, google_search, visit_page 등입니다. 편집 프롬프트는 DS4의 저속 디코딩(Decoding)과 긴 문맥(Long Context)을 의식하여, 앵커(Anchor)가 포함된 편집을 강력하게 권장하고 있습니다. - ds4-agent는 README 상에서 명시적으로 alpha 품질로 분류되며(엔진 본체의 beta보다 앞선 단계), 프로젝트에 나중에 추가되었습니다. 그럼에도 불구하고 "로컬 추론을 에이전트로서 정말로 사용할 수 있는가"를 검증하기 위한 수직 통합(Vertical Integration)으로서 중요합니다.

제5회에서 보았던 ds4-server는 OpenAI/Anthropic 호환 API를 갖추기 위해 많은 변환을 수행했습니다.

  • OpenAI의 툴 호출(Tool Call) JSON
  • Anthropic의 tool_use 블록
  • OpenAI Responses의 아이템 라이프사이클(Lifecycle)
  • DeepSeek V4의 DSML 텍스트
  • 라이브 샘플링된 상태
  • 상태가 없는(Stateless) 클라이언트 트랜스크립트(Transcript)

이는 기존 클라이언트와 접속하기 위해서는 필요하지만, 복잡합니다.

반면 ds4-agent는 처음부터 DS4 / DeepSeek V4를 위해 만들어진 네이티브 에이전트입니다. README는 다음과 같이 설명합니다.

  • 추론은 에이전트 자신의 내부에서 제어됨
  • 소켓(Socket)/API 경계가 없음
  • 세션은 온디스크 KV 캐시 그 자체로 표현됨
  • 툴과 시스템 프롬프트는 DeepSeek V4 Flash / Pro를 위해 수직 설계됨

요컨대, 기존 API 호환이 아니라 "이 엔진과 이 모델에 가장 잘 맞는 에이전트"를 만드는 방향입니다.

ds4_agent.c의 서두 주석은 에이전트의 스레드 모델을 설명하고 있습니다.

/* The agent is intentionally a single process: the UI thread owns terminal
* input/output, while the worker thread owns the live DS4 session and KV state.
* ... used to render sampled assistant text and DSML tool calls as they arrive.
...

서버에서는 클라이언트 스레드가 요청을 큐(Queue)에 쌓고, 단일 그래프 워커가 처리했습니다. 에이전트에서도 라이브 세션을 워커 측에 가두는 생각은 동일합니다.

다른 점은 외부 HTTP 프로토콜이 없다는 것입니다. UI는 터미널 입력과 표시를 담당하고, 워커(Worker)는 ds4_session, 트랜스크립트(Transcript), 도구 실행, KV 저장/로드(Save/Load)를 처리합니다.

agent_worker에는 다음과 같은 상태가 있습니다.

ds4_session *session;
ds4_tokens transcript;
char session_sha[41];
...

여기서 transcript는 렌더링된 채팅 토큰 열이며, session은 라이브 KV 체크포인트(Checkpoint)를 가진 실체입니다.

README에 따르면, 에이전트의 세션은 ~/.ds4/kvcache에 저장됩니다.

주요 명령어

명령어역할
/save현재 세션을 저장
/list저장된 세션을 최근 업데이트 순으로 표시
/switch <sha>세션을 재개
/del <sha>저장된 세션을 삭제
/strip <sha>무거운 KV 페이로드(Payload)를 삭제하고, 렌더링된 텍스트만 남김

/strip이 흥미롭습니다. KV 페이로드(Payload)는 크기 때문에, 필요 없게 되면 트랜스크립트(Transcript)와 제목만 남길 수 있습니다. strip 처리된 세션으로 switch 하면, 저장된 렌더링 텍스트를 프리필(Prefill)하여 KV를 재구축합니다.

전체 KV 세션이라면, switch 후에 프리필(Prefill) 없이 재개할 수 있습니다. 이는 README에서 언급하는 네이티브 에이전트(Native Agent)의 장점 중 하나입니다. 세션의 상태 전이를 도식화하면, "KV의 유무"가 중심에 있다는 것을 알 수 있습니다.

서버의 디스크 KV는 렌더링 후 바이트 프리픽스(Byte Prefix)의 SHA1을 파일명으로 사용했습니다. 에이전트의 세션에서는 조금 다른 동일성(Identity)을 사용합니다.

ds4_agent.c의 주석:

/* Modern sessions:
* SHA1(title || created_at_le64).kv, where title is the first user prompt and
* created_at is preserved across future saves. The title is stored in an
...

저장된 세션의 파일명은 첫 번째 사용자 프롬프트로 만든 제목과 생성 시각의 SHA1입니다. 다시 저장하여 트랜스크립트(Transcript)와 KV 페이로드(Payload)가 업데이트되어도, 세션의 동일성은 변하지 않습니다.

이는 에이전트의 UX에 부합합니다. 대화가 길어질 때마다 파일명이 바뀌면 /switch/list를 다루기 어려워집니다. 세션이라는 단위를 안정시키기 위해, 프리픽스 해시(Prefix Hash)가 아닌 제목 + 생성 시각을 사용하고 있습니다.

다만 파일 형식의 내부 내용은 제4회에서 보았던 KVC / DSV4와 동일한 흐름입니다. 에이전트 전용 타이틀 트레일러(Title Trailer)가 추가될 뿐입니다.

ds4_agent.c에는 에이전트용 도구 프롬프트(Tool Prompt)가 C 언어의 문자열로 임베딩(Embedded)되어 있습니다.

도입부는 다음과 같은 방침을 따릅니다.

  • 로컬 워크스페이스(Local Workspace)에서 동작하는 코딩 에이전트
  • 파일/시스템 작업에는 도구를 사용
  • 큰 파일 내용이나 큰 코드 블록을 답변으로 내놓지 않고, 도구로 생성/편집
  • DSML의 도구 기술을 엄격한 구문으로 작성
  • 도구 호출은 <think></think> 안에 넣어서는 안 됨

도구 프롬프트(Tool Prompt)는 DeepSeek V4의 DSML 토큰을 전제로 토크나이즈(Tokenize)됩니다.

/* The built-in tool prompt is trusted DS4 control text. Tokenize it like a
* rendered chat prompt so the literal DSML markers in the examples become
* the model's dedicated DSML token. Do not apply that tokenizer to user text.
...

이 부분은 중요합니다. 사용자 텍스트에 포함된 DSML 스타일의 문자열을 제어 토큰 (control token)으로 취급해서는 안 됩니다. 반면, 신뢰할 수 있는 시스템/도구 프롬프트 내의 DSML 마커는 모델에게 네이티브한 도구 구문 (tool syntax)으로 가르쳐야 합니다.

에이전트 프롬프트에는 사용 가능한 도구 스키마 (tool schema)가 직접 매립되어 있습니다.

대표적인 도구:

도구역할
read텍스트 파일 / 행 범위 읽기
more이전 read 계열 출력의 나머지 부분 읽기
write파일 생성 또는 전체 교체
editold/new를 이용한 정확한 단일 교체
search파일 검색
list디렉토리 목록
bash셸 명령 (shell command) 실행
bash_status장시간 실행 중인 bash 작업의 상태 확인
bash_stop실행 중인 bash 작업 중지
google_search가시적 브라우저를 통한 웹 검색
visit_pageURL을 가시적 브라우저로 열어 Markdown화

ds4_agent.c에는 각각의 구현 함수가 있습니다.

static char *agent_tool_read(...);
static char *agent_tool_write(...);
static char *agent_tool_edit(...);
...

서버 편에서처럼 OpenAI의 도구 스키마를 DSML로 변환하는 것이 아니라, 처음부터 DSML의 도구 스키마로서 프롬프트에 매립하며, 이를 네이티브 파서 (native parser)가 받아들입니다.

에이전트 프롬프트의 편집 지시는 실무적이고 흥미롭습니다.

write는 신규 파일 또는 의도적인 파일 전체 교체에 사용합니다. 일반적인 변경은 edit를 사용합니다. editold는 현재 파일에서 정확히 한 번만 일치해야 하며, 그렇지 않으면 실패합니다.

더 큰 교체의 경우, [upto]를 사용한 앵커링 (anchored) 편집을 권장합니다.

For large replacements, prefer anchored old text:
write the first lines, then [upto], then the final lines.

이는 로컬 LLM의 디코딩 속도와 컨텍스트 압박 (context pressure)을 잘 이해한 설계입니다.

거대한 파일 전체를 모델이 다시 출력하게 하면 속도가 느려지고 실수도 늘어납니다. 필요한 앵커를 read / search로 수집한 뒤, old/new의 좁은 차이(diff)만을 도구에 전달하는 것이 더 안정적입니다.

DS4 에이전트는 "모델이 똑똑하면 무엇이든 할 수 있다"가 아니라, 로컬 추론의 제약에 맞춰 워크플로우를 구축하고 있습니다.

에이전트 측에도 DSML 파서가 있습니다.

주석:

/* The model streams raw text tokens. This parser recognizes completed DSML
* tool stanzas and keeps a copy of the raw stanza for diagnostics. It is
* deliberately strict after the opening marker ...
...

파서의 상태는 다음과 같이 나뉩니다.

typedef enum {
AGENT_DSML_SEARCH,
AGENT_DSML_STRUCTURAL,
...

시작 마커를 찾기 전까지는 스트리밍 검출기 (streaming detector)가 어느 정도 처리하지만, DSML 블록으로 시작된 후에는 엄격하게 파싱합니다. 오타 복구 로직을 파서 본체에 너무 많이 넣지 않음으로써, 도구 실행의 오작동 (mis-fire)을 방지하고 있습니다.

도구 호출이 완료되면 agent_tool_call에 이름과 인자 (argument)가 들어가며, 네이티브 도구 디스패치 (tool dispatch)로 전달됩니다.

에이전트는 가공되지 않은 어시스턴트 텍스트와 도구 호출을 터미널에 표시합니다. agent_tool_visualizer는 도구 이름이나 파라미터 타입에 따라 표시 방식을 바꿉니다.

예를 들어:

  • read는 경로와 행 범위를 컴팩트하게 표시
  • bash의 명령은 눈에 띄는 색상으로 표시
  • editold/new는 diff 스타일로 표시
  • write / edit의 코드 본체는 코드로 취급

이 부분은 추론 엔진(Inference Engine) 그 자체는 아니지만, 네이티브 에이전트(Native Agent) 경험에는 효과적입니다. 도구 호출(Tool Calling)이 숨겨진 JSON으로서 백그라운드에서 발생하는 것이 아니라, 모델이 무엇을 하려고 하는지를 스트리밍(Streaming) 중에 보여줍니다.

긴 세션에서는 초기 시스템/도구 프롬프트(System/Tool Prompt)가 문맥(Context)의 먼 위치로 흘러가 버립니다. 에이전트는 일정 토큰 수마다 시스템 프롬프트 리마인더(System Prompt Reminder)를 재주입합니다.

#define AGENT_SYSTEM_PROMPT_REMINDER_TOKENS 50000

agent_worker_maybe_append_system_prompt_reminder()는 이전 리마인더로부터 50k 토큰 이상 진행되면, 도구 프롬프트와 추가적인 시스템 지시사항을 다시 트랜스크립트(Transcript)에 넣습니다.

이는 긴 문맥 모델(Long Context Model)에서도 실용적으로 중요합니다. 1M의 문맥이 있더라도, 에이전트의 도구 구문(Tool Syntax)이나 편집 규칙(Editing Rules)은 정기적으로 가까운 위치로 되돌려 놓는 것이 안정적입니다.

에이전트 프롬프트에는 google_searchvisit_page도 있습니다. 구현 주석에는 Web 서브시스템은 Chrome을 실행하고, 에이전트 측은 권한(Permission), 도구 디스패치(Tool Dispatch), visit_page의 상한(Limit)을 다룬다고 되어 있습니다.

첫 번째 Web 호출 시에는 사용자 권한을 요구하는 설계입니다. 이는 네이티브 에이전트가 로컬 머신 외부로 나가는 경계(Boundary)이므로, 파일 도구(File Tool)와는 취급이 다릅니다.

서버 호환 API(Server Compatible API)만으로는 이러한 종류의 UI/권한 플로우를 넣기가 어렵지만, 네이티브 에이전트라면 터미널 UI와 워커 상태(Worker State) 안에 직접 통합할 수 있습니다.

README에서 언급하는 장점을 구현 관점에서 다시 말하면 다음과 같습니다.

장점구현상의 이유
저지연 (Low Latency)소켓/API 경계가 없으며, 워커가 세션을 직접 보유함
...

한편, README는 ds4-agent를 alpha 품질로 정의하며, prime time에는 아직 작업이 필요하다고도 적고 있습니다. 향후에는 네이티브 에이전트에서 얻은 형태를 바탕으로, 상태 유지형 세션 프로토콜(Stateful Session Protocol)을 가진 서버/클라이언트 분리 방식으로 나아갈 가능성이 제시되어 있습니다.

이는 자연스러운 진화입니다. OpenAI/Anthropic 호환 API는 기존 클라이언트 연결에 강점이 있습니다. 반면, 네이티브 에이전트는 DS4에 최적화된 UX와 상태 모델(State Model)을 시험해 볼 수 있습니다. 이 실험 결과를 상태 유지형 프로토콜로 되돌릴 수 있다면, 양자의 장점을 결합할 수 있습니다.

ds4-agent는 DwarfStar의 '추론 엔진 + 전용 GGUF + 에이전트 검증'이라는 사상의 C에 해당하는 부분입니다.

  • 엔진과 동일한 프로세스 내에서 라이브 세션(Live Session)을 조작한다
  • 세션 저장은 온디스크(On-disk) KV 캐시 그 자체이다
  • 도구 호출은 DSML 네이티브이며, JSON 호환 계층을 통하지 않는다
  • 도구 프롬프트는 로컬 코딩 워크플로우에 강력하게 밀착되어 있다
  • /save, /list, /switch, /strip으로 장시간의 로컬 세션을 다룬다
  • 시스템 프롬프트 리마인더나 앵커(Anchor)가 포함된 편집 등, 로컬 추론의 제약에 맞춘 고안이 들어있다

다음 회차는 최종회로서, DwarfStar의 주변 실험 기구들을 정리합니다. directional steering, MTP speculative decoding, ds4-eval, ds4-bench, 자체 데이터 구조 등, 연재 본편에 다 담지 못했던 기술적인 볼거리들을 짚어보겠습니다.

본 기사는 퀵이테레이트 주식회사(Quick Iterate Co., Ltd.)의 로컬 LLM 연구의 일환으로, 공개 리포지토리 antirez/ds4의 코드를 분석한 것입니다. 행 번호, 상수, 벤치마크 값은 열람 커밋 ba00a8a (2026-05-30) / README 취득일 2026-06-01 시점의 것입니다. ds4-agent는 alpha, 엔진 본체는 beta 품질로 활발하게 변화하므로, 인용 부분은 각자 최신 README / 소스를 확인하여 재검토하시기 바랍니다.

퀵이테레이트 주식회사 (Quick Iterate Co., Ltd.)

IoT / 전력 모니터링 / AI / 위성·무선 통신 / 시스템 통합/

로컬 LLM·에이전트 기반에 관한 문의는 언제든 환영합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0