Skip to main content
We’ll go through the following steps:

High Level Concepts

Trace your agent

Evaluate your agent

Next steps

High Level Concepts

In this example, we are building a customer support agent, which takes an input question from customers and decides what to do. In this example, we are deciding between searching for order information or answering the question.
Let’s break this down further: We are taking the user input and passing it to a router / planner prompt template. This template then decides which function call or agent skill to use. Often after calling a function, it goes back to the router template to decide on the next step, which could involve calling another agent skill.

Trace your agent

We have auto-instrumentation for function calling and structured outputs across almost every LLM provider here. We also support tracing for common frameworks using auto-instrumentation such as LangGraph, LlamaIndex Workflows, CrewAI, and AutoGen. To trace a simple agent with function calling, you can use arize-otel, our convenience package for setting up OTEL tracing along with openinference auto-instrumentation, which maps LLM metadata to a standardized set of trace and span attributes. Install the packages this guide uses:
Then set your credentials. Every block below reads them from the environment:
Here’s some sample code on logging all OpenAI calls to Arize AX.
Let’s create the foundation for our customer support agent. We have 2 functions that we define below: product_search, and track_package .
We define a function below called run_prompt, which uses the chat completion call from OpenAI with functions, and returns the tool calls. Notice that we label tool_choice as required, so a function will always be returned.
Let’s test it and see if it returns the right function! If we ask a question about specific products, we’ll get a response that will call the product search function.
This results in a trace that looks like the following:

Evaluate your agent

Once we have generated a set of test cases, we can create evaluators to measure performance. This way, we don’t have to manually inspect every single trace to see if the LLM is doing the right thing. First we need a set of test questions to evaluate against. Generate them with one LLM call, then run each through the agent so every row has both the question and the agent’s response:
Now define the evaluation template that judges whether the router selected a function correctly. The same pattern extends to further checks, such as whether the right function was chosen and whether its arguments were filled correctly — see trace-level evaluation for a worked example running several judges together.
Run the judge with arize-phoenix-evals. create_classifier binds the template to a judge model and the labels it may return, and evaluate_dataframe scores every row of response_df:
The template’s {question} and {response} placeholders are filled from the same-named columns in response_df, which is why the dataframe above uses exactly those names. evaluate_dataframe returns the original rows plus a router_score column holding a Score (its label, numeric score, and explanation). Below is a formatted example merged with the question and response.

Next steps

We covered very simple examples of tracing and evaluating an agent that uses function calling to route user requests and take actions in your application. As you build more capabilities into your agent, you’ll need more advanced tooling to measure and improve performance. You can do all of the following in Arize AX:
  1. Manually create tool spans which log your function calling inputs, latency, and outputs.
  2. Evaluate your agent across multiple levels, not just the router prompt (more info on evaluations).
  3. Create experiments to track changes across models, prompts, and parameters (more info on experiments).