a cleansing firm to request a quote for cleansing a sofa. They requested about its dimension and materials and requested an image of it. In addition they wanted my deal with as a result of journey time varies considerably throughout the town and due to this fact impacts the worth.
After receiving the quote for the sofa, I requested about house cleansing. This began one other trade of messages in regards to the house’s dimension, the specified cleansing depth, and non-compulsory providers. As soon as we agreed on a worth, we chatted slightly extra to discover a appropriate appointment.
Your entire reserving course of took round quarter-hour. This seems like an issue price handing to an AI agent.
On this article, we’ll construct this agent utilizing Python, LangGraph, and LangChain. We’ll create a demo for testing the whole reserving circulate and combine Langfuse for observability.
The AI agent is not going to solely velocity up the method but additionally work 24/7 when deployed into manufacturing.
Please be aware that this isn’t a easy chatbot. It’s a stateful AI agent able to managing a multi-step enterprise course of by combining conversational intelligence with deterministic enterprise guidelines.
The supply code of the agent is offered on GitHub at customer-service-agent. Be at liberty to clone and check it your self.
What does this agent do?
The agent does every little thing the customer-service consultant of this enterprise does:
- Responds to buyer queries and understands their wants.
- Calculates the worth for the service and informs the shopper.
- Handles the shopper’s acceptance or rejection.
- Proposes optimized time slots.
- Confirms and data the appointment.
Why an AI agent for this process?
We may construct a citation software that asks prospects a predefined set of questions. As soon as they approve the worth, the system may robotically schedule an appointment.
This is able to work, however each buyer must observe the identical course of.
An AI agent gives a extra pure and versatile expertise. For instance, a buyer can write:
“Hey! I want a cleansing service for my 2 bed room house on this deal with. I additionally need you to wash inside my fridge. I’m accessible on Tuesday and Wednesday.”.
This question contains all of the required particulars so there isn’t any must ask every other query or make the shopper enter the identical data once more by a kind.
The AI agent can perceive If all required data is already current and proceed on to calculating and presenting a quote.
The AI agent also can deal with the orchestration of any subsequent steps comparable to worth calculation, dealing with buyer’s determination, looking for optimized appointment occasions, and reserving affirmation.
It additionally has the potential to assist further operations, comparable to notifying cleaners about new appointments or contacting close by cleaners to seek out somebody accessible for an pressing request.
Construction of the agent
I created the drawing under to reveal the construction of our AI agent.

The start line is the interplay between a buyer and AI agent. Chatting with the shopper, AI agent tries to get all the data wanted for the service.
The output of the primary chat is reserving or service particulars and the agent converts this to a structured output in order that it may be used in a while by the worth and reserving engines.
The BookingDetails I used within the first model is as follows:
class BookingDetails(BaseModel):
"""Info extracted from the dialog.
``size_info`` is sq. footage for a home and seat depend for a sofa.
Fields are non-compulsory as a result of this mannequin additionally represents partial extraction.
"""
service_type: ServiceType | None = Discipline(default=None)
size_info: float | None = Discipline(default=None, gt=0)
cleaning_depth: CleaningDepth | None = Discipline(default=None)
add_ons: record[str] = Discipline(default_factory=record)
deal with: str | None = Discipline(default=None)
is_complete: bool = False
next_question: str | None = Discipline(
default=None,
exclude=True,
description="A concise query asking just for data nonetheless lacking.",
)
The agent solely asks a brand new query if there may be some lacking particulars. Thus, the agent decides what occurs subsequent, which is a key level that separates an AI agent from a workflow.
LangGraph
We use LangGraph as a result of the reserving workflow wants shared state and should resume throughout a number of buyer messages. Thus, we want a stateful agent.
The state is a TypedDict as proven under:
class AgentState(TypedDict):
messages: Annotated[list[AnyMessage], add_messages]
booking_details: BookingDetails
calculated_price: NotRequired[float | None]
time_options: NotRequired[list[TimeOption]]
selected_slot: NotRequired[TimeOption | None]
standing: BookingStatus
booking_id: NotRequired[str | None]
LangGraph manages state throughout graph execution. Nodes learn the present state and return partial updates. Conditional routing capabilities examine that state to resolve which node runs subsequent.
We will create the graph builder utilizing this state schema:
rom langgraph.graph import StateGraph
graph = StateGraph(AgentState)
Then, we begin including nodes and edges. For instance, the next code snippet exhibits how we will create the worth calculation node.
from customer_service_agent.engines import calculate_price
def calculate_price_node(state: AgentState) -> dict[str, Any]:
return {
"calculated_price": calculate_price(
state["booking_details"]
)
}
graph.add_node("calculate_price", calculate_price_node)
The worth calculation node reads the extracted reserving particulars and returns a partial state replace.
The calculate_price is a operate that calculates the worth utilizing the BookingDetails accessible within the AgentState .
After the information-gathering node runs, a conditional routing operate determines whether or not sufficient data is offered to calculate a worth:
def should_continue_to_pricing(
state: AgentState,
) -> Literal["calculate_price", "end"]:
if state["booking_details"].is_complete:
return "calculate_price"
return "finish"
We join that routing determination to the graph:
graph.add_conditional_edges(
"gather_info",
should_continue_to_pricing,
{
"calculate_price": "calculate_price",
"finish": END,
},
)
If the reserving particulars are full, execution continues to the pricing node. In any other case, the graph ends the present flip and waits for one more buyer message.
The remaining nodes and conditional routes are added in the identical method. Lastly, the graph is compiled with a checkpointer.
graph.compile(checkpointer=checkpointer or MemorySaver())
Observability
Essentially the most essential part of any system is observability. Whether or not it’s a manufacturing line at a manufacturing unit, a standard ML mannequin to detect anomalies, or any AI-agent utilized in manufacturing.
Should you have no idea what goes on in your system, you simply must depend on pure luck to unravel any problem. And it’s sure that your manufacturing system could have points.
There are a lot of options to make use of for observability of an AI agent. We can be utilizing LangFuse, an open-source AI engineering platform designed for tracing, monitoring, evaluating, and debugging giant language mannequin (LLM) functions.
The free tier is sufficient to check our undertaking. You simply must create the key and public keys in LangFuse dashboard and paste them in your .env file:
LANGFUSE_SECRET_KEY=
LANGFUSE_PUBLIC_KEY=
LANGFUSE_BASE_URL="https://cloud.langfuse.com"
We will create a langfuse handler as follows:
def create_langfuse_handler() -> Any | None:
"""Return a configured handler when credentials can be found."""
if not os.getenv("LANGFUSE_PUBLIC_KEY") or not os.getenv("LANGFUSE_SECRET_KEY"):
return None
from langfuse.langchain import CallbackHandler
return CallbackHandler()
def flush_langfuse(handler: Any | None) -> None:
"""Add queued telemetry with out making observability application-critical."""
if handler is None:
return
strive:
from langfuse import get_client
get_client().flush()
besides Exception:
logger.exception("Did not flush LangFuse telemetry")
LangFuse dashboard exhibits each element for us to debug and monitor our AI agent. We will see the prompts, inputs, and outputs. We additionally see the token utilization and value so it’s very simple to detect if there may be sudden state of affairs in our finances.
LangFuse dashboard seems to be like this:

It seems to be difficult at first however when you begin utilizing it, it turns into a lot simpler.
What’s subsequent
The undertaking features a easy CLI to check the end-to-end reserving workflow, however its modular design provides us loads of room for enchancment.
You want an OpenAI API Key to check it however it prices nearly nothing. The screenshot under exhibits the price of a single run:

Each part has entry to the central agent state so the system can simply be prolonged with:
- Frontend interfaces comparable to net, cellular apps, or messaging platforms like WhatsApp.
- A manufacturing database like PostgreSQL.
- Direct connections to actual worker calendars and location-based providers.
I take into account this launch as v0 and I’m planning so as to add extra options and performance on high of it.
Thanks for studying.















