Building a QQ Chat Companion Bot That Remembers Things and Proactively Reaches Out with Warm Isle and DeepSeek
The author describes building a QQ chat companion bot on their own server using the open-source project Warm Isle, with DeepSeek generating replies and NapCat handling QQ login, while persona, long-term memory, and proactive messaging are implemented by Warm Isle. The article provides complete steps for Docker deployment, QR code login, persona configuration, and memory extraction, and lists practical pitfalls such as memory usage, SQLite backups, and group chats not being processed by default. The project uses the AGPL-3.0 license, and commercial use is prohibited for the NapCat and SnowLuma protocol ends.
Why read this
AI score 55
The original article provides complete steps from deployment to persona, memory, and proactive messaging, along with real troubleshooting notes, transferable to self-hosted Agent projects.
Topics
Body · AI translation
Use the open-source project Warm Isle to build a QQ companion chat bot running on your own server from scratch: DeepSeek handles the talking, NapCat handles logging into QQ, and the middle layer of "persona + long-term memory + proactive care" is what Warm Isle does.
Project address:
Why not "just call the API + forward messages"
If you just want something in QQ that can reply, there are plenty of ready-made forwarding scripts online: receive message → assemble prompt → call DeepSeek → send it back, done in a hundred lines of code.
But in real use you'll quickly run into three problems:
It can't remember you. Every conversation is a blank slate; the allergy you mentioned yesterday, the exam you brought up the day before, all rely on you repeating them yourself.
It isn't "a person." Its speech has no fixed tone—one moment it's like customer service, the next like GPT, and late at night it's still asking you "good morning."
It won't reach out to you. If you don't speak, it stays silent forever—and that is precisely the biggest difference between "companion chat" and "Q&A."
What Warm Isle essentially does is fill in these three things: persona, memory, and proactivity. DeepSeek is merely its "mouth."
Overall architecture
Warm Isle: the business layer you write yourself, responsible for persona, memory extraction, proactive messages, stickers, and voice;
DeepSeek: only responsible for "generating a sentence based on context."
The protocol side and the business layer are decoupled—today you use NapCat, tomorrow if you want to switch to SnowLuma that's fine too, and the business code doesn't need to change.
Ubuntu 22.04/24.04, starting from 2C4G. 2G of memory won't run it (QQ + JVM + image pre-screening)
A secondary QQ account
Strongly recommended to use a secondary account, not your main one. Data center IPs have a risk-control probability, so let it age for a few days first
DeepSeek API Key
Domain name (optional)
Only with a domain can you automatically get HTTPS; if you don't have one, start with IP + strong password, and don't run exposed long-term
A bit of Linux basics
Know how to ssh, edit files, and read docker logs
Security group: only open 22 / 80 / 443. The backend's 8080, the protocol side's 3001, and the pre-screening 8081 must never be exposed to the public internet—they all bind only to 127.0.0.1 and go out through the Caddy reverse proxy.
Step 1: Install Docker, pull the code
Step 2: Build the jar
Warm Isle's backend is Spring Boot, and the frontend build artifacts are packaged into the jar, so you need to build once first:
If the server has little memory and tends to OOM during builds, you can also build on your own computer and then scp target/qqbot.jar to the server's /opt/qqbot-src/target/.
Variable names must be in the all-uppercase form like QQBOT_WHITELIST, with dots replaced by underscores; qqbot.whitelist will not take effect inside the container;
Leaving QQBOT_WHITELIST empty = anyone who private-messages it will get a reply, never go live like that;
BOT_NAME can be changed; the default is "Xiaoman."
Step 4: Start the containers
Normally there should be four containers running: qqbot, napcat, imageguard, caddy (plus the internal wsproxy and searxng).
The image pre-screening imageguard needs three ONNX models (clip_vision.onnx / clip_text.onnx / nsfw.onnx). Without the models it won't start, and without it all images will be judged sensitive and never replied to. For how to get the models, see deploy/linux/README.md: copy them from an existing environment, or export them yourself with guard/export_onnx.py.
Open http://your-server-IP/ in a browser and log into the backend with the ADMIN_PASSWORD from .env.
Go to "Bot Account" → click "Scan QR code to log in" → the backend will display the login QR code for QQ in the protocol-side container → scan it with mobile QQ → the account status changes to "Online."
This step is the most error-prone part of the whole process. Remember two symptoms:
Shows "Online" but messages get no reply: this means the protocol side is connected but QQ has lost its login. Click "Refresh QR code" and scan again;
After scanning, it goes offline again a few hours later: most likely QQ kicked the device. The watchdog in the project checks every 5 minutes, sends an email when it drops offline (requires configuring SMTP_*), and when it's "connected but not logged in" only sends the QR code without repeatedly restarting the container—because repeated restarts will flush the QR code away.
Step 6: Give it a persona
Backend → "Persona" → New. You can write it by hand, or "generate from knowledge base":
Upload a passage of a novel/chat log → choose parse type "Generate persona" → it will distill the speaking style;
You can also choose "Line style" to learn only the tone, not the content.
A persona is not better the more detailed it is. In practice, the things that most affect "whether it feels human" are these:
Step 7: Configure memory and proactive messages
Memory: automatically extracted once a day at noon (the time can be changed in the backend), distilling conversations into "fact cards" and "summaries," which are automatically included in the next chat. Isolated by "bot account × chat partner," so nothing crosses over.
Proactive messages: by default silent from 23:30–08:00, at most 3 per day, with at least 2 hours between two messages. Trigger priority is: follow-up due > good morning > good night > silence exceeding 6 hours.
Owner QQ: fill in your own account on the account page; only this account can make the bot change its nickname/avatar.
Step 8: Verify
Use an account on the whitelist to send the bot a line:
Normally you'll receive 1–3 short sentences, not one big paragraph. If there's no response, check in order:
Optional: switch to SnowLuma as the protocol side
Warm Isle currently supports two protocol sides, and you can choose directly when creating a new account in the backend:
NapCat: mature, large community, QR code saved to disk, displayed directly in the backend;
SnowLuma: newer, comes with WebUI/remote desktop, a single instance can run multiple accounts, but it's memory-hungry (300MB–1.2GB resident per account).
How to switch: account card → "Switch connection" → choose the other one → the protocol-side container will be rebuilt, chat history and memory stay untouched, and you just need to scan the QR code again after switching.
Same OneBot v11 protocol, the business layer doesn't need to change at all.
A few real pitfalls
Give it enough memory. On a 3.6G machine, image pre-screening alone eats 1.2G, the JVM 768M, and the protocol side starts at 300M. Before opening a second account, check the memory on the "About" page.
Before the backend has HTTPS, the password is transmitted in plaintext. Either wait until you have a domain with ICP filing (Caddy will automatically sign certificates), or at least change it to a 32-character random string.
Back up SQLite. Chat history and memory are all in a few .db files under data/qqbot/; if the machine dies, it's all gone. Add a cron job to package them to another machine every day.
Group chats are not processed by default. Currently only private chats are handled—if you want it in groups, you'll have to modify MessageDispatcher's routing and @ detection yourself.
About compliance
Warm Isle is an AGPL-3.0 open-source project; you can use it yourself, modify it, and deploy it; when providing services externally, pay attention to AGPL's copyleft nature.
The protocol sides are not under an open-source license: both NapCat and SnowLuma explicitly prohibit commercial use, and commercial use requires separate authorization.
Final words
I've run this thing for a few months, and my deepest takeaway is: model capability stopped being the bottleneck long ago; the hard part is "feeling like a person."
For the same "good night," DeepSeek can write twenty variations, but what really makes people feel "it remembers me" is that it knows you had an interview today, knows you didn't sleep well yesterday, knows it's time for you to sleep at this hour—none of that is in the model; it's in memory and timing.
The project is still growing; feel free to open an issue or just fork it: