diff --git a/zhenxun/services/llm/api.py b/zhenxun/services/llm/api.py index 3d0ef9fd..d9606f80 100644 --- a/zhenxun/services/llm/api.py +++ b/zhenxun/services/llm/api.py @@ -84,7 +84,7 @@ class AI: """ 初始化AI服务 - Args: + 参数: config: AI 配置. history: 可选的初始对话历史. """ @@ -144,7 +144,7 @@ class AI: 进行一次聊天对话。 此方法会自动使用和更新会话内的历史记录。 - Args: + 参数: message: 用户输入的消息。 model: 本次对话要使用的模型。 preserve_media_in_history: 是否在历史记录中保留原始多模态信息。 @@ -152,6 +152,9 @@ class AI: - False: 不保留,替换为占位符,提高效率。 - None (默认): 使用AI实例配置的默认值。 **kwargs: 传递给模型的其他参数。 + + 返回: + str: 模型的文本响应。 """ current_message: LLMMessage if isinstance(message, str): @@ -202,7 +205,18 @@ class AI: timeout: int | None = None, **kwargs: Any, ) -> dict[str, Any]: - """代码执行""" + """ + 代码执行 + + 参数: + prompt: 代码执行的提示词。 + model: 要使用的模型名称。 + timeout: 代码执行超时时间(秒)。 + **kwargs: 传递给模型的其他参数。 + + 返回: + dict[str, Any]: 包含执行结果的字典,包含text、code_executions和success字段。 + """ resolved_model = model or self.config.model or "Gemini/gemini-2.0-flash" config = CommonOverrides.gemini_code_execution() @@ -230,7 +244,18 @@ class AI: instruction: str = "", **kwargs: Any, ) -> dict[str, Any]: - """信息搜索 - 支持多模态输入""" + """ + 信息搜索 - 支持多模态输入 + + 参数: + query: 搜索查询内容,支持文本或多模态消息。 + model: 要使用的模型名称。 + instruction: 搜索指令。 + **kwargs: 传递给模型的其他参数。 + + 返回: + dict[str, Any]: 包含搜索结果的字典,包含text、sources、queries和success字段 + """ resolved_model = model or self.config.model or "Gemini/gemini-2.0-flash" config = CommonOverrides.gemini_grounding() @@ -291,6 +316,19 @@ class AI: ) -> LLMResponse: """ 内容分析 - 接收 UniMessage 物件进行多模态分析和工具呼叫。 + + 参数: + message: 要分析的消息内容(支持多模态)。 + instruction: 分析指令。 + model: 要使用的模型名称。 + use_tools: 要使用的工具名称列表。 + tool_config: 工具配置。 + activated_tools: 已激活的工具列表。 + history: 对话历史记录。 + **kwargs: 传递给模型的其他参数。 + + 返回: + LLMResponse: 模型的完整响应结果。 """ content_parts = await unimsg_to_llm_parts(message or UniMessage()) @@ -435,7 +473,18 @@ class AI: task_type: EmbeddingTaskType | str = EmbeddingTaskType.RETRIEVAL_DOCUMENT, **kwargs: Any, ) -> list[list[float]]: - """生成文本嵌入向量""" + """ + 生成文本嵌入向量 + + 参数: + texts: 要生成嵌入向量的文本或文本列表。 + model: 要使用的嵌入模型名称。 + task_type: 嵌入任务类型。 + **kwargs: 传递给模型的其他参数。 + + 返回: + list[list[float]]: 文本的嵌入向量列表。 + """ if isinstance(texts, str): texts = [texts] if not texts: @@ -475,7 +524,17 @@ async def chat( model: ModelName = None, **kwargs: Any, ) -> str: - """聊天对话便捷函数""" + """ + 聊天对话便捷函数 + + 参数: + message: 用户输入的消息。 + model: 要使用的模型名称。 + **kwargs: 传递给模型的其他参数。 + + 返回: + str: 模型的文本响应。 + """ ai = AI() return await ai.chat(message, model=model, **kwargs) @@ -487,7 +546,18 @@ async def code( timeout: int | None = None, **kwargs: Any, ) -> dict[str, Any]: - """代码执行便捷函数""" + """ + 代码执行便捷函数 + + 参数: + prompt: 代码执行的提示词。 + model: 要使用的模型名称。 + timeout: 代码执行超时时间(秒)。 + **kwargs: 传递给模型的其他参数。 + + 返回: + dict[str, Any]: 包含执行结果的字典。 + """ ai = AI() return await ai.code(prompt, model=model, timeout=timeout, **kwargs) @@ -499,7 +569,18 @@ async def search( instruction: str = "", **kwargs: Any, ) -> dict[str, Any]: - """信息搜索便捷函数""" + """ + 信息搜索便捷函数 + + 参数: + query: 搜索查询内容。 + model: 要使用的模型名称。 + instruction: 搜索指令。 + **kwargs: 传递给模型的其他参数。 + + 返回: + dict[str, Any]: 包含搜索结果的字典。 + """ ai = AI() return await ai.search(query, model=model, instruction=instruction, **kwargs) @@ -513,7 +594,20 @@ async def analyze( tool_config: dict[str, Any] | None = None, **kwargs: Any, ) -> str | LLMResponse: - """内容分析便捷函数""" + """ + 内容分析便捷函数 + + 参数: + message: 要分析的消息内容。 + instruction: 分析指令。 + model: 要使用的模型名称。 + use_tools: 要使用的工具名称列表。 + tool_config: 工具配置。 + **kwargs: 传递给模型的其他参数。 + + 返回: + str | LLMResponse: 分析结果。 + """ ai = AI() return await ai.analyze( message, @@ -535,7 +629,21 @@ async def analyze_multimodal( model: ModelName = None, **kwargs: Any, ) -> str | LLMResponse: - """多模态分析便捷函数""" + """ + 多模态分析便捷函数 + + 参数: + text: 文本内容。 + images: 图片文件路径、字节数据或列表。 + videos: 视频文件路径、字节数据或列表。 + audios: 音频文件路径、字节数据或列表。 + instruction: 分析指令。 + model: 要使用的模型名称。 + **kwargs: 传递给模型的其他参数。 + + 返回: + str | LLMResponse: 分析结果。 + """ message = create_multimodal_message( text=text, images=images, videos=videos, audios=audios ) @@ -552,7 +660,21 @@ async def search_multimodal( model: ModelName = None, **kwargs: Any, ) -> dict[str, Any]: - """多模态搜索便捷函数""" + """ + 多模态搜索便捷函数 + + 参数: + text: 文本内容。 + images: 图片文件路径、字节数据或列表。 + videos: 视频文件路径、字节数据或列表。 + audios: 音频文件路径、字节数据或列表。 + instruction: 搜索指令。 + model: 要使用的模型名称。 + **kwargs: 传递给模型的其他参数。 + + 返回: + dict[str, Any]: 包含搜索结果的字典。 + """ message = create_multimodal_message( text=text, images=images, videos=videos, audios=audios ) @@ -567,7 +689,18 @@ async def embed( task_type: EmbeddingTaskType | str = EmbeddingTaskType.RETRIEVAL_DOCUMENT, **kwargs: Any, ) -> list[list[float]]: - """文本嵌入便捷函数""" + """ + 文本嵌入便捷函数 + + 参数: + texts: 要生成嵌入向量的文本或文本列表。 + model: 要使用的嵌入模型名称。 + task_type: 嵌入任务类型。 + **kwargs: 传递给模型的其他参数。 + + 返回: + list[list[float]]: 文本的嵌入向量列表。 + """ ai = AI() return await ai.embed(texts, model=model, task_type=task_type, **kwargs) @@ -583,14 +716,14 @@ async def pipeline_chat( """ AI模型链式调用,前一个模型的输出作为下一个模型的输入。 - Args: + 参数: message: 初始输入消息(支持多模态) model_chain: 模型名称列表 initial_instruction: 第一个模型的系统指令 final_instruction: 最后一个模型的系统指令 **kwargs: 传递给模型实例的其他参数 - Returns: + 返回: LLMResponse: 最后一个模型的响应结果 """ if not model_chain: diff --git a/zhenxun/services/llm/config/providers.py b/zhenxun/services/llm/config/providers.py index 003edb10..fcdccaba 100644 --- a/zhenxun/services/llm/config/providers.py +++ b/zhenxun/services/llm/config/providers.py @@ -173,7 +173,7 @@ def get_default_providers() -> list[dict[str, Any]]: "api_base": "https://ark.cn-beijing.volces.com", "api_type": "ark", "models": [ - { + { "model_name": "ep-xxxxxxxxxxxxxxxx-xxxxx", }, ], @@ -184,9 +184,7 @@ def get_default_providers() -> list[dict[str, Any]]: "api_base": "https://api.siliconflow.cn", "api_type": "openai", "models": [ - { - "model_name": "deepseek-ai/DeepSeek-V3", - }, + {"model_name": "deepseek-ai/DeepSeek-V3"}, ], }, { diff --git a/zhenxun/services/llm/core.py b/zhenxun/services/llm/core.py index 77bc492d..56591701 100644 --- a/zhenxun/services/llm/core.py +++ b/zhenxun/services/llm/core.py @@ -180,7 +180,16 @@ async def create_llm_http_client( timeout: int = 180, proxy: str | None = None, ) -> LLMHttpClient: - """创建LLM HTTP客户端""" + """ + 创建LLM HTTP客户端 + + 参数: + timeout: 超时时间(秒)。 + proxy: 代理服务器地址。 + + 返回: + LLMHttpClient: HTTP客户端实例。 + """ config = HttpClientConfig(timeout=timeout, proxy=proxy) return LLMHttpClient(config) @@ -209,7 +218,20 @@ async def with_smart_retry( provider_name: str | None = None, **kwargs: Any, ) -> Any: - """智能重试装饰器 - 支持Key轮询和错误分类""" + """ + 智能重试装饰器 - 支持Key轮询和错误分类 + + 参数: + func: 要重试的异步函数。 + *args: 传递给函数的位置参数。 + retry_config: 重试配置。 + key_store: API密钥状态存储。 + provider_name: 提供商名称。 + **kwargs: 传递给函数的关键字参数。 + + 返回: + Any: 函数执行结果。 + """ config = retry_config or RetryConfig() last_exception: Exception | None = None failed_keys: set[str] = set() @@ -318,7 +340,17 @@ class KeyStatusStore: api_keys: list[str], exclude_keys: set[str] | None = None, ) -> str | None: - """获取下一个可用的API密钥(轮询策略)""" + """ + 获取下一个可用的API密钥(轮询策略) + + 参数: + provider_name: 提供商名称。 + api_keys: API密钥列表。 + exclude_keys: 要排除的密钥集合。 + + 返回: + str | None: 可用的API密钥,如果没有可用密钥则返回None。 + """ if not api_keys: return None @@ -362,7 +394,13 @@ class KeyStatusStore: logger.debug(f"记录API密钥成功使用: {self._get_key_id(api_key)}") async def record_failure(self, api_key: str, status_code: int | None): - """记录失败使用""" + """ + 记录失败使用 + + 参数: + api_key: API密钥。 + status_code: HTTP状态码。 + """ key_id = self._get_key_id(api_key) async with self._lock: if status_code in [401, 403]: @@ -380,7 +418,15 @@ class KeyStatusStore: logger.info(f"重置API密钥状态: {self._get_key_id(api_key)}") async def get_key_stats(self, api_keys: list[str]) -> dict[str, dict]: - """获取密钥使用统计""" + """ + 获取密钥使用统计 + + 参数: + api_keys: API密钥列表。 + + 返回: + dict[str, dict]: 密钥统计信息字典。 + """ stats = {} async with self._lock: for key in api_keys: diff --git a/zhenxun/services/llm/manager.py b/zhenxun/services/llm/manager.py index e5fb298d..87bf45ad 100644 --- a/zhenxun/services/llm/manager.py +++ b/zhenxun/services/llm/manager.py @@ -174,14 +174,15 @@ def get_configured_providers() -> list[ProviderConfig]: def find_model_config( provider_name: str, model_name: str ) -> tuple[ProviderConfig, ModelDetail] | None: - """在配置中查找指定的 Provider 和 ModelDetail + """ + 在配置中查找指定的 Provider 和 ModelDetail - Args: + 参数: provider_name: 提供商名称 model_name: 模型名称 - Returns: - 找到的 (ProviderConfig, ModelDetail) 元组,未找到则返回 None + 返回: + tuple[ProviderConfig, ModelDetail] | None: 找到的配置元组,未找到则返回 None """ providers = get_configured_providers() @@ -222,10 +223,11 @@ def _get_model_identifiers(provider_name: str, model_detail: ModelDetail) -> lis def list_model_identifiers() -> dict[str, list[str]]: - """列出所有模型的可用标识符 + """ + 列出所有模型的可用标识符 - Returns: - 字典,键为模型的完整名称,值为该模型的所有可用标识符列表 + 返回: + dict[str, list[str]]: 字典,键为模型的完整名称,值为该模型的所有可用标识符列表 """ providers = get_configured_providers() result = {} @@ -249,7 +251,16 @@ async def get_model_instance( provider_model_name: str | None = None, override_config: dict[str, Any] | None = None, ) -> LLMModel: - """根据 'ProviderName/ModelName' 字符串获取并实例化 LLMModel (异步版本)""" + """ + 根据 'ProviderName/ModelName' 字符串获取并实例化 LLMModel (异步版本) + + 参数: + provider_model_name: 模型名称,格式为 'ProviderName/ModelName'。 + override_config: 覆盖配置字典。 + + 返回: + LLMModel: 模型实例。 + """ cache_key = _make_cache_key(provider_model_name, override_config) cached_model = _get_cached_model(cache_key) if cached_model: @@ -363,7 +374,15 @@ def get_global_default_model_name() -> str | None: def set_global_default_model_name(provider_model_name: str | None) -> bool: - """设置全局默认模型名称""" + """ + 设置全局默认模型名称 + + 参数: + provider_model_name: 模型名称,格式为 'ProviderName/ModelName'。 + + 返回: + bool: 设置是否成功。 + """ if provider_model_name: prov_name, mod_name = parse_provider_model_string(provider_model_name) if not prov_name or not mod_name or not find_model_config(prov_name, mod_name): @@ -383,7 +402,12 @@ def set_global_default_model_name(provider_model_name: str | None) -> bool: async def get_key_usage_stats() -> dict[str, Any]: - """获取所有Provider的Key使用统计""" + """ + 获取所有Provider的Key使用统计 + + 返回: + dict[str, Any]: 包含所有Provider的Key使用统计信息。 + """ providers = get_configured_providers() stats = {} @@ -406,7 +430,16 @@ async def get_key_usage_stats() -> dict[str, Any]: async def reset_key_status(provider_name: str, api_key: str | None = None) -> bool: - """重置指定Provider的Key状态""" + """ + 重置指定Provider的Key状态 + + 参数: + provider_name: 提供商名称。 + api_key: 要重置的特定API密钥,如果为None则重置所有密钥。 + + 返回: + bool: 重置是否成功。 + """ providers = get_configured_providers() target_provider = None diff --git a/zhenxun/services/llm/service.py b/zhenxun/services/llm/service.py index 99c84519..587b15cc 100644 --- a/zhenxun/services/llm/service.py +++ b/zhenxun/services/llm/service.py @@ -46,7 +46,17 @@ class LLMModelBase(ABC): history: list[dict[str, str]] | None = None, **kwargs: Any, ) -> str: - """生成文本""" + """ + 生成文本 + + 参数: + prompt: 输入提示词。 + history: 对话历史记录。 + **kwargs: 其他参数。 + + 返回: + str: 生成的文本。 + """ pass @abstractmethod @@ -58,7 +68,19 @@ class LLMModelBase(ABC): tool_choice: str | dict[str, Any] | None = None, **kwargs: Any, ) -> LLMResponse: - """生成高级响应""" + """ + 生成高级响应 + + 参数: + messages: 消息列表。 + config: 生成配置。 + tools: 工具列表。 + tool_choice: 工具选择策略。 + **kwargs: 其他参数。 + + 返回: + LLMResponse: 模型响应。 + """ pass @abstractmethod @@ -68,7 +90,17 @@ class LLMModelBase(ABC): task_type: EmbeddingTaskType | str = EmbeddingTaskType.RETRIEVAL_DOCUMENT, **kwargs: Any, ) -> list[list[float]]: - """生成文本嵌入向量""" + """ + 生成文本嵌入向量 + + 参数: + texts: 文本列表。 + task_type: 嵌入任务类型。 + **kwargs: 其他参数。 + + 返回: + list[list[float]]: 嵌入向量列表。 + """ pass @@ -187,6 +219,16 @@ class LLMModel(LLMModelBase): 4. 处理HTTP错误和API特定错误。 5. 记录密钥使用状态。 6. 解析成功的响应。 + + 参数: + prepare_request_func: 准备请求的函数。 + parse_response_func: 解析响应的函数。 + http_client: HTTP客户端。 + failed_keys: 失败的密钥集合。 + log_context: 日志上下文。 + + 返回: + Any: 解析后的响应数据。 """ api_key = await self._select_api_key(failed_keys) @@ -445,7 +487,17 @@ class LLMModel(LLMModelBase): history: list[dict[str, str]] | None = None, **kwargs: Any, ) -> str: - """生成文本 - 通过 generate_response 实现""" + """ + 生成文本 - 通过 generate_response 实现 + + 参数: + prompt: 输入提示词。 + history: 对话历史记录。 + **kwargs: 其他参数。 + + 返回: + str: 生成的文本。 + """ self._check_not_closed() messages: list[LLMMessage] = [] @@ -487,7 +539,17 @@ class LLMModel(LLMModelBase): **kwargs: Any, ) -> LLMResponse: """ - 生成高级响应。 + 生成高级响应 + + 参数: + messages: 消息列表。 + config: 生成配置。 + tools: 工具列表。 + tool_choice: 工具选择策略。 + **kwargs: 其他参数。 + + 返回: + LLMResponse: 模型响应。 """ self._check_not_closed() @@ -557,7 +619,17 @@ class LLMModel(LLMModelBase): task_type: EmbeddingTaskType | str = EmbeddingTaskType.RETRIEVAL_DOCUMENT, **kwargs: Any, ) -> list[list[float]]: - """生成文本嵌入向量""" + """ + 生成文本嵌入向量 + + 参数: + texts: 文本列表。 + task_type: 嵌入任务类型。 + **kwargs: 其他参数。 + + 返回: + list[list[float]]: 嵌入向量列表。 + """ self._check_not_closed() if not texts: return [] diff --git a/zhenxun/services/llm/tools/registry.py b/zhenxun/services/llm/tools/registry.py index a4b8222e..daa0c796 100644 --- a/zhenxun/services/llm/tools/registry.py +++ b/zhenxun/services/llm/tools/registry.py @@ -57,7 +57,7 @@ class ToolRegistry: """ 装饰器:在代码中注册一个简单的、无状态的函数工具。 - Args: + 参数: name: 工具的唯一名称。 description: 工具功能的描述。 parameters: OpenAPI格式的函数参数schema的properties部分。 @@ -86,7 +86,7 @@ class ToolRegistry: """ 装饰器:注册一个MCP工具及其配置模型。 - Args: + 参数: name: 工具的唯一名称,必须与配置文件中的名称匹配。 config_model: 一个Pydantic模型,用于定义和验证该工具的 `mcp_config`。 """ @@ -113,7 +113,7 @@ class ToolRegistry: """ 在代码中注册一个 MCP 会话工厂,将其与配置中的工具名称关联。 - Args: + 参数: name: 工具的唯一名称,必须与配置文件中的名称匹配。 factory: 一个返回异步生成器的可调用对象(会话工厂)。 """ diff --git a/zhenxun/services/llm/types/protocols.py b/zhenxun/services/llm/types/protocols.py index 49f5488c..1ab1ace2 100644 --- a/zhenxun/services/llm/types/protocols.py +++ b/zhenxun/services/llm/types/protocols.py @@ -15,10 +15,10 @@ class MCPCompatible(Protocol): """ 将此MCP会话转换为特定LLM提供商API所需的工具格式。 - Args: + 参数: api_type: 目标API的类型 (例如 'gemini', 'openai')。 - Returns: - 一个字典,代表可以在API请求中使用的工具定义。 + 返回: + dict[str, Any]: 一个字典,代表可以在API请求中使用的工具定义。 """ ... diff --git a/zhenxun/services/llm/utils.py b/zhenxun/services/llm/utils.py index f46c3f21..d5e9177d 100644 --- a/zhenxun/services/llm/utils.py +++ b/zhenxun/services/llm/utils.py @@ -28,6 +28,12 @@ async def unimsg_to_llm_parts(message: UniMessage) -> list[LLMContentPart]: """ 将 UniMessage 实例转换为一个 LLMContentPart 列表。 这是处理多模态输入的核心转换逻辑。 + + 参数: + message: 要转换的UniMessage实例。 + + 返回: + list[LLMContentPart]: 转换后的内容部分列表。 """ parts: list[LLMContentPart] = [] for seg in message: @@ -141,16 +147,18 @@ def create_multimodal_message( audio_mimetypes: list[str] | str | None = None, ) -> UniMessage: """ - 创建多模态消息的便捷函数。 + 创建多模态消息的便捷函数 - Args: + 参数: text: 文本内容 images: 图片数据,支持路径、字节数据或URL videos: 视频数据 audios: 音频数据 - *_mimetypes: 对应媒体的MIME类型,bytes数据时需要指定 + image_mimetypes: 图片MIME类型,bytes数据时需要指定 + video_mimetypes: 视频MIME类型,bytes数据时需要指定 + audio_mimetypes: 音频MIME类型,bytes数据时需要指定 - Returns: + 返回: UniMessage: 构建好的多模态消息 """ message = UniMessage() @@ -203,6 +211,12 @@ def message_to_unimessage(message: PlatformMessage) -> UniMessage: """ 将平台特定的 Message 对象转换为通用的 UniMessage。 主要用于处理引用消息等未被自动转换的消息体。 + + 参数: + message: 平台特定的Message对象。 + + 返回: + UniMessage: 转换后的通用消息对象。 """ uni_segments = [] for seg in message: @@ -224,7 +238,13 @@ def message_to_unimessage(message: PlatformMessage) -> UniMessage: def _sanitize_request_body_for_logging(body: dict) -> dict: """ - 净化请求体用于日志记录,移除大数据字段并添加摘要信息。 + 净化请求体用于日志记录,移除大数据字段并添加摘要信息 + + 参数: + body: 原始请求体字典。 + + 返回: + dict: 净化后的请求体字典。 """ try: sanitized_body = copy.deepcopy(body)