# LangSmith: @traceable and Client Wrappers — LLM Observability (Langfuse / LangSmith)

Source: https://www.skillbyai.com/en/llm-observability/lo-ls-traceable

> Trace functions with @traceable, choose run types, and wrap an OpenAI client to capture model calls.

## Runs, run types and nesting

The `@traceable` decorator turns a function call into a LangSmith **run**. Like Langfuse's decorator, it captures arguments as inputs, the return value as outputs, timing and errors, and nested traceable calls become **child runs** in the same trace. The `run_type` tells the UI how to display the run: `llm` runs show messages and token counts, `retriever` runs render returned documents, `tool` runs show tool arguments and results, and the default `chain` is a generic step. You can also pass `name`, `tags` and `metadata` to the decorator, or per call through the special `langsmith_extra` argument, for example to set a precomputed `run_id` you will later attach feedback to. For model calls, `wrap_openai()` wraps an OpenAI client so every completion is logged as an `llm` run with messages, parameters and token usage, nested under the current traceable function. Because uploads happen in a background thread, the decorator adds little latency to your request path.

## Tracing a small pipeline

Requires `langsmith` and `openai` with keys set. A retriever run returns documents shaped with `page_content` and `metadata` so the UI renders them nicely.

```python
from langsmith import traceable
from langsmith.wrappers import wrap_openai
from openai import OpenAI

client = wrap_openai(OpenAI())  # each call becomes an llm run

@traceable(run_type="retriever")
def retrieve(question: str) -> list[dict]:
    return [{"page_content": "Refunds within 7 days.", "metadata": {"source": "faq.md"}}]

@traceable(name="support-answer", tags=["support"], metadata={"prompt_version": "v4"})
def answer(question: str) -> str:
    docs = retrieve(question)
    context = "\n".join(d["page_content"] for d in docs)
    resp = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": f"Answer only from:\n{context}"},
            {"role": "user", "content": question},
        ],
    )
    return resp.choices[0].message.content

answer("Can I get a refund after 10 days?")
```

## Pick run types deliberately

Leaving everything as the default `chain` works, but you lose the specialised views: retrieved documents are shown as raw JSON and model calls do not show token counts. Mark retrieval functions `retriever`, tool functions `tool` and direct model calls `llm`.

**Quiz:** You want LangSmith to display retrieved documents nicely for a vector-search function. Which run type fits?

- [ ] llm
- [ ] parser
- [x] retriever
- [ ] prompt

*Answer:* retriever. The `retriever` run type tells LangSmith the output is a list of documents, so it renders their content and metadata.
