TL;DR
-
AiAgentDemoSrv@v1.0.0exposes one HTTP Listener entry:POST /api/ai/agent/chat. - The Agent is bound with
tags=order-demoand can automatically discover three XML-only tools. - The tools support listing orders, querying order details, and cancelling orders with reason.
- The route returns both natural-language answer (
responseText) and structured tool output (toolData).
Metadata
- Applicable Version:
AiAgentDemoSrv@v1.0.0 - Related Service:
AiAgentDemoSrv@v1.0.0@ai-agent-demo-route.xml
Background and Goal
In many integration scenarios, users do not want to remember exact API paths or payload fields. They want to ask naturally:
- "Show all orders for customer Zhang San"
- "Check details of order ord00xa12"
- "Cancel this order with reason"
The goal of AiAgentDemoSrv is to prove a production-friendly pattern:
- Keep one stable request entry through HTTP Listener.
- Use
langchain4j-agentas the decision layer. - Expose business APIs as
langchain4j-toolsroutes (no extra Java code for each tool). - Return readable answer and machine-friendly JSON in one response.
This article is based on repository routes, properties, and runtime logs, and follows the same component model described in existing LangChain4j/Camel usage docs.
Route and Configuration Breakdown
1) HTTP Listener request entry
From lightesb-camel-app/AiAgentDemoSrv/v1.0.0/ai-agent-demo-route.xml:
<from uri="undertow:http://0.0.0.0:{{server.port}}/api/ai/agent/chat?httpMethodRestrict=POST"/>
From lightesb-camel-app/AiAgentDemoSrv/v1.0.0/common.config.properties:
server.port=19095
HTTP.Listener=true
So the entry endpoint is:
POST http://localhost:19095/api/ai/agent/chat
2) Agent setup and memory wiring
From service.config.properties:
service.ai.route=true
service.ai.type=orderdemo
service.ai.mode=agent
ai.agent.tags=order-demo
ai.system.prompt=You are an order management assistant. You can help users query order status and cancel orders. Please respond in English.
ai.memory.enabled=true
ai.memory.max.turns=10
From the route:
-
CamelLangChain4jAgentSystemMessageis set fromai.system.prompt -
CamelLangChain4jAgentMemoryIdis extracted from request JSON$.memoryId - message body is extracted from
$.message
Then the Agent endpoint is invoked:
<to uri="langchain4j-agent:{{service.ai.type}}Assistant?agent=#genericAiAgent&tags={{ai.agent.tags}}"/>
3) Tool routes (100% XML)
The Agent can discover three tools with tags=order-demo:
queryOrderDetailcancelOrderlistRecentOrders
Each tool is declared via langchain4j-tools:* URI with:
-
descriptionfor model tool selection -
parameter.xxx=typefor argument extraction - internal HTTP call to mock endpoints for demo verification
Example:
<from uri="langchain4j-tools:cancelOrder?tags=order-demo&description=Cancel an existing order by order ID. Requires a reason for cancellation.&parameter.orderId=string&parameter.reason=string"/>
4) Response write-back format
After Agent execution, route packages the final JSON with DataSonnet:
successmemoryId-
responseText(natural language) -
toolData(structured JSON from the latest tool call) timestamp
This pattern works well for both front-end rendering and downstream auditing.
Request and Response Examples
1) Query recent orders
curl -X POST "http://localhost:19095/api/ai/agent/chat" \
-H "Content-Type: application/json" \
-d "{\"memoryId\":\"003\",\"message\":\"Query all order information for customer Zhang San\"}"
Observed from runtime logs:
- Agent chooses
listRecentOrders - Final answer includes order IDs and statuses
-
toolDatacarries structured order list payload
2) Query one order detail
curl -X POST "http://localhost:19095/api/ai/agent/chat" \
-H "Content-Type: application/json" \
-d "{\"memoryId\":\"001\",\"message\":\"Query details for order ord00xa12\"}"
Observed behavior:
- Agent triggers
queryOrderDetail - Tool returns order status, items, and total amount
- Assistant responds in Chinese according to
ai.system.prompt
3) Cancel order in two turns
First request:
curl -X POST "http://localhost:19095/api/ai/agent/chat" \
-H "Content-Type: application/json" \
-d "{\"memoryId\":\"002\",\"message\":\"Cancel order ord00xa12\"}"
Second request with reason:
curl -X POST "http://localhost:19095/api/ai/agent/chat" \
-H "Content-Type: application/json" \
-d "{\"memoryId\":\"002\",\"message\":\"Cancel order ord00xa12 due to seven-day no-reason return\"}"
Observed behavior:
- First turn asks for cancellation reason (
toolData=null) - Second turn triggers
cancelOrder - Final response confirms cancellation reason and order ID
Common Issues and Troubleshooting
1) Agent does not call tools
Check:
-
ai.agent.tagsmatches each tool routetags - tool
descriptionis clear and action-oriented - tool parameters are declared as
parameter.xxx=type
2) Endpoint returns 404 or no listener
Check:
HTTP.Listener=trueserver.port=19095- request path is exactly
/api/ai/agent/chat
3) Tool HTTP call fails silently
Current tool HTTP calls use throwExceptionOnFailure=false. Check logs:
[AI-TOOL] ... httpStatus=...- response body content in servicelog
4) Multi-turn context seems lost
Check:
- stable
memoryIdacross turns ai.memory.enabled=true- max turns and TTL settings in
service.config.properties
5) Chinese response appears garbled
Keep UTF-8 headers in tool routes and preserve requestCharsetProcessor + jsonResponseProcessor.
Summary
AiAgentDemoSrv v1.0.0 demonstrates a practical LightESB pattern for LLM-driven order operations:
- one HTTP Listener request entry
- one Agent orchestration layer
- multiple
langchain4j-toolsbusiness tools - one structured response write-back contract
It is a solid baseline for enterprise scenarios where users prefer natural language operations, while systems still require deterministic API calls and auditable payloads.
Top comments (0)