Getting started — semantic-tracing
Install
Packages are hosted on the internal Ramboll Artifactory registry. Authenticate
once via ~/.netrc:
machine artifactory.ramboll.com
login <your-email-or-empty-string>
password <your-artifactory-token>
Generate a personal access token in the Artifactory UI under Edit Profile → Authentication Settings.
Declare the Artifactory index in your project's uv.toml (uv reads ~/.netrc
automatically). Omitting default = true keeps PyPI as the default for all
other dependencies:
[[index]]
name = "ramtech-pypi"
url = "https://artifactory.ramboll.com/artifactory/api/pypi/ramtech-pypi-internal/simple"
Then add the package:
uv add semantic-tracing
Or install without modifying uv.toml using --extra-index-url:
# uv
uv add semantic-tracing --extra-index-url https://artifactory.ramboll.com/artifactory/api/pypi/ramtech-pypi-internal/simple
# pip
pip install semantic-tracing \
--extra-index-url https://artifactory.ramboll.com/artifactory/api/pypi/ramtech-pypi-internal/simple
Environment variables
setup_tracing() reads these from the environment at call time:
| Variable | Required | Description |
|---|---|---|
LANGFUSE_SECRET_KEY |
yes | Secret key from your Langfuse project settings |
LANGFUSE_PUBLIC_KEY |
yes | Public key from your Langfuse project settings |
LANGFUSE_BASE_URL |
no | Langfuse instance URL; defaults to https://cloud.langfuse.com. The Langfuse SDK still reads the older LANGFUSE_HOST as a deprecated fallback, only when LANGFUSE_BASE_URL is unset |
Store these in a .env file at the project root and load with
python-dotenv or pass them as environment variables directly.
Minimal example
import asyncio
from semantic_tracing import flush, setup_tracing, step, update_current_step
setup_tracing(service_name="my-app", environment="development")
@step("answer_question", as_type="generation")
async def answer(query: str) -> str:
# Replace with your actual LLM call
result = await call_llm(query)
# Attach model and token usage to the span (optional)
update_current_step(model="gpt-4o", usage={"input": 100, "output": 50})
return result
async def main() -> None:
response = await answer("What is the capital of Denmark?")
print(response)
flush() # send buffered spans to Langfuse before process exit
asyncio.run(main())
This creates one trace with one child span in Langfuse. The span type
"generation" tells Langfuse to display token usage and model information
in the UI.
Nesting spans
Calls to @step-decorated functions inside other @step functions form a
parent–child tree automatically via OTel context propagation — no manual
wiring needed:
@step("retrieve_documents")
async def retrieve(query: str) -> list[str]:
return await vector_search(query)
@step("generate_answer", as_type="generation")
async def generate(query: str, docs: list[str]) -> str:
return await call_llm(query, context=docs)
@step("rag_pipeline")
async def rag(query: str) -> str:
docs = await retrieve(query) # child span
return await generate(query, docs) # child span
Reading traces back
After a trace is complete, trace_reader helpers retrieve structured data
from Langfuse — useful in offline evaluation predictors:
from semantic_tracing.trace_reader import fetch_trace, find_observations
trace = await fetch_trace(trace_id)
# find specific observations by name
steps = find_observations(trace, name_in={"answer_question"})
Reading these docs from the installed package
The package carries these pages as they were when the installed version was built, so they can be read without a network or a checkout of this repository:
uv run python -m semantic_tracing.docs list # every page, by name and title
uv run python -m semantic_tracing.docs show tracing-setup
uv run python -m semantic_tracing.docs path # where the files are
A project that also installs semantic-evaluation has eval-docs, which reads
these pages as well and can search them. In show output, a link to
page:<name> is another shipped page and repo:<path> is a file in the SDK's
source repository that is not shipped.
Full reference
- Setup reference — all
setup_tracing()parameters - Observations reference —
span(),event(),propagate() - Generation metrics — model, usage, TTFT, streaming
- Framework integration — LangChain and Microsoft Agent Framework
- Read-side helpers —
fetch_trace(),find_observations()