[커널아카데미] 백엔드 12기 18주차 - 토이프로젝트4

jh5959·2025년 7월 27일

토이프로젝트4

맡은 역할

FastAPI 서버 (AI 기능 백엔드 / 머신러닝 마이크로서비스)
역할: 오직 LLM과 관련된 복잡하고 전문적인 작업을 처리하는 특화된 백엔드

주요 책임

  • 스프링부트 서버로부터 요청을 받아 처리
  • Vector DB 검색, 프롬프트 생성, LLM 호출 등 RAG 파이프라인 실행
  • 최종 생성된 AI 답변을 다시 스프링부트로 전달

트러블 슈팅

## FastAPI 서버 개발 및 디버깅 최종 정리 
7.24(금)

1. 주요 오류 및 해결 과정
1.1. LangChain 파이프라인 데이터 흐름 오류
- 에러: TypeError: argument 'text': 'dict' object cannot be converted to 'PyString'
- 이유: retriever(검색기)가 **문자열(text)**을 입력받아야 하는데, {"question": "..."} **딕셔너리(dict)**를 통째로 입력받아 발생했습니다.
- **해결 방법**: `chain`의 데이터 흐름을 수정하여, `retriever`가 딕셔너리 대신 **사용자의 질문 문자열**을 입력으로 받도록 파이프라인 구조를 변경했습니다.
- **수정 전 코드 (`rag_pipeline.py`)**
    
    Python
    
    ```
    # retriever가 딕셔너리를 통째로 입력받아 오류 발생
    chain = (
        {"context": retriever, "question": lambda x: x["question"]}
        | real_estate_prompt
        | llm
        | StrOutputParser()
    )
    ```
    
- **수정 후 코드 (`rag_pipeline.py`)**
    
    Python
    
    ```
    # retriever 앞에 "(lambda x: x["question"]) |"를 추가하여
    # 입력된 딕셔너리에서 질문(문자열)만 꺼내서 retriever에게 전달하도록 수정
    chain = (
        {
            "context": (lambda x: x["question"]) | retriever,
            "question": (lambda x: x["question"])
        }
        | real_estate_prompt
        | llm
        | StrOutputParser()
    )
    ```


1.2 Pydantic alias 기능 충돌 오류 (최종)
- 에러: ValidationError: 1 validation error for ChatResponse. sessionId Field required
- 이유: ChatResponse 모델에 alias='sessionId'가 설정된 상태에서, 객체를 생성할 때 파이썬 변수명인 session_id를 키워드 인자로 사용하자 Pydantic 라이브러리가 이를 인식하지 못하는 매우 드문 충돌이 발생했습니다.
- **해결 방법**: `ChatResponse` 모델 객체를 생성할 때, 파이썬 변수명(`session_id`) 대신 **`alias`로 지정한 이름(`sessionId`)을 직접 키워드로 사용**하여 Pydantic의 내부적인 충돌을 우회했습니다.

- **수정 전 코드 (`api.py`)**
    
    Python
    
    ```
    # alias가 설정된 모델에 파이썬 변수명으로 값을 전달하여 오류 발생
    return ChatResponse(
        response="...",
        session_id="...", # 이 부분에서 Pydantic이 sessionId를 인식 못함
        success=True
    )
    ```
    
- **수정 후 코드 (`api.py`)**
    
    Python
    
    ```
    # alias로 지정한 'sessionId'를 직접 키워드로 사용하여 충돌을 우회
    return ChatResponse(
        response="...",
        sessionId="...", # session_id -> sessionId 로 키워드 직접 변경
        success=True
    )
    ```

1.3. 클라이언트-서버 응답 모델 불일치 오류
- 에러: ValidationError 또는 클라이언트(스프링부트) 측의 파싱 오류
- 이유: FastAPI가 보내는 JSON 응답의 구조가 스프링부트가 기대하는 Java 클래스의 구조와 달라 발생했습니다.
	- Case 1 (필드 누락): return 구문에서 필수 필드인 session_id를 전달하지 않았습니다.
	- Case 2 (필드명 불일치): FastAPI 모델에는 used_mydata: bool 필드가 있었지만, 스프링부트는 success: bool 필드를 필수로 요구했습니다.

- **수정 전 코드 (`api.py`)**
    
    Python
    ```
    # 모델 필드가 클라이언트 요구사항과 달랐음
    class ChatResponse(BaseModel):
        response: str
        used_mydata: bool # success 필드 대신 잘못된 필드가 있었음
    
    # return 구문에서 필수 필드 누락 및 잘못된 필드 전달
    return ChatResponse(
        response="...",
        # session_id=... 부분이 없었음
        used_mydata=True
    )
    ```
    
- **수정 후 코드 (`api.py`)**
    
    Python
    ```
    # 스프링부트 클래스와 동일하게 필드를 수정
    class ChatResponse(BaseModel):
        response: str
        session_id: str = Field(alias='sessionId')
        success: bool # 올바른 필드명으로 수정
    
    # return 구문에서 모든 필수 필드를 올바르게 전달
    return ChatResponse(
        response="...",
        sessionId="...",
        success=True
    )
    ```

2. 재발 방지를 위한 핵심 원칙
2.1. 명확한 API 명세(Contract) 정의
- 문제점: 클라이언트(스프링부트)와 서버(FastAPI)가 주고받을 데이터의 구조가 달라 ValidationError, 필드 누락 등의 오류가 발생했습니다.
- 예방책 
	- API 문서 공유: FastAPI의 자동 생성 문서 (/docs)를 활용해 양측 개발자가 필드명, 데이터 타입, 필수 여부를 사전에 정확히 맞춥니다.
	- 네이밍 컨벤션 통일: API를 통해 주고받는 JSON 데이터는 camelCase(예: sessionId)로 통일하기로 약속합니다. 파이썬에서는 alias를 사용해 이를 맞춰줍니다.

개인 공부

프롬프트(Prompt)

  • LLM에게 원하는 작업을 요청하기 위해 입력하는 명령어 또는 질문.
  • LLM이 최상의 결과를 생성하도록 유도하는 맥락(Context), 예시(Example), 역할(Role), 지시(Instruction) 등을 모두 포함

샷(Shot)

  • 프롬프트 안에서 LLM에게 제공하는 예시(Example)의 개수를 의미
  • 하나의 예시를 제공하여 LLM이 따라 할 수 있는 샘플을 보여줌
  • ex. "사과"는 영어로 "apple"이야 그럼 "바나나"는 영어로 뭐야?

에이전트(Agent)

  • LLM을 핵심 두뇌(추론 엔진)로 사용하여 스스로 생각하고 계획을 세워 도구를 사용하는 자율적인 시스템

툴(Tool)

  • 에이전트가 목표를 달성하기 위해 사용할 수 있는 외부기능이나 API

결론
프롬프트는 LLM에게 제공하는 형식 같은 것이며 그 안에 샷(예시)포함되어 있음
에이전트스스로 생각해서 사용자의 발화를 분석하고 프롬프트에 따라서 을 선택하여 서비스를 제공함

개인 회고

좋았던 점
어쩌다 보니 FastAPI를 맡게 되었다 배워본 적도 없고 하나도 모르던 터라 걱정을 많이 했지만 이왕 맡게 된 김에 한 번 배워보자 라느나 마음으로 시작했다 처음에는 흐름을 이해하는 것이 어려웠지만 코드를 보면서 공부하니 조금씩 감을 잡았다 무엇보다 팀원분이 도와주셔서 훨씬 수월하게 진행할 수 있었고 덕분에 많은 것을 배울 수 있었다 아직 부족하지만 FastAPI를 접해볼 수 있었던 좋은 기회였다

아쉬운 점
전체적인 흐름을 이해하는 데 여전히 어려움을 느꼈다 어렵다고 느끼는 순간 스스로 깊이 고민하거나 이해하려는 노력을 충분히 하지 않았던 것 같다 완벽하게 이해하지 못하면 쉽게 포기하려는 경향이 있는데 이번에도 그런 모습이 보였던 것 같다 이런 습관을 꼭 고치고 개선해야한다고 생각한다

개선 방향
앞으로는 처음부터 완벽하게 이해하려 하기보다는 전체적인 흐름이나 감을 먼저 잡고 코드를 작성해보면서 몸으로 익히는 방식을 시도해보려고 한다 LLM을 실제로 돌려보면서 동작을 체감하고 그 과정을 통해 이해를 쌓아가야겠다 이제 한 주밖에 남지 않았지만 남은 시간 동안 더 열심히 참여해서 랭체인에 대한 이해를 넓히고 프로젝트도 꼭 완성하고 싶다

0개의 댓글