Agent skill
acm-observability
Agent-actionable reference for ACM-AI's 6-tool observability stack. Teaches how to query traces, inspect graph state, debug Pydantic failures, and analyze costs programmatically.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/acm-observability
SKILL.md
ACM-AI Observability Skill
Decision Tree — Which Tool for Which Problem?
| Problem | Tool | Action |
|---|---|---|
| Wrong extraction data | Langfuse | Query trace by session_id=extraction-{source_id}, examine LLM input/output spans |
| Prompt iteration | LangSmith | Open Playground, edit prompt, re-run side-by-side |
| Pipeline costing | Langfuse | Aggregate GENERATION observations by model, sum tokens/cost |
| Pydantic parse failure | Logfire (via Langfuse) | Search OTel spans for pydantic.validate_* with error status |
| Graph stuck / wrong state | LangGraph API | GET /threads/{id}/state at :2024 |
| Model relationships | erdantic | Run scripts/generate_model_diagrams.py -> docs/diagrams/*.svg |
| Nested JSON exploration | JSON Crack | Paste JSON at localhost:8888 |
| Pipeline healthy across runs? | Langfuse | Historical traces, score trends, session list |
Langfuse Query Patterns
Authentication
# All Langfuse API calls use HTTP Basic auth
curl -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
"$LANGFUSE_BASE_URL/api/public/traces?sessionId=extraction-{source_id}"
Default LANGFUSE_BASE_URL is http://localhost:3000 (self-hosted) or https://cloud.langfuse.com.
Python SDK
from langfuse import Langfuse
client = Langfuse(
public_key=os.getenv("LANGFUSE_PUBLIC_KEY"),
secret_key=os.getenv("LANGFUSE_SECRET_KEY"),
host=os.getenv("LANGFUSE_BASE_URL", "http://localhost:3000"),
)
# List traces for an extraction
traces = client.fetch_traces(session_id=f"extraction-{source_id}")
# Get a specific trace with observations
trace = client.fetch_trace(trace_id)
Common Filters
| Filter | API Parameter | Example |
|---|---|---|
| By source | sessionId |
extraction-source:abc123 |
| By tag | tags |
acm-extraction |
| By date | fromTimestamp |
2026-03-01T00:00:00Z |
| By name | name |
acm_extraction |
Session ID Convention
From langfuse_config.py:135:
"langfuse_session_id": f"extraction-{clean_source_id}"
All extraction traces for a source are grouped under session_id=extraction-{source_id}.
LangGraph API Patterns
The LangGraph dev server runs at http://127.0.0.1:2024.
Start the Server
uv run langgraph dev --no-browser
Registered graphs (from langgraph.json):
acm_extraction— ACM extraction pipelinesupervisor— Multi-agent supervisor
Common Endpoints
# List registered graphs
curl -s http://127.0.0.1:2024/assistants | python -m json.tool
# List threads
curl -s "http://127.0.0.1:2024/threads?limit=10" | python -m json.tool
# Get thread state
curl -s http://127.0.0.1:2024/threads/{thread_id}/state | python -m json.tool
# Get thread history (checkpoints)
curl -s http://127.0.0.1:2024/threads/{thread_id}/history | python -m json.tool
# Dump state to JSON file for JSON Crack
uv run python scripts/dump_state_json.py {thread_id}
Swagger UI
Full API documentation at http://127.0.0.1:2024/docs.
Logfire Safety Guardrails
NEVER Call instrument_pydantic() Without include={}
Blanket logfire.instrument_pydantic() creates an OTel span for EVERY model_validate() call. Docling creates 1 PdfTextCell per PDF character, causing ~48K traces per extraction.
Safe Instrumentation Set
import logfire
logfire.instrument_pydantic(
include={
"ACMExtractionRecord",
"BuildingRoomContext",
"ACMItemRecord",
"ACMExtractionResult",
"ACMItemExtractionResult",
"NormalizedExtractionResult",
}
)
This instruments only ACM domain models (~10-50 traces per run).
OTel Span Nesting
langfuse_tracing() pre-injects OTel trace context via _try_inject_otel_trace_context() so Logfire Pydantic validation spans nest under the Langfuse trace (not as orphan top-level traces).
Wiring Patterns
Pattern 1: Context Manager (Routers)
Used in FastAPI router endpoints:
from open_notebook.observability.langfuse_config import (
langfuse_tracing,
merge_langfuse_into_config,
)
with langfuse_tracing("acm_extraction", source_id=source_id) as (cb, meta):
config = merge_langfuse_into_config(base_config, cb, meta)
result = await graph.ainvoke(input_state, config=config)
Pattern 2: Manual Handler (Commands)
Used in background command handlers:
from open_notebook.observability.langfuse_config import (
get_langfuse_handler,
build_langfuse_metadata,
append_langfuse_callback,
flush_langfuse_handler,
)
handler = get_langfuse_handler()
callbacks = append_langfuse_callback([], handler)
metadata = build_langfuse_metadata(source_id=source_id)
config = {"callbacks": callbacks, "metadata": metadata}
try:
result = graph.invoke(input_state, config=config)
finally:
flush_langfuse_handler(handler)
Critical Rule: Callback Placement
Callbacks belong at the invocation site (routers, commands), NEVER inside graph node functions. Graph nodes receive callbacks automatically via LangGraph's config propagation.
Do NOT Modify Pre-Existing Wiring
acm_extraction.py and source_commands.py have working Langfuse wiring. Do not alter it.
Cross-Tool Workflow Recipes
Recipe 1: Debug a Failed Extraction
- Query Langfuse:
session_id=extraction-{source_id} - Find the trace with errors (look for spans with
statusCode: ERROR) - Examine the LLM input/output in the GENERATION span
- Check Logfire Pydantic spans for validation failures
- If graph state needed:
GET /threads/{thread_id}/stateat:2024 - Cross-reference with SurrealDB:
SELECT * FROM acm_record WHERE source_id = "{source_id}"
Recipe 2: Compare Costs Across Models
- Fetch GENERATION observations from Langfuse filtered by date range
- Group by
modelfield - Sum
totalCost,promptTokens,completionTokens - Compare cost-per-record:
totalCost / records_extracted
Recipe 3: Debug Pydantic Validation
- Verify Logfire is initialized: check
LOGFIRE_ENABLED=trueand Langfuse keys set - Search Langfuse for OTel spans with name pattern
pydantic.validate_* - Filter for spans with error status
- Examine the span attributes for validation error details
- Cross-reference with the LLM output that produced the invalid data
Recipe 4: Inspect Graph Execution Flow
- Start LangGraph dev server:
uv run langgraph dev --no-browser - Find thread:
GET /threads?limit=10 - Get current state:
GET /threads/{id}/state - View checkpoint history:
GET /threads/{id}/history - Dump to JSON Crack:
uv run python scripts/dump_state_json.py {thread_id} - Open
localhost:8888, paste JSON for visual exploration
Environment Variables Reference
| Variable | Purpose | Default |
|---|---|---|
LANGFUSE_ENABLED |
Enable Langfuse tracing | false |
LANGFUSE_PUBLIC_KEY |
Langfuse auth | (required if enabled) |
LANGFUSE_SECRET_KEY |
Langfuse auth | (required if enabled) |
LANGFUSE_BASE_URL |
Langfuse host | https://cloud.langfuse.com |
LOGFIRE_ENABLED |
Enable Logfire -> Langfuse bridge | false |
LANGCHAIN_TRACING_V2 |
Enable LangSmith auto-tracing | false |
LANGCHAIN_API_KEY |
LangSmith auth | (required if tracing enabled) |
Key Source Files
| File | Purpose |
|---|---|
open_notebook/observability/langfuse_config.py |
langfuse_tracing(), get_langfuse_handler(), merge_langfuse_into_config() |
open_notebook/observability/logfire_config.py |
init_logfire(), instrument_pydantic guidance |
open_notebook/observability/langfuse_bridge.py |
emit_pipeline_event() for custom LangChain events |
scripts/dump_state_json.py |
Dump LangGraph thread state to JSON file |
scripts/generate_model_diagrams.py |
Generate erdantic ER diagrams |
scripts/observability/setup_langfuse_datasets.py |
Langfuse dataset/prompt setup |
docs/development/observability.md |
Comprehensive reference (1026 lines) |
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?