Skip to main content

LLM Transaction Configuration

This is a guide to using the public API for instrumenting workflow and agent patterns in AI Agent Observability.

Once you declare the scope of a workflow or AI agent, every LLM API call that occurs within that scope is collected as a "step" under a single LLM transaction instead of as a separate transaction. All you need to do is mark the scope.

Transaction types in AI Agent Observability

There are three types of LLM transactions.

  • Workflow (default) — [Workflow] <name>

  • Agent[Agent] <name>

  • LLMAPI — A standalone call that is not wrapped in a workflow is collected as [LLMAPI] Pure LLM API.

When another workflow runs inside a workflow, the parent and child transactions are linked as a Trajectory so you can trace the call relationship.

Configuring a workflow transaction

Both the decorator and the context manager forms are supported.

Decorator

Use this when the workflow name is fixed per function.

from whatap.llm import workflow

@workflow("support_chat")
async def support_chat(conversation_id, message, history):
intent = await classify_intent(message) # Every LLM call in here
docs = await retrieve(message) # becomes a "step" of this workflow
answer = await generate(message, docs)
return {"intent": intent, "answer": answer}

Context manager

Use this when you determine the workflow name at runtime or want to wrap only part of a function.

from whatap.llm import workflow

with workflow("ticket_triage"):
classification = await _classify(ticket_text)
entities = await _extract(ticket_text)
Caution

Even in asynchronous code, use with as shown above, not async with. Because workflow and agent are synchronous context managers, using await inside the scope is fine, but opening them with async with raises an error.

Configuring an agent transaction

The usage is the same as for a workflow, and only the transaction name prefix changes to [Agent]. Both the decorator and the context manager forms are supported.

Decorator

Use this when the agent execution function is fixed.

from whatap.llm import agent

@agent("react_agent")
async def run_agent(task):
...
return result

Context manager

Use this when you determine the agent name at runtime or want to wrap only part of the execution block.

from whatap.llm import agent

with agent("react_agent"):
result = await react_agent.run(task)

Declaring a scope without modifying code

When you cannot modify the application code, you can specify workflow boundaries through configuration. List the target methods in whatap.conf, and the execution of those methods becomes the workflow boundary. The method name is used as the workflow name.

whatap.conf
workflow_method_patterns=myapp:RagService.run, myapp.agent:run_agent

Use the module:Class.method or module:function form, separated by commas.

Frameworks with automatic instrumentation

For the following frameworks, LLM transactions are collected automatically without declaring a scope.

FrameworkHow it is collected
hermes-agentInstruments the agent execution layer (AIAgent.run_conversation) and registers it as an [Agent] <name> transaction. The gateway inbound (GatewayRunner._handle_message) is registered as a [Workflow] gateway/<platform> transaction, and agents executed within it are linked as child transactions.
LangGraphInstruments the execution boundary of a compiled graph (Pregel.invoke / ainvoke / stream / astream) and registers one graph execution as one LLM transaction. A graph with a tools node (create_react_agent) is registered as [Agent], and others as [Workflow]. Subgraphs are nested as child transactions.