본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 23. 07:42

DocFX를 위한 Markdig 확장 기능 구축: AI 재작성을 통한 원격 콘텐츠 포함

요약

DocFX의 한계를 극복하기 위해 원격 마크다운 콘텐츠를 빌드 시점에 가져와 삽입하는 Markdig 확장 기능인 docfx-remote-include를 소개합니다. 이 도구는 LLM을 활용하여 가져온 콘텐츠의 어조와 스타일을 주변 문맥에 맞게 자동으로 재작성하는 AI 기능을 선택적으로 제공합니다.

핵심 포인트

  • DocFX의 공식 확장 지점을 활용하여 업스트림 업데이트와 호환성 유지
  • HTTP를 통해 원격 마크다운 콘텐츠를 블록 또는 인라인 모드로 삽입
  • LLM을 이용해 가져온 콘텐츠의 어조와 스타일을 자동 조정하는 AI 재작성 기능
  • 특정 벤더에 종속되지 않는 플러그형 IRewriteService 아키텍처 채택

모든 문서화 팀이 직면하는 문제
어떤 규모의 문서화 플랫폼에서든 일해 보셨다면, 다음과 같은 문제에 부딪혀 보셨을 것입니다. 콘텐츠가 여러 곳에 존재하며, 빌드 시점에 이를 하나의 일관된 사이트로 구성해야 한다는 점입니다. API 레퍼런스는 코드에서 생성될 수도 있고, 문제 해결 가이드는 별도의 서비스에 있을 수도 있습니다. 서로 다른 팀이 각기 다른 섹션을 관리하고 있을 수도 있으며, 복제되는 순간 노후화되는 콘텐츠를 일일이 복사해서 붙여넣지 않고 하나의 DocFX 사이트로 통합해야 할 수도 있습니다.

Microsoft의 오픈 소스 문서 생성기인 DocFX는 로컬 Markdown (마크다운) 파일로부터 정적 문서를 구축하는 데 매우 뛰어납니다. 하지만 빌드 시점에 원격 소스로부터 콘텐츠를 가져와 인라인(inlining)으로 삽입하는 기능을 기본적으로 지원하지는 않습니다. 저에게는 바로 그 기능이 필요했습니다. 그래서 직접 만들었습니다.

docfx-remote-include 소개
docfx-remote-include는 DocFX에 원격 콘텐츠 포함 기능을 추가하는 독립적인 Markdig 확장 기능이자 CLI (Command Line Interface) 도구입니다. 이는 DocFX의 포크(fork)가 아닙니다. DocFX의 공개된 BuildOptions.ConfigureMarkdig 확장 지점에 연결되므로, 일반적인 NuGet 의존성으로서 업스트림 릴리스를 추적합니다. DocFX가 업데이트되어도 원격 포함 기능이 깨지지 않습니다.

지시어 (The Directive)
DocFX에 의해 처리되는 모든 Markdown 파일에서 다음과 같이 작성할 수 있습니다:

Some local content.
[ !remoteincludeWelcome ]
More local content.

빌드 시점에, 이 확장 기능은 HTTP를 통해 {baseUrl}/path/to/snippet.md를 가져오고, 응답을 Markdown으로 파싱한 뒤 그 결과를 인라인으로 삽입합니다. 두 가지 모드로 작동합니다:

블록 모드 (Block mode) — 지시어가 해당 라인의 유일한 요소일 때, 가져온 콘텐츠는 전체 블록 콘텐츠(제목, 목록, 단락 등)로 인라인 삽입됩니다.
인라인 모드 (Inline mode) — 지시어가 단락 중간에 나타날 때, 인라인 콘텐츠만 끼워 넣어집니다 (감싸는 <p> 태그 없음).

AI의 반전
여기서부터 흥미로워집니다.

선택적으로 재작성 힌트(rewrite hint)를 추가할 수 있습니다: [ !remoteinclude[Install ]( snippets/install.md "match this page's tone and tense" ) ]. 힌트가 제공되면, 가져온 콘텐츠는 사용자가 선택한 모든 LLM(Azure OpenAI, 로컬 모델 등 무엇이든)을 기반으로 하는 플러그형 IRewriteService를 거치게 되며, 이를 통해 콘텐츠가 주변 페이지의 어조와 스타일에 맞게 조정됩니다. 힌트가 없으면 콘텐츠는 있는 그대로(verbatim) 인라인 처리됩니다. AI 기능은 완전히 선택 사항(opt-in)이며 특정 벤더 종속성(vendor lock-in)이 전혀 없습니다.

아키텍처 결정 사항

왜 포크(Fork)가 아닌 확장 기능(Extension)인가?

DocFX를 포크하는 것은 병렬 코드베이스를 유지해야 함을 의미하며, 업스트림(upstream)의 개선 사항을 따라가지 못하게 됩니다. 대신, docfx-remote-include는 DocFX가 노출하는 공개 ConfigureMarkdig 접점(seam)을 사용합니다:

await Docset.Build("docs/docfx.json", new BuildOptions
{
    ConfigureMarkdig = pipeline => pipeline.UseRemoteInclude(client, options),
});

이는 다음을 의미합니다:

  • DocFX 내부 구현에 따른 유지보수 부담 제로
  • ConfigureMarkdig를 노출하는 모든 DocFX 버전과 호환
  • 다른 Markdig 확장 기능과 결합 가능

인증 유연성

기업용 문서(Enterprise documentation)는 종종 인증 뒤에 존재합니다. 이 확장 기능은 다음과 같은 여러 인증 모드를 기본적으로 지원합니다:

| 모드 | 사용 사례 |
| :--- | : |
| none | 공개 콘텐츠 서비스 |
| default | Azure 기본 자격 증명 (로컬 개발, CI/CD) |
| managedIdentity | Azure Managed Identity (운영 환경) |
| jwt | Bearer 토큰 (사용자 정의 인증) |
| key | API 키 헤더 |

모든 자격 증명은 환경 변수 또는 호스트 콜백(host callbacks)에서 읽으며, 소스 제어에 커밋되는 설정 파일로부터는 절대 읽지 않습니다.

안전 기능

빌드 파이프라인으로 원격 콘텐츠를 가져올 때는 문제가 발생할 수 있습니다:

  • 순환 탐지 (Cycle detection)AsyncLocal 소스 스택을 사용하여 원격 콘텐츠가 다른 원격 콘텐츠를 포함할 때 발생하는 무한 재귀를 방지합니다. 최대 깊이(Max depth)는 기본값 8로 설정됩니다.
  • 동시성 제어 (Concurrency control) — 콘텐츠 서비스에 과부하가 걸리는 것을 방지하기 위해 진행 중인 요청(in-flight requests)은 기본적으로 8개로 제한됩니다.
  • 프로세스 내 캐싱 (In-process caching) — 각 소스 URL은 해당 페이지를 참조하는 페이지 수와 관계없이 빌드당 한 번만 가져옵니다.

기본적으로 실패 처리 (Hard fail by default) — 원격 소스가 404를 반환하면 빌드가 실패합니다. 대신 눈에 보이는 에러 플레이스홀더 (error placeholder)를 렌더링하려면 --allow-missing 옵션을 사용하세요.

시작하기

CLI 도구로서 사용하기

NuGet 소스 추가 (1회성)

dotnet nuget add source "https://nuget.pkg.github.com/saipramod/index.json" \
--name "saipramod" --username YOUR_GITHUB_USERNAME --password YOUR_GITHUB_PAT

도구 설치

dotnet tool install -g Docfx.RemoteInclude.Cli --source "saipramod"

문서 빌드

docfx-ri build docs/docfx.json

설정

docfx.json 옆에 remoteinclude.json을 생성합니다:

{
  "baseUrl" : "https://your-content-service.com/" ,
  "allowMissing" : false ,
  "urlTemplate" : "api/content/GetFile?path={source}" ,
  "auth" : {
    "mode" : "managedIdentity" ,
    "scope" : "api://your-app-id/.default"
  },
  "ai" : {
    "endpoint" : "https://your-aoai.openai.azure.com/" ,
    "deployment" : "gpt-4o-mini" ,
    "contextStrategy" : "section"
  }
}

라이브러리로 사용하기

완전한 제어를 위해 라이브러리를 직접 사용하세요:

using Docfx ;
using Docfx.RemoteInclude ;

using var client = new HttpRemoteContentClient (
    baseUri : new Uri ("https://your-content-service.com/") ,
    authHandler : async ( request , ct ) => {
        request . Headers . Authorization = new ( "Bearer" , await GetJwtAsync ( ct ));
    });

await Docset . Build ( "docs/docfx.json" , new BuildOptions {
    ConfigureMarkdig = pipeline => pipeline
        .UseRemoteInclude ( client , new RemoteIncludeOptions {
            RewriteService = myRewriter ,
            // 선택 사항
        }),
});

HTTP가 아닌 소스(파일 시스템, 데이터베이스, 서명된 URL)의 경우 IRemoteContentClient를 구현하세요. 어떤 LLM(대규모 언어 모델)이든 연결하려면 IRewriteService를 구현하세요.

이것이 중요한 이유

대규모 문서화 플랫폼은 여러 권위 있는 소스로부터 콘텐츠를 구성해야 합니다. 복사하여 붙여넣기(Copy-pasting)는 내용의 불일치(drift)를 발생시킵니다. Git 서브모듈(submodules)은 복잡성을 더합니다. 커스텀 빌드 스크립트는 취약합니다. docfx-remote-include는 DocFX의 기존 파이프라인(pipeline) 내에서 작동하는 깔끔하고 선언적인 구문을 통해 이 문제를 해결합니다.

선택적인 AI 재작성 (AI rewriting) 기능은 서로 다른 소스에서 가져온 콘텐츠가 마치 해당 페이지를 위해 작성된 것처럼 읽힐 수 있음을 의미합니다. 이 프로젝트는 MIT 라이선스를 따르는 오픈 소스이며, 기여를 기다리고 있습니다. GitHub: github.com/saipramod/docfx-remote-include. Sai Pramod Upadhyayula는 Microsoft의 시니어 소프트웨어 엔지니어 (Senior Software Engineer)로, AI 기반 엔터프라이즈 지식 플랫폼 (AI-powered enterprise knowledge platforms) 분야에서 활동하고 있습니다. 그는 "AutoTSG: Learning and Synthesis for Incident Troubleshooting" (ESEC/FSE 2022)의 공동 저자이며, DocFX 오픈 소스 생태계에 기여하고 있습니다.

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0