# LLM 에이전트 빈 응답 버그 해결: Fireworks.ai 완벽 가이드

> 2026-03-04 · Tom Tunguz · 큐레이션 김태우
> https://challengekim.com/insights/llm-agent-empty-response-bug-fix-fireworks-ai-guide-ko
> 원문: https://www.tomtunguz.com/2026-02-23-fixing-empty-response-fireworks/

## 핵심 요약

- **문제**: Julius 에이전트가 Fireworks.ai의 Kimi K2.5 모델을 사용할 때, 도구 실행이 성공적으로 완료되었음에도 사용자에게 비어있는 응답만 전달되는 현상 발생
- **근본 원인**: LLM 완료 후 `response.text` 필드가 비어있을 때 최종 응답을 추출하는 코드의 엣지 케이스
- **해결 방법**: 응답이 비어있을 경우 대화 기록에서 가장 최근의 어시스턴트 메시지로 자동 폴백하도록 로직 개선
- **핵심 교훈**: 다양한 LLM 제공업체의 차이를 처리하고, 사용자에게는 항상 실질적인 콘텐츠를 보장해야 함
- **성능 개선**: 최대 턴 수를 10에서 50으로 증가시켜 복잡한 다단계 작업 처리 능력 강화

## Julius 에이전트의 예상치 못한 버그: 도구 실행 후 빈 응답

AI 시스템을 개발하면서 마주치는 가장 답답한 버그 중 하나는 **작업이 성공적으로 완료되었는데 사용자에게는 빈 응답만 보여주는 경우** 입니다. 정확히 이러한 현상이 Julius 에이전트에서 발생했습니다.

Fireworks.ai의 Kimi K2.5 모델을 사용하여 도구 호출을 처리할 때, 다음과 같은 이상한 동작이 관찰되었습니다:

1. **도구 루프는 성공적으로 실행되었고**
2. **모든 도구 호출이 예상대로 완료되었지만**
3. **사용자에게 전달되는 최종 응답은 완전히 비어 있었습니다**

더 황당한 점은 시스템 관점에서는 이 모든 과정이 완벽하게 작동하는 것처럼 보였다는 것입니다. 도구 실행 메커니즘은 정상 작동했고, 에러 로그도 없었으며, 오직 사용자에게 보이는 최종 응답만 공백이었습니다. 이로 인해 작업이 **실제로는 성공했음에도 불구하고 실패한 것처럼 보였던 것** 입니다.

이 문제는 특히 에이전트 기반 시스템의 신뢰성에 영향을 미쳤습니다. 사용자 입장에서는 명령을 내렸지만 아무 응답도 받지 못했으므로, 시스템이 작동하지 않는다고 느낄 수밖에 없었습니다. 하지만 백그라운드에서는 모든 처리가 정상적으로 완료되고 있었던 것입니다.

## 근본 원인 분석: 대화 처리 코드의 엣지 케이스 발견

문제를 파악하기 위해 대화 처리 코드를 세밀하게 분석했습니다. 특히 LLM이 도구 실행을 완료한 후 어떻게 응답을 생성하는지를 자세히 살펴봤습니다.

### 문제가 있던 원본 코드 구조

LLM이 도구를 실행한 후 `FinishReason::Stop` 상태에 도달했을 때, 코드는 다음과 같은 방식으로 응답 텍스트를 추출하고 있었습니다:

```rust
let final_text = response.text.clone().unwrap_or_default();
```

이 코드는 얼핏 보면 적절해 보입니다. `response.text` 필드에서 텍스트를 가져오고, 만약 그것이 없다면(None이면) 빈 문자열로 기본값을 설정하는 것처럼 말입니다.

하지만 실제로 일어난 일은 다음과 같습니다:

**Fireworks.ai의 Kimi K2.5 모델의 특수한 동작:**

- 모든 도구 호출이 완료된 후
- LLM이 "stop" 완료 이유(finish reason)를 반환했을 때
- `response.text` 필드는 **비어있는 상태** 로 응답했습니다

그 결과, 위의 코드는 `None`을 만나 `unwrap_or_default()`에 의해 빈 문자열(`""`)을 반환했던 것입니다.

### 왜 이것이 문제였는가?

문제의 핵심은 **응답이 진짜로 비어있지 않았다** 는 점입니다. 대화 기록을 살펴보면, 상호작용 초기에 유효한 어시스턴트 응답이 이미 저장되어 있었습니다. 하지만 코드는 이러한 저장된 콘텐츠를 완전히 무시하고, 최종 응답 필드만 확인했던 것입니다.

즉, 다음과 같은 상황이 발생했습니다:

1. **대화 기록**: 어시스턴트의 실질적인 응답 포함 ✓
2. **최종 응답 필드**: 비어있음 (도구 실행 후) ✗
3. **사용자에게 반환된 값**: 비어있는 필드를 기반으로 한 공백 ✗

이것이 바로 **엣지 케이스** 였습니다. 특정 LLM 제공업체(이 경우 Fireworks.ai)가 특정 상황에서(도구 호출 완료 후) 비어있는 `response.text`를 반환하는 경우를 처리하지 못했던 것입니다.

## 해결책: 대화 기록 폴백 시스템 구현

이 문제를 해결하기 위해 완료 처리 로직을 근본적으로 개선했습니다. **응답이 비어있을 때 대화 기록으로 자동 폴백하는 메커니즘** 을 추가했습니다.

### 개선된 코드의 작동 원리

업데이트된 완료 처리 로직은 다음과 같은 단계를 따릅니다:

**1단계: 중지 상태에서 응답 텍스트 확인**
```
LLM이 "stop" 완료 이유를 반환한 상황에서
response.text 필드가 비어있는지 확인
```

**2단계: 비어있으면 대화 기록 검색**
```
만약 response.text가 비어있다면
ConversationState에서 가장 최근의 어시스턴트 메시지를 검색
```

**3단계: 저장된 콘텐츠로 폴백**
```
대화 기록에 저장된 어시스턴트의 마지막 응답을
최종 응답으로 사용
```

### 핵심 메커니즘: ConversationState 활용

이 해결책이 가능했던 이유는 **ConversationState가 이미 모든 메시지의 완전한 기록을 유지하고 있었기 때문** 입니다. 시스템의 설계가 처음부터 모든 상호작용을 추적하도록 되어 있었던 것입니다.

특별히 `last_assistant_text()` 메서드를 활용하여:

- 가장 최근의 어시스턴트 콘텐츠에 접근
- 최종 응답이 비어있을 때 이 저장된 내용으로 대체
- 사용자가 항상 어시스턴트의 마지막 실질적인 응답을 받도록 보장

### 왜 이것이 우수한 해결책인가?

1. **데이터 손실 방지**: 이미 생성된 응답이 버려지지 않음
2. **사용자 경험 개선**: 어떤 상황에서도 의미 있는 콘텐츠 제공
3. **유연한 대응**: 특정 모델 제공업체의 특수성을 자동으로 처리

## LLM 제공업체별 차이: 왜 이런 일이 발생했는가?

이 버그는 단순한 코딩 실수가 아니라 **LLM 제공업체들이 완료 신호를 보내는 방식의 다양성** 에서 비롯된 것입니다.

### 각 제공업체의 다른 동작 방식

**OpenAI의 경우:**

- 도구 호출 완료 후에도 `response.text`에 요약이나 응답 포함
- 사용자에게 일관된 피드백 제공

**Anthropic Claude의 경우:**

- 도구 실행 후 명확한 종료 메시지 제공
- 구조화된 응답 형식 유지

**Fireworks.ai의 Kimi K2.5의 경우:**

- 모든 도구 호출 완료 후 "stop" 신호 발생
- 이때 `response.text` 필드가 비어있을 수 있음
- 실질적인 콘텐츠는 대화 기록에만 저장됨

이러한 차이는 각 제공업체가 효율성과 비용을 고려하여 다르게 구현한 결과입니다. Fireworks.ai는 도구 실행 후 추가 텍스트 생성을 하지 않음으로써 API 호출 비용을 절감하는 전략을 취했을 수 있습니다.

### 프로덕션 환경에서의 영향

이 차이는 특히 다양한 LLM을 지원하는 에이전트 시스템에서 중요한 문제가 됩니다:

- **단일 제공업체에 최적화된 코드**: 다른 모델로 전환할 때 버그 발생
- **사용자 경험의 불일치**: 어떤 모델을 쓰느냐에 따라 서비스 품질이 달라짐
- **유지보수의 어려움**: 각 제공업체마다 특수한 처리 로직 필요

## 성능 개선: 복잡한 작업 처리 능력 강화

빈 응답 버그를 해결한 것과 함께, 또 다른 중요한 개선사항이 적용되었습니다.

### 최대 턴(Turn) 수 증가: 10에서 50으로

**이전 설정:**
```
max_turns = 10
```

이 제한은 간단한 작업에는 충분했지만, 복잡한 다단계 문제를 처리할 때 문제가 되었습니다.

**개선된 설정:**
```
max_turns = 50
```

### 왜 이 변경이 필요했나?

**복잡한 작업의 예시:**

- 데이터베이스 쿼리 → 결과 분석 → 추가 검색 → 최종 보고서 생성
- 이러한 일련의 과정에서 각 단계가 하나의 "턴"을 차지

**실제 시나리오:**

- 간단한 검색: 2-3턴
- 중간 복잡도 작업: 5-8턴
- 복잡한 데이터 분석: 15-30턴

10턴 제한에서는 15턴이 필요한 작업이 중간에 중단되었을 것입니다. 50턴으로 증가시킴으로써, 대부분의 실제 작업을 완전히 처리할 수 있게 되었습니다.

### 성능에 미치는 영향

**긍정적 변화:**

- 더 복잡한 문제를 한 번의 에이전트 실행으로 해결
- 사용자가 중간 결과를 기반으로 재질의할 필요 감소
- 에이전트의 자율성과 효율성 증대

**고려사항:**

- API 호출 비용 증가 (더 많은 턴 = 더 많은 LLM 호출)
- 처리 시간 증가 (하지만 여러 번의 사용자 입력 없음으로 사용성 개선)
- 타임아웃 관리 필요 (매우 복잡한 작업은 여전히 제한 가능)

## 이 문제가 중요한 이유: 에이전트 시스템의 신뢰성

이 수정 사항은 단순히 하나의 버그를 고친 것이 아닙니다. 이것은 **에이전트 기반 AI 시스템의 근본적인 신뢰성을 개선한 것** 입니다.

### 사용자 신뢰에 미치는 영향

**버그 발생 전:**

- 사용자가 명령을 내림
- 시스템이 작업을 처리함
- 사용자는 아무 응답도 받지 못함
- 사용자의 신뢰도 급락 ↓

**버그 수정 후:**

- 사용자가 명령을 내림
- 시스템이 작업을 처리함
- 사용자가 명확한 결과를 받음
- 사용자의 신뢰도 유지 ↑

### 다양한 LLM 제공업체 지원

이제 시스템은 다음과 같은 상황에서도 안정적으로 작동합니다:

- OpenAI, Anthropic, Fireworks.ai, Google, Azure 등 다양한 제공업체
- 같은 제공업체 내에서도 다양한 모델 버전
- 각 제공업체의 독특한 응답 형식 처리

이는 **미래에 새로운 LLM 제공업체를 추가할 때도 강건한 시스템** 을 만들었음을 의미합니다.

### 프로덕션 안정성 강화

특히 프로덕션 환경에서 이 개선은 매우 중요합니다:

- **일관된 서비스 품질**: 어떤 LLM을 사용하든 사용자는 같은 수준의 경험을 받음
- **자동 오류 복구**: 비어있는 응답을 자동으로 처리
- **모니터링 용이성**: 비어있는 응답이 자동 처리되므로 로그에서 추적 가능

## 빌드 검증: 버그 수정의 안정성 확인

이 수정 사항을 배포하기 전에 철저한 검증 과정을 거쳤습니다.

### 검증 절차

**1. 단위 테스트:**

- 대화 기록이 비어있는 경우
- 어시스턴트 메시지가 없는 경우
- 여러 어시스턴트 메시지가 있는 경우
- 각각에 대해 `last_assistant_text()` 메서드의 동작 확인

**2. 통합 테스트:**

- 실제 LLM 호출 시뮬레이션
- Fireworks.ai의 Kimi K2.5 응답 패턴 재현
- 도구 실행 루프 전체 확인

**3. 회귀 테스트:**

- 기존 코드베이스와의 호환성 확인
- 이전에 정상 작동하던 기능들이 여전히 정상 작동하는지 확인
- 성능 저하 확인

### 프로덕션 빌드 결과

- ✅ 클린 빌드 성공
- ✅ 모든 테스트 통과
- ✅ 회귀 없음
- ✅ 성능 저하 없음
- ✅ 배포 준비 완료

이 철저한 검증 과정을 통해 수정 사항이 안정적이고 안전하다는 것을 확인할 수 있었습니다.

## 배운 점: LLM 통합 개발의 핵심 교훈

이 버그 해결 과정에서 얻은 교훈들은 다른 LLM 기반 시스템을 개발할 때도 매우 중요합니다.

### 1. 대화 기록을 신뢰하라: 최종 응답 필드가 전부가 아닙니다

**학습:**
LLM API를 다룰 때, 최종 응답 필드(`response.text`)가 항상 진실의 원천은 아닙니다.

**왜 중요한가?**

- 많은 개발자들은 최종 응답 필드만 확인하는 실수를 합니다
- LLM 제공업체마다 응답 구조가 다릅니다
- 비용 효율성이나 처리 최적화를 위해 의도적으로 다르게 구현할 수 있습니다

**베스트 프랙티스:**
```
항상 대화 기록을 유지하고 확인하세요.
대화 기록은:

- 완전성: 모든 상호작용 포함
- 신뢰성: 최종 응답이 비어있어도 폴백 가능
- 투명성: 전체 맥락 파악 가능

```

**적용 예시:**

- 챗봇 시스템: 사용자와의 전체 대화 기록 유지
- 에이전트 시스템: 모든 도구 호출과 결과 기록
- 분석 시스템: 의사결정 과정의 추적 가능성 확보

### 2. 모델별 차이점을 예상하고 대비하세요

**학습:**
다양한 공급업체는 완료 상태, 응답 형식, 도구 처리 방식을 다르게 구현합니다.

**구체적인 차이점들:**

**OpenAI:**

- 예측 가능한 응답 형식
- 도구 호출 후 일관된 콘텐츠 생성
- 명확한 문서와 지원

**Anthropic:**

- 더 엄격한 안전 제약
- 특정 형식의 도구 호출만 지원
- XML 기반 구조화

**Fireworks.ai:**

- 비용 효율적인 구현
- 도구 호출 후 최소한의 추가 처리
- 높은 처리 속도

**베스트 프랙티스:**
```

1. 각 제공업체의 문서 철저히 읽기
2. 실제 환경에서 테스트하기 (문서와 현실은 다를 수 있음)
3. 제공업체 전환을 고려한 추상화 레이어 만들기
4. 모니터링 시스템으로 예상 밖의 동작 추적

```

**구현 예시:**
```
LLMProvider 추상 클래스
├── OpenAIProvider (특정 처리 방식)
├── AnthropicProvider (특정 처리 방식)
├── FireworksProvider (특정 처리 방식)
└── ...

이렇게 하면 제공업체를 쉽게 전환하고,
각 제공업체의 특수성을 처리할 수 있습니다.
```

### 3. 빈 응답은 보이지 않는 실패입니다

**학습:**
시스템 관점에서는 성공처럼 보이지만, 사용자에게는 실패로 느껴지는 경우가 있습니다.

**왜 이것이 가장 위험한가?**

- **무음의 실패(Silent Failure)**: 로그에 오류가 남지 않음
- **진단의 어려움**: 무엇이 잘못되었는지 파악하기 어려움
- **신뢰 하락**: 사용자는 시스템이 작동하지 않는다고 생각
- **비즈니스 손실**: 기능이 작동해도 사용자는 다른 서비스로 이동

**빈 응답의 원인들:**

- API 응답이 예상과 다름
- 데이터베이스 쿼리가 결과를 반환하지 않음
- 에러 처리 중에 콘텐츠가 손실됨
- 권한 문제로 콘텐츠가 필터링됨

**베스트 프랙티스:**

```

1. 항상 콘텐츠 검증:
   if response.text.is_empty() {
       // 위험! 폴백 메커니즘 필요
       use_fallback_response();
   }

2. 상세한 로깅:
   - 응답이 비어있을 때 왜인지 기록
   - 폴백이 사용되었는지 기록
   - 사용자에게 무엇이 제공되었는지 기록

3. 사용자에게 명확한 피드백:
   - "처리 중입니다"
   - "결과가 생성되었습니다"
   - "다시 시도해주세요" (오류 시)

```

**모니터링 예시:**
```
EmptyResponseMetric {
    timestamp: "2024-01-15T10:30:00Z",
    model: "Kimi K2.5",
    operation: "tool_execution",
    fallback_used: true,
    fallback_source: "conversation_history",
    user_received_content: true
}
```

## LLM 에이전트 개발의 미래: 교훈 적용하기

이 버그 수정 경험에서 얻은 교훈들은 앞으로의 LLM 기반 시스템 개발에 어떻게 적용될 것인가?

### 1. 멀티 제공업체 지원 아키텍처

미래의 에이전트 시스템은 처음부터 여러 LLM 제공업체를 지원하도록 설계되어야 합니다. 이는 비용 최적화, 성능 향상, 위험 분산을 모두 가능하게 합니다.

### 2. 견고한 폴백 메커니즘

대화 기록을 활용한 이번의 폴백 메커니즘처럼, 시스템은 여러 단계의 폴백을 갖춰야 합니다:

- 1단계: 주 응답 사용
- 2단계: 대화 기록에서 폴백
- 3단계: 캐시된 유사 응답 사용
- 4단계: 기본 메시지 제공

### 3. 포괄적인 모니터링

모든 응답이 예상대로 작동하는지 지속적으로 모니터링하고, 이상 패턴을 감지하는 시스템 구축이 필수입니다.

## 결론

Julius 에이전트의 빈 응답 버그는 단순한 코딩 실수가 아니라 **LLM 기반 시스템의 복잡성에서 비롯된 중요한 교훈** 입니다. 이 문제의 해결을 통해 우리는 다음을 배웠습니다:

1. **대화 기록의 중요성**: 최종 응답만이 전부가 아니며, 완전한 대화 기록이 신뢰할 수 있는 폴백을 제공합니다.

2. **LLM 제공업체의 다양성**: 각 제공업체가 다르게 동작할 수 있으며, 이를 유연하게 처리하는 코드 설계가 필수입니다.

3. **사용자 경험의 최우선**: 시스템이 완벽하게 작동해도 사용자가 결과를 받지 못하면 실패이며, 항상 사용자에게 의미 있는 콘텐츠를 전달해야 합니다.

이러한 교훈들을 적용하면, 더욱 안정적이고 신뢰할 수 있는 AI 에이전트 시스템을 구축할 수 있습니다. 특히 프로덕션 환경에서 다양한 LLM을 지원해야 하는 경우, 이 경험이 매우 귀중한 자산이 될 것입니다. 완료된 작업에서 항상 사용자가 의미 있는 출력을 받도록 보장하는 것이 바로 신뢰할 수 있는 AI 시스템의 핵심입니다.

---

원문을 바탕으로 AI 가 한국어로 요약·재구성한 글입니다. 인용·수치는 원문 링크에서 확인해 주세요. [원문 링크](https://www.tomtunguz.com/2026-02-23-fixing-empty-response-fireworks/)
