A support agent answers the 80th ticket of the day. The response is standard — "Your request has been received, we are looking into it" — but each time they have to type it or search through templates. According to statistics, an agent spends up to 30% of their time crafting repetitive replies. AI generation doesn't replace the agent; it removes mechanical work: a draft response is ready in seconds, the agent edits and sends it. However, implementing such a system in the agent's mobile app (not the customer's) brings technical challenges: a fast editor with predictive text, streaming the LLM response, synchronization with conversation history. Our experience — over 5 years in mobile development — shows that the right architecture cuts response time by 40–60% within the first week. As our practice shows, response time drops by 55%. The savings per agent amount to up to 45,000 rubles per month (approximately $500 USD), and the payback period is 2–3 months. For a team of 10 agents, annual savings exceed $60,000 USD.
Contextual generation and ticket context
The main mistake is feeding only the last user message to the LLM. A good response requires context: previous conversations, order status, client tariff. We build a request to OpenAI with full context:
// iOS
struct ResponseGenerationRequest: Encodable {
let model = "gpt-4o-mini"
let stream = true
let messages: [ChatMessage]
}
func buildMessages(ticket: Ticket, history: [Message], agentKnowledgeBase: String) -> [ChatMessage] {
var messages = [ChatMessage]()
messages.append(ChatMessage(
role: "system",
content: """
You are a support agent for \(companyName). Be concise, to the point, no fluff.
Knowledge base:\n\(agentKnowledgeBase)
Customer's order status: \(ticket.orderStatus ?? "no data")
"""
))
history.suffix(6).forEach { msg in
messages.append(ChatMessage(role: msg.role, content: msg.text))
}
messages.append(ChatMessage(role: "user", content: ticket.latestMessage))
return messages
}
suffix(6) — we take the last 6 messages, not the whole history. A long context increases cost and response time, and for most tickets 3–4 last messages are enough. If needed, we plug in RAG for knowledge base search.
Streaming: 10x faster than non-streaming generation for mobile agents
Without streaming, the agent waits 2–5 seconds for the LLM to generate the full response. With stream: true, the first words appear in 300–500 ms. This is critical for the UX in a mobile agent interface — the agent shouldn't sit staring at a loading indicator. Streaming beats non-streaming generation by 10x in initial speed: 300 ms vs 3 seconds.
// Parse SSE stream
func streamResponse(for request: URLRequest) -> AsyncStream<String> {
AsyncStream { continuation in
let task = URLSession.shared.dataTask(with: request) { data, response, error in
// not suitable for streaming
}
// Use URLSession.bytes for SSE
Task {
let (bytes, _) = try await URLSession.shared.bytes(for: request)
for try await line in bytes.lines {
guard line.hasPrefix("data: "),
let json = line.dropFirst(6).data(using: .utf8),
let chunk = try? JSONDecoder().decode(StreamChunk.self, from: json),
let text = chunk.choices.first?.delta.content
else { continue }
continuation.yield(text)
}
continuation.finish()
}
}
}
On Android we use OkHttp with EventSourceListener from okhttp-sse or parse responseBody.source() line by line.
| Parameter | Without streaming | With streaming |
|---|---|---|
| Time to first word | 2–5 s | 300–500 ms |
| UX | Agent waits | Text appears gradually |
| Network load | Entire response at once | Chunks as generated |
Draft editor with edit analytics
The generated text is a draft, not the final answer. The UI must include:
- The editing field opens directly with the text — the agent sees they can edit
- A "Regenerate" button for a new variant on the same topic
- "Adjust tone": more formal / neutral / empathetic — an additional prompt suffix
- A change counter relative to the original — to track how agents edit AI (edit analytics)
// Android Compose
@Composable
fun ResponseEditor(
aiDraft: String,
onSend: (String) -> Unit,
onRegenerate: () -> Unit
) {
var editedText by remember { mutableStateOf(aiDraft) }
val editDistance = remember(editedText, aiDraft) {
levenshteinDistance(aiDraft, editedText) // custom utility
}
Column {
OutlinedTextField(
value = editedText,
onValueChange = { editedText = it },
modifier = Modifier.fillMaxWidth().heightIn(min = 120.dp)
)
Row {
Text("Edits: $editDistance characters", style = MaterialTheme.typography.labelSmall)
Spacer(Modifier.weight(1f))
TextButton(onClick = onRegenerate) { Text("Regenerate") }
Button(onClick = { onSend(editedText) }) { Text("Send") }
}
}
}
The change counter isn't just a UI decoration. It's logged in analytics: if agents edit more than 50% of the text, the model isn't well-tuned to the knowledge base. In our projects, we guarantee ≤30% edits after calibration.
Knowledge base and RAG integration
For specific product questions, the LLM hallucinates without context. We connect RAG (Retrieval-Augmented Generation): before generating a response, we do a vector search over internal documentation and insert relevant pieces into the system prompt. On the backend: Pinecone, Weaviate, or pgvector (if PostgreSQL already exists). The mobile client doesn't participate — it just receives the ready system prompt from the server.
More on RAG setup
- Index documents in a vector DB.
- Create embeddings via OpenAI Embeddings API.
- Configure relevance (top-k = 3–5).
- Integrate into the generation pipeline.
Implementation steps and timeline
Our turnkey service follows a structured process:
- Discovery (1–2 days): Assess your current ticket system, integrate with OpenAI API, and plan streaming setup.
- Core development (1.5–2 weeks): Implement LLM streaming with draft editor on iOS (Swift) and Android (Kotlin), including edit analytics and tone adjustment.
- Backend RAG (1–2 weeks): Set up vector database, embedding pipeline, and connect to your knowledge base.
- Testing and calibration (3–5 days): Reduce edit rate to ≤30% by tuning prompts and RAG parameters.
- Deployment and training (2–3 days): Release to agents, provide documentation, and conduct training sessions.
| Stage | Timeline |
|---|---|
| Basic generation without streaming | 2–3 days |
| Editor with streaming + tone adj. | 1.5–2 weeks |
| RAG integration on backend | 1–2 weeks |
| Full turnkey cycle | 3–4 weeks |
Our experience — over 5 years in mobile development and 10+ projects with AI integration. Contact us to discuss details.







