npx skills add ...
npx skills add ob-labs/agentseek --skill langsmith-trace
LangSmith tracing and trace debugging for AgentSeek templates. Covers CLI installation, adding tracing to LangGraph apps, querying traces, and inspecting run IO. Use when debugging agent backends, investigating slow traces, or adding observability to a template.
npx skills add ob-labs/agentseek --skill langsmith-trace
Add tracing to your agent and query traces for debugging. Supports Python and TypeScript.
[!IMPORTANT] This skill is tuned for AgentSeek template backends (LangGraph + middleware stacks). For general LangSmith concepts, see the upstream langsmith-skills repo.
[!CAUTION] Never pass
--api-keyas a CLI flag or expose API keys in shell commands / tool calls. The CLI readsLANGSMITH_API_KEYfrom the environment automatically. Using--api-key <value>leaks secrets into shell history, process listings, and agent tool-call logs. Always rely on the environment variable set in your shell profile or.envfile.
The binary installs to ~/.local/bin/langsmith. If langsmith is not found after install, add to your shell profile:
Add to ~/.zshrc (or the template's .env file) — the user must fill in their own key:
Key format must start with lsv2_pt_. Get yours at https://smith.langchain.com/settings.
The CLI reads this env var automatically — never use --api-key flags. Do not echo, print, or pass the key value in any shell command or tool call argument.
If you see a JSON array of projects, you're set. Common failures:
command not found — ~/.local/bin not in PATH (see step 1)[] — valid auth but no projects yet; create one in the UI or run a traced appJust set environment variables — no code changes needed:
For serverless (Python): also set LANGCHAIN_CALLBACKS_BACKGROUND=false to ensure traces flush before function exit.
Use the @traceable decorator (Python) or traceable() wrapper (TypeScript) and wrap your LLM client:
This is the recommended workflow for investigating agent behavior:
Look at last_run_start_time to find which project has recent activity. Don't assume — LangGraph apps default to the "default" project, not a named one.
This returns the full run tree — use it to understand the agent's execution flow.
This gives you inputs and outputs for every run (LLM calls, tool calls, middleware).
Our templates produce traces with this typical hierarchy:
Key points:
ChatOpenAI run<tool_name> run (e.g., generate_cover, execute)--full vs --include-io on individual runsProblem: langsmith run get <id> --full can return null for inputs/outputs, even though the data exists. Despite --full being documented as equivalent to --include-metadata --include-io --include-feedback, the underlying API behavior differs for individual run fetches in some CLI versions.
Solution: Always use --include-io explicitly when inspecting specific runs:
--full works reliably on trace export and run list, but has inconsistent behavior on individual run get calls. If this is fixed in a future CLI version, --include-io still works correctly — it's always safe.
--include-ioIf inputs/outputs come back null even with --include-io, the project has IO logging disabled. Check for these environment variables in the template's .env:
Remove or set to false to enable IO capture for debugging.
LangGraph apps trace to the "default" project unless LANGSMITH_PROJECT is explicitly set. Always run langsmith project list first and check last_run_start_time to find where your traces actually landed.
--format pretty for human-readable output during interactive debuggingLANGSMITH_ENDPOINT env var if connecting to a self-hosted LangSmith instanceFull command reference: reference/cli-commands.md
langsmith project listlangsmith project listexport LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=<your-key-here> # must be set; do NOT pass via --api-key flag
export LANGSMITH_PROJECT=my-project # optional, defaults to "default"from langsmith import traceable
from langsmith.wrappers import wrap_openai
from openai import OpenAI
client = wrap_openai(OpenAI())
@traceable
def my_pipeline(question: str) -> str:
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": question}],
)
return resp.choices[0].message.contentimport { traceable } from "langsmith/traceable";
import { wrapOpenAI } from "langsmith/wrappers";
import OpenAI from "openai";
const client = wrapOpenAI(new OpenAI());
const myPipeline = traceable(async (question: string) => {
const resp = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: question }],
});
return resp.choices[0].message.content || "";
}, { name: "my_pipeline" });langsmith trace list --project default --limit 5
# Or with full hierarchy inline (combines steps 2+3):
langsmith trace list --project default --limit 5 --show-hierarchylangsmith trace get <trace-id> --project <name>langsmith run list --trace-ids <trace-id> --project <name> --include-iolangsmith run get <run-id> --include-io<agent_name> (root chain)
├── SkillsMiddleware.before_agent
├── PatchToolCallsMiddleware.before_agent
├── MemoryMiddleware.before_agent
├── model (chain) ← LLM turn
│ ├── TodoListMiddleware.awrap_model_call
│ ├── SkillsMiddleware.awrap_model_call
│ ├── FilesystemMiddleware.awrap_model_call
│ ├── SubAgentMiddleware.awrap_model_call
│ ├── SummarizationMiddleware.awrap_model_call
│ ├── AnthropicPromptCachingMiddleware.awrap_model_call
│ ├── MemoryMiddleware.awrap_model_call
│ └── ChatOpenAI (llm) ← actual LLM call (inputs/outputs here)
├── TodoListMiddleware.after_model
├── tools (chain) ← tool execution
│ ├── FilesystemMiddleware.awrap_tool_call
│ └── <tool_name> (tool) ← actual tool (inputs/outputs here)
├── model (chain) ← next LLM turn
│ └── ... (same middleware stack)
└── TodoListMiddleware.after_model# DO THIS
langsmith run get <run-id> --include-io
# NOT THIS (may return null IO despite docs saying it includes --include-io)
langsmith run get <run-id> --fullLANGCHAIN_HIDE_INPUTS=true # hides inputs from traces
LANGCHAIN_HIDE_OUTPUTS=true # hides outputs from traces