diff --git a/README.md b/README.md index 2c58bc12..7478b99d 100644 --- a/README.md +++ b/README.md @@ -218,7 +218,7 @@ cow install-browser
2. 其他配置 -+ `model`: 模型名称,Agent 模式下推荐使用 `MiniMax-M2.7`、`glm-5-turbo`、`kimi-k2.5`、`qwen3.5-plus`、`claude-sonnet-4-6`、`gemini-3.1-pro-preview`,全部模型名称参考[common/const.py](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/common/const.py)文件 ++ `model`: 模型名称,Agent 模式下推荐使用 `MiniMax-M2.7`、`glm-5-turbo`、`kimi-k2.5`、`qwen3.6-plus`、`claude-sonnet-4-6`、`gemini-3.1-pro-preview`,全部模型名称参考[common/const.py](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/common/const.py)文件 + `character_desc`:普通对话模式下的机器人系统提示词。在 Agent 模式下该配置不生效,由工作空间中的文件内容构成。 + `subscribe_msg`:订阅消息,公众号和企业微信 channel 中请填写,当被订阅时会自动回复, 可使用特殊占位符。目前支持的占位符有{trigger_prefix},在程序中它会自动替换成 bot 的触发词。
@@ -303,7 +303,7 @@ sudo docker logs -f chatgpt-on-wechat ## 模型说明 -以下对所有可支持的模型的配置和使用方法进行说明,模型接口实现在项目的 `models/` 目录下。 +推荐通过 Web 控制台在线管理模型配置,无需手动编辑文件,详见 [模型文档](https://docs.cowagent.ai/models)。以下是手动修改 `config.json` 配置模型的说明:
OpenAI @@ -411,18 +411,18 @@ sudo docker logs -f chatgpt-on-wechat ```json { - "model": "qwen3.5-plus", + "model": "qwen3.6-plus", "dashscope_api_key": "sk-qVxxxxG" } ``` - - `model`: 可填写 `qwen3.5-plus、qwen3-max、qwen-max、qwen-plus、qwen-turbo、qwen-long、qwq-plus` 等 - - `dashscope_api_key`: 通义千问的 API-KEY,参考 [官方文档](https://bailian.console.aliyun.com/?tab=api#/api) ,在 [控制台](https://bailian.console.aliyun.com/?tab=model#/api-key) 创建 + - `model`: 可填写 `qwen3.6-plus、qwen3.5-plus、qwen3-max、qwen-max、qwen-plus、qwen-turbo、qwen-long、qwq-plus` 等 + - `dashscope_api_key`: 通义千问的 API-KEY,参考 [官方文档](https://bailian.console.aliyun.com/?tab=api#/api) ,在 [百炼控制台](https://bailian.console.aliyun.com/?tab=model#/api-key) 创建 方式二:OpenAI 兼容方式接入,配置如下: ```json { "bot_type": "openai", - "model": "qwen3.5-plus", + "model": "qwen3.6-plus", "open_ai_api_base": "https://dashscope.aliyuncs.com/compatible-mode/v1", "open_ai_api_key": "sk-qVxxxxG" } @@ -674,7 +674,7 @@ Coding Plan 是各厂商推出的编程包月套餐,所有厂商均可通过 O ## 通道说明 -以下对可接入通道的配置方式进行说明,应用通道代码在项目的 `channel/` 目录下。 +推荐通过 Web 控制台在线管理通道配置,无需手动编辑文件,详见 [通道文档](https://docs.cowagent.ai/channels/weixin)。以下为手动修改 `config.json` 配置通道的说明: 支持同时可接入多个通道,配置时可通过逗号进行分割,例如 `"channel_type": "feishu,dingtalk"`。 diff --git a/bridge/agent_bridge.py b/bridge/agent_bridge.py index 8f81f325..84b7aad6 100644 --- a/bridge/agent_bridge.py +++ b/bridge/agent_bridge.py @@ -67,7 +67,7 @@ class AgentLLMModel(LLMModel): _MODEL_BOT_TYPE_MAP = { "wenxin": const.BAIDU, "wenxin-4": const.BAIDU, - "xunfei": const.XUNFEI, const.QWEN: const.QWEN, + "xunfei": const.XUNFEI, const.QWEN: const.QWEN_DASHSCOPE, const.MODELSCOPE: const.MODELSCOPE, } _MODEL_PREFIX_MAP = [ diff --git a/bridge/bridge.py b/bridge/bridge.py index 388c2999..3cf55a80 100644 --- a/bridge/bridge.py +++ b/bridge/bridge.py @@ -39,11 +39,8 @@ class Bridge(object): self.btype["chat"] = const.BAIDU if model_type in ["xunfei"]: self.btype["chat"] = const.XUNFEI - if model_type in [const.QWEN]: - self.btype["chat"] = const.QWEN - if model_type in [const.QWEN_TURBO, const.QWEN_PLUS, const.QWEN_MAX]: + if model_type in [const.QWEN, const.QWEN_TURBO, const.QWEN_PLUS, const.QWEN_MAX]: self.btype["chat"] = const.QWEN_DASHSCOPE - # Support Qwen3 and other DashScope models if model_type and (model_type.startswith("qwen") or model_type.startswith("qwq") or model_type.startswith("qvq")): self.btype["chat"] = const.QWEN_DASHSCOPE if model_type and model_type.startswith("gemini"): diff --git a/channel/web/web_channel.py b/channel/web/web_channel.py index a7ea74ed..a5bf389a 100644 --- a/channel/web/web_channel.py +++ b/channel/web/web_channel.py @@ -563,7 +563,7 @@ class ConfigHandler: _RECOMMENDED_MODELS = [ const.MINIMAX_M2_7, const.MINIMAX_M2_5, const.MINIMAX_M2_1, const.MINIMAX_M2_1_LIGHTNING, const.GLM_5_TURBO, const.GLM_5, const.GLM_4_7, - const.QWEN35_PLUS, const.QWEN3_MAX, + const.QWEN36_PLUS, const.QWEN35_PLUS, const.QWEN3_MAX, const.KIMI_K2_5, const.KIMI_K2, const.DOUBAO_SEED_2_PRO, const.DOUBAO_SEED_2_CODE, const.CLAUDE_4_6_SONNET, const.CLAUDE_4_6_OPUS, const.CLAUDE_4_5_SONNET, @@ -592,7 +592,7 @@ class ConfigHandler: "api_key_field": "dashscope_api_key", "api_base_key": None, "api_base_default": None, - "models": [const.QWEN35_PLUS, const.QWEN3_MAX], + "models": [const.QWEN36_PLUS, const.QWEN35_PLUS, const.QWEN3_MAX], }), ("moonshot", { "label": "Kimi", diff --git a/common/const.py b/common/const.py index 654ee5da..f7e67e52 100644 --- a/common/const.py +++ b/common/const.py @@ -7,8 +7,8 @@ XUNFEI = "xunfei" CHATGPTONAZURE = "chatGPTOnAzure" LINKAI = "linkai" CLAUDEAPI= "claudeAPI" -QWEN = "qwen" # 旧版千问接入 -QWEN_DASHSCOPE = "dashscope" # 新版千问接入(百炼) +QWEN = "qwen" # 千问 (兼容旧配置,实际走 DashscopeBot) +QWEN_DASHSCOPE = "dashscope" # 千问 DashScope 接入 GEMINI = "gemini" ZHIPU_AI = "zhipu" MOONSHOT = "moonshot" @@ -81,14 +81,14 @@ TTS_1_HD = "tts-1-hd" DEEPSEEK_CHAT = "deepseek-chat" # DeepSeek-V3对话模型 DEEPSEEK_REASONER = "deepseek-reasoner" # DeepSeek-R1模型 -# Qwen (通义千问 - 阿里云) -QWEN = "qwen" +# Qwen (通义千问 - 阿里云 DashScope) QWEN_TURBO = "qwen-turbo" QWEN_PLUS = "qwen-plus" QWEN_MAX = "qwen-max" QWEN_LONG = "qwen-long" QWEN3_MAX = "qwen3-max" # Qwen3 Max - Agent推荐模型 QWEN35_PLUS = "qwen3.5-plus" # Qwen3.5 Plus - Omni model (MultiModalConversation) +QWEN36_PLUS = "qwen3.6-plus" # Qwen3.6 Plus - Omni model (MultiModalConversation) QWQ_PLUS = "qwq-plus" # MiniMax @@ -172,7 +172,7 @@ MODEL_LIST = [ DEEPSEEK_CHAT, DEEPSEEK_REASONER, # Qwen - QWEN35_PLUS, QWEN3_MAX, QWEN_MAX, QWEN_PLUS, QWEN_TURBO, QWEN_LONG, QWEN, + QWEN36_PLUS, QWEN35_PLUS, QWEN3_MAX, QWEN_MAX, QWEN_PLUS, QWEN_TURBO, QWEN_LONG, # MiniMax MiniMax, MINIMAX_M2_7, MINIMAX_M2_5, MINIMAX_M2_1, MINIMAX_M2_1_LIGHTNING, MINIMAX_M2, MINIMAX_ABAB6_5, diff --git a/docs/en/README.md b/docs/en/README.md index 3090e1b1..8b75ed25 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -165,7 +165,7 @@ Supports mainstream model providers. Recommended models for Agent mode: | GLM | `glm-5-turbo` | | Kimi | `kimi-k2.5` | | Doubao | `doubao-seed-2-0-code-preview-260215` | -| Qwen | `qwen3.5-plus` | +| Qwen | `qwen3.6-plus` | | Claude | `claude-sonnet-4-6` | | Gemini | `gemini-3.1-pro-preview` | | OpenAI | `gpt-5.4` | diff --git a/docs/en/models/index.mdx b/docs/en/models/index.mdx index 8d76af86..90fde345 100644 --- a/docs/en/models/index.mdx +++ b/docs/en/models/index.mdx @@ -6,7 +6,7 @@ description: Supported models and recommended choices for CowAgent CowAgent supports mainstream LLMs from domestic and international providers. Model interfaces are implemented in the project's `models/` directory. - For Agent mode, the following models are recommended based on quality and cost: MiniMax-M2.7, glm-5-turbo, kimi-k2.5, qwen3.5-plus, claude-sonnet-4-6, gemini-3.1-pro-preview + For Agent mode, the following models are recommended based on quality and cost: MiniMax-M2.7, glm-5-turbo, kimi-k2.5, qwen3.6-plus, claude-sonnet-4-6, gemini-3.1-pro-preview ## Configuration @@ -25,7 +25,7 @@ You can also use the [LinkAI](https://link-ai.tech) platform interface to flexib glm-5-turbo, glm-5 and other series models - qwen3.5-plus, qwen3-max and more + qwen3.6-plus, qwen3-max and more kimi-k2.5, kimi-k2 and more diff --git a/docs/en/models/qwen.mdx b/docs/en/models/qwen.mdx index 50dff08b..30f7e485 100644 --- a/docs/en/models/qwen.mdx +++ b/docs/en/models/qwen.mdx @@ -5,14 +5,14 @@ description: Tongyi Qianwen model configuration ```json { - "model": "qwen3.5-plus", + "model": "qwen3.6-plus", "dashscope_api_key": "YOUR_API_KEY" } ``` | Parameter | Description | | --- | --- | -| `model` | Options include `qwen3.5-plus`, `qwen3-max`, `qwen-max`, `qwen-plus`, `qwen-turbo`, `qwq-plus`, etc. | +| `model` | Options include `qwen3.6-plus`, `qwen3.5-plus`, `qwen3-max`, `qwen-max`, `qwen-plus`, `qwen-turbo`, `qwq-plus`, etc. | | `dashscope_api_key` | Create at [Bailian Console](https://bailian.console.aliyun.com/?tab=model#/api-key). See [official docs](https://bailian.console.aliyun.com/?tab=api#/api) | OpenAI-compatible configuration is also supported: @@ -20,7 +20,7 @@ OpenAI-compatible configuration is also supported: ```json { "bot_type": "openai", - "model": "qwen3.5-plus", + "model": "qwen3.6-plus", "open_ai_api_base": "https://dashscope.aliyuncs.com/compatible-mode/v1", "open_ai_api_key": "YOUR_API_KEY" } diff --git a/docs/guide/upgrade.mdx b/docs/guide/upgrade.mdx index 48b45005..7a36d706 100644 --- a/docs/guide/upgrade.mdx +++ b/docs/guide/upgrade.mdx @@ -36,7 +36,7 @@ pip3 install -e . 更新完成后重启服务: ```bash -# 使用 Cow CLI +# 使用 Cow CLI (推荐) cow restart # 或使用 run.sh diff --git a/docs/ja/README.md b/docs/ja/README.md index ac1bb879..eff98b6b 100644 --- a/docs/ja/README.md +++ b/docs/ja/README.md @@ -165,7 +165,7 @@ sudo docker logs -f chatgpt-on-wechat | GLM | `glm-5-turbo` | | Kimi | `kimi-k2.5` | | Doubao | `doubao-seed-2-0-code-preview-260215` | -| Qwen | `qwen3.5-plus` | +| Qwen | `qwen3.6-plus` | | Claude | `claude-sonnet-4-6` | | Gemini | `gemini-3.1-pro-preview` | | OpenAI | `gpt-5.4` | diff --git a/docs/ja/models/index.mdx b/docs/ja/models/index.mdx index 8d79416b..4cec8960 100644 --- a/docs/ja/models/index.mdx +++ b/docs/ja/models/index.mdx @@ -6,7 +6,7 @@ description: CowAgentがサポートするモデルとおすすめの選択肢 CowAgentは国内外の主要なLLMをサポートしています。モデルインターフェースはプロジェクトの`models/`ディレクトリに実装されています。 - Agent モードでは、品質とコストのバランスから以下のモデルをおすすめします: MiniMax-M2.7、glm-5-turbo、kimi-k2.5、qwen3.5-plus、claude-sonnet-4-6、gemini-3.1-pro-preview + Agent モードでは、品質とコストのバランスから以下のモデルをおすすめします: MiniMax-M2.7、glm-5-turbo、kimi-k2.5、qwen3.6-plus、claude-sonnet-4-6、gemini-3.1-pro-preview ## 設定 @@ -25,7 +25,7 @@ CowAgentは国内外の主要なLLMをサポートしています。モデルイ glm-5-turbo、glm-5およびその他のシリーズモデル - qwen3.5-plus、qwen3-maxなど + qwen3.6-plus、qwen3-maxなど kimi-k2.5、kimi-k2など diff --git a/docs/ja/models/qwen.mdx b/docs/ja/models/qwen.mdx index 2e686d18..c491b5e3 100644 --- a/docs/ja/models/qwen.mdx +++ b/docs/ja/models/qwen.mdx @@ -1,18 +1,18 @@ --- -title: Qwen (通义千问) -description: 通义千问モデルの設定 +title: Qwen (通義千問) +description: 通義千問モデルの設定 --- ```json { - "model": "qwen3.5-plus", + "model": "qwen3.6-plus", "dashscope_api_key": "YOUR_API_KEY" } ``` | パラメータ | 説明 | | --- | --- | -| `model` | `qwen3.5-plus`、`qwen3-max`、`qwen-max`、`qwen-plus`、`qwen-turbo`、`qwq-plus`などから選択可能 | +| `model` | `qwen3.6-plus`、`qwen3.5-plus`、`qwen3-max`、`qwen-max`、`qwen-plus`、`qwen-turbo`、`qwq-plus`などから選択可能 | | `dashscope_api_key` | [百炼 Console](https://bailian.console.aliyun.com/?tab=model#/api-key)で作成。[公式ドキュメント](https://bailian.console.aliyun.com/?tab=api#/api)を参照 | OpenAI互換の設定もサポートしています: @@ -20,7 +20,7 @@ OpenAI互換の設定もサポートしています: ```json { "bot_type": "openai", - "model": "qwen3.5-plus", + "model": "qwen3.6-plus", "open_ai_api_base": "https://dashscope.aliyuncs.com/compatible-mode/v1", "open_ai_api_key": "YOUR_API_KEY" } diff --git a/docs/models/index.mdx b/docs/models/index.mdx index 6f20d1b3..3e2b0a47 100644 --- a/docs/models/index.mdx +++ b/docs/models/index.mdx @@ -6,19 +6,20 @@ description: CowAgent 支持的模型及推荐选择 CowAgent 支持国内外主流厂商的大语言模型,模型接口实现在项目的 `models/` 目录下。 - Agent 模式下推荐使用以下模型,可根据效果及成本综合选择:MiniMax-M2.7、glm-5-turbo、kimi-k2.5、qwen3.5-plus、claude-sonnet-4-6、gemini-3.1-pro-preview + Agent 模式下推荐使用以下模型,可根据效果及成本综合选择:MiniMax-M2.7、glm-5-turbo、kimi-k2.5、qwen3.6-plus、claude-sonnet-4-6、gemini-3.1-pro-preview + + 同时支持使用 [LinkAI](https://link-ai.tech) 平台接口,可灵活切换多种模型,并支持知识库、工作流、插件等 Agent 能力。 ## 配置方式 -根据所选模型,在 `config.json` 中填写对应的模型名称和 API Key 即可。每个模型也支持 OpenAI 兼容方式接入,将 `bot_type` 设为 `openai`,配置 `open_ai_api_base` 和 `open_ai_api_key`。 - -同时支持使用 [LinkAI](https://link-ai.tech) 平台接口,可灵活切换多种模型,并支持知识库、工作流、插件等 Agent 能力。 - -也可以通过 [Web 控制台](/channels/web) 在线管理模型配置,无需手动编辑配置文件: +**方式一(推荐):** 通过 [Web 控制台](/channels/web) 在线管理模型配置,无需手动编辑配置文件: +**方式二:** 手动编辑 `config.json`,根据所选模型填写对应的模型名称和 API Key。每个模型也支持 OpenAI 兼容方式接入,将 `bot_type` 设为 `openai`,配置 `open_ai_api_base` 和 `open_ai_api_key` 即可。 + + ## 支持的模型 @@ -29,7 +30,7 @@ CowAgent 支持国内外主流厂商的大语言模型,模型接口实现在 glm-5-turbo、glm-5 等系列模型 - qwen3.5-plus、qwen3-max 等 + qwen3.6-plus、qwen3-max 等 kimi-k2.5、kimi-k2 等 @@ -54,6 +55,7 @@ CowAgent 支持国内外主流厂商的大语言模型,模型接口实现在 + 全部模型名称可参考项目 [`common/const.py`](https://github.com/zhayujie/chatgpt-on-wechat/blob/master/common/const.py) 文件。 diff --git a/docs/models/qwen.mdx b/docs/models/qwen.mdx index df670937..2bc6517d 100644 --- a/docs/models/qwen.mdx +++ b/docs/models/qwen.mdx @@ -5,14 +5,14 @@ description: 通义千问模型配置 ```json { - "model": "qwen3.5-plus", + "model": "qwen3.6-plus", "dashscope_api_key": "YOUR_API_KEY" } ``` | 参数 | 说明 | | --- | --- | -| `model` | 可填 `qwen3.5-plus`、`qwen3-max`、`qwen-max`、`qwen-plus`、`qwen-turbo`、`qwq-plus` 等 | +| `model` | 可填 `qwen3.6-plus`、`qwen3.5-plus`、`qwen3-max`、`qwen-max`、`qwen-plus`、`qwen-turbo`、`qwq-plus` 等 | | `dashscope_api_key` | 在 [百炼控制台](https://bailian.console.aliyun.com/?tab=model#/api-key) 创建,参考 [官方文档](https://bailian.console.aliyun.com/?tab=api#/api) | 也支持 OpenAI 兼容方式接入: @@ -20,7 +20,7 @@ description: 通义千问模型配置 ```json { "bot_type": "openai", - "model": "qwen3.5-plus", + "model": "qwen3.6-plus", "open_ai_api_base": "https://dashscope.aliyuncs.com/compatible-mode/v1", "open_ai_api_key": "YOUR_API_KEY" } diff --git a/models/ali/ali_qwen_bot.py b/models/ali/ali_qwen_bot.py deleted file mode 100644 index c8c25882..00000000 --- a/models/ali/ali_qwen_bot.py +++ /dev/null @@ -1,214 +0,0 @@ -# encoding:utf-8 - -import json -import time -from typing import List, Tuple - -import openai -from models.openai.openai_compat import RateLimitError, Timeout, APIError, APIConnectionError -import broadscope_bailian -from broadscope_bailian import ChatQaMessage - -from models.bot import Bot -from models.ali.ali_qwen_session import AliQwenSession -from models.session_manager import SessionManager -from bridge.context import ContextType -from bridge.reply import Reply, ReplyType -from common.log import logger -from common import const -from config import conf, load_config - -class AliQwenBot(Bot): - def __init__(self): - super().__init__() - self.api_key_expired_time = self.set_api_key() - self.sessions = SessionManager(AliQwenSession, model=conf().get("model", const.QWEN)) - - def api_key_client(self): - return broadscope_bailian.AccessTokenClient(access_key_id=self.access_key_id(), access_key_secret=self.access_key_secret()) - - def access_key_id(self): - return conf().get("qwen_access_key_id") - - def access_key_secret(self): - return conf().get("qwen_access_key_secret") - - def agent_key(self): - return conf().get("qwen_agent_key") - - def app_id(self): - return conf().get("qwen_app_id") - - def node_id(self): - return conf().get("qwen_node_id", "") - - def temperature(self): - return conf().get("temperature", 0.2 ) - - def top_p(self): - return conf().get("top_p", 1) - - def reply(self, query, context=None): - # acquire reply content - if context.type == ContextType.TEXT: - logger.info("[QWEN] query={}".format(query)) - - session_id = context["session_id"] - reply = None - clear_memory_commands = conf().get("clear_memory_commands", ["#清除记忆"]) - if query in clear_memory_commands: - self.sessions.clear_session(session_id) - reply = Reply(ReplyType.INFO, "记忆已清除") - elif query == "#清除所有": - self.sessions.clear_all_session() - reply = Reply(ReplyType.INFO, "所有人记忆已清除") - elif query == "#更新配置": - load_config() - reply = Reply(ReplyType.INFO, "配置已更新") - if reply: - return reply - session = self.sessions.session_query(query, session_id) - logger.debug("[QWEN] session query={}".format(session.messages)) - - reply_content = self.reply_text(session) - logger.debug( - "[QWEN] new_query={}, session_id={}, reply_cont={}, completion_tokens={}".format( - session.messages, - session_id, - reply_content["content"], - reply_content["completion_tokens"], - ) - ) - if reply_content["completion_tokens"] == 0 and len(reply_content["content"]) > 0: - reply = Reply(ReplyType.ERROR, reply_content["content"]) - elif reply_content["completion_tokens"] > 0: - self.sessions.session_reply(reply_content["content"], session_id, reply_content["total_tokens"]) - reply = Reply(ReplyType.TEXT, reply_content["content"]) - else: - reply = Reply(ReplyType.ERROR, reply_content["content"]) - logger.debug("[QWEN] reply {} used 0 tokens.".format(reply_content)) - return reply - - else: - reply = Reply(ReplyType.ERROR, "Bot不支持处理{}类型的消息".format(context.type)) - return reply - - def reply_text(self, session: AliQwenSession, retry_count=0) -> dict: - """ - call bailian's ChatCompletion to get the answer - :param session: a conversation session - :param retry_count: retry count - :return: {} - """ - try: - prompt, history = self.convert_messages_format(session.messages) - self.update_api_key_if_expired() - # NOTE 阿里百炼的call()函数未提供temperature参数,考虑到temperature和top_p参数作用相同,取两者较小的值作为top_p参数传入,详情见文档 https://help.aliyun.com/document_detail/2587502.htm - response = broadscope_bailian.Completions().call(app_id=self.app_id(), prompt=prompt, history=history, top_p=min(self.temperature(), self.top_p())) - completion_content = self.get_completion_content(response, self.node_id()) - completion_tokens, total_tokens = self.calc_tokens(session.messages, completion_content) - return { - "total_tokens": total_tokens, - "completion_tokens": completion_tokens, - "content": completion_content, - } - except Exception as e: - need_retry = retry_count < 2 - result = {"completion_tokens": 0, "content": "我现在有点累了,等会再来吧"} - if isinstance(e, RateLimitError): - logger.warn("[QWEN] RateLimitError: {}".format(e)) - result["content"] = "提问太快啦,请休息一下再问我吧" - if need_retry: - time.sleep(20) - elif isinstance(e, Timeout): - logger.warn("[QWEN] Timeout: {}".format(e)) - result["content"] = "我没有收到你的消息" - if need_retry: - time.sleep(5) - elif isinstance(e, APIError): - logger.warn("[QWEN] Bad Gateway: {}".format(e)) - result["content"] = "请再问我一次" - if need_retry: - time.sleep(10) - elif isinstance(e, APIConnectionError): - logger.warn("[QWEN] APIConnectionError: {}".format(e)) - need_retry = False - result["content"] = "我连接不到你的网络" - else: - logger.exception("[QWEN] Exception: {}".format(e)) - need_retry = False - self.sessions.clear_session(session.session_id) - - if need_retry: - logger.warn("[QWEN] 第{}次重试".format(retry_count + 1)) - return self.reply_text(session, retry_count + 1) - else: - return result - - def set_api_key(self): - api_key, expired_time = self.api_key_client().create_token(agent_key=self.agent_key()) - broadscope_bailian.api_key = api_key - return expired_time - - def update_api_key_if_expired(self): - if time.time() > self.api_key_expired_time: - self.api_key_expired_time = self.set_api_key() - - def convert_messages_format(self, messages) -> Tuple[str, List[ChatQaMessage]]: - history = [] - user_content = '' - assistant_content = '' - system_content = '' - for message in messages: - role = message.get('role') - if role == 'user': - user_content += message.get('content') - elif role == 'assistant': - assistant_content = message.get('content') - history.append(ChatQaMessage(user_content, assistant_content)) - user_content = '' - assistant_content = '' - elif role =='system': - system_content += message.get('content') - if user_content == '': - raise Exception('no user message') - if system_content != '': - # NOTE 模拟系统消息,测试发现人格描述以"你需要扮演ChatGPT"开头能够起作用,而以"你是ChatGPT"开头模型会直接否认 - system_qa = ChatQaMessage(system_content, '好的,我会严格按照你的设定回答问题') - history.insert(0, system_qa) - logger.debug("[QWEN] converted qa messages: {}".format([item.to_dict() for item in history])) - logger.debug("[QWEN] user content as prompt: {}".format(user_content)) - return user_content, history - - def get_completion_content(self, response, node_id): - if not response['Success']: - return f"[ERROR]\n{response['Code']}:{response['Message']}" - text = response['Data']['Text'] - if node_id == '': - return text - # TODO: 当使用流程编排创建大模型应用时,响应结构如下,最终结果在['finalResult'][node_id]['response']['text']中,暂时先这么写 - # { - # 'Success': True, - # 'Code': None, - # 'Message': None, - # 'Data': { - # 'ResponseId': '9822f38dbacf4c9b8daf5ca03a2daf15', - # 'SessionId': 'session_id', - # 'Text': '{"finalResult":{"LLM_T7islK":{"params":{"modelId":"qwen-plus-v1","prompt":"${systemVars.query}${bizVars.Text}"},"response":{"text":"作为一个AI语言模型,我没有年龄,因为我没有生日。\n我只是一个程序,没有生命和身体。"}}}}', - # 'Thoughts': [], - # 'Debug': {}, - # 'DocReferences': [] - # }, - # 'RequestId': '8e11d31551ce4c3f83f49e6e0dd998b0', - # 'Failed': None - # } - text_dict = json.loads(text) - completion_content = text_dict['finalResult'][node_id]['response']['text'] - return completion_content - - def calc_tokens(self, messages, completion_content): - completion_tokens = len(completion_content) - prompt_tokens = 0 - for message in messages: - prompt_tokens += len(message["content"]) - return completion_tokens, prompt_tokens + completion_tokens diff --git a/models/ali/ali_qwen_session.py b/models/ali/ali_qwen_session.py deleted file mode 100644 index 48c5eea7..00000000 --- a/models/ali/ali_qwen_session.py +++ /dev/null @@ -1,62 +0,0 @@ -from models.session_manager import Session -from common.log import logger - -""" - e.g. - [ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "Who won the world series in 2020?"}, - {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."}, - {"role": "user", "content": "Where was it played?"} - ] -""" - -class AliQwenSession(Session): - def __init__(self, session_id, system_prompt=None, model="qianwen"): - super().__init__(session_id, system_prompt) - self.model = model - self.reset() - - def discard_exceeding(self, max_tokens, cur_tokens=None): - precise = True - try: - cur_tokens = self.calc_tokens() - except Exception as e: - precise = False - if cur_tokens is None: - raise e - logger.debug("Exception when counting tokens precisely for query: {}".format(e)) - while cur_tokens > max_tokens: - if len(self.messages) > 2: - self.messages.pop(1) - elif len(self.messages) == 2 and self.messages[1]["role"] == "assistant": - self.messages.pop(1) - if precise: - cur_tokens = self.calc_tokens() - else: - cur_tokens = cur_tokens - max_tokens - break - elif len(self.messages) == 2 and self.messages[1]["role"] == "user": - logger.warn("user message exceed max_tokens. total_tokens={}".format(cur_tokens)) - break - else: - logger.debug("max_tokens={}, total_tokens={}, len(messages)={}".format(max_tokens, cur_tokens, len(self.messages))) - break - if precise: - cur_tokens = self.calc_tokens() - else: - cur_tokens = cur_tokens - max_tokens - return cur_tokens - - def calc_tokens(self): - return num_tokens_from_messages(self.messages, self.model) - -def num_tokens_from_messages(messages, model): - """Returns the number of tokens used by a list of messages.""" - # 官方token计算规则:"对于中文文本来说,1个token通常对应一个汉字;对于英文文本来说,1个token通常对应3至4个字母或1个单词" - # 详情请产看文档:https://help.aliyun.com/document_detail/2586397.html - # 目前根据字符串长度粗略估计token数,不影响正常使用 - tokens = 0 - for msg in messages: - tokens += len(msg["content"]) - return tokens diff --git a/models/bot_factory.py b/models/bot_factory.py index 5c91c7c6..5f2b9370 100644 --- a/models/bot_factory.py +++ b/models/bot_factory.py @@ -46,10 +46,7 @@ def create_bot(bot_type): elif bot_type == const.CLAUDEAPI: from models.claudeapi.claude_api_bot import ClaudeAPIBot return ClaudeAPIBot() - elif bot_type == const.QWEN: - from models.ali.ali_qwen_bot import AliQwenBot - return AliQwenBot() - elif bot_type == const.QWEN_DASHSCOPE: + elif bot_type in (const.QWEN, const.QWEN_DASHSCOPE): from models.dashscope.dashscope_bot import DashscopeBot return DashscopeBot() elif bot_type == const.GEMINI: diff --git a/models/dashscope/dashscope_bot.py b/models/dashscope/dashscope_bot.py index 1b677317..0887751f 100644 --- a/models/dashscope/dashscope_bot.py +++ b/models/dashscope/dashscope_bot.py @@ -26,15 +26,15 @@ dashscope_models = { # Model name prefixes that require MultiModalConversation API instead of Generation API. # Qwen3.5+ series are omni models that only support MultiModalConversation. -MULTIMODAL_MODEL_PREFIXES = ("qwen3.5-",) +MULTIMODAL_MODEL_PREFIXES = ("qwen3.5-", "qwen3.6-") # Qwen对话模型API class DashscopeBot(Bot): def __init__(self): super().__init__() - self.sessions = SessionManager(DashscopeSession, model=conf().get("model") or "qwen-plus") - self.model_name = conf().get("model") or "qwen-plus" + self.sessions = SessionManager(DashscopeSession, model=conf().get("model") or "qwen3.6-plus") + self.model_name = conf().get("model") or "qwen3.6-plus" self.client = dashscope.Generation api_key = conf().get("dashscope_api_key") if api_key: diff --git a/plugins/cow_cli/cow_cli.py b/plugins/cow_cli/cow_cli.py index aed0b410..d08a8414 100644 --- a/plugins/cow_cli/cow_cli.py +++ b/plugins/cow_cli/cow_cli.py @@ -407,7 +407,7 @@ class CowCliPlugin(Plugin): from common import const _EXACT = { "wenxin": const.BAIDU, "wenxin-4": const.BAIDU, - "xunfei": const.XUNFEI, const.QWEN: const.QWEN, + "xunfei": const.XUNFEI, const.QWEN: const.QWEN_DASHSCOPE, const.MODELSCOPE: const.MODELSCOPE, const.MOONSHOT: const.MOONSHOT, "moonshot-v1-8k": const.MOONSHOT, "moonshot-v1-32k": const.MOONSHOT, diff --git a/plugins/godcmd/godcmd.py b/plugins/godcmd/godcmd.py index d844a506..6439411d 100644 --- a/plugins/godcmd/godcmd.py +++ b/plugins/godcmd/godcmd.py @@ -315,7 +315,7 @@ class Godcmd(Plugin): except Exception as e: ok, result = False, "你没有设置私有GPT模型" elif cmd == "reset": - if bottype in [const.OPEN_AI, const.OPENAI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI, const.BAIDU, const.XUNFEI, const.QWEN, const.GEMINI, const.ZHIPU_AI, const.CLAUDEAPI]: + if bottype in [const.OPEN_AI, const.OPENAI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI, const.BAIDU, const.XUNFEI, const.QWEN, const.QWEN_DASHSCOPE, const.GEMINI, const.ZHIPU_AI, const.CLAUDEAPI]: bot.sessions.clear_session(session_id) if Bridge().chat_bots.get(bottype): Bridge().chat_bots.get(bottype).sessions.clear_session(session_id) @@ -341,7 +341,7 @@ class Godcmd(Plugin): ok, result = True, "配置已重载" elif cmd == "resetall": if bottype in [const.OPEN_AI, const.OPENAI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI, - const.BAIDU, const.XUNFEI, const.QWEN, const.GEMINI, const.ZHIPU_AI, const.MOONSHOT, + const.BAIDU, const.XUNFEI, const.QWEN, const.QWEN_DASHSCOPE, const.GEMINI, const.ZHIPU_AI, const.MOONSHOT, const.MODELSCOPE]: channel.cancel_all_session() bot.sessions.clear_all_session() diff --git a/run.sh b/run.sh index 0ee3aa0c..ab47faf4 100755 --- a/run.sh +++ b/run.sh @@ -271,7 +271,7 @@ select_model() { echo -e "${YELLOW}2) Zhipu AI (glm-5-turbo, glm-5, etc.)${NC}" echo -e "${YELLOW}3) Kimi (kimi-k2.5, kimi-k2, etc.)${NC}" echo -e "${YELLOW}4) Doubao (doubao-seed-2-0-code-preview-260215, etc.)${NC}" - echo -e "${YELLOW}5) Qwen (qwen3.5-plus, qwen3-max, qwq-plus, etc.)${NC}" + echo -e "${YELLOW}5) Qwen (qwen3.6-plus, qwen3.5-plus, qwen3-max, qwq-plus, etc.)${NC}" echo -e "${YELLOW}6) Claude (claude-sonnet-4-6, claude-opus-4-6, etc.)${NC}" echo -e "${YELLOW}7) Gemini (gemini-3.1-flash-lite-preview, gemini-3.1-pro-preview, etc.)${NC}" echo -e "${YELLOW}8) OpenAI GPT (gpt-5.4, gpt-5.2, gpt-4.1, etc.)${NC}" @@ -318,7 +318,7 @@ configure_model() { 2) read_model_config "Zhipu AI" "glm-5-turbo" "ZHIPU_KEY" ;; 3) read_model_config "Kimi (Moonshot)" "kimi-k2.5" "MOONSHOT_KEY" ;; 4) read_model_config "Doubao (Volcengine Ark)" "doubao-seed-2-0-code-preview-260215" "ARK_KEY" ;; - 5) read_model_config "Qwen (DashScope)" "qwen3.5-plus" "DASHSCOPE_KEY" ;; + 5) read_model_config "Qwen (DashScope)" "qwen3.6-plus" "DASHSCOPE_KEY" ;; 6) read_model_config "Claude" "claude-sonnet-4-6" "CLAUDE_KEY" read_api_base "CLAUDE_BASE" "https://api.anthropic.com/v1" diff --git a/scripts/run.ps1 b/scripts/run.ps1 index aaa99a47..b68a4bd9 100644 --- a/scripts/run.ps1 +++ b/scripts/run.ps1 @@ -154,7 +154,7 @@ $ModelChoices = @{ "2" = @{ Provider = "Zhipu AI"; Default = "glm-5-turbo"; Key = "ZHIPU_KEY" } "3" = @{ Provider = "Kimi (Moonshot)"; Default = "kimi-k2.5"; Key = "MOONSHOT_KEY" } "4" = @{ Provider = "Doubao (Volcengine Ark)"; Default = "doubao-seed-2-0-code-preview-260215"; Key = "ARK_KEY" } - "5" = @{ Provider = "Qwen (DashScope)"; Default = "qwen3.5-plus"; Key = "DASHSCOPE_KEY" } + "5" = @{ Provider = "Qwen (DashScope)"; Default = "qwen3.6-plus"; Key = "DASHSCOPE_KEY" } "6" = @{ Provider = "Claude"; Default = "claude-sonnet-4-6"; Key = "CLAUDE_KEY"; Base = "https://api.anthropic.com/v1" } "7" = @{ Provider = "Gemini"; Default = "gemini-3.1-pro-preview"; Key = "GEMINI_KEY"; Base = "https://generativelanguage.googleapis.com" } "8" = @{ Provider = "OpenAI GPT"; Default = "gpt-5.4"; Key = "OPENAI_KEY"; Base = "https://api.openai.com/v1" } @@ -169,7 +169,7 @@ function Select-Model { Write-Host "2) Zhipu AI (glm-5-turbo, glm-5, etc.)" Write-Host "3) Kimi (kimi-k2.5, kimi-k2, etc.)" Write-Host "4) Doubao (doubao-seed-2-0-code-preview-260215, etc.)" - Write-Host "5) Qwen (qwen3.5-plus, qwen3-max, qwq-plus, etc.)" + Write-Host "5) Qwen (qwen3.6-plus, qwen3.5-plus, qwen3-max, qwq-plus, etc.)" Write-Host "6) Claude (claude-sonnet-4-6, claude-opus-4-6, etc.)" Write-Host "7) Gemini (gemini-3.1-flash-lite-preview, gemini-3.1-pro-preview, etc.)" Write-Host "8) OpenAI GPT (gpt-5.4, gpt-5.2, gpt-4.1, etc.)"