From 1982257a3b07d1af318528a902cc51fdf9d486a0 Mon Sep 17 00:00:00 2001 From: zhubinyang <1804221960@qq.com> Date: Wed, 29 Apr 2026 16:20:27 +0800 Subject: [PATCH 1/3] Add AtlasCloud provider example and web UI support --- README.md | 11 +- examples/run_atlascloud.py | 232 +++++++++++++++++++++++++++++++++++++ owl/.env_template | 6 +- owl/webapp.py | 87 +++++++++----- owl/webapp_jp.py | 91 +++++++++------ owl/webapp_zh.py | 83 ++++++++----- 6 files changed, 409 insertions(+), 101 deletions(-) create mode 100644 examples/run_atlascloud.py diff --git a/README.md b/README.md index b03aa4937..da37ead1b 100644 --- a/README.md +++ b/README.md @@ -336,6 +336,7 @@ You can set environment variables directly in your terminal: ```bash export OPENAI_API_KEY="your-openai-api-key-here" # Add other required API keys as needed + export ATLASCLOUD_API_KEY="your-atlascloud-api-key-here" ``` - **Windows (Command Prompt)**: @@ -372,6 +373,14 @@ If you prefer using a `.env` file instead, you can: 2. **Configure Your API Keys**: Open the `.env` file in your preferred text editor and insert your API keys in the corresponding fields. + AtlasCloud's OpenAI-compatible LLM endpoint requires the `/v1` suffix: + + ```bash + ATLASCLOUD_API_KEY="your-atlascloud-api-key-here" + ATLASCLOUD_API_BASE_URL="https://api.atlascloud.ai/v1" + ATLASCLOUD_MODEL_NAME="deepseek-ai/DeepSeek-V3-0324" + ``` + > **Note**: For the minimal example (`examples/run_mini.py`), you only need to configure the LLM API key (e.g., `OPENAI_API_KEY`). ### **MCP Desktop Commander Setup** @@ -421,7 +430,7 @@ python examples/run_qwen_zh.py python examples/run_deepseek_zh.py # Run with other OpenAI-compatible models -python examples/run_openai_compatible_model.py +python examples/run_atlascloud.py # Run with Gemini model python examples/run_gemini.py diff --git a/examples/run_atlascloud.py b/examples/run_atlascloud.py new file mode 100644 index 000000000..cb95aa531 --- /dev/null +++ b/examples/run_atlascloud.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python3 +# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= + +""" +Workforce example using AtlasCloud's OpenAI-compatible LLM endpoint. + +AtlasCloud exposes an OpenAI-compatible chat completions API at: +https://api.atlascloud.ai/v1 + +Configuration priority: +1. ATLASCLOUD_API_KEY environment variable + +Optional environment variables: +- ATLASCLOUD_API_BASE_URL (default: https://api.atlascloud.ai/v1) +- ATLASCLOUD_MODEL_NAME (default: deepseek-ai/DeepSeek-V3-0324) + +Run with: +python examples/run_atlascloud.py +python examples/run_atlascloud.py "Your task here" +""" + +import os +import sys +import pathlib +from typing import Any, Dict, List + +from dotenv import load_dotenv + +from camel.agents import ChatAgent +from camel.logger import set_log_level +from camel.models import ModelFactory +from camel.societies import Workforce +from camel.tasks.task import Task +from camel.toolkits import ( + BrowserToolkit, + CodeExecutionToolkit, + ExcelToolkit, + FileToolkit, + FunctionTool, + SearchToolkit, +) +from camel.types import ModelPlatformType + +from owl.utils import DocumentProcessingToolkit + +ATLAS_BASE_URL = "https://api.atlascloud.ai/v1" +ATLAS_MODEL_NAME = "deepseek-ai/DeepSeek-V3-0324" + +BASE_DIR = pathlib.Path(__file__).parent.parent +ENV_PATH = BASE_DIR / "owl" / ".env" + +load_dotenv(dotenv_path=str(ENV_PATH)) +set_log_level(level="DEBUG") + + +def load_atlascloud_api_key() -> str | None: + """Load AtlasCloud API key from environment variables.""" + api_key = os.getenv("ATLASCLOUD_API_KEY") + if api_key: + return api_key.strip() + + return None + + +def get_atlascloud_config() -> tuple[str, str, str]: + """Return AtlasCloud base URL, API key, and model name.""" + api_url = os.getenv("ATLASCLOUD_API_BASE_URL", ATLAS_BASE_URL).strip() + model_name = os.getenv("ATLASCLOUD_MODEL_NAME", ATLAS_MODEL_NAME).strip() + api_key = load_atlascloud_api_key() + + if not api_key: + raise ValueError( + "Missing AtlasCloud API key. Set ATLASCLOUD_API_KEY in your " + "environment or owl/.env file." + ) + + return api_url, api_key, model_name + + +def create_atlas_model(): + """Create an OpenAI-compatible model backed by AtlasCloud.""" + api_url, api_key, model_name = get_atlascloud_config() + return ModelFactory.create( + model_platform=ModelPlatformType.OPENAI_COMPATIBLE_MODEL, + model_type=model_name, + url=api_url, + api_key=api_key, + model_config_dict={"temperature": 0}, + ) + + +def construct_agent_list() -> List[Dict[str, Any]]: + """Construct a list of agents with AtlasCloud-backed model instances.""" + web_model = create_atlas_model() + document_processing_model = create_atlas_model() + reasoning_model = create_atlas_model() + browsing_model = create_atlas_model() + planning_model = create_atlas_model() + + search_toolkit = SearchToolkit() + document_processing_toolkit = DocumentProcessingToolkit( + model=document_processing_model + ) + code_runner_toolkit = CodeExecutionToolkit(sandbox="subprocess", verbose=True) + file_toolkit = FileToolkit() + excel_toolkit = ExcelToolkit() + browser_toolkit = BrowserToolkit( + headless=False, + web_agent_model=browsing_model, + planning_agent_model=planning_model, + ) + + web_agent = ChatAgent( + """You are a helpful assistant that can search the web, extract webpage content, simulate browser actions, and provide relevant information to solve the given task. +Keep in mind that: +- Do not be overly confident in your own knowledge. Searching can provide a broader perspective and help validate existing knowledge. +- If one way fails to provide an answer, try other ways or methods. The answer does exist. +- If the search snippet is unhelpful but the URL comes from an authoritative source, try visit the website for more details. +- When looking for specific numerical values (e.g., dollar amounts), prioritize reliable sources and avoid relying only on search snippets. +- When solving tasks that require web searches, check Wikipedia first before exploring other websites. +- You can also simulate browser actions to get more information or verify the information you have found. +- Browser simulation is also helpful for finding target URLs. Browser simulation operations do not necessarily need to find specific answers, but can also help find web page URLs that contain answers (usually difficult to find through simple web searches). You can find the answer to the question by performing subsequent operations on the URL, such as extracting the content of the webpage. +- Do not solely rely on document tools or browser simulation to find the answer, you should combine document tools and browser simulation to comprehensively process web page information. Some content may need to do browser simulation to get, or some content is rendered by javascript. +- In your response, you should mention the urls you have visited and processed. + +Here are some tips that help you perform web search: +- Never add too many keywords in your search query! Some detailed results need to perform browser interaction to get, not using search toolkit. +- If the question is complex, search results typically do not provide precise answers. It is not likely to find the answer directly using search toolkit only, the search query should be concise and focuses on finding official sources rather than direct answers. +- The results you return do not have to directly answer the original question, you only need to collect relevant information. +""", + model=web_model, + tools=[ + FunctionTool(search_toolkit.search_duckduckgo), + FunctionTool(search_toolkit.search_wiki), + FunctionTool(document_processing_toolkit.extract_document_content), + *browser_toolkit.get_tools(), + ], + ) + + document_processing_agent = ChatAgent( + "You are a helpful assistant that can process documents and multimodal data, and can interact with file system.", + document_processing_model, + tools=[ + FunctionTool(document_processing_toolkit.extract_document_content), + FunctionTool(code_runner_toolkit.execute_code), + *file_toolkit.get_tools(), + ], + ) + + reasoning_coding_agent = ChatAgent( + "You are a helpful assistant that specializes in reasoning and coding, and can think step by step to solve the task. When necessary, you can write python code to solve the task. If you have written code, do not forget to execute the code. Never generate codes like 'example code', your code should be able to fully solve the task. You can also leverage multiple libraries, such as requests, BeautifulSoup, re, pandas, etc, to solve the task. For processing excel files, you should write codes to process them.", + reasoning_model, + tools=[ + FunctionTool(code_runner_toolkit.execute_code), + FunctionTool(excel_toolkit.extract_excel_content), + FunctionTool(document_processing_toolkit.extract_document_content), + ], + ) + + return [ + { + "name": "Web Agent", + "description": "A helpful assistant that can search the web, extract webpage content, and retrieve relevant information.", + "agent": web_agent, + }, + { + "name": "Document Processing Agent", + "description": "A helpful assistant that can process a variety of local and remote documents, including pdf, docx, images, audio, and video, etc.", + "agent": document_processing_agent, + }, + { + "name": "Reasoning Coding Agent", + "description": "A helpful assistant that specializes in reasoning, coding, and processing excel files. However, it cannot access the internet to search for information. If the task requires python execution, it should be informed to execute the code after writing it.", + "agent": reasoning_coding_agent, + }, + ] + + +def construct_workforce() -> Workforce: + """Construct a workforce with coordinator and task agents.""" + task_agent = ChatAgent( + "You are a helpful assistant that can decompose tasks and assign tasks to workers.", + model=create_atlas_model(), + ) + coordinator_agent = ChatAgent( + "You are a helpful assistant that can assign tasks to workers.", + model=create_atlas_model(), + ) + + workforce = Workforce( + "Workforce", + task_agent=task_agent, + coordinator_agent=coordinator_agent, + ) + + for agent_dict in construct_agent_list(): + workforce.add_single_agent_worker( + agent_dict["description"], + worker=agent_dict["agent"], + ) + + return workforce + + +def main(): + r"""Main function to run OWL with AtlasCloud as the provider.""" + default_task_prompt = ( + "Summarize the github stars, fork counts, and recent activity of camel-ai " + "owl, then save the result as a local markdown file." + ) + task_prompt = sys.argv[1] if len(sys.argv) > 1 else default_task_prompt + + task = Task(content=task_prompt) + workforce = construct_workforce() + processed_task = workforce.process_task(task) + print(f"\033[94mAnswer: {processed_task.result}\033[0m") + + +if __name__ == "__main__": + main() diff --git a/owl/.env_template b/owl/.env_template index 8d5ea06b7..36afbe31e 100644 --- a/owl/.env_template +++ b/owl/.env_template @@ -7,6 +7,10 @@ OPENAI_API_KEY="Your_Key" # OPENAI_API_BASE_URL="" +# AtlasCloud API (https://www.atlascloud.ai/docs/get-started) +# ATLASCLOUD_API_KEY="Your_Key" +# ATLASCLOUD_API_BASE_URL="https://api.atlascloud.ai/v1" +# ATLASCLOUD_MODEL_NAME="deepseek-ai/DeepSeek-V3-0324" # Qwen API (https://help.aliyun.com/zh/model-studio/developer-reference/get-api-key) # QWEN_API_KEY="Your_Key" @@ -48,4 +52,4 @@ CHUNKR_API_KEY="Your_Key" # Firecrawl API (https://www.firecrawl.dev/) FIRECRAWL_API_KEY="Your_Key" -#FIRECRAWL_API_URL="https://api.firecrawl.dev" \ No newline at end of file +#FIRECRAWL_API_URL="https://api.firecrawl.dev" diff --git a/owl/webapp.py b/owl/webapp.py index 7ee0053cb..79b442207 100644 --- a/owl/webapp.py +++ b/owl/webapp.py @@ -11,8 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= -# Import from the correct module path -from utils import run_society import os import gradio as gr import time @@ -25,6 +23,8 @@ import threading import queue import re +from camel.tasks.task import Task +from utils import run_society os.environ["PYTHONIOENCODING"] = "utf-8" @@ -250,6 +250,7 @@ def process_message(role, content): "run_mistral": "Using Mistral models to process tasks", "run_openai_compatible_model": "Using openai compatible model to process tasks", "run_ollama": "Using local ollama model to process tasks", + "run_atlascloud": "Using AtlasCloud's OpenAI-compatible model to process tasks", "run_qwen_mini_zh": "Using qwen model with minimal configuration to process tasks", "run_qwen_zh": "Using qwen model to process tasks", "run_azure_openai": "Using azure openai model to process tasks", @@ -270,6 +271,11 @@ def process_message(role, content): OPENAI_API_KEY='Your_Key' # OPENAI_API_BASE_URL="" +# AtlasCloud API (https://www.atlascloud.ai/docs/get-started) +# ATLASCLOUD_API_KEY='Your_Key' +# ATLASCLOUD_API_BASE_URL="https://api.atlascloud.ai/v1" +# ATLASCLOUD_MODEL_NAME="deepseek-ai/DeepSeek-V3-0324" + # Azure OpenAI API # AZURE_OPENAI_BASE_URL="" # AZURE_API_VERSION="" @@ -374,43 +380,58 @@ def run_owl(question: str, example_module: str) -> Tuple[str, str, str]: f"❌ Error: {str(e)}", ) - # Check if it contains the construct_society function - if not hasattr(module, "construct_society"): + if hasattr(module, "construct_society"): + try: + logging.info("Building society simulation...") + society = module.construct_society(question) + except Exception as e: + logging.error( + f"Error occurred while building society simulation: {str(e)}" + ) + return ( + f"Error occurred while building society simulation: {str(e)}", + "0", + f"❌ Error: Build failed - {str(e)}", + ) + + try: + logging.info("Running society simulation...") + answer, chat_history, token_info = run_society(society) + logging.info("Society simulation completed") + except Exception as e: + logging.error( + f"Error occurred while running society simulation: {str(e)}" + ) + return ( + f"Error occurred while running society simulation: {str(e)}", + "0", + f"❌ Error: Run failed - {str(e)}", + ) + elif hasattr(module, "construct_workforce"): + try: + logging.info("Building workforce...") + workforce = module.construct_workforce() + processed_task = workforce.process_task(Task(content=question)) + answer = processed_task.result + token_info = {} + logging.info("Workforce run completed") + except Exception as e: + logging.error(f"Error occurred while running workforce: {str(e)}") + return ( + f"Error occurred while running workforce: {str(e)}", + "0", + f"❌ Error: Run failed - {str(e)}", + ) + else: logging.error( - f"construct_society function not found in module {module_path}" + f"Neither construct_society nor construct_workforce was found in module {module_path}" ) return ( - f"construct_society function not found in module {module_path}", + f"Module {module_path} is missing a supported entrypoint", "0", "❌ Error: Module interface incompatible", ) - # Build society simulation - try: - logging.info("Building society simulation...") - society = module.construct_society(question) - - except Exception as e: - logging.error(f"Error occurred while building society simulation: {str(e)}") - return ( - f"Error occurred while building society simulation: {str(e)}", - "0", - f"❌ Error: Build failed - {str(e)}", - ) - - # Run society simulation - try: - logging.info("Running society simulation...") - answer, chat_history, token_info = run_society(society) - logging.info("Society simulation completed") - except Exception as e: - logging.error(f"Error occurred while running society simulation: {str(e)}") - return ( - f"Error occurred while running society simulation: {str(e)}", - "0", - f"❌ Error: Run failed - {str(e)}", - ) - # Safely get token count if not isinstance(token_info, dict): token_info = {} @@ -632,6 +653,8 @@ def get_api_guide(key: str) -> str: return "https://help.aliyun.com/zh/model-studio/developer-reference/get-api-key" elif "deepseek" in key_lower: return "https://platform.deepseek.com/api_keys" + elif "atlascloud" in key_lower: + return "https://www.atlascloud.ai/docs/get-started" elif "ppio" in key_lower: return "https://ppinfra.com/settings/key-management?utm_source=github_owl" elif "google" in key_lower: diff --git a/owl/webapp_jp.py b/owl/webapp_jp.py index 1db2a2998..e96323389 100644 --- a/owl/webapp_jp.py +++ b/owl/webapp_jp.py @@ -11,8 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= -# 正しいモジュールパスからインポート -from utils import run_society import os import gradio as gr import time @@ -25,6 +23,8 @@ import threading import queue import re +from camel.tasks.task import Task +from utils import run_society os.environ["PYTHONIOENCODING"] = "utf-8" @@ -248,6 +248,7 @@ def process_message(role, content): "run_deepseek_zh": "中国語タスクを処理するためにdeepseekモデルを使用します", "run_openai_compatible_model": "OpenAI互換モデルを使用してタスクを処理します", "run_ollama": "ローカルのollamaモデルを使用してタスクを処理します", + "run_atlascloud": "AtlasCloud の OpenAI 互換モデルを使用してタスクを処理します", "run_qwen_mini_zh": "最小限の設定でqwenモデルを使用してタスクを処理します", "run_qwen_zh": "qwenモデルを使用して中国語タスクを処理します", "run_azure_openai": "Azure OpenAIモデルを使用してタスクを処理します", @@ -266,6 +267,11 @@ def process_message(role, content): OPENAI_API_KEY='あなたのキー' # OPENAI_API_BASE_URL="" +# AtlasCloud API (https://www.atlascloud.ai/docs/get-started) +# ATLASCLOUD_API_KEY='Your_Key' +# ATLASCLOUD_API_BASE_URL="https://api.atlascloud.ai/v1" +# ATLASCLOUD_MODEL_NAME="deepseek-ai/DeepSeek-V3-0324" + # Azure OpenAI API # AZURE_OPENAI_BASE_URL="" # AZURE_API_VERSION="" @@ -370,45 +376,56 @@ def run_owl(question: str, example_module: str) -> Tuple[str, str, str]: f"❌ エラー: {str(e)}", ) - # Check if it contains the construct_society function - if not hasattr(module, "construct_society"): - logging.error( - f"construct_society 関数がモジュール {module_path} に見つかりません" - ) - return ( - f"construct_society 関数がモジュール {module_path} に見つかりません", - "0", - "❌ エラー: モジュールインターフェースが互換性がありません", - ) - - # Build society simulation - try: - logging.info("社会シミュレーションを構築中...") - society = module.construct_society(question) - - except Exception as e: - logging.error( - f"社会シミュレーションの構築中にエラーが発生しました: {str(e)}" - ) - return ( - f"社会シミュレーションの構築中にエラーが発生しました: {str(e)}", - "0", - f"❌ エラー: 構築に失敗しました - {str(e)}", - ) + if hasattr(module, "construct_society"): + try: + logging.info("社会シミュレーションを構築中...") + society = module.construct_society(question) + except Exception as e: + logging.error( + f"社会シミュレーションの構築中にエラーが発生しました: {str(e)}" + ) + return ( + f"社会シミュレーションの構築中にエラーが発生しました: {str(e)}", + "0", + f"❌ エラー: 構築に失敗しました - {str(e)}", + ) - # Run society simulation - try: - logging.info("社会シミュレーションを実行中...") - answer, chat_history, token_info = run_society(society) - logging.info("社会シミュレーションが完了しました") - except Exception as e: + try: + logging.info("社会シミュレーションを実行中...") + answer, chat_history, token_info = run_society(society) + logging.info("社会シミュレーションが完了しました") + except Exception as e: + logging.error( + f"社会シミュレーションの実行中にエラーが発生しました: {str(e)}" + ) + return ( + f"社会シミュレーションの実行中にエラーが発生しました: {str(e)}", + "0", + f"❌ エラー: 実行に失敗しました - {str(e)}", + ) + elif hasattr(module, "construct_workforce"): + try: + logging.info("Workforce を構築中...") + workforce = module.construct_workforce() + processed_task = workforce.process_task(Task(content=question)) + answer = processed_task.result + token_info = {} + logging.info("Workforce 実行が完了しました") + except Exception as e: + logging.error(f"Workforce の実行中にエラーが発生しました: {str(e)}") + return ( + f"Workforce の実行中にエラーが発生しました: {str(e)}", + "0", + f"❌ エラー: 実行に失敗しました - {str(e)}", + ) + else: logging.error( - f"社会シミュレーションの実行中にエラーが発生しました: {str(e)}" + f"construct_society または construct_workforce がモジュール {module_path} に見つかりません" ) return ( - f"社会シミュレーションの実行中にエラーが発生しました: {str(e)}", + f"モジュール {module_path} に対応するエントリポイントがありません", "0", - f"❌ エラー: 実行に失敗しました - {str(e)}", + "❌ エラー: モジュールインターフェースが互換性がありません", ) # Safely get token count @@ -630,6 +647,8 @@ def get_api_guide(key: str) -> str: return "https://help.aliyun.com/zh/model-studio/developer-reference/get-api-key" elif "deepseek" in key_lower: return "https://platform.deepseek.com/api_keys" + elif "atlascloud" in key_lower: + return "https://www.atlascloud.ai/docs/get-started" elif "google" in key_lower: return "https://coda.io/@jon-dallas/google-image-search-pack-example/search-engine-id-and-google-api-key-3" elif "search_engine_id" in key_lower: diff --git a/owl/webapp_zh.py b/owl/webapp_zh.py index 1524cc132..e63044fb0 100644 --- a/owl/webapp_zh.py +++ b/owl/webapp_zh.py @@ -11,8 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= -# Import from the correct module path -from utils import run_society import os import gradio as gr import time @@ -25,6 +23,8 @@ import threading import queue import re # For regular expression operations +from camel.tasks.task import Task +from utils import run_society os.environ["PYTHONIOENCODING"] = "utf-8" @@ -249,6 +249,7 @@ def process_message(role, content): "run_deepseek_zh": "使用eepseek模型处理中文任务", "run_openai_compatible_model": "使用openai兼容模型处理任务", "run_ollama": "使用本地ollama模型处理任务", + "run_atlascloud": "使用 AtlasCloud 的 OpenAI 兼容模型处理任务", "run_qwen_mini_zh": "使用qwen模型最小化配置处理任务", "run_qwen_zh": "使用qwen模型处理任务", "run_azure_openai": "使用azure openai模型处理任务", @@ -269,6 +270,11 @@ def process_message(role, content): OPENAI_API_KEY='Your_Key' # OPENAI_API_BASE_URL="" +# AtlasCloud API (https://www.atlascloud.ai/docs/get-started) +# ATLASCLOUD_API_KEY='Your_Key' +# ATLASCLOUD_API_BASE_URL="https://api.atlascloud.ai/v1" +# ATLASCLOUD_MODEL_NAME="deepseek-ai/DeepSeek-V3-0324" + # Azure OpenAI API # AZURE_OPENAI_BASE_URL="" # AZURE_API_VERSION="" @@ -361,39 +367,52 @@ def run_owl(question: str, example_module: str) -> Tuple[str, str, str]: logging.error(f"导入模块 {module_path} 时发生错误: {str(e)}") return (f"导入模块时发生错误: {module_path}", "0", f"❌ 错误: {str(e)}") - # 检查是否包含construct_society函数 - if not hasattr(module, "construct_society"): - logging.error(f"模块 {module_path} 中未找到 construct_society 函数") - return ( - f"模块 {module_path} 中未找到 construct_society 函数", - "0", - "❌ 错误: 模块接口不兼容", - ) - - # 构建社会模拟 - try: - logging.info("正在构建社会模拟...") - society = module.construct_society(question) + if hasattr(module, "construct_society"): + try: + logging.info("正在构建社会模拟...") + society = module.construct_society(question) + except Exception as e: + logging.error(f"构建社会模拟时发生错误: {str(e)}") + return ( + f"构建社会模拟时发生错误: {str(e)}", + "0", + f"❌ 错误: 构建失败 - {str(e)}", + ) - except Exception as e: - logging.error(f"构建社会模拟时发生错误: {str(e)}") - return ( - f"构建社会模拟时发生错误: {str(e)}", - "0", - f"❌ 错误: 构建失败 - {str(e)}", + try: + logging.info("正在运行社会模拟...") + answer, chat_history, token_info = run_society(society) + logging.info("社会模拟运行完成") + except Exception as e: + logging.error(f"运行社会模拟时发生错误: {str(e)}") + return ( + f"运行社会模拟时发生错误: {str(e)}", + "0", + f"❌ 错误: 运行失败 - {str(e)}", + ) + elif hasattr(module, "construct_workforce"): + try: + logging.info("正在构建 Workforce...") + workforce = module.construct_workforce() + processed_task = workforce.process_task(Task(content=question)) + answer = processed_task.result + token_info = {} + logging.info("Workforce 运行完成") + except Exception as e: + logging.error(f"运行 Workforce 时发生错误: {str(e)}") + return ( + f"运行 Workforce 时发生错误: {str(e)}", + "0", + f"❌ 错误: 运行失败 - {str(e)}", + ) + else: + logging.error( + f"模块 {module_path} 中既没有 construct_society,也没有 construct_workforce" ) - - # 运行社会模拟 - try: - logging.info("正在运行社会模拟...") - answer, chat_history, token_info = run_society(society) - logging.info("社会模拟运行完成") - except Exception as e: - logging.error(f"运行社会模拟时发生错误: {str(e)}") return ( - f"运行社会模拟时发生错误: {str(e)}", + f"模块 {module_path} 缺少受支持的入口函数", "0", - f"❌ 错误: 运行失败 - {str(e)}", + "❌ 错误: 模块接口不兼容", ) # 安全地获取令牌计数 @@ -615,6 +634,8 @@ def get_api_guide(key: str) -> str: return "https://help.aliyun.com/zh/model-studio/developer-reference/get-api-key" elif "deepseek" in key_lower: return "https://platform.deepseek.com/api_keys" + elif "atlascloud" in key_lower: + return "https://www.atlascloud.ai/docs/get-started" elif "ppio" in key_lower: return "https://ppinfra.com/settings/key-management?utm_source=github_owl" elif "google" in key_lower: From b10291aaa5a9f26e610eada57acbd025a18da264 Mon Sep 17 00:00:00 2001 From: lucaszhu-hue Date: Mon, 25 May 2026 17:10:59 +0800 Subject: [PATCH 2/3] docs: add Atlas Cloud README intro --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index da37ead1b..60bf28982 100644 --- a/README.md +++ b/README.md @@ -382,6 +382,10 @@ If you prefer using a `.env` file instead, you can: ``` > **Note**: For the minimal example (`examples/run_mini.py`), you only need to configure the LLM API key (e.g., `OPENAI_API_KEY`). +> 🎁 **[Atlas Cloud](https://www.atlascloud.ai/?utm_source=github&utm_medium=link&utm_campaign=owl)** is a full-modal AI inference platform that gives developers a single AI API to access video generation, image generation, and LLM APIs. Instead of managing multiple vendor integrations, you connect once and get unified access to 300+ curated models across all modalities. +> +> Check out Atlas Cloud's new coding plan promotion for more budget-friendly API access: [https://www.atlascloud.ai/console/coding-plan](https://www.atlascloud.ai/console/coding-plan) + ### **MCP Desktop Commander Setup** From 3988629b495f0e5fac44931b6e82e7b1820590ac Mon Sep 17 00:00:00 2001 From: lucaszhu-hue Date: Mon, 1 Jun 2026 23:06:02 +0800 Subject: [PATCH 3/3] docs: add Atlas 50 LLM model pool --- README.md | 8 ++++++++ README_ja.md | 20 ++++++++++++++++++++ README_zh.md | 20 ++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/README.md b/README.md index 60bf28982..98b139807 100644 --- a/README.md +++ b/README.md @@ -386,6 +386,14 @@ If you prefer using a `.env` file instead, you can: > > Check out Atlas Cloud's new coding plan promotion for more budget-friendly API access: [https://www.atlascloud.ai/console/coding-plan](https://www.atlascloud.ai/console/coding-plan) +Validated Atlas chat model pool for `ATLASCLOUD_MODEL_NAME`: + +- `deepseek-ai/DeepSeek-V3-0324`, `deepseek-ai/deepseek-r1-0528`, `moonshotai/Kimi-K2-Instruct`, `Qwen/Qwen3-Coder`, `Qwen/Qwen3-235B-A22B-Instruct-2507`, `deepseek-ai/DeepSeek-V3.1`, `moonshotai/Kimi-K2-Instruct-0905`, `Qwen/Qwen3-Next-80B-A3B-Instruct`, `Qwen/Qwen3-Next-80B-A3B-Thinking`, `Qwen/Qwen3-30B-A3B-Instruct-2507` +- `deepseek-ai/DeepSeek-V3.1-Terminus`, `deepseek-ai/DeepSeek-V3.2-Exp`, `zai-org/GLM-4.6`, `MiniMaxAI/MiniMax-M2`, `Qwen/Qwen3-VL-235B-A22B-Instruct`, `moonshotai/Kimi-K2-Thinking`, `google/gemini-2.5-flash`, `google/gemini-2.5-flash-lite`, `openai/gpt-5.1`, `openai/gpt-5.1-chat` +- `openai/gpt-4o`, `openai/gpt-4o-mini`, `openai/gpt-4.1`, `openai/gpt-4.1-mini`, `openai/gpt-4.1-nano`, `openai/o1`, `openai/o3`, `openai/o3-mini`, `openai/o4-mini`, `anthropic/claude-sonnet-4.5-20250929` +- `deepseek-ai/deepseek-v3.2`, `openai/gpt-5`, `openai/gpt-5-chat`, `openai/gpt-5-mini`, `openai/gpt-5-nano`, `openai/gpt-5.2`, `openai/gpt-5.2-chat`, `google/gemini-2.5-pro`, `anthropic/claude-opus-4.5-20251101`, `google/gemini-3-flash-preview` +- `zai-org/glm-4.7`, `minimaxai/minimax-m2.1`, `google/gemini-2.0-flash`, `qwen/qwen3-8b`, `qwen/qwen3-235b-a22b-thinking-2507`, `qwen/qwen3-vl-235b-a22b-thinking`, `qwen/qwen3-30b-a3b`, `qwen/qwen3-30b-a3b-thinking-2507`, `deepseek-ai/deepseek-ocr`, `xai/grok-4-0709` + ### **MCP Desktop Commander Setup** diff --git a/README_ja.md b/README_ja.md index 40d78c1ef..c8754564e 100644 --- a/README_ja.md +++ b/README_ja.md @@ -262,6 +262,26 @@ OWLは、さまざまなサービスと対話するために複数のAPIキー > **注意**:最小限の例(`examples/run_mini.py`)の場合、LLM APIキー(例:`OPENAI_API_KEY`)のみを設定する必要があります。 + Atlas Cloud の OpenAI 互換 LLM エンドポイントでは `/v1` サフィックスが必要です: + + ```bash + ATLASCLOUD_API_KEY="your-atlascloud-api-key-here" + ATLASCLOUD_API_BASE_URL="https://api.atlascloud.ai/v1" + ATLASCLOUD_MODEL_NAME="deepseek-ai/DeepSeek-V3-0324" + ``` + + > 🎁 **[Atlas Cloud](https://www.atlascloud.ai/?utm_source=github&utm_medium=link&utm_campaign=owl)** は、動画生成、画像生成、LLM API を単一の統合 API で利用できるフルモーダル AI 推論プラットフォームです。 + > + > 最新のコーディングプラン特典はこちら:https://www.atlascloud.ai/console/coding-plan + + `ATLASCLOUD_MODEL_NAME` 向けに検証済みの Atlas `50` モデルプール: + + - `deepseek-ai/DeepSeek-V3-0324`, `deepseek-ai/deepseek-r1-0528`, `moonshotai/Kimi-K2-Instruct`, `Qwen/Qwen3-Coder`, `Qwen/Qwen3-235B-A22B-Instruct-2507`, `deepseek-ai/DeepSeek-V3.1`, `moonshotai/Kimi-K2-Instruct-0905`, `Qwen/Qwen3-Next-80B-A3B-Instruct`, `Qwen/Qwen3-Next-80B-A3B-Thinking`, `Qwen/Qwen3-30B-A3B-Instruct-2507` + - `deepseek-ai/DeepSeek-V3.1-Terminus`, `deepseek-ai/DeepSeek-V3.2-Exp`, `zai-org/GLM-4.6`, `MiniMaxAI/MiniMax-M2`, `Qwen/Qwen3-VL-235B-A22B-Instruct`, `moonshotai/Kimi-K2-Thinking`, `google/gemini-2.5-flash`, `google/gemini-2.5-flash-lite`, `openai/gpt-5.1`, `openai/gpt-5.1-chat` + - `openai/gpt-4o`, `openai/gpt-4o-mini`, `openai/gpt-4.1`, `openai/gpt-4.1-mini`, `openai/gpt-4.1-nano`, `openai/o1`, `openai/o3`, `openai/o3-mini`, `openai/o4-mini`, `anthropic/claude-sonnet-4.5-20250929` + - `deepseek-ai/deepseek-v3.2`, `openai/gpt-5`, `openai/gpt-5-chat`, `openai/gpt-5-mini`, `openai/gpt-5-nano`, `openai/gpt-5.2`, `openai/gpt-5.2-chat`, `google/gemini-2.5-pro`, `anthropic/claude-opus-4.5-20251101`, `google/gemini-3-flash-preview` + - `zai-org/glm-4.7`, `minimaxai/minimax-m2.1`, `google/gemini-2.0-flash`, `qwen/qwen3-8b`, `qwen/qwen3-235b-a22b-thinking-2507`, `qwen/qwen3-vl-235b-a22b-thinking`, `qwen/qwen3-30b-a3b`, `qwen/qwen3-30b-a3b-thinking-2507`, `deepseek-ai/deepseek-ocr`, `xai/grok-4-0709` + ### オプション2:環境変数を直接設定 または、ターミナルで環境変数を直接設定することもできます: diff --git a/README_zh.md b/README_zh.md index 28871f1cc..76eb301b3 100644 --- a/README_zh.md +++ b/README_zh.md @@ -259,6 +259,26 @@ OWL 需要各种 API 密钥来与不同的服务进行交互。`owl/.env_templat > **注意**:对于最小示例(`examples/run_mini.py`),你只需要配置 LLM API 密钥(例如,`OPENAI_API_KEY`)。 + Atlas Cloud 的 OpenAI 兼容 LLM 端点需要保留 `/v1` 后缀: + + ```bash + ATLASCLOUD_API_KEY="your-atlascloud-api-key-here" + ATLASCLOUD_API_BASE_URL="https://api.atlascloud.ai/v1" + ATLASCLOUD_MODEL_NAME="deepseek-ai/DeepSeek-V3-0324" + ``` + + > 🎁 **[Atlas Cloud](https://www.atlascloud.ai/?utm_source=github&utm_medium=link&utm_campaign=owl)** 是一个全模态 AI 推理平台,开发者通过一个统一 API 即可访问视频生成、图像生成和 LLM API,无需维护多家厂商接入。 + > + > 可查看 Atlas Cloud 最新编程计划优惠活动:https://www.atlascloud.ai/console/coding-plan + + `ATLASCLOUD_MODEL_NAME` 已验证可用的 Atlas `50` 个聊天模型池: + + - `deepseek-ai/DeepSeek-V3-0324`, `deepseek-ai/deepseek-r1-0528`, `moonshotai/Kimi-K2-Instruct`, `Qwen/Qwen3-Coder`, `Qwen/Qwen3-235B-A22B-Instruct-2507`, `deepseek-ai/DeepSeek-V3.1`, `moonshotai/Kimi-K2-Instruct-0905`, `Qwen/Qwen3-Next-80B-A3B-Instruct`, `Qwen/Qwen3-Next-80B-A3B-Thinking`, `Qwen/Qwen3-30B-A3B-Instruct-2507` + - `deepseek-ai/DeepSeek-V3.1-Terminus`, `deepseek-ai/DeepSeek-V3.2-Exp`, `zai-org/GLM-4.6`, `MiniMaxAI/MiniMax-M2`, `Qwen/Qwen3-VL-235B-A22B-Instruct`, `moonshotai/Kimi-K2-Thinking`, `google/gemini-2.5-flash`, `google/gemini-2.5-flash-lite`, `openai/gpt-5.1`, `openai/gpt-5.1-chat` + - `openai/gpt-4o`, `openai/gpt-4o-mini`, `openai/gpt-4.1`, `openai/gpt-4.1-mini`, `openai/gpt-4.1-nano`, `openai/o1`, `openai/o3`, `openai/o3-mini`, `openai/o4-mini`, `anthropic/claude-sonnet-4.5-20250929` + - `deepseek-ai/deepseek-v3.2`, `openai/gpt-5`, `openai/gpt-5-chat`, `openai/gpt-5-mini`, `openai/gpt-5-nano`, `openai/gpt-5.2`, `openai/gpt-5.2-chat`, `google/gemini-2.5-pro`, `anthropic/claude-opus-4.5-20251101`, `google/gemini-3-flash-preview` + - `zai-org/glm-4.7`, `minimaxai/minimax-m2.1`, `google/gemini-2.0-flash`, `qwen/qwen3-8b`, `qwen/qwen3-235b-a22b-thinking-2507`, `qwen/qwen3-vl-235b-a22b-thinking`, `qwen/qwen3-30b-a3b`, `qwen/qwen3-30b-a3b-thinking-2507`, `deepseek-ai/deepseek-ocr`, `xai/grok-4-0709` + ### 选项 2:直接设置环境变量 或者,你可以直接在终端中设置环境变量: