QingChat
QingChat
QingChat 当前由两个核心部分组成:
- ChatBot:独立 AI 服务,负责模型调用、Agent、工具调用、会话管理与 Web 页面
- QQChat:QQ 接入器,负责监听 QQ 消息并调用 ChatBot 服务
项目结构
qing-chat/ ├─ ChatBot/ │ ├─ agent/ │ ├─ loguru/ │ ├─ prompt/ │ ├─ service/ │ ├─ tools/ │ ├─ config.yaml │ └─ main.py ├─ QQChat/ │ ├─ Client/ │ ├─ plugins/ │ ├─ config.yaml │ └─ main.py ├─ logs/ │ ├─ bot/ │ ├─ npcat/ │ └─ web/ ├─ main.py ├─ qingchat_cli.py ├─ setup.py └─ requirements.txt
环境准备
建议使用独立虚拟环境。
安装依赖:
python -m pip install -r requirements.txt python -m pip install -e .
安装完成后可直接使用命令:
qingchat run qingchat stop qingchat status
配置说明
ChatBot 配置
文件位置:
ChatBot/config.yaml
主要配置项:
llm.api_keyllm.base_urlllm.model_namellm.temperaturehistory.max_historysession_store.backendsession_store.redis.urlsession_store.redis.ttl_secondsresponse.multi_segment_separatorservice.hostservice.port
当前默认值说明:
history.max_history: 20- 表示单个会话最多保留最近
20条消息 - 由于每轮通常会写入
user和assistant两条消息,约等于最近10轮对话
- 表示单个会话最多保留最近
session_store.backend: redis- 表示短期会话上下文默认存入 Redis,而不是保存在
AgentChatBot进程内内存中
- 表示短期会话上下文默认存入 Redis,而不是保存在
session_store.redis.ttl_seconds: 86400- 表示单个会话在 Redis 中默认保留
1天,超时后会自动过期
- 表示单个会话在 Redis 中默认保留
QQChat 配置
文件位置:
QQChat/config.yaml
主要配置项:
bot_uinadaptersplugin.plugins_dirchatbot_service.base_urlchatbot_service.timeout
启动方式
方式一:直接运行总入口
python main.py
说明:
- 会同时启动 ChatBot 和 QQChat
- 当前终端会被占用
- 适合本地开发与调试
方式二:使用轻量启动器后台运行
先安装命令入口:
python -m pip install -e .
后台启动:
qingchat run
查看状态:
qingchat status
停止服务:
qingchat stop
说明:
qingchat run本质上是后台启动根目录main.pyqingchat stop通过 PID 文件停止服务- PID 文件位置为
logs/qingchat.pid
单独启动
单独启动 ChatBot
python ChatBot/main.py
单独启动 QQChat
python QQChat/main.py
Web 页面
启动 ChatBot 后,可访问两个前端页面:
- 聊天页:
http://127.0.0.1:8000/ - 日志页:
http://127.0.0.1:8000/logs-ui
如果 ChatBot/config.yaml 中配置了其他 host 或端口,请按实际配置访问。
页面说明:
/与/chat-ui:面向用户的聊天页面/logs-ui:面向运维查看的日志与服务状态页面/api/logs:日志页对应的数据接口
日志目录
所有日志统一存放于根目录 logs/ 下:
logs/web- ChatBot Web 服务日志
- 如
service.log、runtime.log
logs/npcat- QQChat / ncatbot 日志
- 如
runtime.log及 ncatbot 自身日志
logs/bot- Agent 相关日志
- 如
agent.log
多段回复说明
ChatBot 支持多段回复,分隔符配置在:
ChatBot/config.yaml
字段:
response: multi_segment_separator: "|||"
你可以修改 Prompt,让模型按这个分隔符输出多段内容。
OpenAI 兼容接口
ChatBot 现在同时保留原生接口和 OpenAI 风格兼容接口:
- 原生聊天接口:
POST /chat - OpenAI 兼容接口:
POST /v1/chat/completions - 模型列表接口:
GET /v1/models
兼容接口的设计目标是让其他程序可以直接复用 OpenAI SDK 或常见的 chat.completions 调用方式。
会话约定
- 推荐显式传
channel、user_id、conversation_id,用于区分渠道、用户与具体对话线程 - 原生接口仍兼容旧字段
session_id,未升级的调用方可以继续使用 - 如果没有
session_id,但带了 OpenAI 标准字段user,会自动将user视为会话用户标识 - 如果两者都不传,则按无状态请求处理,不保存服务端历史
- 兼容接口当前只支持
stream=false
当前推荐理解方式:
channel- 表示消息来自哪个接入渠道,如
web、qq
- 表示消息来自哪个接入渠道,如
user_id- 表示同一真实用户或同一渠道内的稳定用户标识
conversation_id- 表示该用户当前具体的对话线程
- Web 场景下通常一个浏览器标签页对应一个
conversation_id - QQ 场景下通常一个群或一个私聊线程对应一个
conversation_id
原生接口示例
curl -X POST "http://127.0.0.1:8000/chat" \ -H "Content-Type: application/json" \ -d "{ \"message\": \"你好\", \"channel\": \"web\", \"user_id\": \"demo-user\", \"conversation_id\": \"browser-tab-a\" }"
OpenAI 兼容接口示例
curl -X POST "http://127.0.0.1:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"qingchat\", \"messages\": [ {\"role\": \"system\", \"content\": \"请简洁回答\"}, {\"role\": \"user\", \"content\": \"你好,做个自我介绍\"} ], \"channel\": \"web\", \"user_id\": \"demo-user\", \"conversation_id\": \"browser-tab-a\", \"stream\": false }"
使用 OpenAI Python SDK
将 base_url 指向 ChatBot 服务即可:
from openai import OpenAI client = OpenAI( api_key="not-needed", base_url="http://127.0.0.1:8000/v1", ) response = client.chat.completions.create( model="qingchat", messages=[ {"role": "system", "content": "请简洁回答"}, {"role": "user", "content": "你好,做个自我介绍"}, ], extra_body={ "channel": "web", "user_id": "demo-user", "conversation_id": "browser-tab-a", }, stream=False, ) print(response.choices[0].message.content)
兼容性说明
messages支持system、developer、user、assistantsystem和developer会作为额外系统指令,与项目内置系统 Prompt 合并- 当前实际生效的模型和温度仍以
ChatBot/config.yaml为准 - OpenAI 兼容响应会返回单条
assistant文本内容;如果内部生成了多段回复,会自动合并为普通文本
聊天前端页面
项目中新增了一个最轻量的聊天前端示例目录:
WebChatDemo/
页面文件:
WebChatDemo/index.html
打开方式
推荐直接启动 ChatBot 后,在浏览器访问:
http://127.0.0.1:8000/chat-ui
如果 ChatBot/config.yaml 中配置了其他 host 或端口,请按实际地址访问。
页面能力
- 基于浏览器原生 HTML、CSS、JavaScript,无需前端构建
- 直接调用
POST /v1/chat/completions - 支持通过设置按钮填写
API Base URL - 每个浏览器标签页自动生成独立
conversation_id - 同一浏览器会复用稳定
user_id - 支持清空本地聊天记录
- 支持调用
/session/clear清理服务端会话
当前实现下:
- 同一浏览器会复用一个稳定
user_id - 每个标签页会自动生成独立
conversation_id - 因此多个 Web 窗口默认会话隔离,不会共用短期上下文
日志页面
- 日志页地址:
http://127.0.0.1:8000/logs-ui - 展示 ChatBot 服务状态
- 展示 QQChat 接入器配置
- 展示 Web、Npcat、Agent 三类日志
- 每 5 秒自动刷新一次
跨域说明
- ChatBot 服务已启用基础 CORS,便于独立前端页面直接调用接口
- 如果后续要正式对外发布,建议将
allow_origins收紧为你的前端域名列表,而不是长期使用全开放配置
常见问题
1. qingchat 命令找不到
先执行:
python -m pip install -e .
如果仍未生效,可临时使用:
python -m qingchat_cli run python -m qingchat_cli status python -m qingchat_cli stop
2. 日志页能打开但日志为空
可能原因:
- 服务刚启动,还未产生日志
- 对应模块尚未运行
- 当前日志目录下没有目标日志文件
3. QQChat 无法访问 ChatBot
检查:
QQChat/config.yaml中chatbot_service.base_urlChatBot/config.yaml中service.host与service.port- 两边是否在同一网络环境中
当前设计
- ChatBot 作为独立服务提供 AI 能力
- QQChat 只作为 QQ 渠道接入器
- QQChat 通过 Client 调用 ChatBot 接口
- 根
main.py负责本地开发阶段的一键编排 qingchat命令负责后台启动与停止
当前实现模式
AgentChatBot当前仍采用单例执行器模式- 单进程内只会创建一个
AgentChatBot实例 - 单例主要复用模型客户端、Prompt、工具注册和 Agent graph 等重资源
- 单进程内只会创建一个
- 短期会话上下文已从
AgentChatBot内部内存字典迁移到SessionStore- 当前默认后端为 Redis
- 每个会话按
channel + conversation_id进行隔离存储
- 会话长度由
history.max_history控制- 当前默认保留最近
20条消息,约等于最近10轮对话
- 当前默认保留最近
- 会话过期时间由
session_store.redis.ttl_seconds控制- 当前默认值为
86400秒,即1天
- 当前默认值为
- 当前请求并发策略为“同会话串行、不同会话可并发”
- 同一个
conversation_id会按会话级锁串行执行,避免历史被并发写坏 - 不同
conversation_id可以并发调用模型
- 同一个
- 当前会话锁仍为进程内锁,不是 Redis 分布式锁
- 适合本地单机、单进程运行
- 如果后续启用多 worker、多实例或多副本部署,需要进一步迁移为 Redis 分布式锁