August 13, 2026 · 20 min read
AI agents — systems that can reason, plan, and execute actions using external tools — are transforming how businesses automate workflows. Chinese LLMs now offer function calling capabilities rivaling GPT-4 at a fraction of the cost. This guide walks you through building production-ready agents with DeepSeek, GLM-4, and Qwen via TokenEase.
A production AI agent needs four core capabilities:
| Model | Function Calling | Parallel Tools | Tool Choice | Cost per 1M tokens |
|---|---|---|---|---|
| GPT-4o | Native | Yes | auto/required/none | $5.00 / $15.00 |
| DeepSeek-V4 | Native | Yes | auto/required | $0.50 / $2.00 |
| GLM-4 | Native | Yes | auto | $0.70 / $2.10 |
| Qwen-Max | Native | Yes | auto | $0.50 / $2.00 |
| Kimi-K2 | Native | Yes | auto | $0.30 / $1.20 |
Tools are defined as JSON schemas that the LLM can understand:
# Tool definitions for a data analysis agent
tools = [
{
"type": "function",
"function": {
"name": "query_database",
"description": "Execute a SQL query against the analytics database",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "SQL SELECT query to execute"
},
"limit": {
"type": "integer",
"description": "Maximum rows to return",
"default": 100
}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "send_email",
"description": "Send an email to a specified recipient",
"parameters": {
"type": "object",
"properties": {
"to": {
"type": "string",
"description": "Email address of recipient"
},
"subject": {
"type": "string",
"description": "Email subject line"
},
"body": {
"type": "string",
"description": "Email body content"
}
},
"required": ["to", "subject", "body"]
}
}
},
{
"type": "function",
"function": {
"name": "generate_chart",
"description": "Create a chart from data and return as base64 PNG",
"parameters": {
"type": "object",
"properties": {
"chart_type": {
"type": "string",
"enum": ["bar", "line", "pie", "scatter"],
"description": "Type of chart to generate"
},
"data": {
"type": "string",
"description": "JSON array of data points"
},
"title": {
"type": "string",
"description": "Chart title"
}
},
"required": ["chart_type", "data", "title"]
}
}
}
]
import requests
import json
TOKEN = "your_tokenease_api_key"
BASE_URL = "https://tokenease.io/v1"
def chat_with_tools(messages, tools=None, model="deepseek-v4"):
"""Send chat completion request with tool support"""
payload = {
"model": model,
"messages": messages,
"temperature": 0.3
}
if tools:
payload["tools"] = tools
payload["tool_choice"] = "auto"
response = requests.post(
f"{BASE_URL}/chat/completions",
headers={"Authorization": f"Bearer {TOKEN}"},
json=payload
)
return response.json()
# Example: Ask the agent to analyze sales data
messages = [
{"role": "system", "content": "You are a data analysis assistant. Use available tools to help users."},
{"role": "user", "content": "What were our top 5 products by revenue last month?"}
]
response = chat_with_tools(messages, tools=tools)
print(json.dumps(response, indent=2))
class AIAgent:
def __init__(self, model="deepseek-v4", max_iterations=10):
self.model = model
self.max_iterations = max_iterations
self.messages = []
self.tool_registry = {}
def register_tool(self, name, func):
"""Register a Python function as a tool"""
self.tool_registry[name] = func
def execute_tool(self, tool_call):
"""Execute a tool call and return the result"""
function_name = tool_call["function"]["name"]
arguments = json.loads(tool_call["function"]["arguments"])
if function_name not in self.tool_registry:
return {"error": f"Unknown tool: {function_name}"}
try:
result = self.tool_registry[function_name](**arguments)
return {"result": result}
except Exception as e:
return {"error": str(e)}
def run(self, user_input, tools=None):
"""Main agent loop"""
self.messages.append({"role": "user", "content": user_input})
for i in range(self.max_iterations):
# Get LLM response
response = chat_with_tools(self.messages, tools, self.model)
message = response["choices"][0]["message"]
# Add assistant message to history
self.messages.append(message)
# Check if tool calls were made
tool_calls = message.get("tool_calls", [])
if not tool_calls:
# No tool calls — return the final answer
return message["content"]
# Execute each tool call
for tool_call in tool_calls:
result = self.execute_tool(tool_call)
# Add tool result to messages
self.messages.append({
"role": "tool",
"tool_call_id": tool_call["id"],
"content": json.dumps(result)
})
return "Max iterations reached without completing the task."
# Initialize agent
agent = AIAgent(model="deepseek-v4")
# Register actual tool implementations
import sqlite3
def query_database(query, limit=100):
conn = sqlite3.connect("analytics.db")
cursor = conn.cursor()
cursor.execute(query + f" LIMIT {limit}")
rows = cursor.fetchall()
columns = [description[0] for description in cursor.description]
conn.close()
return {"columns": columns, "rows": rows}
def send_email(to, subject, body):
# Integration with your email service
return {"status": "sent", "to": to, "subject": subject}
agent.register_tool("query_database", query_database)
agent.register_tool("send_email", send_email)
# Run the agent
result = agent.run(
"What were our top 5 products by revenue last month? Send the results to manager@company.com",
tools=tools
)
print(result)
For complex tasks, add a planning layer before execution:
class PlanningAgent(AIAgent):
def plan(self, user_input):
"""Generate a step-by-step plan"""
plan_prompt = f"""Given the user request, create a step-by-step plan.
Available tools: query_database, send_email, generate_chart
User request: {user_input}
Respond with a JSON array of steps:
[{{"step": 1, "action": "tool_name", "reason": "why"}}, ...]"""
response = chat_with_tools(
[{"role": "user", "content": plan_prompt}],
model=self.model
)
plan_text = response["choices"][0]["message"]["content"]
# Extract JSON from response
try:
plan = json.loads(plan_text[plan_text.find("["):plan_text.rfind("]")+1])
return plan
except:
return [{"step": 1, "action": "direct_response", "reason": "Simple query"}]
def run_with_plan(self, user_input, tools=None):
"""Execute with planning"""
plan = self.plan(user_input)
print(f"Plan: {json.dumps(plan, indent=2)}")
# Execute each step
for step in plan:
if step["action"] == "direct_response":
return self.run(user_input, tools)
else:
# Execute specific tool step
pass
return self.run(user_input, tools)
# Example: Complex multi-step task
complex_task = """
1. Query last month's sales data
2. Identify top 5 products
3. Generate a bar chart of their revenue
4. Email the chart to the sales team
"""
agent = PlanningAgent(model="glm-4")
result = agent.run_with_plan(complex_task, tools=tools)
class StatefulAgent(PlanningAgent):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.memory = [] # Short-term memory
self.facts = {} # Extracted facts
def extract_facts(self, text):
"""Extract key facts from conversations"""
prompt = f"Extract key facts from this text as JSON key-value pairs:\n{text}"
response = chat_with_tools([{"role": "user", "content": prompt}], model=self.model)
try:
facts = json.loads(response["choices"][0]["message"]["content"])
self.facts.update(facts)
except:
pass
def get_context(self):
"""Build context from memory and facts"""
context = "Known facts:\n"
for k, v in self.facts.items():
context += f"- {k}: {v}\n"
context += f"\nRecent conversation:\n"
for msg in self.memory[-5:]: # Last 5 interactions
context += f"{msg['role']}: {msg['content']}\n"
return context
def run(self, user_input, tools=None):
# Enhance user input with context
context = self.get_context()
enhanced_input = f"Context: {context}\n\nCurrent request: {user_input}"
result = super().run(enhanced_input, tools)
# Store interaction in memory
self.memory.append({"role": "user", "content": user_input})
self.memory.append({"role": "assistant", "content": result})
# Extract facts
self.extract_facts(result)
return result
# Conversation continuity
agent = StatefulAgent(model="deepseek-v4")
agent.run("My company is Acme Corp and I'm the CTO", tools=tools)
agent.run("What's our server uptime?", tools=tools) # Knows "our" = Acme Corp
class RobustAgent(StatefulAgent):
def execute_tool(self, tool_call):
"""Execute with retry and error handling"""
function_name = tool_call["function"]["name"]
arguments = json.loads(tool_call["function"]["arguments"])
max_retries = 3
for attempt in range(max_retries):
try:
result = self.tool_registry[function_name](**arguments)
return {"status": "success", "result": result}
except Exception as e:
if attempt < max_retries - 1:
# Ask LLM to fix arguments
fix_prompt = f"""Tool '{function_name}' failed with: {str(e)}
Arguments: {json.dumps(arguments)}
Please provide corrected arguments as JSON."""
fix_response = chat_with_tools(
[{"role": "user", "content": fix_prompt}],
model=self.model
)
try:
new_args = json.loads(fix_response["choices"][0]["message"]["content"])
arguments = new_args
except:
pass
else:
return {"status": "error", "error": str(e), "attempts": attempt + 1}
def run(self, user_input, tools=None):
"""Run with comprehensive error handling"""
try:
result = super().run(user_input, tools)
return result
except Exception as e:
fallback_prompt = f"""The agent encountered an error: {str(e)}
User request: {user_input}
Please provide a helpful response or ask clarifying questions."""
response = chat_with_tools(
[{"role": "user", "content": fallback_prompt}],
model=self.model
)
return response["choices"][0]["message"]["content"]
# Production-ready agent
agent = RobustAgent(model="glm-4", max_iterations=15)
agent.register_tool("query_database", query_database)
agent.register_tool("send_email", send_email)
DeepSeek-V4 and GLM-4 support calling multiple tools in parallel:
def execute_parallel(agent, tool_calls):
"""Execute independent tool calls in parallel"""
from concurrent.futures import ThreadPoolExecutor
def execute_single(tc):
return agent.execute_tool(tc)
with ThreadPoolExecutor(max_workers=4) as executor:
results = list(executor.map(execute_single, tool_calls))
return results
# When the LLM returns multiple tool_calls, execute them in parallel
if len(tool_calls) > 1:
results = execute_parallel(agent, tool_calls)
else:
results = [agent.execute_tool(tool_calls[0])]
def validate_sql_query(query):
"""Prevent destructive SQL operations"""
forbidden = ["DROP", "DELETE", "UPDATE", "INSERT", "ALTER", "CREATE"]
upper_query = query.upper()
for word in forbidden:
if word in upper_query:
return False, f"Forbidden operation: {word}"
if not upper_query.strip().startswith("SELECT"):
return False, "Only SELECT queries allowed"
return True, "Valid"
# Wrap database tool with validation
def safe_query_database(query, limit=100):
is_valid, msg = validate_sql_query(query)
if not is_valid:
return {"error": msg}
return query_database(query, limit)
| Strategy | Savings | Implementation |
|---|---|---|
| Tool result caching | 30-50% | Cache repeated queries |
| Model cascading | 60% | Use Kimi for planning, DeepSeek for execution |
| Early termination | 20% | Stop when answer is sufficient |
| Batch tool calls | 15% | Combine independent queries |
# Complete customer support agent
cs_tools = [
{
"type": "function",
"function": {
"name": "search_knowledge_base",
"description": "Search help articles for solutions",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "check_order_status",
"description": "Look up order by ID",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string"}
},
"required": ["order_id"]
}
}
},
{
"type": "function",
"function": {
"name": "create_ticket",
"description": "Escalate to human support",
"parameters": {
"type": "object",
"properties": {
"issue": {"type": "string"},
"priority": {"type": "string", "enum": ["low", "medium", "high"]}
},
"required": ["issue", "priority"]
}
}
}
]
# Agent handles:
# "Where is my order ORD-12345?" → check_order_status
# "How do I reset my password?" → search_knowledge_base
# "I was charged twice" → create_ticket(high) + check_order_status
Start building your AI agent today with TokenEase:
For more on production patterns, see our guides on failover and load balancing and A/B testing AI models.
Last updated: August 2026. Function calling capabilities vary by model version.