pstone — Profit Stone Telemetry SDK
고객 AI 앱에 설치하는 in-process 관측 SDK입니다.
OpenTelemetry로 LLM·도구 호출을 수집해 Profit Stone SaaS Ingest API로 보내고, Backend가 Workspace API Key로 workspace_id를 붙여 ClickHouse에 저장합니다.
Sentry를 붙이듯, 앱에 패키지를 설치하고 init에 API Key만 넣으면 됩니다.
from pstone import pstone
pstone.init("psk_live_...")
상태: 0.1.0 Alpha — Python MVP. JS(
@pstone/sdk)는 후속.
설계 문서: docs/sdk-design.md
목차
설치
일반 (배포 후)
pip install pstone
OpenAI / Anthropic 계측을 쓰려면 해당 SDK도 앱에 설치되어 있어야 합니다.
pip install pstone openai anthropic
# 또는 extras (패키지 배포 설정에 따름)
pip install "pstone[openai,anthropic]"
개발 (이 레포)
cd profitstone_sdk
uv sync
uv run pytest
빠른 시작
- Profit Stone Dashboard에서 Workspace API Key를 발급합니다.
- 앱 시작 시점에
pstone.init을 한 번 호출합니다 (Sentryinit과 동일). - 기존 OpenAI / Anthropic 호출 코드는 그대로 둡니다.
init이 설치된 라이브러리를 자동 계측합니다.
import os
from openai import OpenAI
from pstone import pstone
# 1) SDK 초기화 (앱 부팅 시 1회)
pstone.init(os.environ["PSTONE_API_KEY"])
# 2) 평소처럼 AI 호출 — Span이 자동 수집되어 Ingest로 전송됨
client = OpenAI()
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)
# 3) 프로세스 종료 전 (선택) 미전송 Span flush
pstone.flush()
Anthropic도 동일합니다.
from anthropic import Anthropic
from pstone import pstone
pstone.init("psk_live_...")
client = Anthropic()
msg = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=256,
messages=[{"role": "user", "content": "Hello"}],
)
API Key
| 항목 | 설명 |
|---|---|
| 발급 위치 | Dashboard → Workspace → API Keys |
| 스코프 | Workspace 단위 (backend-design.md) |
| 전달 | pstone.init("psk_...") 또는 환경 변수 PSTONE_API_KEY |
| 서버 처리 | Backend가 키를 검증하고 workspace_id를 찾아 ClickHouse에 함께 저장 |
SDK는 workspace_id를 직접 보내지 않습니다. 키만 보내면 됩니다.
from pstone import pstone
# 인자로 전달
pstone.init("psk_live_xxxxxxxx")
# 또는 환경 변수만 설정한 뒤
# export PSTONE_API_KEY=psk_live_xxxxxxxx
pstone.init()
키를 소스코드·로그·이슈에 커밋하지 마세요.
환경 변수
| 변수 | 필수 | 설명 |
|---|---|---|
PSTONE_API_KEY |
권장 | Workspace API Key (init 인자 생략 시 사용) |
PSTONE_INGEST_URL |
선택 | Ingest 베이스 URL (기본 https://api.profitstone.ai) |
PSTONE_SERVICE_NAME |
선택 | OTel service.name (기본 pstone-app) |
실제 전송 경로는 {PSTONE_INGEST_URL}/v1/ingest/traces 입니다.
로컬 Backend에 붙일 때:
export PSTONE_API_KEY=psk_test_...
export PSTONE_INGEST_URL=http://localhost:8000
pstone.init(ingest_url="http://localhost:8000")
OpenAI / Anthropic 계측
자동 (권장)
pstone.init(..., instrument=True) (기본값)이면, 프로세스에 openai / anthropic 패키지가 설치되어 있을 때 chat / messages API를 패치합니다.
- OpenAI:
chat.completions.create(및parse가 있으면 함께) - Anthropic:
messages.create - OpenAI-compatible (예: Perplexity 등
OpenAI클라이언트 + 커스텀base_url): OpenAI 계측 경로를 그대로 탑니다.
명시적 wrap
글로벌 패치 대신 클라이언트만 감쌀 수 있습니다.
from openai import OpenAI
from anthropic import Anthropic
from pstone import pstone
pstone.init("psk_live_...", instrument=False)
openai_client = pstone.wrap_openai(OpenAI())
anthropic_client = pstone.wrap_anthropic(Anthropic())
수집되는 주요 속성
OpenTelemetry gen_ai.* 계열:
| Attribute | 예 |
|---|---|
gen_ai.system |
openai, anthropic |
gen_ai.request.model |
gpt-4o-mini |
gen_ai.prompt |
메시지 직렬화 (redaction 적용 가능) |
gen_ai.completion |
응답 텍스트 |
gen_ai.usage.input_tokens |
입력 토큰 |
gen_ai.usage.output_tokens |
출력 토큰 |
계측 코드는 원본 API 예외를 바꾸지 않습니다. Span 기록 실패는 조용히 무시되어 앱 핫 패스를 보호합니다.
옵션
pstone.init(
"psk_live_...",
ingest_url="https://api.profitstone.ai",
service_name="my-ai-app",
capture_content=True, # 프롬프트·completion 수집
redact=True, # 이메일·전화번호 등 기본 PII 마스킹
instrument=True, # 자동 패치 on/off
instrument_openai=True,
instrument_anthropic=True,
)
| 옵션 | 기본 | 설명 |
|---|---|---|
capture_content |
True |
프롬프트/completion을 Span에 넣을지 |
redact |
True |
기본 PII 마스킹 |
instrument |
True |
자동 계측 전체 on/off |
instrument_openai |
True |
OpenAI 패치 |
instrument_anthropic |
True |
Anthropic 패치 |
use_batch |
True |
BatchSpanProcessor (테스트에선 False 권장) |
민감 프롬프트를 보내지 않으려면:
pstone.init("psk_live_...", capture_content=False)
수동 Span
자동 계측 밖(커스텀 HTTP 등)에서는 헬퍼를 직접 쓸 수 있습니다.
from pstone.span import start_llm_span, record_llm_response
with start_llm_span(
name="custom.llm",
system="perplexity",
model="sonar",
prompt=[{"role": "user", "content": "hi"}],
) as span:
# ... 호출 ...
record_llm_response(
span,
completion="...",
input_tokens=10,
output_tokens=20,
)
flush / shutdown
| 메서드 | 용도 |
|---|---|
pstone.flush() |
대기 중인 Span을 Ingest로 강제 전송 |
pstone.shutdown() |
flush + 계측 해제 + TracerProvider 종료 |
배치 전송이므로, 짧은 CLI/스크립트는 종료 전에 flush()를 호출하세요.
try:
# ...
finally:
pstone.flush()
pstone.shutdown()
데이터 흐름
고객 앱
pstone.init(API Key)
→ OpenTelemetry Tracer + OTLP/HTTP Exporter
→ AI API 호출 시 Span 기록
→ POST {INGEST_URL}/v1/ingest/traces
Authorization: Bearer <API Key>
profitstone_backend
→ API Key 검증 → workspace_id 해석
→ ClickHouse에 span + workspace_id 저장
SDK는 DB에 직접 붙지 않습니다. HTTPS Ingest만 사용합니다.
로컬 개발
cd profitstone_sdk
uv sync
uv run pytest
uv build
테스트는 InMemorySpanExporter로 Ingest 없이 Span 속성만 검증합니다.
관련 문서:
| 문서 | 경로 |
|---|---|
| SDK 설계 | docs/sdk-design.md |
| 아키텍처 | ../profitstone_docs/개발문서/architecture.md |
| Backend | ../profitstone_backend/docs/backend-design.md |
| 에이전트 맵 | AGENTS.md |
PyPI 배포
pip install pstone이 되려면 PyPI에 업로드해야 합니다.
uv build
uv publish # UV_PUBLISH_TOKEN 또는 Trusted Publisher
성공 직후부터 사용자가 pip install pstone을 사용할 수 있습니다.
절차 상세: docs/sdk-design.md §13.
라이선스
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pstone-0.1.0.tar.gz.
File metadata
- Download URL: pstone-0.1.0.tar.gz
- Upload date:
- Size: 119.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.27 {"installer":{"name":"uv","version":"0.11.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76c200738f01f8f7383a20e7bf0432b3ac5c56b9fbe74868840e0b721621c8a0
|
|
| MD5 |
7e0878c44538229f2155eed04b0dd878
|
|
| BLAKE2b-256 |
1dfcbbffaa800d550d591edb3c1211193d67e0a7a8cc6b3836c05f0ca9554e31
|
File details
Details for the file pstone-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pstone-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.27 {"installer":{"name":"uv","version":"0.11.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa509041d7c89c61cec599a9f92dc6af68c73c6b540dadfaece3a8f82634db35
|
|
| MD5 |
6c525356e0f00d324d05828a39afaca9
|
|
| BLAKE2b-256 |
70b34e2a3315c73dfacefbfc3631e979e7346cca7f792d870da454e8e3687379
|