An intelligent conversational agent built with OpenAI's SDK and Render Workflows, featuring tool calling and multi-turn conversations.
Customer support agent that can:
- Answer questions using a knowledge base
- Look up order status
- Process refunds
- Maintain conversation context
- Make intelligent decisions about which tools to use
This pattern is useful for:
- Customer service automation
- Interactive assistants
- Task automation agents
- Intelligent workflow orchestration
- AI-powered help desks
- Tool Calling: Agent can call functions to perform actions (order lookup, refunds, knowledge base search)
- Multi-Turn Conversations: Maintains context across multiple interactions
- Dynamic Tool Selection: AI decides which tools to use based on user intent
- Stateful Workflows: Preserves conversation history
- Error Handling: Robust handling of API failures with retries
- Extensible: Easy to add new tools and capabilities
multi_turn_conversation (orchestrator)
└── agent_turn (for each message)
├── call_llm_with_tools (OpenAI API call)
└── execute_tool (if tools requested)
├── get_order_status
├── process_refund
└── search_knowledge_base
- Python 3.10+
- OpenAI API key
# Navigate to example directory
cd openai-agent
# Install dependencies
pip install -r requirements.txt
# Set OpenAI API key
export OPENAI_API_KEY="your-openai-api-key"
# Run the workflow service
python main.pyService Type: Workflow
Build Command:
cd openai-agent && pip install -r requirements.txtStart Command:
cd openai-agent && python main.pyRequired:
RENDER_API_KEY- Your Render API key (from Render dashboard)OPENAI_API_KEY- Your OpenAI API key (from OpenAI platform)
-
Create Workflow Service
- Go to Render Dashboard
- Click "New +" → "Workflow"
- Connect your repository
- Name:
openai-agent-workflows
-
Configure Build Settings
- Build Command:
cd openai-agent && pip install -r requirements.txt - Start Command:
cd openai-agent && python main.py
- Build Command:
-
Set Environment Variables
- Add
RENDER_API_KEYin the Environment section - Add
OPENAI_API_KEYin the Environment section - Get Render API key from: Render Dashboard → Account Settings → API Keys
- Get OpenAI API key from: https://platform.openai.com/api-keys
- Add
-
Deploy
- Click "Create Workflow"
- Render will build and start your workflow service
Once deployed, you can test the agent directly in the Render Dashboard:
- Go to your Workflow service in Render Dashboard
- Click the "Manual Run" or "Start Task" button
- Select the task you want to test
- Enter the task input as JSON in the text area
- Click "Start task"
Important: The OpenAI agent workflow expects array inputs, not JSON objects. The first element is the user message, the second is the conversation history.
Recommended Starting Point: Start with agent_turn for a single conversation turn, or multi_turn_conversation to see how the agent maintains context across multiple messages.
Test single conversation turn:
Task: agent_turn
Input:
[
"What is the status of order ORD-001?",
[]
]This will make the agent look up the order and respond with status information.
Test order refund:
Task: agent_turn
Input:
[
"I need a refund for order ORD-002, it arrived damaged.",
[]
]The agent will process the refund and provide confirmation.
Test knowledge base search:
Task: agent_turn
Input:
[
"What is your return policy?",
[]
]The agent will search the knowledge base and provide policy information.
Test multi-turn conversation:
Task: multi_turn_conversation
Input:
{
"messages": [
"What is your return policy?",
"What is the status of order ORD-001?",
"Can you process a refund for that order? It arrived damaged."
]
}This will process all messages in sequence, maintaining context between turns.
Note: The agent uses OpenAI GPT-4, so you'll see the AI making intelligent decisions about which tools to call based on the user's message.
Once deployed, interact with the agent via the Render API or SDK:
from render_sdk import Render
# Uses RENDER_API_KEY environment variable automatically
render = Render()
# Single turn conversation
task_run = await render.workflows.run_task(
"openai-agent-workflows/agent_turn",
{
"user_message": "What is the status of order ORD-001?",
"conversation_history": []
}
)
result = await task_run
print(f"Agent: {result.results['response']}")
# Multi-turn conversation
task_run = await render.workflows.run_task(
"openai-agent-workflows/multi_turn_conversation",
{
"messages": [
"What is your return policy?",
"What is the status of order ORD-001?",
"Can you process a refund for that order? It arrived damaged."
]
}
)
result = await task_run
for turn in result.results['turns']:
print(f"User: {turn['user']}")
print(f"Agent: {turn['assistant']}")
print(f"Tools used: {[t['tool'] for t in turn['tool_calls']]}")
print()Looks up order status by order ID.
Input: {"order_id": "ORD-001"}
Output: Order status, tracking number, ETA
Processes a refund for an order.
Input: {"order_id": "ORD-001", "reason": "Item damaged"}
Output: Refund confirmation with refund ID
Searches the knowledge base for information.
Input: {"query": "shipping policy"}
Output: Relevant articles and information
get_order_status: Looks up order status. Called as a subtask when the agent needs order information.
process_refund: Processes refunds. Called as a subtask when the agent needs to issue a refund.
search_knowledge_base: Searches for information. Called as a subtask when the agent needs help articles.
call_llm_with_tools: Calls OpenAI API with tool definitions. The model decides whether to call tools or respond directly.
execute_tool: Dynamically executes a tool as a subtask based on the agent's decision:
@app.task
async def execute_tool(tool_name: str, arguments: dict) -> dict:
# Map tool names to tasks
tool_map = {
"get_order_status": get_order_status,
"process_refund": process_refund,
"search_knowledge_base": search_knowledge_base
}
# SUBTASK CALL: Execute the appropriate tool function
result = await tool_map[tool_name](**arguments)
return resultagent_turn: Executes a single conversation turn with nested subtask execution:
await call_llm_with_tools(...)- Call LLM with user message- If tools requested:
await execute_tool(...)for each tool (which then calls the actual tool task) await call_llm_with_tools(...)again with tool results to generate final response
This demonstrates nested subtask calling: agent_turn → execute_tool → get_order_status (3 levels deep!).
multi_turn_conversation: Orchestrates multiple conversation turns:
for user_message in messages:
# SUBTASK CALL: Process each message through agent_turn
turn_result = await agent_turn(user_message, conversation_history)
conversation_history = turn_result["conversation_history"]This demonstrates calling subtasks in a loop to maintain conversation state.
To add a new tool capability:
- Define the tool function:
@app.task
def new_tool(param: str) -> dict:
"""Tool: Description of what this tool does."""
# Implementation
return {"result": "data"}- Add tool definition in
agent_turn:
{
"type": "function",
"function": {
"name": "new_tool",
"description": "Description for the AI",
"parameters": {
"type": "object",
"properties": {
"param": {
"type": "string",
"description": "Parameter description"
}
},
"required": ["param"]
}
}
}- Add to tool map in
execute_tool:
tool_map = {
"get_order_status": get_order_status,
"process_refund": process_refund,
"search_knowledge_base": search_knowledge_base,
"new_tool": new_tool # Add here
}Order Status Inquiry:
User: "What is the status of order ORD-001?"
→ Agent calls get_order_status(order_id="ORD-001")
Agent: "Your order ORD-001 has been shipped! The tracking number is 1Z999AA1234567890 and the estimated delivery is October 15th."
Refund Request:
User: "I need a refund for order ORD-002, the item is defective."
→ Agent calls process_refund(order_id="ORD-002", reason="Item defective")
Agent: "I've processed your refund for order ORD-002. Your refund ID is REF-ORD-002-20241010... The amount of $99.99 will be returned to your original payment method within 5-7 business days."
Knowledge Base Query:
User: "What is your shipping policy?"
→ Agent calls search_knowledge_base(query="shipping policy")
Agent: "We offer free shipping on orders over $50. Standard shipping takes 3-5 business days, and express shipping is available for $15 with delivery in 1-2 business days."
- Python-only: Workflows are only supported in Python via render-sdk
- No Blueprint Support: Workflows don't support render.yaml blueprint configuration
- OpenAI Costs: Be mindful of API costs when running the agent frequently
- Model Selection: Currently uses GPT-4; can be changed to GPT-3.5-turbo for cost savings
- Tool Safety: In production, add authorization checks before executing sensitive tools
- Rate Limiting: Consider implementing rate limits for production deployments