ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring AI 시리즈 11화 – ChatClient 고급 프롬프트 구성 전략과 문서 삽입 기법
    기술과 산업/AI 2025. 8. 13. 10:55
    728x90

    RAG 시스템에서 검색된 문서를 프롬프트에 어떻게 구성하느냐에 따라 LLM의 응답 품질이 결정됩니다. 이 글에서는 Spring AI의 ChatClient를 활용한 고급 프롬프트 구성 방식과 문서 삽입 전략을 실전 예제 중심으로 소개합니다.

     


     

    단순하게 “문서를 넣자”는 위험한 생각

     

    많은 초보 구현에서 이런 식의 프롬프트가 사용됩니다.

    [문서들]
    
    {document1}
    {document2}
    {document3}
    
    질문: 사용자가 입력한 질문
    답변:

    이 구조, 잘못되진 않았지만 지나치게 단순하고, 모델에게 역할이 명확하지 않으며, 문맥 유지가 어렵습니다.

    특히 여러 문서를 삽입하면 모델은 어디까지를 참고해야 할지 혼란스러워합니다.

     

    고급 RAG 시스템은 단순히 “문서를 붙이는” 수준을 넘어서야 합니다.

    Spring AI의 ChatClientPromptTemplate은 이를 구조화하고 반복 가능한 방식으로 프롬프트를 설계하는 데 유리한 도구입니다.

     


     

    구성 전략 1 – 역할(Role)과 목표(Objective)를 명확히 명시하자

     

    예시:

    당신은 고객 문서 기반으로 질문에 정확히 답하는 AI 비서입니다.  
    아래 제공된 문서를 기반으로만 답변해주세요.  
    추측하지 말고, 문서에 명확히 존재하는 정보만 사용하세요.
    
    [문서 내용]
    {context}
    
    [질문]
    {question}
    
    [답변]

    LLM은 맥락과 역할, 제한사항을 명확히 설명할수록 더 안정적이고 일관된 응답을 생성합니다.

     


     

    구성 전략 2 – 문서들을 구조화된 형태로 삽입

     

    단순한 나열이 아닌, 각 문서를 명시적으로 구분하고, 출처 또는 제목을 붙여줍니다.

    StringBuilder context = new StringBuilder();
    int i = 1;
    for (Document doc : topKDocuments) {
        context.append("문서 ").append(i++).append(":\n");
        context.append(doc.getContent()).append("\n\n");
    }

    LLM의 입장에서는 구분점이 명확한 것이 문맥 해석에 훨씬 유리합니다.

     


     

    구성 전략 3 – 템플릿화를 통해 프롬프트를 재사용 가능하게 만들기

     

    Spring AI의 PromptTemplate을 활용하면 다음처럼 설계할 수 있습니다.

    PromptTemplate template = new PromptTemplate("""
    당신은 문서를 기반으로 질문에 정확히 답하는 AI입니다.
    
    문서 목록:
    {context}
    
    사용자 질문:
    {question}
    
    문서를 참고하여 답변해주세요:
    """);
    template.add("context", contextString);
    template.add("question", userInput);

    이 방식은 프롬프트를 쉽게 테스트하거나 튜닝할 수 있으며,

    유닛 테스트 또는 A/B 테스트 적용에도 매우 유리합니다.

     


     

    구성 전략 4 – 문서 요약 후 삽입 (Intermediate Summarization)

     

    문서가 너무 길거나 많을 경우, 각 문서를 간략히 요약한 뒤 요약만 넣는 전략이 유효합니다.

    for (Document doc : docs) {
        String summary = chatClient.call("다음 문서를 3줄로 요약해줘:\n" + doc.getContent())
                              .getResult().getOutput().getContent();
        context.append(summary).append("\n---\n");
    }

    이렇게 하면 보다 간결한 프롬프트로 모델의 집중도를 높이고, 토큰 소모도 줄일 수 있습니다.

     


     

    구성 전략 5 – JSON/표/포맷 지정 요청

     

    응답의 포맷을 지정하는 것도 매우 효과적입니다.

    답변은 다음과 같은 형식을 지켜주세요:
    
    - 핵심 요약 (한 문장)
    - 문서 내 근거 인용
    - 표 형식 비교 (가능한 경우)

    또는

    답변은 반드시 JSON 형식으로 다음 구조를 따르세요:
    {
      "summary": "...",
      "source": "...",
      "reasoning": "..."
    }

    이렇게 하면 후처리 코드 작성도 쉬워지고, LLM이 혼동할 가능성도 줄어듭니다.

     


     

    실전 예시: 프롬프트 통합 코드

    String context = prepareContext(docs);
    PromptTemplate promptTemplate = new PromptTemplate("""
    당신은 사내 지식 문서를 기반으로 질문에 답변하는 AI입니다.
    다음은 참고할 문서들입니다:
    
    {context}
    
    사용자 질문:
    {question}
    
    문서를 참고하여 구체적으로 답변해주세요.
    답변은 반드시 문서에서 근거를 찾은 경우에만 작성해주세요.
    """);
    
    promptTemplate.add("context", context);
    promptTemplate.add("question", userInput);
    
    String answer = chatClient.call(promptTemplate.create())
                    .getResult().getOutput().getContent();

     


     

    실전에서 자주 발생하는 문제와 개선 팁

    문제개선 방법

    답변이 문서와 무관하거나 추측 기반임 “문서에 기반한 정보만 사용” 강조, role 설정 강화
    너무 긴 문서로 인해 토큰 초과 발생 TextSplitter로 분할 → 요약 → 삽입
    여러 문서에 대한 응답 정확도 저하 각 문서 요약 후 비교 요청 or 하나씩 비교하는 방식
    응답 일관성 부족 응답 포맷 지정 (JSON, Markdown, List 등)

     


     

    요약

    전략 요소설명

    Role 정의 모델의 역할, 제한 명확히 전달
    문서 삽입 방식 구분된 청크 구조, 번호 부여
    프롬프트 템플릿화 테스트와 반복 개선을 위한 기반
    문서 요약 삽입 토큰 제한 대응, 응답 품질 향상
    출력 포맷 요청 일관된 결과, 자동화/후처리 가능

     

     

    728x90
Designed by Tistory.