🎨 feat(llm): 统一LLM服务函数文档格式

This commit is contained in:
webjoin111 2025-07-07 14:10:51 +08:00
parent bfb3170b60
commit a348c3d276
8 changed files with 353 additions and 51 deletions

View File

@ -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]: 包含执行结果的字典包含textcode_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]: 包含搜索结果的字典包含textsourcesqueries和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:

View File

@ -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"},
],
},
{

View File

@ -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:

View File

@ -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

View File

@ -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 []

View File

@ -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: 一个返回异步生成器的可调用对象会话工厂
"""

View File

@ -15,10 +15,10 @@ class MCPCompatible(Protocol):
"""
将此MCP会话转换为特定LLM提供商API所需的工具格式
Args:
参数:
api_type: 目标API的类型 (例如 'gemini', 'openai')
Returns:
一个字典代表可以在API请求中使用的工具定义
返回:
dict[str, Any]: 一个字典代表可以在API请求中使用的工具定义
"""
...

View File

@ -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)