· 7 min read
Telegram + AI: Using Message Entities to Build Smarter Bots and Better UX
Most Telegram AI bots treat incoming text as plain strings and then struggle with formatting, links, mentions, and commands. This tutorial shows how to use Telegram message entities as a first-class input layer so your bot can route, parse, and respond more reliably.
Most Telegram AI bot tutorials start with /start, a text prompt, and a call to an LLM. That works for demos, but it ignores one of Telegram’s most useful and overlooked features: message entities.
Entities are Telegram’s structured metadata for text. They tell you what part of a message is a mention, hashtag, URL, bot command, code block, bold text, blockquote, and more. If you are building AI features on Telegram, entities let you move beyond brittle string matching and create bots that understand intent, preserve formatting, and react to rich input correctly.
This tutorial focuses on how Telegram developers can use message entities as a practical input layer for AI bots.
Why message entities matter for AI bots
If you read Telegram messages as plain text, you lose important structure:
@usernamebecomes just text, even though it may be a target mention/summarizeis not clearly separated from the rest of the user input- inline code and code blocks get flattened
- URLs, hashtags, and mentions are hard to classify reliably
- formatting such as bold or italic may be useful for intent extraction
For AI workflows, that structure is valuable. You can use it to:
- route commands before sending content to an LLM
- preserve code blocks when generating explanations
- detect whether a message includes a mention, URL, or file reference
- extract user intent from a formatted prompt
- create hybrid command + freeform interfaces
The result is a bot that feels more native to Telegram and less like a generic chat wrapper.
What Telegram message entities are
Telegram entities are typed spans in a message. Each entity includes:
typeoffsetlength
Depending on the client and API method, you may also see extra fields such as url or language hints.
Common entity types include:
bolditalicunderlinestrikethroughspoilercodepretext_linktext_mentionurlmentionhashtagcashtagbot_commandemailphone_numberblockquoteexpandable_blockquotecustom_emoji
For AI bots, the most useful categories are usually:
- Commands:
bot_command - User targets:
mention,text_mention - Links and references:
url,text_link - Code:
code,pre - Formatting:
bold,italic,spoiler,blockquote
The overlooked use case: entity-aware prompts
A common mistake is this:
- Receive message text
- Strip everything to plain text
- Send it to the LLM
- Hope the model infers intent correctly
That approach makes bots fragile.
Instead, treat Telegram entities as part of the prompt input. Use them to build a structured representation of the message before it reaches your AI layer.
Example user message:
/summarize Please review this code:\n
```js
const x = 2;
console.log(x)
```
If you only pass the raw string, your model sees one blob of text. If you pass structure, your application can tell the model:
- the message starts with a command
- there is a code block
- the user wants a summary, not a rewrite
That one change improves routing, token efficiency, and output quality.
Parsing entities in practice
The exact code depends on your Telegram library, but the logic is the same.
Step 1: read both text and entities
When a message arrives, inspect:
message.textmessage.entities
If the message is formatted, also check:
message.captionmessage.caption_entities
for media messages with attached text.
Step 2: reconstruct the message as structured segments
Instead of flattening the message, build segments like:
- plain text
- command
- mention
- code block
- link
- emphasized text
A simple normalized shape might look like this:
{
"text": "/summarize Please review this code:",
"entities": [
{ "type": "bot_command", "offset": 0, "length": 10 },
{ "type": "pre", "offset": 33, "length": 31 }
]
}
Step 3: derive intent before calling the model
Use entities for deterministic routing:
- if the first entity is
bot_command, route to a command handler - if there is a
preentity, consider code analysis mode - if the message contains
text_link, extract the URL and process it separately - if the message is a reply and includes mentions, combine context with thread state
This reduces the amount of work your model has to do.
Example: building a /summarize bot that respects code blocks
Suppose you want a bot that summarizes text and code.
Bad version
The bot sends the entire message to the model as plain text:
prompt = f"Summarize this message: {message.text}"
Problems:
- command text is mixed into the user content
- code may be interpreted as prose
- formatting is lost
- long messages may be harder to segment
Better version
Use entities to split command and content.
Pseudo-code:
def extract_command_and_body(message):
text = message.text or ""
entities = message.entities or []
command = None
body = text
for e in entities:
if e.type == "bot_command" and e.offset == 0:
command = text[e.offset:e.offset + e.length]
body = text[e.offset + e.length:].lstrip()
break
return command, body, entities
Then build a structured prompt:
command, body, entities = extract_command_and_body(message)
payload = {
"task": "summarize",
"user_text": body,
"entities": [
{
"type": e.type,
"offset": e.offset,
"length": e.length
}
for e in entities
]
}
Now your LLM receives both the text and the formatting map.
A strong prompt instruction might be:
Summarize the user message. Preserve code semantics. If a code block is present, explain its purpose separately from the surrounding prose.
That gives the model useful constraints without forcing it to infer structure from raw text.
Example: extracting mentions for AI-assisted moderation
If you run a group bot, mentions are more than decoration.
A user may write:
Please ask @alex to check this.
or
Ping Alex about the deployment.
The first contains a structured mention entity. The second does not.
That distinction matters if you are building moderation, routing, or delegation flows.
Use case
Your bot can detect when a message is explicitly directed at a user and:
- create a task for that user
- attach the message to a thread
- notify a downstream workflow
- avoid misclassifying ordinary text as a target instruction
Important caveat
Do not assume every mention entity maps to a real chat member. The entity may refer to a username, a text mention, or a user not present in the current chat context. Handle that gracefully.
Example: preserving code blocks for coding assistants
This is the most practical AI use case for entities.
If your bot helps with debugging, code review, or architecture questions, you should treat code entities as first-class data.
Why?
Because code blocks change how the model should read the message.
A user message like:
Here’s my issue:
```python
def add(a, b):
return a + b
```
Why does this fail in production?
should not be processed the same way as a casual question.
What to do
- Detect
preandcodeentities - Extract the exact code span
- Preserve language hints if available
- Send code and prose separately to the model
Suggested payload:
{
"user_question": "Why does this fail in production?",
"code_blocks": [
{
"language": "python",
"content": "def add(a, b):\n return a + b"
}
]
}
This is much better than dumping everything into one prompt.
How to use entities to improve response formatting
Telegram message entities are not just for parsing input. They also help you format AI output correctly.
If your bot returns:
- explanations
- code snippets
- warnings
- step lists
then you should send formatted output using Telegram’s entity-aware methods rather than hand-rolling Markdown and hoping it parses.
Why this matters
Markdown parsing is easy to break when your response contains:
- backticks
- underscores
- user-supplied text
- nested formatting
With entities, you can generate text and formatting separately.
That gives you:
- fewer parse errors
- cleaner escapes
- more predictable rendering across Telegram clients
If your library supports it, prefer sending entities instead of raw formatting markup.
Pattern: build a Telegram entity adapter layer
For a production bot, create one small module that converts Telegram messages into your own internal format.
Example internal model:
{
"text": "Please review this code",
"segments": [
{ "type": "text", "value": "Please review this code" }
],
"commands": ["/review"],
"has_code": true,
"mentions": ["@alex"],
"links": ["https://example.com"]
}
Your AI layer should consume this normalized shape, not the raw Telegram object.
Benefits:
- easier testing
- easier mocking
- cleaner prompt design
- less Telegram-specific code inside your AI logic
This separation also makes it easier to switch models later.
Handling media captions with entities
Many developers forget that Telegram messages can carry text in captions.
If a user sends:
- a screenshot with a caption
- a PDF with a note
- a video with instructions
then the caption may include valuable structured text.
Check:
captioncaption_entities
Treat these the same way as message text and entities.
This is especially useful for AI bots that:
- describe images through OCR results plus caption context
- summarize attached documents
- classify media submissions
Avoiding common mistakes
1. Don’t strip formatting too early
If you remove entities before routing, you lose information that can improve classification.
2. Don’t trust command text alone
A command at the start of a message is useful, but validate it with entity data rather than string splitting only.
3. Don’t send every entity to the model blindly
Some entities are useful for your app logic, others are noise. Decide what matters.
4. Don’t assume entity offsets are character-safe in your own substring logic
Telegram offsets are based on the API’s text representation. Be careful with libraries and Unicode handling. Test with emoji, combining characters, and non-Latin scripts.
5. Don’t forget edited messages
If your bot reacts to structured text, handle edits carefully. A user may change a command or replace a code block after submission.
A practical architecture for Telegram + AI
Here is a robust flow:
- Receive update
- Extract text, caption, and entities
- Normalize into internal segments
- Run deterministic routing
- command handler
- code assistant
- moderation workflow
- generic chat fallback
- Build an entity-aware prompt for the LLM
- Post-process output
- Send formatted Telegram response
This design keeps the AI layer useful without making it responsible for everything.
When entities are especially valuable
Use this feature when your bot handles:
- developer support
- code review
- support triage
- moderation
- task assignment
- knowledge retrieval
- form-like chat interactions
In all of these cases, message structure is part of the signal.
Final takeaway
The overlooked Telegram feature here is not a flashy AI integration. It is the structured metadata already present in every rich message.
If you use message entities well, your Telegram AI bot can:
- understand user intent more reliably
- preserve code and formatting
- route commands without brittle parsing
- produce cleaner responses
- feel much more native to Telegram
That is a big upgrade over the usual “send text to model, hope for the best” approach.
If you are building a serious Telegram bot, make entities part of your architecture from day one.