본문 바로가기
IT개발/AI 공부

5. 추론 결과 가공

by jusyBear 2025. 3. 22.
반응형

Ollama API 응답 결과 가공하기: 효과적인 프롬프트 결과 파싱 기법

API 응답 데이터 처리

들어가며

로컬 LLM을 구축하고 API를 통해 상호작용하는 방법을 알아보았다면, 이제 API 응답 결과를 어떻게 효과적으로 가공하고 활용할지 고민해볼 차례입니다. 특히 문서 요약, 키워드 추출과 같은 응용 분야에서는 AI 모델의 응답을 정확하게 파싱하고 구조화된 형태로 변환하는 것이 매우 중요합니다.

이 글에서는 Ollama API를 통해 받은 응답 데이터를 처리하는 다양한 방법과 각 방식의 장단점을 살펴보겠습니다.


프롬프트 응답 파싱의 중요성

LLM은 기본적으로 텍스트 형태의 응답을 생성합니다. 이 텍스트를 그대로 사용하는 것은 간단하지만, 자동화된 시스템에서는 응답에서 특정 정보를 추출하고 구조화된 형태로 변환해야 하는 경우가 많습니다.

예를 들어, 다음과 같은 상황을 생각해볼 수 있습니다:

  • 긴 문서에서 핵심 키워드와 주요 개념 추출
  • 텍스트 요약에서 중요 포인트 구조화
  • 텍스트 응답에서 JSON, CSV 등의 구조화된 데이터 형식으로 변환

텍스트 파싱 vs JSON 파싱

프롬프트 응답을 처리하는 두 가지 주요 접근 방식을 비교해보겠습니다.

1. 텍스트 파싱 접근법

초기에는 모델의 응답을 일반 텍스트로 받아 파싱하는 방법을 많이 사용했습니다.

def parse_text_response(response_text):
    # 정규 표현식이나 문자열 처리 함수를 사용하여 파싱
    has_summary = "요약" in response_text or "핵심" in response_text

    # 키워드 추출 예시
    import re
    keywords_match = re.search(r"키워드: (.*?)(?:\n|$)", response_text)
    keywords = keywords_match.group(1).split(", ") if keywords_match else []

    # 점수 추출 예시
    importance_match = re.search(r"중요도: (\d+)/10", response_text)
    importance = int(importance_match.group(1)) if importance_match else None

    return {
        "has_summary": has_summary,
        "keywords": keywords,
        "importance": importance
    }

장점:

  • 모델이 자연스러운 형태로 응답 생성 가능
  • 추론 과정(사고 과정)을 볼 수 있어 결과의 신뢰성 판단 가능
  • 복잡한 설명과 함께 결론 제시 가능

단점:

  • 정규 표현식 파싱이 복잡하고 오류 가능성 높음
  • 모델 응답 형식이 조금만 바뀌어도 파싱 실패 가능성
  • 응답에 특수문자나 줄바꿈이 있을 경우 파싱 오류 발생

2. JSON 형식 응답 접근법

최근에는 모델에게 직접 JSON 형식으로 응답하도록 요청하는 방법이 많이 사용됩니다.

def request_json_response(document):
    url = "http://localhost:11434/api/generate"
    payload = {
        "model": "hf.co/nanowell/DeepSeek-R1-Distill-Qwen-32B-Q4_K_M-GGUF:latest",
        "prompt": f"""다음 문서를 분석하고 JSON 형식으로만 응답해주세요:
        {{
            "summary": "200자 이내의 요약",
            "keywords": ["키워드1", "키워드2", ...],
            "main_topics": ["주제1", "주제2", ...],
            "sentiment": "긍정/부정/중립",
            "importance": 1-10 사이의 중요도 점수
        }}

        문서: {document}
        """,
        "stream": False,
        "format": "json"  # 일부 모델에서 지원
    }

    response = requests.post(url, json=payload)
    if response.status_code == 200:
        try:
            # 직접 JSON으로 파싱
            return json.loads(response.json()["response"])
        except json.JSONDecodeError:
            print("응답이 유효한 JSON 형식이 아닙니다")
            return None

장점:

  • 응답 구조가 일관되어 파싱이 간단하고 안정적
  • 프로그래매틱 처리가 쉬움
  • 자동화된 시스템에 통합하기 용이함

단점:

  • 모델의 사고 과정(think)이 생략되어 어떻게 결론에 도달했는지 불투명
  • 복잡한 추론이 필요한 경우 결과의 품질이 저하될 수 있음
  • 모델이 JSON 형식을 정확히 따르지 못할 수 있음

하이브리드 접근법: 사고 과정과 구조화된 응답 동시에 얻기

텍스트 파싱의 유연성과 JSON 파싱의 안정성을 모두 활용하는 하이브리드 접근법도 가능합니다.

def hybrid_response_parsing(document):
    url = "http://localhost:11434/api/generate"
    payload = {
        "model": "hf.co/nanowell/DeepSeek-R1-Distill-Qwen-32B-Q4_K_M-GGUF:latest",
        "prompt": f"""다음 문서를 분석하고 두 부분으로 응답해주세요:

        1. 먼저 문서의 분석 과정을 자세히 설명해주세요(사고 과정).

        2. 그 다음, 분석 결과를 다음 JSON 형식으로 제공해주세요:
        {{
            "summary": "200자 이내의 요약",
            "keywords": ["키워드1", "키워드2", ...],
            "main_topics": ["주제1", "주제2", ...],
            "sentiment": "긍정/부정/중립"
        }}

        문서: {document}
        """,
        "stream": False
    }

    response = requests.post(url, json=payload)
    if response.status_code == 200:
        full_response = response.json()["response"]

        # JSON 부분 추출
        import re
        json_match = re.search(r'({.*})', full_response.replace('\n', ''))

        if json_match:
            try:
                json_data = json.loads(json_match.group(1))
                return {
                    "thinking_process": full_response,
                    "structured_data": json_data
                }
            except json.JSONDecodeError:
                print("JSON 부분 파싱 실패")

        return {"thinking_process": full_response, "structured_data": None}

실제 구현 예제: 문서 요약 및 키워드 추출

다음은 Ollama API를 사용하여 문서를 분석하고 요약 및 키워드를 추출하는 완전한 예제입니다:

import requests
import json
import re

def analyze_document(document_text):
    url = "http://localhost:11434/api/generate"
    payload = {
        "model": "hf.co/nanowell/DeepSeek-R1-Distill-Qwen-32B-Q4_K_M-GGUF:latest",
        "prompt": f"""다음 문서를 분석하고 요약 및 키워드를 추출해주세요.

        먼저 문서의 주요 내용을 자세히 분석한 다음, 결론을 JSON 형식으로 제공해주세요.

        문서:
        {document_text}

        JSON 형식:
        ```json
        {{
            "summary": "300자 이내의 문서 요약",
            "keywords": ["키워드1", "키워드2", "키워드3", ...],
            "main_topics": ["주제1", "주제2", ...],
            "sentiment": "긍정/부정/중립",
            "readability": "상/중/하 (읽기 난이도)"
        }}
        ```
        """,
        "stream": False
    }

    try:
        response = requests.post(url, json=payload)

        if response.status_code == 200:
            full_response = response.json()["response"]

            # JSON 부분 추출
            json_match = re.search(r'```json\s*(.*?)\s*```', full_response, re.DOTALL)

            if json_match:
                try:
                    json_str = json_match.group(1).strip()
                    document_analysis = json.loads(json_str)

                    return {
                        "full_analysis": full_response,
                        "document_analysis": document_analysis
                    }
                except json.JSONDecodeError as e:
                    print(f"JSON 파싱 오류: {e}")
            else:
                print("응답에서 JSON 형식을 찾을 수 없습니다.")
        else:
            print(f"API 요청 실패: {response.status_code}")
            print(response.text)

    except Exception as e:
        print(f"오류 발생: {str(e)}")

    return None

# 사용 예시
document = """
인공지능(AI)은 인간의 학습능력, 추론능력, 지각능력, 자연언어의 이해능력 등을 컴퓨터 프로그램으로 구현한 기술이다.
인공지능이라는 용어는 1956년 다트머스 회의에서 처음 사용되었다. 인공지능 연구의 역사는 수학적 추론의 형식화 노력으로 거슬러 올라간다.
20세기 중반에는 앨런 튜링의 튜링 테스트, 존 맥카시의 "인공지능"이라는 용어 개발, 그리고 첫 인공 신경망의 제안 등 현대 인공지능 발전의 초석이 마련되었다.
최근에는 머신러닝과 딥러닝 기술의 발전으로 음성 인식, 자연어 처리, 이미지 인식 등 다양한 분야에서 획기적인 성과를 이루고 있다.
"""

result = analyze_document(document)
if result:
    print("전체 분석:")
    print(result["full_analysis"])
    print("\n구조화된 문서 분석:")
    print(json.dumps(result["document_analysis"], indent=2, ensure_ascii=False))

 


언어 선택의 중요성: 영어 vs 한국어 프롬프트

주목할 점은 프롬프트 작성 시 사용하는 언어에 따라 결과의 품질이 크게 달라질 수 있다는 것입니다. 경험적으로 한글보다 영어로 프롬프트를 작성할 때 더 생산적이고 정확한 데이터를 얻을 수 있는 경우가 많습니다.

이는 대부분의 LLM 모델이 영어 데이터를 중심으로 학습되었기 때문입니다. 특히 다음과 같은 경우에 영어 프롬프트가 유리합니다:

  • 기술적인 내용이나 전문 용어가 많이 포함된 경우
  • 구조화된 데이터(JSON, CSV 등)를 요청할 때
  • 정확한 형식 지정이 필요한 경우

실무에서는 한국어 결과가 필요하더라도 프롬프트는 영어로 작성하고 결과를 한국어로 반환하도록 지시하는 하이브리드 접근법을 고려해볼 수 있습니다.

def request_with_english_prompt(document_korean):
    prompt = f"""Analyze the following Korean document and respond in Korean with a summary and keywords.

    Document: {document_korean}

    Please format your response in JSON:
    ```json
    {{
        "summary": "문서의 요약 (한국어로)",
        "keywords": ["키워드1", "키워드2", ...],
        "main_topics": ["주제1", "주제2", ...]
    }}
    ```
    """

    # 이하 API 호출 코드

 


응답 결과 형식 선택 시 고려사항

프로젝트에 적합한 응답 형식을 선택할 때 고려해야 할 사항들:

  1. 용도와 자동화 수준:
    1. 완전 자동화된 시스템 → JSON 형식 권장
    2. 사람의 검토가 필요한 경우 → 텍스트 형식 또는 하이브리드 접근법 권장
  2. 신뢰성 요구사항:
    1. 의사결정의 근거가 중요한 경우 → 사고 과정이 포함된 접근법 필요
    2. 단순 요약이나 키워드 추출만 필요한 경우 → 구조화된 형식만으로 충분
  3. 모델 성능:
    1. 모델이 JSON 형식을 정확히 생성할 수 있는지 테스트 필요
    2. 일부 모델은 구조화된 응답 생성 능력이 제한적일 수 있음
  4. 에러 처리:
    1. JSON 파싱 실패 시 대체 처리 방법 고려
    2. 중요한 문서 분석에는 여러 형식의 백업 처리 로직 구현 권장

결론

Ollama API를 통해 LLM과 상호작용할 때, 응답 결과를 어떻게 파싱하고 가공할지는 프로젝트의 성패를 좌우하는 중요한 요소입니다. 텍스트 기반 파싱은 유연하지만 불안정할 수 있고, JSON 기반 파싱은 안정적이지만 사고 과정이 생략될 수 있습니다.

최적의 접근법은 프로젝트의 요구사항과 사용 사례에 따라 달라질 수 있으며, 필요에 따라 하이브리드 접근법을 통해 두 방식의 장점을 모두 활용하는 것이 가능합니다.

문서 요약, 키워드 추출과 같은 작업을 자동화할 때는 항상 모델의 응답을 검증하고, 적절한 에러 처리와 백업 로직을 구현하는 것을 잊지 마세요.

참고 자료

  1. Ollama API Github 공식 문서

  • 해당 글은 직접 작성한 내용을 AI를 통해 가다듬는 방식으로 작성되었습니다.
  • 해당 글의 예시 중 일부는 AI를 통해서 제작되었습니다.
반응형