Lab 02 — The same instrumented chain with LangSmith
Localized walkthrough. Run the canonical public lab locally and preserve the result as evidence.
Localized walkthrough. Run the canonical public lab locally and preserve the result as evidence.
Run it#
python modulo-05-llmops/labs/02_langsmith_tracing.py
Localized source walkthrough#
"""Lab 02 — The same instrumented chain with LangSmith.
Without ``--send``, tracing is disabled and it works as a local smoke test. With ``--send``, it requires
LANGSMITH_API_KEY, enables the specified project, and sends a trace of simulated functions: it does
not consume an LLM API.
Execution:
python modulo-05-llmops/labs/02_langsmith_tracing.py
python modulo-05-llmops/labs/02_langsmith_tracing.py --send --project llmops-course
"""
from __future__ import annotations
import argparse
import os
from pathlib import Path
from dotenv import load_dotenv
from rich.console import Console
REPO_ROOT = Path(__file__).resolve().parents[2]
load_dotenv(REPO_ROOT / ".env")
console = Console()
def configure(send: bool, project: str) -> None:
if send and not os.getenv("LANGSMITH_API_KEY"):
raise RuntimeError("falta LANGSMITH_API_KEY para --send")
os.environ["LANGSMITH_TRACING"] = "true" if send else "false"
os.environ["LANGSMITH_PROJECT"] = project
def build_traced_pipeline():
from langsmith import traceable
@traceable(name="retrieve-policy", run_type="retriever")
def retrieve(question: str) -> list[dict]:
return [
{
"id": "security-rotate-01",
"content": "Revocar una clave expuesta antes de crear la sustituta.",
}
]
@traceable(name="generate-grounded", run_type="llm", metadata={"model": "simulated"})
def generate(question: str, contexts: list[dict]) -> dict:
return {
"answer": "Revoca la clave expuesta antes de crear la sustituta.",
"citations": [contexts[0]["id"]],
"usage": {"input_tokens": 44, "output_tokens": 13},
}
@traceable(name="support-answer", run_type="chain", tags=["course", "offline-data"])
def answer(question: str) -> dict:
contexts = retrieve(question)
return generate(question, contexts)
return answer
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--send", action="store_true")
parser.add_argument("--project", default="llm-engineering-program")
return parser.parse_args()
def main() -> int:
args = parse_args()
configure(args.send, args.project)
pipeline = build_traced_pipeline()
result = pipeline("¿Qué hago si expongo una clave?")
console.print_json(data=result)
mode = "enviada" if args.send else "local, envío desactivado"
console.print(f"[dim]Traza {mode}; proyecto={args.project}[/dim]")
return 0
if __name__ == "__main__":
raise SystemExit(main())