> For the complete documentation index, see [llms.txt](https://genos-docs.gitbook.io/default/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://genos-docs.gitbook.io/default/v1.9.4/advanced-tutorials/guides/langfuse.md).

# Langfuse 연동

GenOS에서 "Langfuse"는 두 가지 맥락으로 쓰입니다. 하나는 GenOS 자체가 서빙 실행마다 내부적으로 기록하는 Langfuse이고, 다른 하나는 코드 서빙을 개발하는 사용자가 자신의 Langfuse(Self-hosting 또는 Cloud)를 직접 연동해 트레이스를 남기는 경우입니다. 이 문서는 두 경우 모두를 다루며, 특히 후자를 GenOS 코드 서빙 환경에 실제로 연동하는 방법에 초점을 둡니다.

<figure><img src="https://1274363562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoJuB29xjw7zmR91VXmqf%2Fuploads%2F4UiCrbxxh320xBpScdJC%2F01_overview.png?alt=media&amp;token=3e225d72-dfb0-4e58-aebe-b05a42a8e13d" alt=""><figcaption></figcaption></figure>

### 주요 개념

| 개념                | 설명                                                                                                                                                                                                                                                                                                                                           |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| trace             | 워크플로우가 한 번 실행되어 결과를 얻기까지의 과정입니다. GenOS 기준으로는 1턴에 해당합니다.                                                                                                                                                                                                                                                                                      |
| session           | trace들의 모음입니다. 에이전트가 멀티턴 대화를 지원할 때, 하나의 대화에 속한 여러 턴(trace)을 묶는 단위로 사용합니다.                                                                                                                                                                                                                                                                    |
| observation       | 개별 동작 1회를 의미합니다. 문서 검색, LLM 생성, 에이전트 동작 등 함수 단위 동작 하나하나가 observation이 되며, span 형태로 trace 안에 중첩됩니다.                                                                                                                                                                                                                                           |
| GenOS 내부 Langfuse | GenOS가 서빙(모델·코드)이 호출될 때마다 자동으로 기록하는 Langfuse입니다. `서빙 > 코드 서빙(또는 모델 서빙) > 이용 로그`에서 확인할 수 있습니다.                                                                                                                                                                                                                                                |
| 외부(개인) Langfuse   | 개발자가 별도로 가입한 Langfuse 프로젝트(Self-hosting 또는 Cloud)입니다. 코드 서빙 개발 중 자신의 에이전트 실행을 상세히 추적하고 싶을 때 직접 연동합니다.                                                                                                                                                                                                                                        |
| `traceparent`     | trace\_id와 parent span id를 하나의 문자열로 실어 보내는 [W3C Trace Context 표준 헤더](https://www.w3.org/TR/trace-context/#traceparent-header)입니다. 형식은 `<version>-<trace-id>-<parent-id>-<flags>`이며, trace-id는 32자리, parent-id는 16자리 16진수 문자열입니다. 예: `00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01`. GenOS와 Langfuse 간 trace를 이어 붙일 때 이 헤더를 사용합니다. |

### GenOS 이용 로그에서 트레이스 확인하기

GenOS는 서빙이 실행될 때마다 내부 Langfuse에 trace를 자동으로 기록합니다. 별도 연동 없이도 아래 경로로 확인할 수 있습니다.

**1단계.** `서빙 > 코드 서빙(또는 모델 서빙)`에서 확인하려는 서빙을 더블클릭합니다.

<figure><img src="https://1274363562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoJuB29xjw7zmR91VXmqf%2Fuploads%2Fgit-blob-8d8caae96199b39946ab8b1b0632c0b51ba2a492%2F02_code_serving_list.png?alt=media" alt=""><figcaption></figcaption></figure>

**2단계.** `이용 로그` 탭에서 확인하려는 로그 항목을 클릭합니다.

<figure><img src="https://1274363562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoJuB29xjw7zmR91VXmqf%2Fuploads%2FS1sKFRCZs8eXlBcfrMEt%2F03_code_serving_log_list.png?alt=media&amp;token=80d1a3be-6ae2-4d9f-9b07-616f3359742e" alt=""><figcaption></figcaption></figure>

**3단계.** Langfuse 형태의 트레이스 상세 화면이 표시됩니다.

<figure><img src="https://1274363562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoJuB29xjw7zmR91VXmqf%2Fuploads%2F4UiCrbxxh320xBpScdJC%2F01_overview.png?alt=media&amp;token=3e225d72-dfb0-4e58-aebe-b05a42a8e13d" alt=""><figcaption></figcaption></figure>

이 화면에서는 검색(retrieve) 결과, LLM 입출력, 도구 호출 등 요청 처리 과정이 observation 단위로 펼쳐져 표시됩니다. 코드 서빙 안에 별도 계측을 추가하면(아래 GenOS 자체 이용 로그와 내 트레이스 연결하기 참고), 이 화면의 trace 안에 자신의 span을 자식으로 이어 붙일 수도 있습니다.

### 코드 서빙에 Langfuse 연동하기

개발 중인 코드 서빙에 자신의 Langfuse를 연동해 요청 처리 과정을 상세히 추적하려면 아래 순서를 따릅니다.

#### 1. Langfuse 키 발급

Langfuse(Self-hosting 또는 Cloud)에 가입한 뒤 프로젝트에서 `public key`와 `secret key`를 발급받습니다.

#### 2. 환경 변수 설정

발급받은 값을 코드 서빙 배포 환경 변수로 등록합니다. `서빙 > 코드 서빙 > (해당 서빙) > 코드 서빙 리비전 상세 > 환경 설정` 탭에서 추가할 수 있습니다.

<figure><img src="https://1274363562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoJuB29xjw7zmR91VXmqf%2Fuploads%2FoWDsGr4RmzszyGzTsRDx%2F04_code_serving_env_vars.png?alt=media&amp;token=09026b2d-53a9-49e5-ad29-f43acac0f082" alt=""><figcaption></figcaption></figure>

| 환경 변수                 | 설명                                               |
| --------------------- | ------------------------------------------------ |
| `LANGFUSE_HOST`       | 사용 중인 Langfuse의 base URL (Self-hosting 또는 Cloud) |
| `LANGFUSE_PUBLIC_KEY` | Langfuse에서 발급받은 public key                       |
| `LANGFUSE_SECRET_KEY` | Langfuse에서 발급받은 secret key                       |

> **참고** — 세 값 중 하나라도 비어 있으면(또는 `langfuse` 패키지 import에 실패하면) SDK 전체가 자동으로 no-op으로 폴백합니다. `get_client()`, `@observe`, `propagate_attributes`를 그대로 호출해도 에러 없이 계측만 조용히 건너뛰고 나머지 로직은 정상 동작합니다.

#### 3. SDK 설치

사용하는 언어에 맞춰 Langfuse SDK를 설치합니다. Python의 경우:

```bash
pip install langfuse
```

#### 4. 계측 코드 작성

Langfuse는 코드에 계측을 붙이는 방식을 크게 세 가지로 지원합니다. 상황에 따라 섞어 쓰는 경우가 많으므로 모두 알아두는 것이 좋습니다.

| 방식               | 설명                                                                                                                                 |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Context Manager  | `with client.start_as_current_observation(...)`로 span/generation을 열고, 블록이 끝나면 자동으로 닫는 방식입니다. 입출력 구간이 함수 경계와 딱 맞지 않을 때 적합합니다.       |
| Decorator        | 함수에 `@observe(as_type=...)`를 붙이면 함수의 인자/반환값이 자동으로 input/output으로 캡처됩니다. 중첩 호출 시 부모-자식 span 관계도 자동으로 만들어집니다.                        |
| Manual Lifecycle | `start_observation()`으로 observation을 생성해 두고 원하는 시점에 `.update()`/`.end()`를 직접 호출하는 저수준 방식입니다. `with` 블록으로 묶기 어려운 콜백·이벤트 핸들러에 적합합니다. |

**Decorator 방식 예시** (가장 간단하게 시작할 수 있는 방식):

```python
from langfuse import get_client, observe

@observe(as_type="span", name="rag-pipeline")   # 최상위 호출 -> trace 루트가 됨
async def run_rag_pipeline(question: str) -> str:
    documents = retrieve_documents(question)     # 자동으로 자식 span
    return generate_answer(question, documents)

@observe(as_type="retriever", name="retrieve-documents")
def retrieve_documents(question: str) -> list: ...

@observe(as_type="generation", name="generate-answer")   # LLM 호출 함수는 generation으로
def generate_answer(question: str, documents: list) -> str: ...

# 응답 반환 전 flush 필수 (아래 IMPORTANT 참고)
get_client().flush()
```

**Context Manager 방식 예시** (입출력 구간이 함수 경계로 깔끔히 나뉘지 않을 때):

```python
from langfuse import get_client

client = get_client()

with client.start_as_current_observation(
    as_type="span", name="rag-pipeline", input=question
) as root_span:
    with client.start_as_current_observation(
        as_type="retriever", name="retrieve-documents", input=question
    ) as retriever_span:
        documents = retrieve_documents(question)
        retriever_span.update(output=documents)

    with client.start_as_current_observation(
        as_type="generation", name="generate-answer", model="gpt-4o-mini"
    ) as generation_span:
        answer = generate_answer(question, documents)
        generation_span.update(output=answer)

    root_span.update(output=answer)

client.flush()
```

**Manual Lifecycle 방식 예시** (콜백·이벤트 핸들러 등 `with` 블록으로 묶기 어려운 경우):

```python
from langfuse import get_client

client = get_client()

root_span = client.start_observation(as_type="span", name="rag-pipeline", input=question)
try:
    retriever_span = root_span.start_observation(
        as_type="retriever", name="retrieve-documents", input=question
    )
    try:
        documents = retrieve_documents(question)
        retriever_span.update(output=documents)
    finally:
        retriever_span.end()

    answer = generate_answer(question, documents)
    root_span.update(output=answer)
finally:
    root_span.end()

client.flush()
```

> **중요** — 응답을 반환하기 전에 `client.flush()`를 반드시 호출해야 합니다. Langfuse SDK는 trace/span 데이터를 백그라운드에서 배치로 전송하므로, flush 없이 프로세스가 먼저 종료되면(서버리스 환경 등) 아직 전송되지 않은 trace가 유실될 수 있습니다.

### GenOS 자체 이용 로그와 내 트레이스 연결하기

코드 서빙 안에 붙인 계측을 GenOS의 이용 로그 화면에서 하나의 trace로 보이게 하려면 아래 조건과 절차가 필요합니다.

실제로 연결되면 아래처럼 GenOS가 자동으로 기록하는 구간(`POST /code_serving/...` → `code_serving` → `workflow`, "GenOS 내장 로그")과 코드에 직접 붙인 계측(`rag-agent-turn`, `master-agent-turn` → `agent-loop` → `llm_call` 등, "커스텀 로그")이 하나의 트레이스 안에서 부모-자식 관계로 나란히 표시됩니다.

<figure><img src="https://1274363562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoJuB29xjw7zmR91VXmqf%2Fuploads%2FUyx9neZpL8DTraSrn3lS%2F05_genos_log_vs_custom_log.png?alt=media&amp;token=b3b84510-ef50-4580-ab69-fb45eb56b71d" alt=""><figcaption></figcaption></figure>

#### GenOS 내부 Langfuse 프로젝트 값 사용

코드가 기록하는 곳이 "GenOS가 이용 로그에서 보여주는 바로 그 Langfuse 프로젝트"여야 합니다. 즉 환경 변수 설정에서 쓰는 `LANGFUSE_HOST`/`LANGFUSE_PUBLIC_KEY`/`LANGFUSE_SECRET_KEY`가 개인적으로 만든 외부 프로젝트 값이 아니라 GenOS 내부 Langfuse 프로젝트 값이어야 합니다.

> **중요** — 이 값은 코드나 설정 파일에서 알아낼 수 없습니다. GenOS 인프라/플랫폼 담당자에게 문의해 발급받아야 하며, 발급받은 값은 코드에 하드코딩하지 말고 코드 서빙 배포 환경 변수로만 등록해야 합니다. 외부 Langfuse 값을 그대로 쓰면 trace 자체는 정상적으로 기록되지만, GenOS 이용 로그와는 무관한 별개 프로젝트에 쌓여 이용 로그 화면에서는 보이지 않습니다.

#### `traceparent` 헤더로 이어 붙이기

GenOS는 코드 서빙을 호출하기 전에 이미 이용 로그용 trace를 하나 열어 두고, `traceparent` 헤더로 그 trace\_id/parent span id를 실어 보냅니다. 코드에서 이 헤더를 파싱해 `langfuse_trace_id`/`langfuse_parent_observation_id`로 넘기면 새 trace를 만드는 대신 GenOS가 이미 열어 둔 trace 안에 자식 span으로 이어 붙습니다.

```python
traceparent = request.headers.get("traceparent")
# "00-<trace-id 32hex>-<parent-id 16hex>-<flags>" 형식을 파싱해
# langfuse_trace_id / langfuse_parent_observation_id로 전달 (형식은 아래 표 참고)
```

| 항목                         | 형식                                                             |
| -------------------------- | -------------------------------------------------------------- |
| trace-id                   | 32자리 16진수 (예: `4bf92f3577b34da6a3ce929d0e0e4736`), 전부 `0`이면 무효 |
| parent-id (observation id) | 16자리 16진수 (예: `00f067aa0ba902b7`), 전부 `0`이면 무효                 |
| version                    | 2자리 16진수, 항상 `00`                                              |
| flags                      | 2자리 16진수. 새로 만들 때는 sampled를 뜻하는 `01` 고정                        |

> **참고** — GenOS 게이트웨이는 `x-genos-trace-id` 헤더도 함께 보내지만, 코드 서빙 입장에서는 무시해도 됩니다. 이 헤더는 최외곽 진입점에서만 root trace\_id를 시딩하는 용도로 잠깐 쓰일 뿐, 내부 홉들을 거치며 값이 보존되지 않아 코드 서빙까지 도달하는 경로에서는 항상 비어 있습니다. 안정적으로 전달되는 것은 `traceparent` 헤더뿐입니다.

#### 제약 사항

* **경로 제약**: 워크플로우 경로(코드 서빙 게이트웨이 경유 호출 포함)에서는 게이트웨이가 헤더를 그대로 통과시키므로 가능합니다. 반면 **A2A 경로에서는 불가능**합니다 — GenOS가 A2A 프로토콜 스펙에 맞춰 헤더/body를 직접 재구성하는 과정에서 `traceparent`처럼 임의로 실은 값이 사라집니다.
* **parent span은 하나뿐**: `traceparent`는 parent-id 슬롯이 하나뿐인 규격이고, GenOS도 이용 로그 trace 트리 안의 특정 위치를 지정해 주는 기능은 제공하지 않습니다. 코드가 받는 parent span은 항상 GenOS가 그 호출을 위해 미리 열어 둔 span 하나이며, 그 밑에서 원하는 만큼 자식 span을 쌓는 방식으로만 계측할 수 있습니다.

### 멀티턴 대화를 세션으로 묶기

GenOS는 멀티턴 대화 자체를 지원하지 않고, 워크플로우 호출 시 `x-genos-session-id` 헤더로 세션 ID만 전달합니다. 이전 기록 조회, 프롬프트 구성, 답변 저장은 코드에서 직접 구현해야 합니다.

같은 `x-genos-session-id` 값을 Langfuse의 `session_id`로도 재사용하면, GenOS 기준 한 대화가 Langfuse에서도 하나의 session으로 묶여 여러 턴의 trace를 이어서 확인할 수 있습니다. 이전 턴의 답변이 이번 턴 프롬프트에 잘못 반영된 경우처럼 턴 하나만 봐서는 원인을 알기 어려운 문제를 디버깅할 때 유용합니다.

```python
# 1. GenOS가 전달한 세션 ID 추출
session_id = request.headers.get("x-genos-session-id")
return await handle_turn(payload, session_id=session_id)
```

```python
# 2. 추출한 세션 ID를 Langfuse에도 그대로 부여
from langfuse import propagate_attributes

with propagate_attributes(session_id=session_id):
    # 이 블록 안에서 생성되는 trace/span 전부에 session_id가 태깅됨
    agent_result = await run_agent(payload.question, history=history)
```

`propagate_attributes`는 계측 코드 작성에서 소개한 Context Manager·Decorator·Manual Lifecycle 중 어떤 방식을 쓰든 바깥을 한 겹 더 감싸는 역할만 하므로 그대로 함께 쓸 수 있습니다. 헤더가 없는 경우(로컬 curl 테스트 등) `session_id`는 `None`이 되고, `propagate_attributes(session_id=None)`은 아무것도 태깅하지 않는 안전한 no-op으로 동작합니다.

### 멀티 에이전트 구조의 트레이스 한 번에 보기

마스터 에이전트가 여러 서브 에이전트를 API·A2A·MCP 등 통신 기반으로 호출하는 구조에서, 전체를 하나의 Langfuse trace 트리로 모아 보려면 마스터 에이전트가 사용 중인 trace 정보를 서브 에이전트에 전파해야 합니다. 앞서 GenOS 자체 이용 로그와 내 트레이스 연결하기에서 본 것처럼, 마스터 에이전트가 도구 호출로 서브 에이전트(`ask_internal_rag_agent`)를 부르면 그 아래에 서브 에이전트의 GenOS 내장 로그·커스텀 로그가 다시 중첩되는 구조가 됩니다.

<figure><img src="https://1274363562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoJuB29xjw7zmR91VXmqf%2Fuploads%2FUyx9neZpL8DTraSrn3lS%2F05_genos_log_vs_custom_log.png?alt=media&amp;token=b3b84510-ef50-4580-ab69-fb45eb56b71d" alt=""><figcaption></figcaption></figure>

#### 필요한 정보

* **Trace-ID**: 어떤 trace에 기록할 것인가
* **Parent-Span-ID**: 어떤 span 하위에 붙일 것인가

이 두 값은 `traceparent` 헤더에 실어 함께 전달합니다. 형식 검증 규칙은 위 표와 동일합니다.

#### GenOS에서 전달 가능 여부

* **워크플로우(코드 서빙 게이트웨이 경유 포함)**: 가능. 게이트웨이가 요청 헤더를 body와 마찬가지로 그대로 통과시키므로, `traceparent` 헤더에 실어 보내면 상대 에이전트의 라우터까지 그대로 도달합니다.
* **A2A**: 불가능. GenOS가 A2A 프로토콜 스펙에 맞춰 헤더/body를 직접 재구성하므로 임의의 헤더/필드가 유지되지 않습니다.

#### 서브 에이전트를 호출할 때: parent-id 교체

전달받은 `traceparent`를 그대로 서브 에이전트에 넘기면 안 됩니다. trace-id는 같아야 하지만, parent-id는 지금 이 호출을 하는 자신의 span id로 바꿔야 합니다. 그대로 넘기면 서브 에이전트가 자신이 원래 속했던 부모 span 아래로 바로 붙어버려, 그 사이에 있던 마스터 에이전트의 처리 과정(도구 호출 등)이 트리에서 빠지게 됩니다.

예를 들어 도구 호출 span `ask_internal_rag_agent` 아래에 서브 에이전트의 로그를 남기고 싶다면, `traceparent`의 parent-id 부분을 `ask_internal_rag_agent`의 span\_id로 교체해서 전달합니다.

<figure><img src="https://1274363562-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoJuB29xjw7zmR91VXmqf%2Fuploads%2FBosM0z7xxNEmrhCMUao7%2F06_traceparent_parent_id_swap.png?alt=media&amp;token=1a5f7f11-bb39-48bc-87b1-430e6e849722" alt=""><figcaption></figcaption></figure>

```python
# 서브 에이전트를 호출하는 지점(예: 도구 호출)에서
client = get_client()
trace_id = client.get_current_trace_id()
parent_span_id = client.get_current_observation_id()  # 지금 이 tool span 자신의 id
traceparent = f"00-{trace_id}-{parent_span_id}-01" if trace_id and parent_span_id else None
result = call_sub_agent(instruction=instruction, traceparent=traceparent)
```

서브 에이전트 쪽에서는 이렇게 전달받은 `traceparent`를 그대로 `langfuse_trace_id`/`langfuse_parent_observation_id`로 넘기면 됩니다. 새 trace를 만드는 것이 아니라, 전달받은 그 span 바로 아래에 자기 span을 이어 붙이는 방식입니다.

```python
# Decorator 방식으로 전달받는 경우 — 함수 시그니처에 별도 선언 불필요
call_sub_agent(
    instruction=instruction,
    langfuse_trace_id=trace_id,
    langfuse_parent_observation_id=parent_span_id,
)
```

### Langfuse Score로 응답 품질 평가하기

코드 서빙 안에서 직접 채점 로직(예: LLM-judge)을 작성해 Langfuse trace에 점수를 남기고 싶다면 Score API를 사용합니다.

> **참고** — 이 기능은 GenOS admin-front의 **평가지표** 메뉴(Custom Evaluator, 평가 기준 설정 등)와는 다릅니다. 아래 표에서 차이와 사용 시점을 구분합니다.

| 구분    | GenOS 평가지표 (admin-front)                                          | Langfuse Score (코드)                                                                |
| ----- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| 설정 방식 | admin-front `평가지표` 메뉴에서 Custom Evaluator·평가 기준을 UI로 설정. 코드 수정 불필요 | 코드 안에 채점 로직을 직접 작성하고 `score_current_trace`/`create_score`를 호출                      |
| 적용 대상 | 설정한 워크플로우의 이용 로그 trace에 자동·샘플링 적용                                 | 개발자가 지정한 지점(코드 실행 중 또는 사후)에만 적용                                                    |
| 평가 기준 | GenOS가 제공하는 판정 모델·평가 기준 화면에서 관리                                   | 코드에서 프롬프트·채점 로직을 완전히 자유롭게 정의                                                       |
| 언제 사용 | 운영 중인 워크플로우 품질을 코드 수정 없이 지속적으로 모니터링하고 싶을 때                        | GenOS 기본 평가 기준으로 커버되지 않는 세밀한 커스텀 로직이 필요하거나, 코드 서빙 개발 단계에서 데이터셋 기반 오프라인 실험을 하고 싶을 때 |

두 기능 모두 결과적으로 Langfuse trace에 점수(score)를 남기지만 설정 주체와 시점이 다르므로 혼동하지 않아야 합니다. GenOS 평가지표 기능 자체에 대한 상세 내용은 GenOS 평가지표 메뉴의 별도 안내를 참고합니다.

**현재 trace에 즉시 점수 기록** (에이전트 실행 중 inline으로 사용):

```python
from langfuse import get_client

client = get_client()
client.score_current_trace(name="groundedness", value=0.8, comment="근거 문서와 답변이 일치함")
```

**특정 trace/observation을 사후에 채점**하고 싶다면 `create_score`를 사용합니다. "현재" trace에 묶이지 않고 임의의 `trace_id`/`observation_id`를 지정할 수 있습니다:

```python
from langfuse import Langfuse

langfuse = Langfuse()
langfuse.create_score(
    name="groundedness",
    value=0.8,
    trace_id="abcdef1234567890abcdef1234567890",
    observation_id="fedcba0987654321",
    data_type="NUMERIC",
    comment="근거 문서와 답변이 일치함",
)
```

**데이터셋 기반으로 여러 케이스를 한 번에 평가**하고 싶다면 Experiment 기능을 사용합니다. 로컬 데이터는 `langfuse.run_experiment(name=..., data=local_data, task=my_task)`로, Langfuse에 등록해둔 데이터셋은 `langfuse.get_dataset("my-evaluation-dataset")` 후 `dataset.run_experiment(name=..., task=my_task)`로 실행합니다.

### 오류·예외 처리

| 증상                                     | 원인                                                                                                  | 해결 방법                                                                    |
| -------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| 트레이스가 전혀 기록되지 않음                       | `LANGFUSE_HOST`/`LANGFUSE_PUBLIC_KEY`/`LANGFUSE_SECRET_KEY` 중 하나 이상 미설정 또는 `langfuse` 패키지 import 실패 | SDK가 자동으로 no-op 폴백된 상태입니다. 세 환경 변수가 모두 올바르게 설정됐는지 확인합니다.                 |
| 프로세스 종료 직후 일부 trace가 Langfuse에 보이지 않음  | `client.flush()` 미호출로 배치 전송 전에 프로세스 종료                                                              | 응답 반환 직전에 `client.flush()`를 호출합니다.                                       |
| 서브 에이전트 호출을 A2A로 연결했는데 하나의 trace로 안 보임 | A2A 경로는 GenOS가 헤더/body를 재구성해 `traceparent`가 유지되지 않음                                                 | A2A 경로에서는 trace propagation이 불가능합니다. 워크플로우(코드 서빙 게이트웨이 경유) 경로를 사용합니다.    |
| 코드에는 trace가 남는데 GenOS 이용 로그 화면에는 안 보임  | 코드가 개인 외부 Langfuse 프로젝트 값을 쓰고 있어 GenOS 내부 Langfuse 프로젝트와 다름                                         | GenOS 인프라/플랫폼 담당자에게 GenOS 내부 Langfuse 프로젝트의 키를 받아 배포 환경 변수로 등록합니다.       |
| 멀티에이전트 trace에서 마스터 에이전트의 도구 호출 구간이 빠짐  | 서브 에이전트 호출 시 받은 `traceparent`를 그대로 전달(parent-id 미교체)                                                | 서브 에이전트를 호출하는 지점의 현재 span id로 parent-id를 교체한 새 `traceparent`를 만들어 전달합니다. |

### 사용자 시나리오

#### 코드 서빙 개발 중 내 에이전트 실행을 실시간으로 추적하고 싶다

코드 서빙에 Langfuse 연동하기를 따라 환경 변수를 설정하고 Decorator 방식으로 계측 코드를 붙입니다. Langfuse 프로젝트에서 검색·LLM 입출력·도구 호출 등을 observation 단위로 확인할 수 있습니다.

#### 운영 중인 서빙의 이용 로그에서 문제를 진단하고 싶다

별도 연동 없이 GenOS 이용 로그에서 트레이스 확인하기의 화면 경로로 확인합니다. 코드 서빙에 계측을 추가로 붙였고 GenOS 내부 Langfuse 키를 사용 중이라면, GenOS 자체 이용 로그와 내 트레이스 연결하기에 따라 자신의 세부 span까지 같은 화면에서 확인할 수 있습니다.

#### 멀티턴 대화를 하나의 흐름으로 묶어서 보고 싶다

멀티턴 대화를 세션으로 묶기에 따라 `x-genos-session-id`를 Langfuse `session_id`로 재사용합니다. 이전 턴의 응답이 이번 턴에 잘못 반영된 경우처럼 턴 하나만으로는 원인 파악이 어려운 문제를 진단할 때 유용합니다.

#### 마스터-서브 에이전트 구조를 하나의 trace로 보고 싶다

멀티 에이전트 구조의 트레이스 한 번에 보기에 따라 마스터 에이전트가 서브 에이전트를 호출할 때 parent-id를 교체한 `traceparent`를 함께 전달합니다. 단, 이 방식은 워크플로우(코드 서빙 게이트웨이 경유) 경로에서만 가능하며 A2A 경로에서는 불가능합니다.

#### 코드에서 직접 정의한 기준으로 응답 품질을 채점하고 싶다

Langfuse Score로 응답 품질 평가하기에 따라 코드 안에 채점 로직을 작성하고 `score_current_trace`(또는 사후 채점이면 `create_score`)로 점수를 남깁니다. GenOS 평가지표 메뉴의 기준으로 충분하다면 코드를 수정할 필요 없이 admin-front에서 설정하는 쪽이 더 간단합니다.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://genos-docs.gitbook.io/default/v1.9.4/advanced-tutorials/guides/langfuse.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
