This period of time I've been working on a project called Pi Bot.
At first, the idea was actually very simple: I wanted a Bot that could stay in a chat environment for a long time. But after really starting to work on it, I discovered that "receiving a message and then calling a large model again" was only the easiest part. A Chatbot that responds to every sentence, writes a small essay for every question, and forgets what was discussed after turning its head, even if it uses a very powerful model, would be very difficult for people to feel like it really belongs in this chat space.
So later on, I spent more time not pursuing "answering intelligently", but rather thinking about another thing: how to make a Pi Agent more like a person who understands how to get along with others.
First, learn when to speak up
Group chats and one-on-one Q&A are completely different things.
If someone mentions its name, calls out to it, or references its previous reply, it should of course respond. But most of the time, the conversation in the group is not directed at the Bot. When two people are joking with each other, someone casually sends a picture, or simply exclaims, if it jumps out to summarize every time, its presence will quickly become a disturbance.
I've given Pi Bot a separate set of participation judgments: being mentioned, waking up to keywords, referencing, naturally continuing the conversation, public questions, and hot chat status will all produce different triggering reasons. It also has quiet periods, and at night it won't suddenly appear because of ordinary idle chat; after the group has been cold for a long time, it can try to naturally warm up the conversation, but if it can't think of anything suitable to say, it's better not to speak.
Here's a small design I like: Pi Agent can explicitly choose to skip_reply. Silence is not a generation failure, and it won't send a NO_REPLY placeholder to the group; instead, it's a normal, explainable decision.
I think this is important. A Chatbot that's like a human should first have the ability to not speak.
Memory is not just dumping chat records
Many Agent projects mention "memory", and their approach is to constantly append historical messages to the context. In the short term, this seems effective, but after chatting for a long time, the cost, noise, and errors will all increase together.
In Pi Bot, I've broken down the state into three layers:
transcriptsaves the actual conversations that have occurred;memorysaves facts that are still valuable after a week, such as member preferences, fixed titles, and long-term relationships;behaviorsaves the ways of getting along that everyone has taught it, such as "respond briefly" or "don't always interrupt".
These three layers are independent of each other and can all be audited and corrected. If someone says "you remembered wrong", the Agent shouldn't just apologize on the spot and continue to make the same mistake next time; it will go find the corresponding memory, modify the attribution, correct the content, or completely forget it. Changes in expression preferences will enter behavior, and won't be mixed with factual memories.
I've deliberately not made it remember everything. One-time requests, temporary emotions, and chat summaries are not worth entering long-term memory by default. Remembering more doesn't equal understanding better; sometimes it's the opposite.
The form of replies, beyond text, also belongs to the conversation
In real chats, people won't always just send text.
Pi Bot can handle images, audio, voice, video, files, links, references, and member mentions, but what I care more about is when it should use these abilities. It won't analyze every picture just because it has a visual model; it will only call the understanding tool when the current question really depends on the image. When someone sends a voice message, it can follow the other person's message format and respond with voice, or enter continuous voice or whisper mode.
Emotions are not an additional function hidden deep in the menu. I've given the Agent an emotion retrieval and sending tool: when it encounters short attitudes like "haha", "ridiculous", or "indeed", if the emotion library has a suitable one, it can just send the emotion and not add a sentence of equivalent text. The project also integrates meme generation, image battles, and repetition logic, and pictures uploaded by itself can be directly added to the emotion library.
These functions may not be significant on their own, but they greatly affect a Bot's "feel" in a chat.
Pi Agent is responsible for thinking, but not everything is handed over to the model
The project uses Pi Agent at its bottom layer. Every time it runs, the Core will reorganize the current message, recent context, recalled long-term memory, learned behavior, and available tools for it, rather than letting the model directly face the platform's raw data.
I've also drawn a boundary: just because the platform declares it can "do something" doesn't mean the model automatically gets that ability. An Adapter may support sending files, parsing media, or managing members, but only explicitly registered and restricted Tool Providers will enter Pi Agent's tool list. External web pages, attachment bodies, MCP return values, and platform metadata are all untrusted materials and can't be turned into system instructions.
There are also some things that don't need to call the large model at all. For example, fixed entry and exit notifications, responses to being touched, and repetition after two people send the same content can all be handed over to deterministic plugins. Only when semantic judgment, memory, or tool collaboration is needed will Pi Agent be called upon, which is faster and more controllable.
I don't want it to "forget" because of a single restart
Making a demo for a Chatbot is easy, but long-term operation is another matter.
Pi Bot will save incoming events before judging whether to trigger the model; the same event won't be run through the Agent repeatedly; messages in the same conversation will be strictly serialized to avoid generating and being unable to see each other; reply records and pending actions will be committed in the same transaction. If a message fails to send temporarily, it will be left in the durable outbox, and the process will continue to retry after recovery.
Media itself won't be directly stuffed into SQLite or the main prompt, only saving AssetRef, and binary data will be handed over to an independent AssetStore. This is a bit more troublesome, but after the project has been running for a long time, whether the state is clear and whether faults can be recovered is more important than writing a few fewer lines of code.
The entire core has also been designed to be independent of the chat platform: the Adapter is responsible for connections, event conversion, and actual sending, while the Core only receives standard events and outputs standard actions. When switching to a different chat entrance, there's no need to rewrite memory, plugins, and Agent logic.
Now it's no longer just a chat script
The current project already has multiple model providers, primary and secondary model degradation, knowledge retrieval, MCP, visual understanding, speech-to-text and TTS, timed tasks, group chat summaries, active participation, emoticon libraries, and meme generation. I have also created a React management interface to configure the Bot, personas, models, plugins, knowledge bases, conversations, and running status.
However, I would still like to view it as an ongoing experiment: how can a Chatbot evolve from a "question-answering interface" to an Agent with memory, tact, and the ability to coexist? There are many details worth continuing to work on.
The project has been open-sourced under the MIT License:
GitHub:JimiZhou/pi-bot
If you are also working on Chatbots, Pi Agents, long-term memory, or group chat participation strategies, or if you find any details that can be improved for a more natural experience, you are welcome to submit an issue or directly submit a PR. Many useful small features often come from a simple suggestion like "can this be made more convenient".
若无法加载请检查网络环境。
若无法加载请检查网络环境,或切回 Disqus 稍后再试。