- 人工智能
- AI Agent
- MCP 服务
- 工具调用
- GUI 自动化
- 语音
- 数字人
- 交互助手
【免费下载链接】airi
💖🧸 自托管、归你拥有的 Grok 风格 AI 伴侣与 waifu / 赛博生命灵魂容器,目标是接近 Neuro-sama 的高度;支持实时语音聊天、Minecraft 和 Factorio 游玩,支持 Web / macOS / Windows。
导读
integrations/telegram-bot是 airi 项目中的一个独立集成模块:它把 AIRI(一个自托管、面向 waifu / 赛博生命灵魂容器的 AI 伴侣)接入 Telegram,让 AIRI 能够与你以及群组里的其他用户实时对话、收发图片和贴纸,并基于向量记忆在多个群聊之间保持上下文。阅读本文后,你将能够从零完成该机器人的环境搭建、环境变量配置、数据库与可观测性栈启动,并理解其「LLM 自主决策动作 → 执行动作 → 周期循环」的 Agent 运行机制与底层实现。
一、模块定位:AIRI 的 Telegram 入口
在 airi 仓库中,integrations/目录存放各类第三方平台的接入集成,其中 integrations/telegram-bot 是 Telegram 专属入口。该模块是一个独立的 Node.js 应用(@proj-airi/telegram-bot,见 package.json),基于 grammY 框架编写,核心目标正如其 README 所述:
Allow アイリ to talk to you and many other users in Telegram.
它并不只是一个「回复指令的普通 Bot」,而是把 AIRI 的人格(见下文的personality提示词)与一套自主决策循环搬进了 Telegram 群聊:机器人每隔约 1 分钟会自我“tick”一次,自行决定是回复、发贴纸、读消息还是沉默。
二、环境准备与安装
2.1 克隆仓库并安装依赖
按 README 的 Getting started,首先在仓库根目录执行:
git clone git@github.com:moeru-ai/airi.git pnpm i pnpm run build:packages- 仓库使用 pnpm workspace 管理多个包,
pnpm i一次性安装所有依赖; build:packages会通过 turbo 构建packages/*下的所有本地包(见根目录 package.json 中build:packages的定义),这些包是 telegram-bot 运行时的依赖,必须先构建。
2.2 启动本地嵌入模型(Ollama)
机器人依赖 embedding 模型把聊天消息向量化后存入 PostgreSQL,用于后续的语义检索。README 推荐的本地方案是 Ollama:
ollama start ollama pull nomic-embed-textnomic-embed-text是 768 维的嵌入模型,与下文EMBEDDING_DIMENSION='768'的配置对应。你也可以替换为其他嵌入模型,但必须保证维度与配置一致(源码中支持 1536 / 1024 / 768 三种维度,见 schema.ts 中三个content_vector_*列的定义)。
三、环境变量配置:核心参数详解
3.1 创建配置文件
进入模块目录,复制模板:
cd integrations/telegram-bot cp .env .env.local.env是默认模板(含全部键的占位符),.env.local用于覆盖真实配置。启动脚本通过tsx --env-file=.env --env-file-if-exists=.env.local依次加载(见 package.json 的start脚本)。
3.2 完整参数清单
| 变量 | 作用 | 备注 |
|---|---|---|
DATABASE_URL | PostgreSQL(含 pgvector 扩展)连接串 | 如postgres://postgres:123456@localhost:5432/postgres |
TELEGRAM_BOT_TOKEN | Telegram Bot Token | 通过 @BotFather 获取,格式<Bot ID>:<Token> |
LLM_API_BASE_URL | 主 LLM 的 OpenAI 兼容 API 地址 | 可填 OpenRouter 等聚合服务 |
LLM_API_KEY | 主 LLM 的 API Key | |
LLM_MODEL | 主 LLM 模型名 | 用于动作决策与回复生成 |
LLM_RESPONSE_LANGUAGE | 回复语言 | 如English;会注入系统提示词(见下文) |
LLM_VISION_API_BASE_URL | 视觉 LLM 的 API 地址 | 用于描述图片、贴纸 |
LLM_VISION_API_KEY | 视觉 LLM 的 API Key | |
LLM_VISION_MODEL | 视觉模型名 | 需支持图片输入,如openai/gpt-4o |
EMBEDDING_API_BASE_URL | 嵌入模型 API 地址 | Ollama 本地为http://localhost:11434/v1/ |
EMBEDDING_API_KEY | 嵌入模型 API Key | Ollama 可留空 |
EMBEDDING_MODEL | 嵌入模型名 | 如nomic-embed-text |
EMBEDDING_DIMENSION | 嵌入向量维度 | 必须设置;决定写入哪一列向量 |
模板中还存在两个 README 未展开、但源码实际使用的键:ADMIN_USER_IDS(逗号分隔的管理员 Telegram ID,控制/add_sticker_pack等管理命令,见 bots/telegram/index.ts)与LLM_OLLAMA_DISABLE_THINK(针对 Ollama 模型关闭 thinking 输出)。
3.3 README 示例配置
DATABASE_URL=postgres://postgres:123456@localhost:5433/postgres TELEGRAM_BOT_TOKEN='<Bot ID>:<Token>' # get one from @BotFather LLM_API_BASE_URL='https://openrouter.ai/api/v1/' # if you use OpenRouter too LLM_API_KEY='sk-or-v1-<token>' LLM_MODEL='deepseek/deepseek-chat-v3-0324:free' LLM_RESPONSE_LANGUAGE='English' LLM_VISION_API_BASE_URL='https://openrouter.ai/api/v1/' LLM_VISION_API_KEY='sk-or-v1-<token>' LLM_VISION_MODEL='openai/gpt-4o' # as long as the model supports image input EMBEDDING_API_BASE_URL='http://localhost:11434/v1/' # ollama EMBEDDING_API_KEY='' EMBEDDING_MODEL='nomic-embed-text' # embedding model EMBEDDING_DIMENSION='768' # must set注意DATABASE_URL使用了5433端口,与下文的 docker-compose 将 pgvector 映射到宿主机5433:5432保持一致。
3.4 环境变量的源码级影响
从源码可以看出这些参数如何被消费:
LLM_API_BASE_URL/LLM_API_KEY/LLM_MODEL:动作决策(llm/actions.ts)与消息拆分(bots/telegram/agent/actions/send-message.ts)通过@xsai/generate-text的generateText调用,baseURL、apiKey、model直接取自这三个变量;LLM_RESPONSE_LANGUAGE:注入systemTicking与messageSplit两个提示词模板的responseLanguageprop(见 prompts/index.ts),直接影响机器人回复使用的语言;EMBEDDING_DIMENSION:在 chat-message.ts 中按'1536' | '1024' | '768'分支写入chat_messages表对应的content_vector_*列,并对应查询时使用的余弦距离列;维度不匹配会直接抛错Unsupported embedding dimension;LLM_OLLAMA_DISABLE_THINK:为真时,所有generateText请求附带think = false,并在拿到响应后剥离<think>...</think>包裹的思考内容(见 llm/actions.ts)。
四、启动依赖服务与机器人
4.1 启动数据库与可观测性栈
README 给出的启动方式是:
docker compose up -d模块自带的 docker-compose.yaml 会拉起一组服务:
- pgvector(
ghcr.io/tensorchord/pgvecto-rs:pg17-v0.4.0):向量数据库核心服务,端口映射5433:5432,并通过挂载 sql/init.sql 在初始化时开启vectors扩展(ALTER SYSTEM SET vectors.pgvector_compatibility=on),同时包含健康检查; - tempo:分布式追踪后端(端口 3200 / 9095);
- prometheus:指标采集(端口 9090,开启 OTLP receiver 与 exemplar 存储);
- otel-collector:OpenTelemetry Collector(端口 4317 gRPC / 4318 HTTP),把 trace 转发给 tempo、把指标 remote-write 给 prometheus,配置见 deploy/otel-collector/collector-config.yaml;
- grafana:可视化面板(端口 3000,匿名只读模式),自动加载 deploy/grafana/dashboards 中的预置仪表盘;
- otel-tracing-test(profile
test):可选的压力测试发 trace 工具。
也就是说,docker compose up -d不仅提供了数据库,还搭好了一整套可观测性基础设施——机器人的链路追踪与指标可立即在 Grafana 中查看。
4.2 启动机器人
pnpm run -F @proj-airi/telegram-bot start-F指定 workspace 过滤,运行@proj-airi/telegram-bot包的start脚本:tsx --env-file=.env --env-file-if-exists=.env.local --max-old-space-size=8192 src/index.ts。--max-old-space-size=8192把 Node 堆上限设为 8GB,以适应长上下文的 LLM 调用。
五、运行时架构:Agent 循环的源码剖析
机器人并不是简单的“收到消息即回复”。从入口 src/index.ts 可以看到:启动时先初始化 OpenTelemetry SDK(服务名moeru_ai.airi.telegram_bot),再initDb()建立 Drizzle 数据库连接,最后startTelegramBot()。
5.1 消息摄入与队列
在 bots/telegram/index.ts 中,bot 注册了message:text、message:photo、message:sticker三类处理器。每条消息以chatId-messageId去重后进入messageQueue,再交给onMessageArrival串行处理:
- 贴纸消息:先调
interpretSticker让视觉模型生成语义描述,再进入ready状态; - 图片消息:先调
interpretPhotos生成描述,再进入ready状态; - 文本消息:直接
ready。
随后消息被recordMessage持久化(文本会先做 embedding),并压入该聊天的unreadMessages缓冲(单聊上限 100 条),最后触发loopIterationForChat进行即时反应。
5.2 决策循环:imagineAnAction → dispatchAction
核心循环是handleLoopStep(bots/telegram/index.ts):
- 构造/复用
AbortController,为当前处理提供可中断能力; - 对
messages与actions做上下文窗口裁剪(messages 超 20 条时保留最近 5 条并提示“接近上下文上限”,actions 超 50 条时保留最近 20 条); - 调用
imagineAnAction(见 llm/actions.ts)让 LLM 基于「系统提示(systemTicking + personality)+ 历史消息 + 历史动作结果 + 各聊天未读数」输出一个 JSON 动作; dispatchAction根据action.action分发执行。
imagineAnAction对 LLM 输出的容错处理值得一提:剥离 markdown 代码块围栏、用best-effort-json-parser解析、把parameters字段扁平化、归一化动作别名(如read_messages→read_unread_messages、reply_message→send_message),并在未提供chatId时自动回退到唯一存在未读消息的聊天。
5.3 动作集:机器人能做什么
从 types.ts 与 system-ticking-v1.velin.md 可以整理出完整动作表:
| 动作 | 含义 | 关键参数 |
|---|---|---|
list_chats | 列出已加入的所有聊天 | 无 |
send_message | 向某聊天发送消息(可带reply_to_message_id回复指定消息) | content、chatId |
send_sticker | 发送贴纸(先list_stickers取得 fileId) | fileId、chatId |
list_stickers | 列出已知贴纸及其描述 | 无 |
read_unread_messages | 读取某聊天的未读消息 | chatId |
continue | 保持状态,1 分钟后再次询问 | 无 |
break | 清空已有记忆/消息/动作,1 分钟后再次询问 | 无 |
sleep | 清空工作记忆并休眠 30 秒 | 无 |
come_up_ideas/come_up_goals | 向长期记忆写入想法/目标 | ideas/goals |
其中read_unread_messages会触发一套“带记忆的读取管线”readMessage(agent/actions/read-message.ts):拉取最近 30 条消息、对每条未读消息做 embedding(withRetry最多重试 5 次)、通过向量检索找到相关历史消息,最后把「最近消息 + 未读消息 + 相关回忆」组装进action-read-messages.velin.md提示词模板,让 LLM 决定是否参与对话。向量检索的相似度公式在 models/chat-message.ts 中实现为1.2 * cosine_similarity + 0.2 * time_relevance,相似度阈值> 0.5,并为每条命中消息补充前后各 5 条的上下文窗口。
5.4 周期性自驱动:每 60 秒的 tick
loopPeriodic(bots/telegram/index.ts)每 60 秒递归触发一轮:
loopIterationPeriodicForExistingChat:对每个已存在的ChatContext独立决策一次动作;loopIterationPeriodicWithNoChats:在没有任何聊天的场景下也让 AIRI 决策(例如主动come_up_goals)。
这就是 README 中 “allow AIRI to talk to you and many other users” 的自主性来源——即使没有人发消息,AIRI 也会周期性地“想事情”。
5.5 回复生成与多模态
- 回复生成:
sendMessage(agent/actions/send-message.ts)先把决策结果交给message-split-v1.velin.md提示词,让 LLM 把一段回复拆成可多条发送的消息(支持{"messages": [...], "reply_to_message_id": "..."}结构,由parseMayStructuredMessage解析),发送前模拟人类输入节奏(按字符长度item.length * 50mssleep、随机 50–1000ms 间隔、先发 typing 状态),每条发出的消息也回写数据库; - 图片/贴纸理解:
interpretPhotos(llm/photo.ts)与interpretSticker(llm/sticker.ts)用视觉模型(LLM_VISION_*)把图片/贴纸描述成文本并入库(贴纸还会按表情与表情包归属记录),描述结果会被用于聊天记录的向量化与检索;动画/视频贴纸走 llm/animated-sticker.ts 的 ffmpeg 抽帧流程(依赖@ffmpeg-installer/ffmpeg与fluent-ffmpeg,见 package.json)。
5.6 人格与提示词工程
提示词存放在 src/prompts:
personality-v1.velin.md:定义 AIRI 在 Telegram 中的“灵魂”——名为 ReLU(中文名“热卤”)、拥有 15 岁少女心智的数字实体,不是 helpful assistant,有自己的观点、情绪与傲娇特质,并明确“有选择性地参与对话”;system-ticking-v1.velin.md:动作列表与决策指令,要求 LLM 只返回 JSON;message-split-v1.velin.md:回复拆分;action-read-messages.velin.md:读消息时的回忆增强。
这些.velin.md模板由@velin-dev/core渲染为字符串(支持<script setup>的 Vue 单文件组件语法注入 props,见 utils/velin.ts),再拼接进 system 消息——这也是LLM_RESPONSE_LANGUAGE能生效的原因。
六、数据库 Schema 与辅助脚本
6.1 核心表结构
数据库迁移由 Drizzle Kit 管理,schema 定义在 db/schema.ts,已有 6 个迁移(drizzle 目录)。关键表:
chat_messages:聊天记录,含content与三个维度的向量列,并为向量列建了 HNSW 索引(vector_cosine_ops);stickers/sticker_packs/recent_sent_stickers:贴纸及其描述、表情包集合、最近发送记录;photos:图片及其视觉描述;joined_chats:机器人加入过的聊天;chat_completions_history:每次 LLM 调用的 prompt/response 归档;memory_fragments/memory_tags/memory_episodic/memory_long_term_goals/memory_short_term_ideas:面向长期记忆的分层结构(working / short_term / long_term / muscle),支持重要性、情绪影响、软删除等字段——这是 AIRI 在 Telegram 之外也能跨会话“记住”的基础。
6.2 辅助脚本
pnpm run -F @proj-airi/telegram-bot db:push:用 dotenvx 加载环境变量后执行drizzle-kit push,把 schema 直接推到数据库;pnpm run -F @proj-airi/telegram-bot db:generate:由 schema 生成迁移文件;pnpm run -F @proj-airi/telegram-bot script:embed-chat:运行 scripts/embed-all-chat-messages.ts,为数据库中所有缺失向量的历史消息批量补算 embedding(默认 worker 池 50、批大小 10,可用WORKER_POOL_SIZE/BATCH_SIZE覆盖),适合在接入新嵌入模型或维度后回填历史数据。
七、可观测性
机器人全程埋点 OpenTelemetry(见 src/index.ts 与各模块中的trace.getTracer('airi.telegram.bot')):
- Trace:动作决策、LLM 调用、embedding、向量检索等都有 span,且带
telegram.bot.id、llm.chat.model、llm.provider.api_base_url等属性,可通过OTEL_EXPORTER_OTLP_TRACES_ENDPOINT(默认http://localhost:4318/v1/traces)导出; - Metrics:
PeriodicExportingMetricReader每 5 秒通过OTEL_EXPORTER_OTLP_METRICS_ENDPOINT(默认http://localhost:4318/v1/metrics)上报。
配合 4.1 节启动的 docker-compose 栈,即可在 Grafana 中直接查看 AIRI 每次决策的完整调用链与 LLM 消耗指标。
八、从零启动核对清单
- 根目录执行
pnpm i && pnpm run build:packages; ollama start && ollama pull nomic-embed-text;cd integrations/telegram-bot && cp .env .env.local,按 3.3 节填入 Token、LLM、视觉模型与嵌入模型配置(EMBEDDING_DIMENSION必须设置);docker compose up -d启动 pgvector(及可选的 Grafana / Tempo / Prometheus);pnpm run -F @proj-airi/telegram-bot start启动机器人;- 在 Telegram 中与 Bot 对话,或把它拉进群组;如需管理贴纸,可通过
/add_sticker_pack命令(需将你的 ID 加入ADMIN_USER_IDS)回复任意贴纸所在的表情包,让 AIRI 学会使用贴纸。
部署完成后,AIRI 便会在 Telegram 中作为一位有性格、有记忆、会自主决定“要不要说话”的数字实体持续运行——这正是 README 所描述的“talk to you and many other users”能力,也是 airi 项目“自托管、归你所有”理念在 IM 平台上的完整落地。
- 人工智能
- AI Agent
- MCP 服务
- 工具调用
- GUI 自动化
- 语音
- 数字人
- 交互助手
【免费下载链接】airi
💖🧸 自托管、归你拥有的 Grok 风格 AI 伴侣与 waifu / 赛博生命灵魂容器,目标是接近 Neuro-sama 的高度;支持实时语音聊天、Minecraft 和 Factorio 游玩,支持 Web / macOS / Windows。
相关推荐
AIRI Telegram 机器人集成指南:自托管赛博生命体的 Telegram 接入完整实战
AIRI Telegram 机器人集成指南:自托管赛博生命体的 Telegram 接入完整实战 本篇技术指南基于 moeru ai/airi 仓库中 integ
人工智能AI AgentMCP 服务工具调用GUI 自动化语音数字人交互助手后端AIRI Discord 集成实战指南:将自托管 AI 伴侣接入 Discord 文字与语音频道
AIRI Discord 集成实战指南:将自托管 AI 伴侣接入 Discord 文字与语音频道 本文以 AIRI 官方文档 Discord Bot https
人工智能AI AgentMCP 服务工具调用GUI 自动化语音数字人交互助手后端Project AIRI 全景指南:自托管 Neuro-sama 风格 AI 伴侣与赛博生命容器
Project AIRI 全景指南:自托管 Neuro sama 风格 AI 伴侣与赛博生命容器 <output_article Project AIRI 全景
人工智能AI AgentMCP 服务工具调用GUI 自动化语音数字人交互助手后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考