> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fim.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 환경 변수

> FIM One의 완전한 구성 참조.

모든 구성은 `.env`를 통해 수행됩니다. `example.env`를 복사하고 값을 입력하세요:

```bash theme={null}
cp example.env .env
```

## 설정 수준

각 통합에는 중요도를 나타내는 설정 수준이 있습니다:

| 수준     | 의미         | 설정되지 않았을 때의 동작                          |
| ------ | ---------- | --------------------------------------- |
| **필수** | 핵심 시스템 종속성 | 시스템 오류 발생 — 채팅 및 주요 기능이 작동하지 않음         |
| **권장** | 중요한 기능 활성화 | 우아한 성능 저하 — 기능이 명확하게 사용 불가능하지만 시스템은 실행됨 |
| **선택** | 향상 기능      | 투명한 성능 저하 — 시스템이 정상 작동하며, 기능만 없음        |

> **참고**: 관리자가 설정한 모델(관리자 → 모델 페이지)은 LLM 환경 변수를 대체할 수 있습니다. 상태 확인은 두 소스를 모두 고려합니다.

## 프론트엔드 (로컬 개발 전용)

프론트엔드에는 **로컬 개발 전용** 별도의 env 파일이 있습니다: `frontend/.env.local`.

> **이 파일은 Docker에서 사용되지 않습니다.** Docker 컨테이너 내에서 Next.js는 `/api/*`를 Python 백엔드로 내부적으로 프록시합니다 (포트 8000은 컨테이너 내부용이므로), 프론트엔드 env 파일이 필요하지 않습니다.

로컬 개발의 경우 기본값이 그대로 작동합니다 — 백엔드가 기본이 아닌 포트에서 실행되지 않는 한 `frontend/.env.local`을 생성할 **필요가 없습니다**.

필요한 경우 `frontend/.env.local`을 수동으로 생성하여 재정의할 수 있습니다:

```bash theme={null}
echo 'NEXT_PUBLIC_API_URL=http://localhost:9000' > frontend/.env.local
```

| 변수                    | 기본값                            | 설명                                                                                                                                      |
| --------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `NEXT_PUBLIC_API_URL` | `http://localhost:8000` *(자동)* | **브라우저**가 직접 API 호출(OAuth 리다이렉트, 스트리밍)에 사용하는 백엔드 URL입니다. 설정되지 않은 경우 `window.location`에서 자동 감지됩니다 — 백엔드가 로컬에서 비표준 포트에서 실행되는 경우에만 재정의하세요. |

> **빌드 타임 참고**: `NEXT_PUBLIC_*` 변수는 `pnpm build` 시점에 JS 번들에 포함됩니다. 런타임에 변경하는 것(예: 루트 `.env`를 통해)은 효과가 없습니다 — 이것이 로컬 개발 전용으로 `frontend/.env.local`에 있는 이유입니다.

***

## LLM (필수)

| 변수                                | 필수    | 기본값                                   | 설명                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| --------------------------------- | ----- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `LLM_API_KEY`                     | **예** | —                                     | LLM 제공商의 API 키                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `LLM_BASE_URL`                    | 아니오   | `https://api.openai.com/v1`           | OpenAI 호환 API의 기본 URL                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `LLM_MODEL`                       | 아니오   | `gpt-4o`                              | 주 모델 — 계획, 분석 및 ReAct 智能体에 사용됨                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `FAST_LLM_MODEL`                  | 아니오   | *(`LLM_MODEL`로 폴백)*                   | 빠른 모델 — DAG 단계 실행에 사용됨 (더 저렴하고 빠름)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `LLM_TEMPERATURE`                 | 아니오   | `0.7`                                 | 기본 샘플링 온도                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `LLM_CONTEXT_SIZE`                | 아니오   | `128000`                              | 주 LLM의 상下文窗口 크기                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `LLM_MAX_OUTPUT_TOKENS`           | 아니오   | `64000`                               | 주 LLM의 호출당 최대 출력 토큰                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `FAST_LLM_API_KEY`                | 아니오   | *(`LLM_API_KEY`로 폴백)*                 | 빠른 모델 제공商의 API 키. 빠른 모델이 주 모델과 다른 제공商에서 호스팅될 때 사용                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `FAST_LLM_BASE_URL`               | 아니오   | *(`LLM_BASE_URL`로 폴백)*                | 빠른 모델 제공商의 기본 URL                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `FAST_LLM_TEMPERATURE`            | 아니오   | *(`LLM_TEMPERATURE`로 폴백)*             | 빠른 모델의 샘플링 온도                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `FAST_LLM_CONTEXT_SIZE`           | 아니오   | *(`LLM_CONTEXT_SIZE`로 폴백)*            | 빠른 LLM의 상下文窗口 크기                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `FAST_LLM_MAX_OUTPUT_TOKENS`      | 아니오   | *(`LLM_MAX_OUTPUT_TOKENS`로 폴백)*       | 빠른 LLM의 호출당 최대 출력 토큰                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `LLM_REASONING_EFFORT`            | 아니오   | *(비활성화됨)*                             | 지원되는 모델의 확장 사고 수준 (OpenAI o-series, Gemini 2.5+, Claude). 값: `low`, `medium`, `high`. LiteLLM은 이를 각 제공商의 네이티브 형식으로 자동 변환합니다. 모델의 사고 과정은 UI "thinking" 단계에 표시됩니다.                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `LLM_REASONING_BUDGET_TOKENS`     | 아니오   | *(노력에서 자동)*                           | Anthropic 사고를 위한 명시적 토큰 예산 (최소 1024). OpenAI/Gemini의 경우 노력 수준이 직접 사용됩니다. `LLM_REASONING_EFFORT`가 설정된 경우에만 효과적입니다.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `LLM_JSON_MODE_ENABLED`           | 아니오   | `true`                                | `response_format=json_object`의 전역 토글. 제공商이 LiteLLM의 어시스턴트 프리필 주입을 거부하는 경우 `false`로 설정 (예: AWS Bedrock 릴레이 → 2번째 이상 智能体 반복에서 `ValidationException`). 비활성화되면 구조화된 호출은 JSON 모드를 건너뛰고 일반 텍스트 정규식 추출로 폴백 — 품질 손실 없음. 모든 모델 (ENV 구성 및 Admin 구성)에 적용됩니다.                                                                                                                                                                                                                                                                                                                                                                 |
| `LLM_TOOL_CHOICE_ENABLED`         | 아니오   | `true`                                | 구조화된 출력 추출에서 강제 `tool_choice`의 전역 토글 (Level 1 — 네이티브 함수 호출). 모델이 강제 도구 선택으로 오류를 반환하는 경우 `false`로 설정 (예: `tool_choice='specified'`를 거부하는 사고 모드 모델). 비활성화되면 구조화된 호출은 네이티브 FC를 건너뛰고 JSON 모드에서 시작합니다. Settings → Models → Advanced에서 모델별 재정의 가능.                                                                                                                                                                                                                                                                                                                                                                      |
| `REASONING_LLM_MODEL`             | 아니오   | *(`LLM_MODEL`로 폴백)*                   | 추론 계층의 모델 이름. 깊이 있는 분석이 필요한 작업에 사용됨 (예: DAG 계획, 계획 분석)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `REASONING_LLM_API_KEY`           | 아니오   | *(`LLM_API_KEY`로 폴백)*                 | 추론 모델 제공商의 API 키                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `REASONING_LLM_BASE_URL`          | 아니오   | *(`LLM_BASE_URL`로 폴백)*                | 추론 모델 제공商의 기본 URL                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `REASONING_LLM_TEMPERATURE`       | 아니오   | *(`LLM_TEMPERATURE`로 폴백)*             | 추론 모델의 샘플링 온도                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `REASONING_LLM_CONTEXT_SIZE`      | 아니오   | *(`LLM_CONTEXT_SIZE`로 폴백)*            | 추론 모델의 상下文窗口 크기                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `REASONING_LLM_MAX_OUTPUT_TOKENS` | 아니오   | *(`LLM_MAX_OUTPUT_TOKENS`로 폴백)*       | 추론 모델의 호출당 최대 출력 토큰                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `REASONING_LLM_EFFORT`            | 아니오   | *(`LLM_REASONING_EFFORT`로 폴백)*        | 추론 모델 계층의 추론 노력 수준. 값: `low`, `medium`, `high`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `REASONING_LLM_BUDGET`            | 아니오   | *(`LLM_REASONING_BUDGET_TOKENS`로 폴백)* | 추론을 위한 토큰 예산 (주로 Anthropic). 추론 계층의 자동 계산 예산을 재정의합니다.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `LLM_SUPPORTS_VISION`             | 아니오   | `true` *(낙관적)*                        | ENV 모드 문서 OCR (MarkItDown + `markitdown-ocr`를 통해)이 시도되는지 여부를 제어합니다. **Admin → Models에서 활성 모델 그룹이 구성되지 않은 경우에만 적용됩니다** (순수 ENV 모드). 기본값 `true`가 적용되면 `convert_to_markdown` 및 RAG 수집은 `LLM_MODEL`이 비전을 지원한다고 가정하고 이미지 OCR을 위해 호출합니다 — 이는 모든 일반적인 선택에 대한 올바른 동작입니다 (`gpt-4o`, `claude-3-5-sonnet`, `gemini-1.5-pro/flash`). ENV 구성된 `LLM_MODEL`이 비전을 지원하지 않는 경우 `false`로 설정하십시오 (예: `deepseek-v3`, `qwen-chat`, `llama-3.1`, `gpt-3.5-turbo`, `o1-mini`) 실패한 비전 호출을 건너뛰고 텍스트 전용 추출로 직접 이동합니다. Admin → Models 패널에 활성 모델 그룹이 있으면 이 플래그는 무시되고 그룹의 `supports_vision` 플래그가 인수합니다 — 관리자가 선별한 선택은 항상 DB 모드의 신뢰할 수 있는 출처입니다. |

> **해결 순서**: 사용자 선호도 → Admin 모델 (DB) → ENV 폴백. Admin → Models에서 역할이 "General"인 관리 모델이 구성된 경우 이러한 ENV 변수는 폴백으로만 제공됩니다. 상태 확인은 두 출처를 모두 고려합니다.

### MarkItDown OCR 해상도

`convert_to_markdown` 내장 도구와 RAG 수집 파이프라인은 모두 Microsoft의 [MarkItDown](https://github.com/microsoft/markitdown) + 공식 [`markitdown-ocr`](https://github.com/microsoft/markitdown/tree/main/packages/markitdown-ocr) 플러그인을 사용하여 문서에서 텍스트를 추출합니다 — 비전 기능이 있는 LLM을 사용할 수 있을 때 임베드된 이미지와 스캔된 PDF 페이지에 대한 OCR을 포함합니다.

**비전 LLM 해상도 순서** (첫 번째 일치 우선):

| # | 소스                                                             | 우선순위 근거                                                                                                   |
| - | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| 1 | 에이전트의 **기본 LLM** (`supports_vision=True`인 경우)                  | 일관성: 동일한 API 키, 동일한 청구 버킷, 대화와 동일한 속도 제한 풀.                                                               |
| 2 | 활성 **ModelGroup → Fast Model** (`supports_vision=True`인 경우)    | Fast 모델(`gpt-4o-mini`, `claude-haiku`, `gemini-1.5-flash`)은 이상적인 OCR 워크호스입니다 — 저렴하고, 낮은 지연시간, 보통 멀티모달입니다. |
| 3 | 활성 **ModelGroup → General Model** (`supports_vision=True`인 경우) | 기본 모델이 그룹에 없을 때의 품질 폴백입니다.                                                                                |
| 4 | **ENV 기본 LLM** (`LLM_MODEL`)                                   | 순수 ENV 모드에 대한 낙관적 폴백입니다. 활성 ModelGroup이 없을 때만 사용됩니다. `LLM_SUPPORTS_VISION`으로 제어됩니다.                       |

**추론 모델은 OCR에 선호되지 않습니다.** 추론 계층(`o1`, `o3-mini`, `DeepSeek-R1`)은 역사적으로 비전 지원이 부족하며 OCR에는 잘못된 도구입니다 — OCR은 인식 작업이지 숙고 작업이 아닙니다. 워크스페이스에 `supports_vision=True`인 추론 모델만 있는 경우 기본 LLM 경로를 통해 여전히 선택되지만, 리졸버는 fast/general보다 높게 순위를 매기지 않습니다.

**제로 회귀 폴백**: 어떤 수준에서도 비전 기능이 있는 모델을 찾을 수 없을 때, OCR은 자동으로 비활성화되고 MarkItDown은 텍스트 전용 모드에서 실행됩니다. Word/PowerPoint/Excel 임베드된 이미지 OCR은 사용할 수 없게 됩니다(이 기능이 출시되기 전과 동일), 하지만 다른 모든 텍스트 추출(제목, 표, 단락 텍스트)은 변경 없이 계속 작동합니다. **이 기능을 추가하여 추출이 이전 동작보다 악화된 경우는 절대 없습니다.**

\*\*OpenAI가 아닌 제공자(Anthropic, Google Gemini 등)\*\*는 투명하게 지원됩니다: 해석된 LLM은 `LiteLLMOpenAIShim`으로 래핑되어 `chat.completions.create(...)` 호출을 `litellm.completion()`을 통해 라우팅하며, 이는 제공자별 메시지 형식 변환(예: Anthropic의 `source.type="base64"` 이미지 블록)을 처리합니다. 하나의 shim은 LiteLLM이 지원하는 모든 제공자를 포함합니다 — 새로운 제공자를 추가하는 데 FIM One에서 코드 변경이 필요하지 않습니다.

### 확장 사고 (추론)

`LLM_REASONING_EFFORT`가 설정되면 FIM One은 모델의 확장 사고 기능을 활성화하여 내부 사고의 연쇄가 UI의 "thinking" 단계에 표시됩니다. FIM One은 [LiteLLM](https://github.com/BerriAI/litellm)을 사용하여 추론 노력 매개변수를 각 제공자의 기본 형식으로 자동으로 변환합니다.

#### 지원되는 제공자

| 제공자                            | `LLM_BASE_URL`                                             | 작동 방식                                              | 추론 콘텐츠 반환? |
| ------------------------------ | ---------------------------------------------------------- | -------------------------------------------------- | ---------- |
| **OpenAI** (o1 / o3 / o4-mini) | `https://api.openai.com/v1`                                | `reasoning_effort` 기본적으로 전송됨                       | 예          |
| **Anthropic** (Claude 3.7+)    | `https://api.anthropic.com/v1/`                            | LiteLLM이 기본 Anthropic API를 통해 `thinking` 매개변수로 라우팅 | 예          |
| **Google Gemini** (2.5+)       | `https://generativelanguage.googleapis.com/v1beta/openai/` | `reasoning_effort`를 호환성 엔드포인트로 전송                  | 예          |

LiteLLM은 `LLM_BASE_URL`에서 제공자를 자동으로 감지하고 올바른 API 형식으로 매핑합니다. 알 수 없는 URL은 OpenAI 호환으로 처리됩니다.

#### 중요한 주의사항

<Warning>
  **타사 프록시 / 사용자 정의 엔드포인트는 보장되지 않습니다.**
  `LLM_BASE_URL`이 타사 API 프록시(예: OpenRouter, one-api, 사용자 정의 게이트웨이)를 가리키는 경우, LiteLLM은 URL을 기반으로 올바르게 라우팅하려고 시도합니다. 그러나 프록시가 비표준 형식을 예상하는 경우 추론이 예상대로 작동하지 않을 수 있습니다. 프록시의 예상 매개변수 형식에 대해서는 프록시의 설명서를 참조하세요.
</Warning>

#### 추론 활성화 시 온도 제약

일부 제공자는 추론이 활성화되었을 때 온도 제약을 적용합니다:

* **Anthropic**: 확장 사고가 활성화되면 `temperature=1`이 필수입니다. Anthropic에서 확장 사고를 사용하는 경우 `LLM_TEMPERATURE=1`을 **반드시** 설정해야 합니다 — Anthropic은 사고가 활성화되었을 때 다른 값을 거부합니다.
* **OpenAI GPT-5.x**: 항상 `temperature=1`만 지원합니다. LiteLLM의 `drop_params` 필터링이 이를 자동으로 처리합니다 — 지원되지 않는 온도 값은 자동으로 삭제됩니다. GPT-5.x의 경우 사용자 조치가 필요하지 않습니다.

#### `LLM_REASONING_BUDGET_TOKENS` 작동 방식

이 변수는 **주로 Anthropic 경로에서 의미가 있습니다**. 설정되면 자동 계산된 예산을 재정의하고 LiteLLM을 통해 `thinking` 매개변수에서 `budget_tokens`로 전송됩니다. 설정되지 않으면 예산은 `LLM_MAX_OUTPUT_TOKENS` x 노력 비율에서 파생됩니다:

| `LLM_REASONING_EFFORT` | 예산 비율 | 예시 (max\_tokens = 64000) |
| ---------------------- | ----- | ------------------------ |
| `low`                  | 20%   | 12,800 tokens            |
| `medium`               | 50%   | 32,000 tokens            |
| `high`                 | 80%   | 51,200 tokens            |

최소 예산은 1,024 tokens입니다(Anthropic의 하드 최소값).

OpenAI 및 Gemini의 경우, 제공자가 `reasoning_effort` 수준에 따라 토큰 할당을 내부적으로 처리합니다 — `LLM_REASONING_BUDGET_TOKENS`는 영향을 미치지 않습니다.

***

## 에이전트 실행

### ReAct Agent

| Variable                            | Required | Default | Description                                                                                                                                                                                                                                                                                      |
| ----------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `REACT_MAX_ITERATIONS`              | No       | `20`    | ReAct 요청당 최대 도구 호출 반복 횟수입니다. 높을수록 더 철저하지만 느리고 비용이 많이 듭니다                                                                                                                                                                                                                                         |
| `REACT_MAX_TURN_TOKENS`             | No       | `0`     | 긴급 차단 장치: 단일 ReAct 턴당 누적 토큰의 최대값(모든 반복에 걸친 프롬프트 + 완료). 기본값 `0` = 무제한. **이것은 일일 토큰 제어용이 아닙니다** — 그 목적으로는 사용자별 `token_quota`를 사용하세요. 이것은 무한 도구 호출 루프에 갇힌 에이전트 같은 극단적인 상황에 대한 최후의 안전 장치입니다. 이 한계에 도달하면 작업이 중간에 중단되어 지금까지 소비한 모든 토큰이 낭비되고 불완전한 결과가 반환됩니다. 특정 폭주 에이전트 문제를 해결해야 하는 경우가 아니면 `0`으로 유지하세요 |
| `REACT_TOOL_SELECTION_THRESHOLD`    | No       | `12`    | 등록된 도구의 총 개수가 이 임계값을 초과하면 각 요청 전에 경량 LLM 호출이 가장 관련성 높은 부분 집합을 선택합니다                                                                                                                                                                                                                              |
| `REACT_TOOL_SELECTION_MAX`          | No       | `6`     | 스마트 선택 후 유지할 최대 도구 개수(`REACT_TOOL_SELECTION_THRESHOLD`를 초과할 때만 적용)                                                                                                                                                                                                                               |
| `REACT_SELF_REFLECTION_INTERVAL`    | No       | `6`     | N번의 도구 호출마다 자체 반성 프롬프트를 주입하여 에이전트가 방향을 수정하고 루프를 피하도록 돕습니다                                                                                                                                                                                                                                        |
| `REACT_TOOL_OBS_TRUNCATION`         | No       | `8000`  | 최종 답변을 종합할 때 도구 관찰당 최대 문자 수입니다. 더 높은 값은 더 많은 구조화된 데이터(JSON, 테이블)를 보존하지만 더 많은 토큰을 소비합니다                                                                                                                                                                                                           |
| `REACT_TOOL_RESULT_BUDGET`          | No       | `40000` | 단일 세션의 모든 도구 결과에 대한 집계 토큰 예산입니다. 도구 결과 토큰의 총합이 이 한계를 초과하면 새 결과는 알림과 함께 잘립니다. 대규모 API 응답(예: 각각 8K를 반환하는 5개 연결기 호출)으로 인한 컨텍스트 팽창을 방지합니다. 한계를 비활성화하려면 `0`으로 설정하세요                                                                                                                                   |
| `REACT_COMPLETION_CHECK_SKIP_CHARS` | No       | `800`   | 에이전트의 최종 답변이 이 많은 문자를 초과할 때 사후 답변 완료 확인 LLM 호출을 건너뜁니다. 길고 상세한 답변은 "뭔가 놓친 게 없나?" 검증 왕복이 필요하지 않습니다. 더 적극적으로 건너뛰려면 낮게 설정하고, 항상 확인을 실행하려면 매우 큰 값으로 설정하세요                                                                                                                                             |
| `REACT_CYCLE_DETECTION_THRESHOLD`   | No       | `2`     | 동일한 인수로 같은 도구가 이 횟수만큼 연속으로 호출될 때 결정론적 경고가 주입되어 에이전트에게 다른 접근 방식을 시도하도록 지시합니다. 자체 반성(LLM이 루프를 인식하는 데 의존)과 달리 이것은 우회할 수 없는 해시 기반 확인입니다. DAG 단계에도 적용됩니다                                                                                                                                              |
| `REACT_COMPLETION_CHECK_MIN_TOOLS`  | No       | `3`     | 완료 체크리스트가 작동하기 전의 최소 도구 호출 수입니다. 간단한 작업(1-2개 도구 호출)은 불필요한 지연을 피하기 위해 검증을 건너뜁니다. 항상 켜진 검증을 원하면 `1`로 설정하세요. DAG 단계에도 적용됩니다                                                                                                                                                                         |
| `REACT_TURN_PROFILE_ENABLED`        | No       | `true`  | 턴별 단계 수준 타이밍 로그(`memory_load`, `compact`, `tool_schema_build`, `llm_first_token`, `llm_total`, `tool_exec`)를 내보냅니다. 턴당 하나의 구조화된 로그 라인입니다. 프로파일링을 완전히 비활성화하려면(오버헤드 없음) `false`로 설정하세요                                                                                                             |
| `REACT_PLAN_TOOL_ENABLED`           | No       | `true`  | `update_plan` 할일 도구를 등록하여 에이전트가 다단계 작업 중에 계획 체크리스트를 작성하고 유지하도록 합니다. DAG 단계 에이전트 및 도구가 없는 에이전트의 경우 자동으로 건너뜁니다                                                                                                                                                                                     |
| `REACT_PLAN_REMINDER_INTERVAL`      | No       | `3`     | `update_plan` 호출 없이 도구 라운드가 진행되다가 오래된 계획 미리 알림(전체 체크리스트 포함)이 대화에 다시 주입되어 컨텍스트 압축을 거쳐도 계획이 유지되는 횟수입니다                                                                                                                                                                                             |
| `REACT_MAX_CONTINUATIONS`           | No       | `3`     | 모델의 답변이 제공자의 출력 토큰 한계(`finish_reason=length`)로 잘릴 때의 최대 연속 라운드 수입니다. 잘린 세그먼트는 에이전트 루프와 스트리밍된 종합 모두에서 하나의 매끄러운 답변으로 연결됩니다                                                                                                                                                                         |
| `REACT_BACKGROUND_TOOLS_ENABLED`    | No       | `true`  | 느린 도구(샌드박스된 python/shell/node 실행)에 `run_in_background` 옵션을 제공합니다. 에이전트는 즉시 작업 ID를 받고 계속 작업하며, 도구가 완료되면 결과가 `<task_notification>` 메시지로 도착합니다                                                                                                                                                      |
| `REACT_BG_WAIT_TIMEOUT`             | No       | `300`   | 에이전트가 답변을 최종화하려고 할 때 여전히 실행 중인 백그라운드 도구를 기다릴 최대 초 단위 시간입니다. 이 기간 내에 완료되지 않은 작업은 명시적 타임아웃 알림과 함께 취소됩니다                                                                                                                                                                                            |
| `DAG_CHECKPOINT_EVIDENCE_CHARS`     | No       | `4000`  | DAG 충돌 복구 체크포인트 파일(`data/dag_checkpoints/`)의 단계별 증거 한계입니다. 단계 요약은 전체 형태로 저장됩니다                                                                                                                                                                                                                   |
| `DAG_CHECKPOINT_MAX_AGE_HOURS`      | No       | `24`    | 이보다 오래된 DAG 체크포인트는 로드 시 무시되므로 오래된 충돌 잔여물이 새로운 실행으로 복구되지 않습니다                                                                                                                                                                                                                                     |
| `LLM_RATE_LIMIT_PER_USER`           | No       | `true`  | 단일 프로세스 전역 버킷 대신 사용자별 키 지정 속도 제한 버킷을 사용합니다. 한 명의 시끄러운 사용자가 같은 워커의 다른 모든 사용자를 굶주리게 하는 것을 방지합니다. 기본 속도는 버킷당 분당 60개 요청 및 분당 100K 토큰으로 하드코딩되어 있습니다 — 이 설정은 버킷이 공유(전역)인지 분할(사용자별)인지만 제어합니다. 레거시 전역 버킷으로 되돌리려면 `false`로 설정하세요(권장하지 않음)                                                                 |

### DAG Planner

| Variable                         | Required | Default | Description                                                                                                                                                                                                                                                             |
| -------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MAX_CONCURRENCY`                | No       | `5`     | DAG 실행기에서 병렬로 실행할 수 있는 최대 단계 수                                                                                                                                                                                                                                          |
| `DAG_STEP_MAX_ITERATIONS`        | No       | `15`    | 각 DAG 단계 내에서 도구 호출의 최대 반복 횟수                                                                                                                                                                                                                                            |
| `DAG_STEP_TIMEOUT`               | No       | `600`   | 단계 실행 타임아웃(초). 이를 초과하는 단계는 실패로 표시되고 종속 단계는 연쇄 스킵됨                                                                                                                                                                                                                       |
| `DAG_MAX_REPLAN_ROUNDS`          | No       | `3`     | 목표가 달성되지 않았을 때 자동 재계획 시도의 최대 횟수. 사용자 중단(주입)은 무제한이며 이 예산에 포함되지 않음                                                                                                                                                                                                        |
| `DAG_REPLAN_STOP_CONFIDENCE`     | No       | `0.8`   | 목표가 달성 불가능하다는 에이전트 신뢰도가 이 임계값을 초과할 때 재시도 중단 (`0.0` = 조기 중단 안 함, `1.0` = 모든 실패 시 중단)                                                                                                                                                                                     |
| `DAG_VERIFY_TRUNCATION`          | No       | `2000`  | 단계 검증자 LLM에 전송되는 단계 출력의 최대 문자 수                                                                                                                                                                                                                                         |
| `DAG_ANALYZER_TRUNCATION`        | No       | `10000` | 실행 후 분석기 포맷팅 시 단계 결과당 최대 문자 수                                                                                                                                                                                                                                           |
| `DAG_STEP_EVIDENCE_CHARS`        | No       | `16000` | 단계별로 보존되는 원본 도구 출력(웹 페치, 검색 결과, 파일 읽기)의 최대 문자 수로, 권위 있는 "소스 증거"로 사용됨. 이는 분석기 및 최종 종합에 단계의 요약과 함께 제공되므로, 답변의 사실적 주장(합계, 열거, 심각도)을 요약이 자동으로 누락하거나 잘못 레이블한 항목 대신 소스에 대해 검증할 수 있음. `0`으로 설정하면 증거 캡처 비활성화                                                                    |
| `DAG_REPLAN_RECENT_TRUNCATION`   | No       | `500`   | 재계획 컨텍스트 구축 시 가장 최근 라운드의 단계 결과당 최대 문자 수                                                                                                                                                                                                                                 |
| `DAG_REPLAN_OLDER_TRUNCATION`    | No       | `200`   | 재계획 컨텍스트 구축 시 이전 라운드의 단계 결과당 최대 문자 수. 이전 라운드는 컨텍스트 절약을 위해 더 적극적으로 잘림                                                                                                                                                                                                    |
| `DAG_TOOL_CACHE`                 | No       | `true`  | 단일 DAG 실행 내에서 동일한 도구 호출 캐싱. `cacheable`로 명시적으로 표시된 도구(검색, 지식 검색 같은 읽기 전용 도구)만 캐시됨. `false`로 설정하면 캐싱 완전 비활성화                                                                                                                                                             |
| `DAG_STEP_VERIFICATION`          | No       | `false` | 각 DAG 단계 후 일반 LLM 기반 품질 검사. 실패 시 단계는 피드백과 함께 한 번 재시도됨. **기본값 해제** — 모든 단계에서 지연을 추가하며 거의 필요하지 않음. 대부분의 단계 출력은 재검사 없이 허용 가능함. 단계 결과 품질이 낮은 것을 자주 관찰할 때만 사용                                                                                                                |
| `DAG_CITATION_VERIFICATION`      | No       | `true`  | 전문 도메인 단계에 대한 인용 정확성 검사. **전제 조건**: 쿼리가 먼저 LLM 도메인 분류기에 의해 전문 도메인으로 분류되어야 함(`ESCALATION_DOMAINS` 참조). 도메인이 감지되고 이 플래그가 `true`일 때, 완료된 각 단계는 법률/의료/금융 인용에 대해 스캔되고 정확성 검증됨 — 환각된 기사 번호, 위조된 판례 참조, 잘못된 규제 인용을 포착함. 도메인 분류가 `null`을 반환하면(일반 쿼리), 이 설정에 관계없이 인용 검증이 실행되지 않음 |
| `DAG_CITATION_VERIFY_TRUNCATION` | No       | `6000`  | 인용 검증 프롬프트에 전송되는 단계 결과의 최대 문자 수                                                                                                                                                                                                                                         |

### 도메인 분류

ReAct 및 DAG 실행 **이전**에 실행되는 독립적인 LLM 기반 도메인 감지 레이어를 제어합니다. 쿼리가 전문 도메인으로 분류되면 시스템은 도메인 인식 기능을 활성화합니다: 추론 모델로의 모델 에스컬레이션, 도메인별 SOP 지침, 인용 검증(DAG만 해당).

| 변수                   | 필수  | 기본값                                             | 설명                                                                                                                                                                                                                         |
| -------------------- | --- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ESCALATION_DOMAINS` | 아니요 | `legal,medical,financial,tax,compliance,patent` | 전문 도메인의 쉼표로 구분된 목록입니다. 빠른 LLM이 각 쿼리를 이 목록에 대해 분류합니다. 일치하면 시스템은: (1) 더 높은 정확도를 위해 추론 모델로 업그레이드, (2) 도메인별 SOP 지침 주입(예: 작성 전 검색을 통해 인용 검증), (3) DAG 단계에 대한 인용 검증 활성화. 필요에 따라 사용자 정의 도메인 추가(예: `legal,education,construction`) |

### Context Guard

대화가 모델의 한계를 초과하지 않도록 방지하는 자동 컨텍스트 윈도우 관리를 제어합니다.

| Variable                       | Required | Default | Description                                            |
| ------------------------------ | -------- | ------- | ------------------------------------------------------ |
| `CONTEXT_GUARD_DEFAULT_BUDGET` | No       | `32000` | 컨텍스트 윈도우 관리를 위한 기본 토큰 예산입니다. 대화가 이를 초과하면 이전 메시지가 압축됩니다 |
| `CONTEXT_GUARD_MAX_MSG_CHARS`  | No       | `50000` | 단일 메시지의 하드 문자 제한입니다. 이를 초과하는 메시지는 안전 장치로 잘립니다          |
| `CONTEXT_GUARD_KEEP_RECENT`    | No       | `4`     | 대화 기록을 압축할 때 보존할 가장 최근 메시지의 개수입니다                      |

### Content Guardrails

콘텐츠를 검사하는 가드레일의 쉼표로 구분된 이름입니다. 도구 권한 게이트(`core/hooks/*`)와 보안 계층(`core/security/*`)과는 독립적입니다. 전체 그림은 [Content Guardrails](/configuration/guardrails)를 참조하세요.

| Variable                         | Required | Default     | Description                                                                                                                     |
| -------------------------------- | -------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `FIM_GUARDRAILS_INPUT`           | No       | `jailbreak` | 활성 입력 가드레일입니다. 기본값인 `jailbreak` 정규식 감지기는 알려진 프롬프트 오버라이드 구문이 감지되면 LLM 토큰이 소비되기 전에 턴을 중단합니다. 비활성화하려면 비워두세요. 알 수 없는 이름은 로깅되고 건너뜁니다 |
| `FIM_GUARDRAILS_OUTPUT`          | No       | (empty)     | 활성 출력 가드레일입니다. 현재 제공: `max_length`(답변 문자 수 제한). 에이전트가 최종 답변을 생성한 후 실행됩니다                                                        |
| `FIM_GUARDRAIL_MAX_OUTPUT_CHARS` | No       | `50000`     | `max_length` 출력 가드레일에서 사용하는 문자 제한입니다. `FIM_GUARDRAILS_OUTPUT`에 `max_length`가 나열되어 있을 때만 적용됩니다                                   |

### 에이전트 워크스페이스

| 변수                            | 필수  | 기본값    | 설명                                                          |
| ----------------------------- | --- | ------ | ----------------------------------------------------------- |
| `WORKSPACE_OFFLOAD_THRESHOLD` | 아니오 | `8000` | 도구 출력이 이 문자 수를 초과하면 워크스페이스 파일에 저장되고 잘린 미리보기가 대화 컨텍스트에 주입됩니다 |
| `WORKSPACE_PREVIEW_CHARS`     | 아니오 | `2000` | 잘린 워크스페이스 참조에 포함할 미리보기 문자 수                                 |
| `WORKSPACE_CLEANUP_MAX_HOURS` | 아니오 | `72`   | 이 시간보다 오래된 워크스페이스 파일은 자동 정리 대상입니다                           |

### 시스템

| 변수                          | 필수 | 기본값 | 설명                                                                                                                                                                                                       |
| --------------------------- | -- | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ~~`SYSTEM_PROMPT_RESERVE`~~ | —  | —   | **제거됨.** 이전에는 시스템 프롬프트에 대한 컨텍스트 예산에서 고정 4K 예약을 뺐습니다. ContextGuard가 이미 메시지 목록 토큰을 추정할 때 시스템 프롬프트를 포함하기 때문에 이중 계산이 발생했습니다. 이제 예산 공식은 단순히 `context_size - max_output_tokens`이며, 시스템 프롬프트의 실제 크기는 동적으로 계산됩니다 |

***

## 웹 도구 (선택사항)

| 변수                    | 필수  | 기본값                             | 설명                                                                                                                |
| --------------------- | --- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `JINA_API_KEY`        | 아니오 | —                               | Jina API 키. 서비스별 키가 설정되지 않았을 때 **검색, 가져오기, 임베딩 및 재순위 지정**을 위한 공유 폴백으로 작동합니다. [jina.ai](https://jina.ai/)에서 발급받으세요 |
| `TAVILY_API_KEY`      | 아니오 | —                               | Tavily Search API 키 (설정되어 있고 `WEB_SEARCH_PROVIDER`가 설정되지 않은 경우 자동 선택)                                             |
| `BRAVE_API_KEY`       | 아니오 | —                               | Brave Search API 키 (설정되어 있고 `WEB_SEARCH_PROVIDER`가 설정되지 않은 경우 자동 선택)                                              |
| `EXA_API_KEY`         | 아니오 | —                               | Exa Search API 키 (설정되어 있고 `WEB_SEARCH_PROVIDER`가 설정되지 않은 경우 자동 선택). [exa.ai](https://exa.ai/)에서 발급받으세요            |
| `WEB_SEARCH_PROVIDER` | 아니오 | `jina`                          | 검색 제공자 선택: `jina` / `tavily` / `brave` / `exa`                                                                    |
| `WEB_FETCH_PROVIDER`  | 아니오 | `jina` (키가 설정된 경우, 그 외 `httpx`) | 가져오기 제공자: `jina` (Jina Reader API 사용) / `httpx` (직접 HTTP 요청, API 키 불필요)                                           |

> **빠른 시작 팁**: `JINA_API_KEY`만 설정하면 웹 검색, 웹 가져오기, 임베딩 및 재순위 지정이 모두 한 번에 활성화됩니다 — 하나의 키로 네 가지 서비스를 이용할 수 있습니다. 아래 변수를 사용하여 각 서비스를 개별적으로 재정의할 수 있습니다.

***

## RAG 및 지식 기반 (권장)

### 임베딩

임베딩은 텍스트를 벡터로 변환하여 지식 기반 검색에 사용합니다. FIM One은 표준 **OpenAI 호환 `/v1/embeddings` 엔드포인트**를 사용하므로, Jina뿐만 아니라 이 인터페이스를 제공하는 모든 제공자와 함께 작동합니다.

| 변수                    | 필수  | 기본값                              | 설명              |
| --------------------- | --- | -------------------------------- | --------------- |
| `EMBEDDING_API_KEY`   | 아니요 | *(falls back to `JINA_API_KEY`)* | 임베딩 제공자의 API 키  |
| `EMBEDDING_BASE_URL`  | 아니요 | `https://api.jina.ai/v1`         | 임베딩 제공자의 기본 URL |
| `EMBEDDING_MODEL`     | 아니요 | `jina-embeddings-v3`             | 모델 식별자          |
| `EMBEDDING_DIMENSION` | 아니요 | `1024`                           | 벡터 차원           |

**제공자 예시** — 세 변수를 설정하여 전환하세요:

| 제공자               | `EMBEDDING_BASE_URL`          | `EMBEDDING_MODEL`        | `EMBEDDING_DIMENSION` |
| ----------------- | ----------------------------- | ------------------------ | --------------------- |
| **Jina** *(기본값)*  | `https://api.jina.ai/v1`      | `jina-embeddings-v3`     | `1024`                |
| **OpenAI**        | `https://api.openai.com/v1`   | `text-embedding-3-small` | `1536`                |
| **Voyage**        | `https://api.voyageai.com/v1` | `voyage-3`               | `1024`                |
| **Ollama** *(로컬)* | `http://localhost:11434/v1`   | `nomic-embed-text`       | `768`                 |

<Warning>
  **임베딩 모델 또는 차원을 변경하면 기존의 모든 지식 기반 벡터가 무효화됩니다.** 이전 벡터는 다른 임베딩 공간에서 계산되었으므로 검색 정확도가 조용히 저하될 것입니다. 전환 후 **모든 지식 기반 인덱스를 다시 구축해야 합니다**.
</Warning>

### 검색

| 변수               | 필수  | 기본값         | 설명                                                           |
| ---------------- | --- | ----------- | ------------------------------------------------------------ |
| `RETRIEVAL_MODE` | 아니오 | `grounding` | `grounding` (인용 및 신뢰도 점수가 포함된 전체 파이프라인) 또는 `simple` (기본 RAG) |

### Reranker

Reranker는 검색된 문서를 다시 점수 매겨 관련성을 개선합니다. 세 가지 공급자가 지원되며 `RERANKER_PROVIDER`를 통해 선택하거나 시스템이 사용 가능한 API 키에서 자동 감지하도록 할 수 있습니다.

| Variable                | Required | Default                              | Description                                                                                    |
| ----------------------- | -------- | ------------------------------------ | ---------------------------------------------------------------------------------------------- |
| `RERANKER_PROVIDER`     | No       | *(auto-detect)*                      | `jina` / `cohere` / `openai`. 설정하지 않으면: `COHERE_API_KEY`가 설정된 경우 Cohere를 사용하고, 그렇지 않으면 Jina 사용 |
| `RERANKER_MODEL`        | No       | `jina-reranker-v2-base-multilingual` | 모델 식별자 (Jina 및 OpenAI 공급자에 적용)                                                                 |
| `COHERE_API_KEY`        | No       | —                                    | Cohere API 키 (설정되고 `RERANKER_PROVIDER`가 설정되지 않은 경우 Cohere reranker 자동 선택)                      |
| `COHERE_RERANKER_MODEL` | No       | `rerank-multilingual-v3.0`           | Cohere 전용 reranker 모델                                                                          |

> **Jina**는 `JINA_API_KEY`를 사용합니다 (위의 Web Tools에서). **OpenAI**는 `LLM_API_KEY` / `LLM_BASE_URL`을 재사용합니다 — 추가 키가 필요하지 않습니다. **Cohere**는 자체 `COHERE_API_KEY`가 필요합니다.

> Reranker는 **선택 사항**입니다 — 지식 베이스 검색은 fusion 점수 매기기를 사용하여 이 없이도 작동합니다. Embedding은 지식 베이스 기능에 **권장**됩니다.

### 벡터 저장소

| 변수                 | 필수  | 기본값                   | 설명                                          |
| ------------------ | --- | --------------------- | ------------------------------------------- |
| `VECTOR_STORE_DIR` | 아니요 | `./data/vector_store` | LanceDB 벡터 저장소 데이터용 디렉토리 (파일 기반, 외부 서비스 없음) |

***

## 코드 실행

| 변수                     | 필수  | 기본값                | 설명                                                                                                                         |
| ---------------------- | --- | ------------------ | -------------------------------------------------------------------------------------------------------------------------- |
| `CODE_EXEC_BACKEND`    | 아니오 | `local`            | `local` (직접 호스트 실행) 또는 `docker` (격리된 컨테이너)                                                                                 |
| `DOCKER_PYTHON_IMAGE`  | 아니오 | `python:3.11-slim` | Python 실행용 Docker 이미지                                                                                                      |
| `DOCKER_NODE_IMAGE`    | 아니오 | `node:20-slim`     | Node.js 실행용 Docker 이미지                                                                                                     |
| `DOCKER_SHELL_IMAGE`   | 아니오 | `python:3.11-slim` | 셸 실행용 Docker 이미지                                                                                                           |
| `DOCKER_MEMORY`        | 아니오 | *(Docker 기본값)*     | 컨테이너당 RAM 제한 (예: `256m`, `512m`, `1g`)                                                                                     |
| `DOCKER_CPUS`          | 아니오 | *(Docker 기본값)*     | 컨테이너당 CPU 할당량 (예: `0.5`, `1.0`)                                                                                            |
| `SANDBOX_TIMEOUT`      | 아니오 | `120`              | 기본 실행 타임아웃(초)                                                                                                              |
| `DOCKER_HOST_DATA_DIR` | 아니오 | *(설정되지 않음)*        | `./data` 볼륨 마운트의 호스트 측 절대 경로. DooD(Docker-outside-of-Docker) 배포에 필수이며, `docker-compose.yml`은 `${PWD}/data`를 통해 자동으로 설정합니다. |

> **보안**: `local` 모드는 AI가 생성한 코드를 호스트에서 직접 실행합니다. 인터넷 공개 또는 다중 사용자 배포의 경우, 항상 `CODE_EXEC_BACKEND=docker`로 설정하세요.

***

## 도구 아티팩트

도구 실행(코드 실행, 템플릿 렌더링, 이미지 생성)으로 생성된 파일의 크기 제한입니다.

| 변수                    | 필수  | 기본값                | 설명                     |
| --------------------- | --- | ------------------ | ---------------------- |
| `MAX_ARTIFACT_SIZE`   | 아니오 | `10485760` (10 MB) | 단일 아티팩트 파일의 최대 크기(바이트) |
| `MAX_ARTIFACTS_TOTAL` | 아니오 | `52428800` (50 MB) | 세션당 총 아티팩트의 최대 크기(바이트) |

***

## 문서 처리 (선택사항)

업로드된 PDF/DOCX 파일이 LLM 사용을 위해 어떻게 처리되는지를 제어합니다. 비전 기능이 있는 모델(GPT-4o, Claude 3/4, Gemini)은 더 높은 충실도를 위해 PDF 페이지를 렌더링된 이미지로 받을 수 있습니다.

| 변수                          | 필수  | 기본값    | 설명                                                               |
| --------------------------- | --- | ------ | ---------------------------------------------------------------- |
| `DOCUMENT_PROCESSING_MODE`  | 아니오 | `auto` | `auto` (모델이 지원하면 비전), `vision` (항상 페이지 렌더링), `text` (항상 텍스트만 추출) |
| `DOCUMENT_VISION_DPI`       | 아니오 | `150`  | PDF 페이지 렌더링을 위한 DPI. 높을수록 = 더 나은 품질, 더 많은 토큰                     |
| `DOCUMENT_VISION_MAX_PAGES` | 아니오 | `20`   | PDF당 이미지로 렌더링할 최대 페이지 수                                          |

> **참고**: 모델별 비전 지원은 관리자 → 모델의 `supports_vision` 토글을 통해 구성됩니다. 명시적으로 설정되지 않으면 시스템이 모델 이름에서 비전 기능을 자동으로 감지합니다.

***

## 이미지 생성 (선택사항)

| 변수                   | 필수  | 기본값                              | 설명                                                                                              |
| -------------------- | --- | -------------------------------- | ----------------------------------------------------------------------------------------------- |
| `IMAGE_GEN_PROVIDER` | 아니오 | `google`                         | `google` (Gemini 네이티브 API) 또는 `openai` (OpenAI 호환 `/v1/images/generations`)                     |
| `IMAGE_GEN_API_KEY`  | 아니오 | —                                | Google AI Studio 키 (`google`) 또는 프록시/OpenAI API 키 (`openai`)                                    |
| `IMAGE_GEN_MODEL`    | 아니오 | `gemini-3.1-flash-image-preview` | 이미지 생성 모델 (예: `dall-e-3`, `gemini-nano-banana-2`)                                               |
| `IMAGE_GEN_BASE_URL` | 아니오 | *(공급자별)*                         | Google: `https://generativelanguage.googleapis.com/v1beta`; OpenAI: `https://api.openai.com/v1` |

***

## Email (SMTP) (권장)

`SMTP_HOST`, `SMTP_USER`, `SMTP_PASS`가 모두 설정되면 `email_send` 내장 도구를 자동으로 등록합니다.

| Variable                 | Required | Default              | Description                                                                                                           |
| ------------------------ | -------- | -------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `SMTP_HOST`              | Cond.    | —                    | SMTP 서버 호스트명                                                                                                          |
| `SMTP_PORT`              | No       | `465`                | SMTP 포트                                                                                                               |
| `SMTP_SSL`               | No       | `ssl`                | TLS 모드: `ssl` (포트 465) / `tls` (STARTTLS, 포트 587) / `none` 또는 `""` (평문, 자격증명이 평문으로 전송됨). 다른 값은 평문으로 자동 폴백되지 않고 거부됩니다. |
| `SMTP_USER`              | Cond.    | —                    | SMTP 로그인 사용자명                                                                                                         |
| `SMTP_PASS`              | Cond.    | —                    | SMTP 로그인 비밀번호                                                                                                         |
| `SMTP_FROM`              | No       | *(uses `SMTP_USER`)* | From 헤더에 표시되는 발신자 주소                                                                                                  |
| `SMTP_FROM_NAME`         | No       | —                    | From 헤더에 표시되는 표시 이름                                                                                                   |
| `SMTP_REPLY_TO`          | No       | —                    | Reply-To 주소; 회신이 `SMTP_FROM` 대신 여기로 전송됨                                                                               |
| `SMTP_ALLOWED_DOMAINS`   | No       | —                    | 쉼표로 구분된 도메인 허용 목록 (예: `example.com,corp.io`); 나열된 도메인 외의 수신자를 차단함                                                     |
| `SMTP_ALLOWED_ADDRESSES` | No       | —                    | 쉼표로 구분된 정확한 주소 허용 목록; `SMTP_ALLOWED_DOMAINS`과 함께 적용됨; 모든 수신자를 허용하려면 둘 다 설정하지 않음 (공유 메일박스의 경우 권장하지 않음)                 |

***

## 커넥터

| 변수                             | 필수  | 기본값           | 설명                                                                                                                                                                    |
| ------------------------------ | --- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CONNECTOR_RESPONSE_MAX_CHARS` | 아니오 | `50000`       | 배열이 아닌 JSON / 일반 텍스트 커넥터 응답의 최대 문자 수                                                                                                                                  |
| `CONNECTOR_RESPONSE_MAX_ITEMS` | 아니오 | `10`          | 커넥터 응답이 JSON 배열일 때 유지할 최대 배열 항목 수                                                                                                                                     |
| `CREDENTIAL_ENCRYPTION_KEY`    | 아니오 | *(설정되지 않음)*   | 커넥터 자격증명 blob에 대한 Fernet 암호화 키. 설정되면 `connector_credentials`에 저장된 인증 토큰이 저장 시 암호화됩니다. 설정되지 않으면 자격증명이 일반 텍스트 JSON으로 저장됩니다(하위 호환성). 이 키를 변경하면 기존의 모든 암호화된 자격증명이 무효화됩니다. |
| `CONNECTOR_TOOL_MODE`          | 아니오 | `progressive` | 커넥터 도구가 에이전트에 노출되는 방식. `progressive`: `discover`/`execute` 하위 명령이 있는 단일 `ConnectorMetaTool`(커넥터당 \~30 토큰). `classic`: 작업당 하나의 도구(레거시, 작업당 \~250 토큰).                  |
| `DATABASE_TOOL_MODE`           | 아니오 | `progressive` | 데이터베이스 커넥터 도구가 에이전트에 노출되는 방식. `progressive`: `list_tables`/`discover`/`query` 하위 명령이 있는 단일 `DatabaseMetaTool`. `legacy`: 데이터베이스 커넥터당 작업당 하나의 도구(각 3개 도구).             |
| `MCP_TOOL_MODE`                | 아니오 | `progressive` | MCP 서버 도구가 에이전트에 노출되는 방식. `progressive`: `discover`/`call` 하위 명령이 있는 단일 `MCPServerMetaTool`. `legacy`: MCP 서버 작업당 하나의 도구(원본 개별 도구).                                   |

***

## Platform

| Variable                         | Required | Default                                 | Description                                                                                                                                                                                                           |
| -------------------------------- | -------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DATABASE_URL`                   | No       | `sqlite+aiosqlite:///./data/fim_one.db` | 데이터베이스 연결 문자열. **SQLite** (설정 불필요): `sqlite+aiosqlite:///./data/fim_one.db`. **PostgreSQL** (프로덕션): `postgresql+asyncpg://user:pass@localhost:5432/fim_one`. Docker Compose는 PostgreSQL을 자동으로 설정합니다.                  |
| `JWT_SECRET_KEY`                 | No       | `CHANGE_ME`                             | JWT 토큰 서명용 비밀 키. 플레이스홀더 값 `CHANGE_ME` (또는 기타 레거시 기본값)는 첫 시작 시 안전한 256비트 난수 키를 자동 생성하고 `.env`에 기록합니다. 프로덕션에서는 명시적으로 설정하여 재시작 및 복제본 간에 토큰이 유효하게 유지되도록 하세요.                                                              |
| `FIM_BCRYPT_COST`                | No       | `12`                                    | 비밀번호 해싱을 위한 bcrypt 작업 계수(4-31로 제한됨). 기본값 12는 최신 CPU에서 해시당 약 200ms 소요됩니다. 약한 하드웨어에서는 낮추고, 보안 강화 배포에서는 높이세요.                                                                                                            |
| `CORS_ORIGINS`                   | No       | —                                       | 기본 localhost 항목 외에 허용되는 추가 CORS 원본의 쉼표 구분 목록. 프론트엔드가 비localhost 도메인에서 실행될 때 필수입니다(예: `https://app.example.com`).                                                                                                      |
| `UPLOADS_DIR`                    | No       | `./uploads`                             | 업로드된 파일을 위한 디렉토리                                                                                                                                                                                                      |
| `MAX_UPLOAD_SIZE_MB`             | No       | `50`                                    | 최대 파일 업로드 크기(메가바이트 단위, 백엔드 적용)                                                                                                                                                                                        |
| `NEXT_PUBLIC_MAX_UPLOAD_SIZE_MB` | No       | `50`                                    | 프론트엔드 UI에 표시되는 최대 파일 업로드 크기. **빌드 타임 변수** — `MAX_UPLOAD_SIZE_MB`와 일치해야 합니다.                                                                                                                                           |
| `MCP_SERVERS`                    | No       | —                                       | MCP 서버 설정의 JSON 배열(`uv sync --extra mcp` 필요)                                                                                                                                                                          |
| `ALLOW_STDIO_MCP`                | No       | `false`                                 | stdio MCP 서버 허용. 신뢰할 수 있는 로컬 배포에서만 `true`로 설정하세요                                                                                                                                                                      |
| `ALLOWED_STDIO_COMMANDS`         | No       | `npx,uvx,node,python,python3,deno,bun`  | stdio MCP 서버에 허용되는 기본 명령어의 쉼표 구분 목록. `ALLOW_STDIO_MCP=true`일 때만 적용됩니다                                                                                                                                                 |
| `LOG_LEVEL`                      | No       | `INFO`                                  | 로깅 레벨: `DEBUG` / `INFO` / `WARNING` / `ERROR` / `CRITICAL`                                                                                                                                                            |
| `REDIS_URL`                      | No       | —                                       | 워커 간 인터럽트 릴레이를 위한 Redis 연결 URL. **`WORKERS>1`일 때 필수** — 없으면 스트림 중 인터럽트/주입 요청이 다른 워커에 도달하여 자동으로 실패할 수 있습니다. Docker Compose에서 자동 설정됩니다.                                                                                 |
| `WORKERS`                        | No       | `1`                                     | Uvicorn 워커 프로세스. `1`은 안전하며 외부 서비스가 필요 없습니다. 프로덕션 멀티워커의 경우 PostgreSQL을 사용하세요(SQLite는 단일 쓰기). SQLite는 가벼운 로드 하에서 로컬 개발에 적합합니다. 인증, OAuth, 파일 작업은 완전히 멀티워커 안전합니다(JWT 기반). Docker Compose는 PostgreSQL과 Redis를 자동으로 설정합니다. |

<Warning>
  **멀티워커 체크리스트** (`WORKERS>1`):

  * **중지(스트림 중단)** — 항상 작동하며, 추가 설정이 필요 없습니다(신호는 동일한 TCP 연결을 통해 이동).
  * **주입(스트림 중 후속)** — **`REDIS_URL` 필수**. Redis 없으면 주입 요청이 실행 중인 실행에 대한 지식이 없는 다른 워커에 도달하여 자동으로 실패합니다.
  * **프로덕션**: PostgreSQL(`DATABASE_URL`) 사용. SQLite의 단일 쓰기 잠금은 동시 쓰기 시 경합을 유발할 수 있습니다.
  * **로컬 개발**: SQLite + 멀티워커는 가벼운 사용에 적합합니다. 주입 기능을 사용하면 `REDIS_URL`을 추가하세요.
</Warning>

## 워크플로우 실행 보관

오래된 워크플로우 실행을 자동으로 정리하는 백그라운드 작업입니다. 워크플로우 설정 UI에서 구성한 워크플로우별 재정의가 이러한 전역 기본값보다 우선합니다.

| 변수                                    | 필수  | 기본값   | 설명                                   |
| ------------------------------------- | --- | ----- | ------------------------------------ |
| `WORKFLOW_RUN_MAX_AGE_DAYS`           | 아니요 | `30`  | 이 일수보다 오래된 워크플로우 실행 삭제               |
| `WORKFLOW_RUN_MAX_PER_WORKFLOW`       | 아니요 | `100` | 워크플로우당 최대 이 개수의 실행 유지(가장 오래된 것부터 삭제) |
| `WORKFLOW_RUN_CLEANUP_INTERVAL_HOURS` | 아니요 | `24`  | 백그라운드 정리 작업 실행 빈도(시간 단위)             |

### 채널 확인 요청 만료

`FeishuGateHook` 또는 Approval Playground와 같은 채널 hook에서 생성된 대기 중인 승인 요청을 오래된 것으로 표시하는 백그라운드 sweeper입니다. 나중에 잊혀진 카드를 클릭해도 이미 해제된 agent 상태가 뒤집히지 않도록 합니다.

| Variable                                      | Required | Default | Description                                 |
| --------------------------------------------- | -------- | ------- | ------------------------------------------- |
| `CHANNEL_CONFIRMATION_TTL_MINUTES`            | No       | `1440`  | 이 시간보다 오래된 대기 중인 확인은 자동으로 만료됩니다 (기본값: 24시간) |
| `CHANNEL_CONFIRMATION_SWEEP_INTERVAL_SECONDS` | No       | `600`   | 만료 sweeper가 실행되는 빈도 (기본값: 10분마다)            |

## OAuth (선택 사항)

공급자에 대해 `CLIENT_ID`와 `CLIENT_SECRET`이 모두 설정되면 로그인 페이지에 해당 OAuth 버튼이 자동으로 표시됩니다.

| 변수                      | 필수       | 기본값                          | 설명                                                                                                                                                                                    |
| ----------------------- | -------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GITHUB_CLIENT_ID`      | 아니오      | —                            | GitHub OAuth App 클라이언트 ID. [github.com/settings/developers](https://github.com/settings/developers) → OAuth Apps에서 생성                                                                 |
| `GITHUB_CLIENT_SECRET`  | 아니오      | —                            | GitHub OAuth App 클라이언트 시크릿                                                                                                                                                            |
| `GOOGLE_CLIENT_ID`      | 아니오      | —                            | Google OAuth 클라이언트 ID. [console.cloud.google.com/apis/credentials](https://console.cloud.google.com/apis/credentials)에서 생성                                                            |
| `GOOGLE_CLIENT_SECRET`  | 아니오      | —                            | Google OAuth 클라이언트 시크릿                                                                                                                                                                |
| `DISCORD_CLIENT_ID`     | 아니오      | —                            | Discord OAuth2 클라이언트 ID. [discord.com/developers](https://discord.com/developers/applications)에서 생성                                                                                   |
| `DISCORD_CLIENT_SECRET` | 아니오      | —                            | Discord OAuth2 클라이언트 시크릿                                                                                                                                                              |
| `FEISHU_APP_ID`         | 아니오      | —                            | Feishu (Lark) App ID. [open.feishu.cn](https://open.feishu.cn/app)에서 생성. `contact:user.email:readonly` 권한 필요                                                                          |
| `FEISHU_APP_SECRET`     | 아니오      | —                            | Feishu (Lark) App Secret                                                                                                                                                              |
| `FRONTEND_URL`          | **프로덕션** | `http://localhost:3000`      | OAuth 완료 후 브라우저가 이동할 위치. 프로덕션에서 설정 필수 (예: `https://yourdomain.com`)                                                                                                                   |
| `API_BASE_URL`          | **프로덕션** | `http://localhost:8000`      | 외부에서 접근 가능한 백엔드 URL, OAuth 콜백 URL 구성에 사용. 프로덕션에서 설정 필수                                                                                                                                |
| `NEXT_PUBLIC_API_URL`   | **프로덕션** | *(자동 감지: `<hostname>:8000`)* | OAuth 리다이렉트를 위한 브라우저 측 API 기본 URL. **이것은 프론트엔드 빌드 타임 변수**입니다 — 로컬 개발의 경우 `frontend/.env.local`에서 설정하거나, 커스텀 프로덕션 배포의 경우 Docker 빌드 인자로 전달하세요. 자동 감지는 표준 리버스 프록시 설정(포트 80/443)에서 작동합니다. |

> **프로덕션** = 로컬에서는 선택 사항(기본값 작동), 하지만 인터넷에 노출된 배포의 경우 **필수**입니다.

### 각 제공자에 등록할 OAuth 콜백 URL

백엔드는 콜백 URL을 다음과 같이 구성합니다: `{API_BASE_URL}/api/auth/oauth/{provider}/callback`

| 제공자     | 등록할 콜백 URL                                               |
| ------- | -------------------------------------------------------- |
| GitHub  | `https://yourdomain.com/api/auth/oauth/github/callback`  |
| Google  | `https://yourdomain.com/api/auth/oauth/google/callback`  |
| Discord | `https://yourdomain.com/api/auth/oauth/discord/callback` |

***

## Cloudflare Tunnel (선택사항)

Cloudflare의 네트워크를 통해 모든 트래픽을 라우팅하여 포트를 직접 노출하지 않습니다. Nginx, SSL 인증서 및 열린 방화벽 규칙의 필요성을 제거합니다. 설정 지침은 [프로덕션 배포](/quickstart#cloudflare-tunnel) 섹션을 참조하세요.

<Warning>
  **중국 본토 사용자**: Cloudflare Free/Pro/Business 플랜은 중국 본토에 PoP가 없습니다. 트래픽이 해외 엣지로 라우팅되어 502 오류가 자주 발생합니다. 중국 네트워크가 있는 Cloudflare Enterprise가 없는 한 주요 사용자가 중국 본토에 있는 경우 이를 사용하지 마세요.
</Warning>

| 변수                        | 필수                  | 기본값 | 설명                                                                                                                                                         |
| ------------------------- | ------------------- | --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CLOUDFLARE_TUNNEL_TOKEN` | **예** (Tunnel 사용 시) | —   | Cloudflare Zero Trust → Networks → Tunnels → your tunnel → Configure에서 가져온 토큰입니다. `eyJ...`로 시작합니다. `docker-compose.tunnel.yml`의 `cloudflared` 사이드카에 필요합니다. |

***

## 분석 (선택사항)

모든 분석 제공자는 선택사항입니다. 원하는 조합으로 설정하면 모든 활성 제공자가 동시에 로드됩니다. 분석을 완전히 비활성화하려면 모두 비워두세요(로컬 개발에 권장).

| 변수                                 | 필수  | 기본값                                 | 설명                                                                                                               |
| ---------------------------------- | --- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `NEXT_PUBLIC_GA_MEASUREMENT_ID`    | 아니요 | —                                   | Google Analytics 4 측정 ID (예: `G-XXXXXXXXXX`). [analytics.google.com](https://analytics.google.com)에서 발급받으세요      |
| `NEXT_PUBLIC_UMAMI_SCRIPT_URL`     | 아니요 | —                                   | Umami 분석 스크립트 URL (예: `https://your-umami.com/script.js`). 자체 호스팅, 개인정보 보호 친화적 대안 — [umami.is](https://umami.is) |
| `NEXT_PUBLIC_UMAMI_WEBSITE_ID`     | 아니요 | —                                   | Umami 웹사이트 ID. `NEXT_PUBLIC_UMAMI_SCRIPT_URL`이 설정되어 있을 때 필수                                                      |
| `NEXT_PUBLIC_PLAUSIBLE_DOMAIN`     | 아니요 | —                                   | Plausible 분석 도메인 (예: `yourdomain.com`). 경량, 개인정보 보호 친화적 — [plausible.io](https://plausible.io)                   |
| `NEXT_PUBLIC_PLAUSIBLE_SCRIPT_URL` | 아니요 | `https://plausible.io/js/script.js` | 자체 호스팅 인스턴스용 커스텀 Plausible 스크립트 URL                                                                              |

> 모든 `NEXT_PUBLIC_*` 분석 변수는 **빌드 시간** 변수입니다 — 변경사항을 적용하려면 프론트엔드를 다시 빌드해야 합니다.

## Stripe 결제 (선택사항)

Stripe는 Pro 구독을 지원합니다. 세 변수를 모두 비워두면 결제 기능이 비활성화되며, FIM One의 나머지 기능은 정상 작동합니다. **`STRIPE_SECRET_KEY`와 `STRIPE_WEBHOOK_SECRET`을 함께 설정해야 합니다**. 부분적인 설정은 첫 사용 시 오류를 발생시킵니다.

| 변수                          | 필수  | 기본값                                          | 설명                                                                                                                                                                           |
| --------------------------- | --- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `STRIPE_SECRET_KEY`         | 아니요 | —                                            | Stripe API 시크릿 키입니다. `sk_test_` / `sk_live_`(전체 액세스) 또는 `rk_test_` / `rk_live_`(제한된 키)로 시작해야 합니다. Stripe 대시보드 → Developers → API keys에서 발급받으세요. `sk_live_*` 키를 소스에 커밋하지 마세요. |
| `STRIPE_WEBHOOK_SECRET`     | 아니요 | —                                            | Stripe 웹훅 서명 시크릿(`whsec_*`)입니다. Stripe 대시보드 → Developers → Webhooks → Add endpoint에서 웹훅 엔드포인트를 등록할 때 생성됩니다. 인바운드 웹훅 페이로드를 검증하는 데 필요합니다.                                      |
| `STRIPE_BILLING_RETURN_URL` | 아니요 | `http://localhost:3000/settings?tab=billing` | Checkout 또는 Customer Portal 세션 후 Stripe가 사용자를 리다이렉트할 URL입니다. 프로덕션 결제 설정 페이지로 설정하세요(예: `https://your-domain.com/settings?tab=billing`).                                       |
