# bai-langfuse

BAI 프로젝트 공통 Langfuse 연동 패키지. **Core Agent**와 **Sub Agent** 모두에서 사용합니다.

설정은 **환경 변수**로만 합니다. `config` / `settings` 모듈에 의존하지 않습니다.

## 환경 변수

| 변수 | 설명 | 기본값 |
|------|------|--------|
| `LANGFUSE_ENABLED` | Langfuse 사용 여부 | `true` |
| `LANGFUSE_PUBLIC_KEY` | Langfuse Public Key | (필수) |
| `LANGFUSE_SECRET_KEY` | Langfuse Secret Key | (필수) |
| `LANGFUSE_HOST` | Langfuse 서버 URL | `https://langfuse.bai.biztechi.biz` |
| `ENVIRONMENT` | `development`이면 Langfuse 호스트에 대해 SSL 검증 비활성화 | `development` |
| `AGENT_TYPE` | 메타데이터용 (예: Core, HR, Management) | `Core` |

## 설치

로컬에서 다른 BAI 앱과 함께 사용할 때 (동일 저장소 내):

```bash
# bai-core-agent 또는 bai-sub-agent 디렉터리에서
pip install -e ../bai-langfuse
```

또는 각 앱의 `requirements.txt`에 `-e ../bai-langfuse`가 포함되어 있으면:

```bash
pip install -r requirements.txt
```

## API 요약

### 공통 (Core / Sub 공통)

- **`get_langfuse_callback(trace_id=None, session_id=None, user_id=None, parent_observation_id=None, trace_name=None)`**  
  LangChain용 CallbackHandler 생성.  
  - Core: `trace_id` + `trace_name="사용자 요청"`  
  - Sub: `trace_id` + `parent_observation_id` (config.metadata에서 전달)
- **`create_child_span(trace_id, name, parent_observation_id=None)`**  
  자식 span 생성.
- **`get_current_observation_id()`**  
  현재 observation ID 조회.
- **`flush_langfuse()`**  
  대기 중인 데이터 전송.
- **`get_usage_from_response(response)`**  
  AIMessage 등에서 usage dict 추출 (input/output/cache 토큰).

### Core Agent 전용

- **`log_llm_generation(state, node_name, llm, messages, response, output_extractor=None)`**  
  `state`에서 `context.trace_id`를 읽어 LLM generation 로깅.
- **`CaptureAIMessageCallback(storage)`**  
  LLM 호출 시 AIMessage 캡처 (usage 확인용).

### Sub Agent 전용

- **`log_llm_generation_span(node_name, trace_id, model, input_prompt=None, input_messages=None, output="", usage=None, model_parameters=None, parent_observation_id=None)`**  
  trace_id/model/input/output/usage를 직접 넘겨 generation 로깅.

## 사용 예 (Core Agent)

```python
from bai_langfuse import (
    get_langfuse_callback,
    flush_langfuse,
    log_llm_generation,
    get_usage_from_response,
    CaptureAIMessageCallback,
    create_child_span,
    get_current_observation_id,
)

# 콜백 (trace 이름 지정)
callback = get_langfuse_callback(
    trace_id=trace_id,
    session_id=session_id,
    user_id=user_id,
    trace_name="사용자 요청",
)
# LLM 호출 후
flush_langfuse()
```

## 사용 예 (Sub Agent)

```python
from bai_langfuse import (
    get_langfuse_callback,
    create_child_span,
    get_current_observation_id,
    log_llm_generation_span,
)

# 콜백 (parent_observation_id로 Core와 계층 연결)
callback = get_langfuse_callback(
    trace_id=trace_id,
    user_id=user_id,
    session_id=session_id,
    parent_observation_id=parent_observation_id,
)
# 노드 내 span
span_ctx = create_child_span(trace_id, "NodeName", get_current_observation_id())
if span_ctx:
    with span_ctx:
        ...
# 명시적 generation 로깅 (선택)
log_llm_generation_span(
    node_name="Generator",
    trace_id=trace_id,
    model="claude-3-5-sonnet",
    input_messages=messages,
    output=response_text,
    usage={"input": 100, "output": 50},
)
```

## 의존성

- `langfuse` (>=2.0)
- `langchain-core` (>=0.2)
- `requests` (>=2.28)
