A tool call is a single tool invocation inside a trace — its name, arguments, result, and success or failure. Typing a span as a tool tells Lemma to show it as a tool execution with its input and output.
Tool execution usually happens in your application code, so framework auto-instrumentation often cannot see it. Recording tool calls explicitly is one of the highest-value things you can do.
Create tool spans inside the trace root callback so they nest under the trace.
import { startActiveObservation } from "@langfuse/tracing" ;
const docs = await startActiveObservation (
"search_docs" ,
async ( tool ) => {
const result = await searchDocs ( query );
tool . update ({ input: { query }, output: result });
return result ;
},
{ asType: "tool" },
);
from langfuse import get_client
langfuse = get_client()
with langfuse.start_as_current_observation( name = "search_docs" , as_type = "tool" ) as tool:
result = search_docs(query)
tool.update( input = { "query" : query}, output = result)
The observation name is the tool name.
The observation name is the tool name. Record the arguments as input and the result as output.
Record failures
A tool that fails is exactly what you will want to debug later. Mark it:
await startActiveObservation (
"lookup_customer" ,
async ( tool ) => {
tool . update ({ input: { customerId } });
try {
const customer = await lookupCustomer ( customerId );
tool . update ({ output: customer });
return customer ;
} catch ( error ) {
tool . update ({
level: "ERROR" ,
statusMessage: error instanceof Error ? error . message : String ( error ),
});
throw error ;
}
},
{ asType: "tool" },
);
with langfuse.start_as_current_observation( name = "lookup_customer" , as_type = "tool" ) as tool:
tool.update( input = { "customer_id" : customer_id})
try :
customer = lookup_customer(customer_id)
tool.update( output = customer)
except Exception as error:
tool.update( level = "ERROR" , status_message = str (error))
raise
If your agent runs many tools, wrap the executor once so every tool call is traced consistently:
import { startActiveObservation } from "@langfuse/tracing" ;
async function runTool < T >( name : string , args : unknown , fn : () => Promise < T >) : Promise < T > {
return startActiveObservation (
name ,
async ( tool ) => {
tool . update ({ input: args });
const output = await fn ();
tool . update ({ output });
return output ;
},
{ asType: "tool" },
);
}
// usage
const docs = await runTool ( "search_docs" , { query }, () => searchDocs ( query ));
Capture arguments and results only when safe. Redact secrets, credentials, and sensitive user data before passing them to input / output.
Next steps
Spans Trace retrieval, ranking, and app logic.
Threads & context Group conversations and attach users and metadata.