Install any skill in seconds. Free to start, no credit card required.
Get Started Free →LLM observability platform for tracing, evaluation, and monitoring. Use when debugging LLM applications, evaluating model outputs against datasets, monitoring production systems, or building systematic testing pipelines for AI applications.
.claude/skills/openlair-langsmith-observability/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 100% | 27 |
| gemini-3.1-pro-preview | 100% | 3 |
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 257% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 181% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 191% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 118% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 1% | 0% |
Development platform for debugging, evaluating, and monitoring language models and AI applications.
Use LangSmith when:
Key features:
Use alternatives instead:
bashpip install langsmith # Set environment variables export LANGSMITH_API_KEY="your-api-key" export LANGSMITH_TRACING=true
pythonfrom langsmith import traceable from openai import OpenAI client = OpenAI() @traceable def generate_response(prompt: str) -> str: response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": prompt}] ) return response.choices[0].message.content # Automatically traced to LangSmith result = generate_response("What is machine learning?")
pythonfrom langsmith.wrappers import wrap_openai from openai import OpenAI # Wrap client for automatic tracing client = wrap_openai(OpenAI()) # All calls automatically traced response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "Hello!"}] )
A run is a single execution unit (LLM call, chain, tool). Runs form hierarchical traces showing the full execution flow.
pythonfrom langsmith import traceable @traceable(run_type="chain") def process_query(query: str) -> str: # Parent run context = retrieve_context(query) # Child run response = generate_answer(query, context) # Child run return response @traceable(run_type="retriever") def retrieve_context(query: str) -> list: return vector_store.search(query) @traceable(run_type="llm") def generate_answer(query: str, context: list) -> str: return llm.invoke(f"Context: {context}\n\nQuestion: {query}")
Projects organize related runs. Set via environment or code:
pythonimport os os.environ["LANGSMITH_PROJECT"] = "my-project" # Or per-function @traceable(project_name="my-project") def my_function(): pass
pythonfrom langsmith import Client client = Client() # List runs runs = list(client.list_runs( project_name="my-project", filter='eq(status, "success")', limit=100 )) # Get run details run = client.read_run(run_id="...") # Create feedback client.create_feedback( run_id="...", key="correctness", score=0.9, comment="Good answer" )
pythonfrom langsmith import Client client = Client() # Create dataset dataset = client.create_dataset("qa-test-set", description="QA evaluation") # Add examples client.create_examples( inputs=[ {"question": "What is Python?"}, {"question": "What is ML?"} ], outputs=[ {"answer": "A programming language"}, {"answer": "Machine learning"} ], dataset_id=dataset.id )
pythonfrom langsmith import evaluate def my_model(inputs: dict) -> dict: # Your model logic return {"answer": generate_answer(inputs["question"])} def correctness_evaluator(run, example): prediction = run.outputs["answer"] reference = example.outputs["answer"] score = 1.0 if reference.lower() in prediction.lower() else 0.0 return {"key": "correctness", "score": score} results = evaluate( my_model, data="qa-test-set", evaluators=[correctness_evaluator], experiment_prefix="v1" ) print(f"Average score: {results.aggregate_metrics['correctness']}")
pythonfrom langsmith.evaluation import LangChainStringEvaluator # Use LangChain evaluators results = evaluate( my_model, data="qa-test-set", evaluators=[ LangChainStringEvaluator("qa"), LangChainStringEvaluator("cot_qa") ] )
pythonfrom langsmith import tracing_context with tracing_context( project_name="experiment-1", tags=["production", "v2"], metadata={"version": "2.0"} ): # All traceable calls inherit context result = my_function()
pythonfrom langsmith import trace with trace( name="custom_operation", run_type="tool", inputs={"query": "test"} ) as run: result = do_something() run.end(outputs={"result": result})
pythondef sanitize_inputs(inputs: dict) -> dict: if "password" in inputs: inputs["password"] = "***" return inputs @traceable(process_inputs=sanitize_inputs) def login(username: str, password: str): return authenticate(username, password)
pythonimport os os.environ["LANGSMITH_TRACING_SAMPLING_RATE"] = "0.1" # 10% sampling
pythonfrom langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate # Tracing enabled automatically with LANGSMITH_TRACING=true llm = ChatOpenAI(model="gpt-4o") prompt = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant."), ("user", "{input}") ]) chain = prompt | llm # All chain runs traced automatically response = chain.invoke({"input": "Hello!"})
pythonfrom langsmith import Client client = Client() # Pull prompt from hub prompt = client.pull_prompt("my-org/qa-prompt") # Use in application result = prompt.invoke({"question": "What is AI?"})
pythonfrom langsmith import AsyncClient async def main(): client = AsyncClient() runs = [] async for run in client.list_runs(project_name="my-project"): runs.append(run) return runs
pythonfrom langsmith import Client client = Client() # Collect user feedback def record_feedback(run_id: str, user_rating: int, comment: str = None): client.create_feedback( run_id=run_id, key="user_rating", score=user_rating / 5.0, # Normalize to 0-1 comment=comment ) # In your application record_feedback(run_id="...", user_rating=4, comment="Helpful response")
pythonfrom langsmith import test @test def test_qa_accuracy(): result = my_qa_function("What is Python?") assert "programming" in result.lower()
pythonfrom langsmith import evaluate def run_evaluation(): results = evaluate( my_model, data="regression-test-set", evaluators=[accuracy_evaluator] ) # Fail CI if accuracy drops assert results.aggregate_metrics["accuracy"] >= 0.9, \ f"Accuracy {results.aggregate_metrics['accuracy']} below threshold"
Traces not appearing:
pythonimport os # Ensure tracing is enabled os.environ["LANGSMITH_TRACING"] = "true" os.environ["LANGSMITH_API_KEY"] = "your-key" # Verify connection from langsmith import Client client = Client() print(client.list_projects()) # Should work
High latency from tracing:
python# Enable background batching (default) from langsmith import Client client = Client(auto_batch_tracing=True) # Or use sampling os.environ["LANGSMITH_TRACING_SAMPLING_RATE"] = "0.1"
Large payloads:
python# Hide sensitive/large fields @traceable( process_inputs=lambda x: {k: v for k, v in x.items() if k != "large_field"} ) def my_function(data): pass
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 4,369 | 2,482 | -43% | 1 | 1 | 0% | 823 | 2,935 | +257% | 0 | 0 | — |
case-02 | pass→pass | 2,572 | 2,260 | -12% | 1 | 1 | 0% | 454 | 2,957 | +551% | 0 | 0 | — |
case-03 | pass→pass | 4,109 | 2,652 | -35% | 1 | 1 | 0% | 771 | 3,008 | +290% | 0 | 0 | — |
case-04 | pass→pass | 4,082 | 2,310 | -43% | 1 | 1 | 0% | 801 | 3,048 | +281% | 0 | 0 | — |
case-05 | pass→pass | 6,824 | 4,533 | -34% | 1 | 1 | 0% | 1,325 | 3,510 | +165% | 0 | 0 | — |
case-06 | pass→pass | 2,525 | 2,056 | -19% | 1 | 1 | 0% | 482 | 2,890 | +500% | 0 | 0 | — |
case-07 | pass→pass | 4,795 | 3,318 | -31% | 1 | 1 | 0% | 743 | 3,139 | +322% | 0 | 0 | — |
case-08 | pass→pass | 3,530 | 3,015 | -15% | 1 | 1 | 0% | 611 | 3,057 | +400% | 0 | 0 | — |
case-09 | pass→pass | 4,243 | 2,788 | -34% | 1 | 1 | 0% | 811 | 3,052 | +276% | 0 | 0 | — |
case-10 | pass→pass | 3,800 | 2,622 | -31% | 1 | 1 | 0% | 705 | 3,018 | +328% | 0 | 0 | — |
case-11 | fail→pass | 5,240 | 1,927 | -63% | 1 | 1 | 0% | 1,017 | 2,853 | +181% | 0 | 0 | — |
case-12 | pass→pass | 3,647 | 2,711 | -26% | 1 | 1 | 0% | 726 | 2,934 | +304% | 0 | 0 | — |
case-13 | fail→pass | 5,427 | 2,497 | -54% | 1 | 1 | 0% | 1,022 | 2,973 | +191% | 0 | 0 | — |
case-14 | fail→pass | 7,276 | 3,528 | -52% | 1 | 1 | 0% | 1,490 | 3,252 | +118% | 0 | 0 | — |
case-15 | pass→pass | 4,722 | 2,234 | -53% | 1 | 1 | 0% | 859 | 2,954 | +244% | 0 | 0 | — |
case-16 | pass→pass | 2,958 | 1,869 | -37% | 1 | 1 | 0% | 588 | 2,871 | +388% | 0 | 0 | — |
case-17 | fail→pass | 16,928 | 3,531 | -79% | 1 | 1 | 0% | 3,046 | 3,063 | +1% | 0 | 0 | — |
case-18 | pass→pass | 7,743 | 2,440 | -68% | 1 | 1 | 0% | 1,476 | 2,972 | +101% | 0 | 0 | — |
case-19 | pass→pass | 3,121 | 1,776 | -43% | 1 | 1 | 0% | 578 | 2,854 | +394% | 0 | 0 | — |
case-20 | fail→pass | 3,481 | 1,805 | -48% | 1 | 1 | 0% | 687 | 2,833 | +312% | 0 | 0 | — |
case-21 | pass→pass | 10,771 | 2,909 | -73% | 1 | 1 | 0% | 1,795 | 2,985 | +66% | 0 | 0 | — |
case-22 | fail→pass | 11,816 | 3,402 | -71% | 1 | 1 | 0% | 2,118 | 3,159 | +49% | 0 | 0 | — |
case-23 | pass→pass | 13,210 | 5,282 | -60% | 1 | 1 | 0% | 2,387 | 3,462 | +45% | 0 | 0 | — |
case-24 | pass→pass | 10,319 | 6,162 | -40% | 1 | 1 | 0% | 1,886 | 3,587 | +90% | 0 | 0 | — |
case-25 | pass→pass | 15,030 | 8,834 | -41% | 1 | 1 | 0% | 2,756 | 4,179 | +52% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 25 cases were attempted. The headline lift of +28 percentage points is the difference between those two pass rates over the 25 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.