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_key
  • llm.base_url
  • llm.model_name
  • llm.temperature
  • history.max_history
  • session_store.backend
  • session_store.redis.url
  • session_store.redis.ttl_seconds
  • response.multi_segment_separator
  • service.host
  • service.port

当前默认值说明:

  • history.max_history: 20
    • 表示单个会话最多保留最近 20 条消息
    • 由于每轮通常会写入 userassistant 两条消息,约等于最近 10 轮对话
  • session_store.backend: redis
    • 表示短期会话上下文默认存入 Redis,而不是保存在 AgentChatBot 进程内内存中
  • session_store.redis.ttl_seconds: 86400
    • 表示单个会话在 Redis 中默认保留 1 天,超时后会自动过期

QQChat 配置

文件位置:

QQChat/config.yaml

主要配置项:

  • bot_uin
  • adapters
  • plugin.plugins_dir
  • chatbot_service.base_url
  • chatbot_service.timeout

启动方式

方式一:直接运行总入口

python main.py

说明:

  • 会同时启动 ChatBot 和 QQChat
  • 当前终端会被占用
  • 适合本地开发与调试

方式二:使用轻量启动器后台运行

先安装命令入口:

python -m pip install -e .

后台启动:

qingchat run

查看状态:

qingchat status

停止服务:

qingchat stop

说明:

  • qingchat run 本质上是后台启动根目录 main.py
  • qingchat 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.logruntime.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 调用方式。

会话约定

  • 推荐显式传 channeluser_idconversation_id,用于区分渠道、用户与具体对话线程
  • 原生接口仍兼容旧字段 session_id,未升级的调用方可以继续使用
  • 如果没有 session_id,但带了 OpenAI 标准字段 user,会自动将 user 视为会话用户标识
  • 如果两者都不传,则按无状态请求处理,不保存服务端历史
  • 兼容接口当前只支持 stream=false

当前推荐理解方式:

  • channel
    • 表示消息来自哪个接入渠道,如 webqq
  • 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 支持 systemdeveloperuserassistant
  • systemdeveloper 会作为额外系统指令,与项目内置系统 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.yamlchatbot_service.base_url
  • ChatBot/config.yamlservice.hostservice.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 分布式锁