Repository navigation
feat(ai): 체인 밖 외부 호출(TTS·임베딩·라이브 STT) 호출 로깅 - #247
Merged
Merged
Conversation
`CoreAiLogCallback` 은 LangChain 콜백이라 체인을 타는 호출만 잡는다. TTS·임베딩· 라이브 STT 는 `ai_request_logs` 에 한 줄도 남지 않았다. 그 대가를 운영에서 치렀다 — TTS 요청 245건 중 43건이 실패했는데 원인을 사후에 알 방법이 없다. 지금 "정상"으로 보이는 것도 정상이 아니라 안 보이는 것이다. 반대로 STT·LLM 타임아웃을 근거 있게 고칠 수 있었던 건 순전히 이 표에 latency 와 status 가 남아 있었기 때문이다(성공 p50 3.6초 vs 실패 60.8초). - observability/ai_call_log.py — 공용 record_ai_call(fire-and-forget) + measure_ai_call(지연 측정 + 성공/실패 자동 기록). 관측이 본 작업을 죽이지 않도록 태스크로 떼고 예외는 삼킨다. - TTS: LoggingTtsProvider 데코레이터. consumer 가 아니라 provider 를 감쌌다 — TTS 는 generate.tts consumer 말고도 followup 의 문장 단위 인라인 합성에서도 호출되므로 consumer 만 계측하면 라이브 경로가 통째로 빠진다. - 임베딩: 시도마다 한 행 + `[n/N]` 접두. 429 재시도로 사용자에겐 실패가 안 보였지만 몇 번 만에 통과하는지 아무도 몰랐다. - 라이브 STT: 스트림 1건당 한 행. 빈 전사는 FAILED 로 남겨 무음과 상류 무응답을 구분할 단서를 만든다. - voice_consumer 의 수동 기록도 공용 헬퍼로 통일(동작 동일). - MessagingRuntime.core_client 노출 → WS 핸들러도 같은 클라이언트 사용.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
작업 내용
observability/ai_call_log.py— 공용record_ai_call(fire-and-forget) +measure_ai_call(지연 측정 + 성공/실패 자동 기록)LoggingTtsProvider데코레이터 (tts.synthesize)[n/N]접두 (embedding.embed)stt.live)voice_consumer의 수동 기록을 공용 헬퍼로 통일 (동작 동일)MessagingRuntime.core_client노출 → WS 핸들러도 같은 클라이언트 사용변경 이유 / 배경
CoreAiLogCallback은 LangChain 콜백이라 체인을 타는 호출만 잡습니다. 확인해 보니record_ai_log호출부가 이게 전부였습니다:즉 TTS·임베딩·라이브 STT 는
ai_request_logs에 한 줄도 남지 않았습니다.그 대가를 운영에서 치렀습니다. TTS 요청 245건 중 43건이 실패했는데(전부 6월) 원인을 사후에 알 방법이 없습니다. 지금 "정상"으로 보이는 것도 정상이 아니라 안 보이는 것일 수 있습니다.
반대 사례가 이 PR 의 근거입니다 — 직전 PR 들(#244/#246)에서 STT 와 LLM 타임아웃을 근거를 갖고 고칠 수 있었던 건 순전히 이 표에 latency 와 status 가 남아 있었기 때문입니다:
설계 결정
TTS 는 consumer 가 아니라 provider 를 감쌌습니다. TTS 는
generate.ttsconsumer 말고도 followup consumer 의 문장 단위 인라인 합성(Part B)에서 호출됩니다. consumer 쪽만 계측하면 라이브 경로가 통째로 빠집니다. 대신 세션/사용자 맥락은 싣지 않습니다 —synthesize(text, *, voice)시그니처를 호출부마다 바꿔야 해서 비용 대비 이득이 적고, 실패율·지연·모델별 사용량은 이것만으로 보입니다.재시도가 있는 경로는 시도마다 한 행입니다(STT 규약과 동일). 실패율의 분모가 '요청'이 아니라 '시도'가 되므로, 사용자에게 보인 실패만 세려면
[N/N]으로 끝난 행만 셉니다. 이 규약 덕분에 재시도율 자체가 관측됩니다 — 임베딩은 429 재시도로 사용자에게 실패가 안 보였지만 몇 번 만에 통과하는지 아무도 몰랐고, batch_size·백오프를 조정하려면 그 숫자가 필요합니다.라이브 STT 의 빈 전사는 FAILED 로 남깁니다. 무음일 수도, 상류가 조용히 죽었을 수도 있습니다 — 지금은 구분할 단서조차 없어서 일단 구분 가능한 상태로 만듭니다.
관측이 본 작업을 죽이면 안 됩니다. 기록은 태스크로 떼고 예외는 삼킵니다(Core 가 죽어도 TTS 합성은 계속). 회귀 테스트로 고정했습니다.
테스트
tests/test_ai_call_log.py7건 — fire-and-forget, Core 장애 무영향, 500자 절단, 지연 측정, 실패 기록 + 재raise, TTS 데코레이터 성공/실패tests/test_embedder.py+1건 — 429 → 재시도 → 성공 시[1/2] FAILED+SUCCESS두 행uv run pytest413 passed,black/flake8clean영향 범위
ai_request_logs스키마 그대로)ai_request_logs에는 보존 정책이 있어(VolatileRetention) 무한 증가하진 않지만, 보존 기간·주기가 적절한지 봐주세요.리뷰어 체크포인트
docs/observability.md §3.1에 두 기록 경로 표를 추가했습니다. 새 외부 API 를 붙일 때 이 표를 갱신하는 규약이 지켜질 만한지.🤖 Generated with Claude Code