* ✨ feat(llm): 全面重构LLM服务模块,增强多模态与工具支持 🚀 核心功能增强 - 多模型链式调用:新增 `pipeline_chat` 支持复杂任务流处理 - 扩展提供商支持:新增 ARK(火山方舟)、SiliconFlow(硅基流动) 适配器 - 多模态处理增强:支持URL媒体文件下载转换,提升输入灵活性 - 历史对话支持:AI.analyze 方法支持历史消息上下文和可选 UniMessage 参数 - 文本嵌入功能:新增 `embed`、`analyze_multimodal`、`search_multimodal` 等API - 模型能力系统:新增 `ModelCapabilities` 统一管理模型特性(多模态、工具调用等) 🔧 架构重构与优化 - MCP工具系统重构:配置独立化至 `data/llm/mcp_tools.json`,预置常用工具 - API调用逻辑统一:提取通用 `_perform_api_call` 方法,消除代码重复 - 跨平台兼容:Windows平台MCP工具npx命令自动包装处理 - HTTP客户端增强:兼容不同版本httpx代理配置(0.28+版本适配) 🛠️ API与配置完善 - 统一返回类型:`AI.analyze` 统一返回 `LLMResponse` 类型 - 消息转换工具:新增 `message_to_unimessage` 转换函数 - Gemini适配器增强:URL图片下载编码、动态安全阈值配置 - 缓存管理:新增模型实例缓存和管理功能 - 配置预设:扩展 CommonOverrides 预设配置选项 - 历史管理优化:支持多模态内容占位符替换,提升效率 📚 文档与开发体验 - README全面重写:新增完整使用指南、API参考和架构概览 - 文档内容扩充:补充嵌入模型、缓存管理、工具注册等功能说明 - 日志记录增强:支持详细调试信息输出 - API简化:移除冗余函数,优化接口设计 * 🎨 feat(llm): 统一LLM服务函数文档格式 * ✨ feat(llm): 添加新模型并简化提供者配置加载 * 🚨 auto fix by pre-commit hooks --------- Co-authored-by: webjoin111 <455457521@qq.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
24 KiB
🚀 Zhenxun LLM 服务模块
本模块是一个功能强大、高度可扩展的统一大语言模型(LLM)服务框架。它旨在将各种不同的 LLM 提供商(如 OpenAI、Gemini、智谱AI等)的 API 封装在一个统一、易于使用的接口之后,让开发者可以无缝切换和使用不同的模型,同时支持多模态输入、工具调用、智能重试和缓存等高级功能。
目录
✨ 核心特性
- 多提供商支持: 内置对 OpenAI、Gemini、智谱AI 等多种 API 的适配器,并可通过通用 OpenAI 兼容适配器轻松接入更多服务。
- 统一的 API: 提供从简单到高级的三层 API,满足不同场景的需求,无论是快速聊天还是复杂的分析任务。
- 强大的工具调用 (Function Calling): 支持标准的函数调用和实验性的 MCP (Model Context Protocol) 工具,让 LLM 能够与外部世界交互。
- 多模态能力: 无缝集成
UniMessage,轻松处理文本、图片、音频、视频等混合输入,支持多模态搜索和分析。 - 文本嵌入向量化: 提供统一的嵌入接口,支持语义搜索、相似度计算和文本聚类等应用。
- 智能重试与 Key 轮询: 内置健壮的请求重试逻辑,当 API Key 失效或达到速率限制时,能自动轮询使用备用 Key。
- 灵活的配置系统: 通过配置文件和代码中的
LLMGenerationConfig,可以精细控制模型的生成行为(如温度、最大Token等)。 - 高性能缓存机制: 内置模型实例缓存,减少重复初始化开销,提供缓存管理和监控功能。
- 丰富的配置预设: 提供
CommonOverrides类,包含创意模式、精确模式、JSON输出等多种常用配置预设。 - 可扩展的适配器架构: 开发者可以轻松编写自己的适配器来支持新的 LLM 服务。
🧠 核心概念
- 适配器 (Adapter): 这是连接我们统一接口和特定 LLM 提供商 API 的“翻译官”。例如,
GeminiAdapter知道如何将我们的标准请求格式转换为 Google Gemini API 需要的格式,并解析其响应。 - 模型实例 (
LLMModel): 这是框架中的核心操作对象,代表一个具体配置好的模型。例如,一个LLMModel实例可能代表使用特定 API Key、特定代理的Gemini/gemini-1.5-pro。所有与模型交互的操作都通过这个类的实例进行。 - 生成配置 (
LLMGenerationConfig): 这是一个数据类,用于控制模型在生成内容时的行为,例如temperature(温度)、max_tokens(最大输出长度)、response_format(响应格式) 等。 - 工具 (Tool): 代表一个可以让 LLM 调用的函数。它可以是一个简单的 Python 函数,也可以是一个更复杂的、有状态的 MCP 服务。
- 多模态内容 (
LLMContentPart): 这是处理多模态输入的基础单元,一个LLMMessage可以包含多个LLMContentPart,如一个文本部分和多个图片部分。
🛠️ 安装与配置
该模块作为 zhenxun 项目的一部分被集成,无需额外安装。核心配置主要涉及两个文件。
服务提供商配置 (config.yaml)
核心配置位于项目 /data/config.yaml 文件中的 AI 部分。
# /data/configs/config.yaml
AI:
# (可选) 全局默认模型,格式: "ProviderName/ModelName"
default_model_name: Gemini/gemini-2.5-flash
# (可选) 全局代理设置
proxy: http://127.0.0.1:7890
# (可选) 全局超时设置 (秒)
timeout: 180
# (可选) Gemini 的安全过滤阈值
gemini_safety_threshold: BLOCK_MEDIUM_AND_ABOVE
# 配置你的AI服务提供商
PROVIDERS:
# 示例1: Gemini
- name: Gemini
api_key:
- "AIzaSy_KEY_1" # 支持多个Key,会自动轮询
- "AIzaSy_KEY_2"
api_base: https://generativelanguage.googleapis.com
api_type: gemini
models:
- model_name: gemini-2.5-pro
- model_name: gemini-2.5-flash
- model_name: gemini-2.0-flash
- model_name: embedding-001
is_embedding_model: true # 标记为嵌入模型
max_input_tokens: 2048 # 嵌入模型特有配置
# 示例2: 智谱AI
- name: GLM
api_key: "YOUR_ZHIPU_API_KEY"
api_type: zhipu # 适配器类型
models:
- model_name: glm-4-flash
- model_name: glm-4-plus
temperature: 0.8 # 可以为特定模型设置默认温度
# 示例3: 一个兼容OpenAI的自定义服务
- name: MyOpenAIService
api_key: "sk-my-custom-key"
api_base: "http://localhost:8080/v1"
api_type: general_openai_compat # 使用通用OpenAI兼容适配器
models:
- model_name: Llama3-8B-Instruct
max_tokens: 2048 # 可以为特定模型设置默认最大Token
MCP 工具配置 (mcp_tools.json)
此文件位于 /data/llm/mcp_tools.json,用于配置通过 MCP 协议启动的外部工具服务。如果文件不存在,系统会自动创建一个包含示例的默认文件。
{
"mcpServers": {
"baidu-map": {
"command": "npx",
"args": ["-y", "@baidumap/mcp-server-baidu-map"],
"env": {
"BAIDU_MAP_API_KEY": "<YOUR_BAIDU_MAP_API_KEY>"
},
"description": "百度地图工具,提供地理编码、路线规划等功能。"
},
"sequential-thinking": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-sequential-thinking"],
"description": "顺序思维工具,用于帮助模型进行多步骤推理。"
}
}
}
📘 使用指南
我们提供了三层 API,以满足从简单到复杂的各种需求。
等级1: 便捷函数 - 最快速的调用方式
这些函数位于 zhenxun.services.llm 包的顶层,为你处理了所有的底层细节。
from zhenxun.services.llm import chat, search, code, pipeline_chat, embed, analyze_multimodal, search_multimodal
from zhenxun.services.llm.utils import create_multimodal_message
# 1. 纯文本聊天
response_text = await chat("你好,请用苏轼的风格写一首关于月亮的诗。")
print(response_text)
# 2. 带网络搜索的问答
search_result = await search("马斯克的Neuralink公司最近有什么新进展?")
print(search_result['text'])
# print(search_result['sources']) # 查看信息来源
# 3. 执行代码
code_result = await code("用Python画一个心形图案。")
print(code_result['text']) # 包含代码和解释的回复
# 4. 链式调用
image_msg = create_multimodal_message(images="path/to/cat.jpg")
final_poem = await pipeline_chat(
message=image_msg,
model_chain=["Gemini/gemini-1.5-pro", "GLM/glm-4-flash"],
initial_instruction="详细描述这只猫的外观和姿态。",
final_instruction="将上述描述凝练成一首可爱的短诗。"
)
print(final_poem.text)
# 5. 文本嵌入向量生成
texts_to_embed = ["今天天气真好", "我喜欢打篮球", "这部电影很感人"]
vectors = await embed(texts_to_embed, model="Gemini/embedding-001")
print(f"生成了 {len(vectors)} 个向量,每个向量维度: {len(vectors[0])}")
# 6. 多模态分析便捷函数
response = await analyze_multimodal(
text="请分析这张图片中的内容",
images="path/to/image.jpg",
model="Gemini/gemini-1.5-pro"
)
print(response)
# 7. 多模态搜索便捷函数
search_result = await search_multimodal(
text="搜索与这张图片相关的信息",
images="path/to/image.jpg",
model="Gemini/gemini-1.5-pro"
)
print(search_result['text'])
等级2: AI 会话类 - 管理有状态的对话
当你需要进行有上下文的、连续的对话时,AI 类是你的最佳选择。
from zhenxun.services.llm.api import AI, AIConfig
# 初始化一个AI会话,可以传入自定义配置
ai_config = AIConfig(model="GLM/glm-4-flash", temperature=0.7)
ai_session = AI(config=ai_config)
# 更完整的AIConfig配置示例
advanced_config = AIConfig(
model="GLM/glm-4-flash",
default_embedding_model="Gemini/embedding-001", # 默认嵌入模型
temperature=0.7,
max_tokens=2000,
enable_cache=True, # 启用模型缓存
enable_code=True, # 启用代码执行功能
enable_search=True, # 启用搜索功能
timeout=180, # 请求超时时间(秒)
# Gemini特定配置选项
enable_gemini_json_mode=True, # 启用Gemini JSON模式
enable_gemini_thinking=True, # 启用Gemini 思考模式
enable_gemini_safe_mode=True, # 启用Gemini 安全模式
enable_gemini_multimodal=True, # 启用Gemini 多模态优化
enable_gemini_grounding=True, # 启用Gemini 信息来源关联
)
advanced_session = AI(config=advanced_config)
# 进行连续对话
await ai_session.chat("我最喜欢的城市是成都。")
response = await ai_session.chat("它有什么好吃的?") # AI会知道“它”指的是成都
print(response)
# 在同一个会话中,临时切换模型进行一次调用
response_gemini = await ai_session.chat(
"从AI的角度分析一下成都的科技发展潜力。",
model="Gemini/gemini-1.5-pro"
)
print(response_gemini)
# 清空历史,开始新一轮对话
ai_session.clear_history()
等级3: 直接模型控制 - get_model_instance
这是最底层的 API,为你提供对模型实例的完全控制。推荐使用 async with 语句来优雅地管理模型实例的生命周期。
from zhenxun.services.llm import get_model_instance, LLMMessage
from zhenxun.services.llm.config import LLMGenerationConfig
# 1. 获取模型实例
# get_model_instance 返回一个异步上下文管理器
async with await get_model_instance("Gemini/gemini-1.5-pro") as model:
# 2. 准备消息列表
messages = [
LLMMessage.system("你是一个专业的营养师。"),
LLMMessage.user("我今天吃了汉堡和可乐,请给我一些健康建议。")
]
# 3. (可选) 定义本次调用的生成配置
gen_config = LLMGenerationConfig(
temperature=0.2, # 更严谨的回复
max_tokens=300
)
# 4. 生成响应
response = await model.generate_response(messages, config=gen_config)
# 5. 处理响应
print(response.text)
if response.usage_info:
print(f"Token 消耗: {response.usage_info['total_tokens']}")
🌟 功能深度剖析
精细化控制模型生成 (LLMGenerationConfig 与 CommonOverrides)
LLMGenerationConfig: 一个 Pydantic 模型,用于覆盖模型的默认生成参数。CommonOverrides: 一个包含多种常用配置预设的类,如creative(),precise(),gemini_json()等,能极大地简化配置过程。
from zhenxun.services.llm.config import LLMGenerationConfig, CommonOverrides
# LLMGenerationConfig 完整参数示例
comprehensive_config = LLMGenerationConfig(
temperature=0.7, # 生成温度 (0.0-2.0)
max_tokens=1000, # 最大输出token数
top_p=0.9, # 核采样参数 (0.0-1.0)
top_k=40, # Top-K采样参数
frequency_penalty=0.0, # 频率惩罚 (-2.0-2.0)
presence_penalty=0.0, # 存在惩罚 (-2.0-2.0)
repetition_penalty=1.0, # 重复惩罚 (0.0-2.0)
stop=["END", "\n\n"], # 停止序列
response_format={"type": "json_object"}, # 响应格式
response_mime_type="application/json", # Gemini专用MIME类型
response_schema={...}, # JSON响应模式
thinking_budget=0.8, # Gemini思考预算 (0.0-1.0)
enable_code_execution=True, # 启用代码执行
safety_settings={...}, # 安全设置
response_modalities=["TEXT"], # 响应模态类型
)
# 创建一个配置,要求模型输出JSON格式
json_config = LLMGenerationConfig(
temperature=0.1,
response_mime_type="application/json" # Gemini特有
)
# 对于OpenAI兼容API,可以这样做
json_config_openai = LLMGenerationConfig(
temperature=0.1,
response_format={"type": "json_object"}
)
# 使用框架提供的预设 - 基础预设
safe_config = CommonOverrides.gemini_safe()
creative_config = CommonOverrides.creative()
precise_config = CommonOverrides.precise()
balanced_config = CommonOverrides.balanced()
# 更多实用预设
concise_config = CommonOverrides.concise(max_tokens=50) # 简洁模式
detailed_config = CommonOverrides.detailed(max_tokens=3000) # 详细模式
json_config = CommonOverrides.gemini_json() # JSON输出模式
thinking_config = CommonOverrides.gemini_thinking(budget=0.8) # 思考模式
# Gemini特定高级预设
code_config = CommonOverrides.gemini_code_execution() # 代码执行模式
grounding_config = CommonOverrides.gemini_grounding() # 信息来源关联模式
multimodal_config = CommonOverrides.gemini_multimodal() # 多模态优化模式
# 在调用时传入config对象
# await model.generate_response(messages, config=json_config)
赋予模型能力:工具使用 (Function Calling)
工具调用让 LLM 能够与外部函数、API 或服务进行交互。
1. 注册工具
函数工具注册
使用 @tool_registry.function_tool 装饰器注册一个简单的函数工具。
from zhenxun.services.llm import tool_registry
@tool_registry.function_tool(
name="query_stock_price",
description="查询指定股票代码的当前价格。",
parameters={
"stock_symbol": {"type": "string", "description": "股票代码, 例如 'AAPL' 或 'GOOG'"}
},
required=["stock_symbol"]
)
async def query_stock_price(stock_symbol: str) -> dict:
"""一个查询股票价格的伪函数"""
print(f"--- 正在查询 {stock_symbol} 的价格 ---")
if stock_symbol == "AAPL":
return {"symbol": "AAPL", "price": 175.50, "currency": "USD"}
return {"error": "未知的股票代码"}
MCP工具注册
对于更复杂的、有状态的工具,可以使用 @tool_registry.mcp_tool 装饰器注册MCP工具。
from contextlib import asynccontextmanager
from pydantic import BaseModel
from zhenxun.services.llm import tool_registry
# 定义工具的配置模型
class MyToolConfig(BaseModel):
api_key: str
endpoint: str
timeout: int = 30
# 注册MCP工具
@tool_registry.mcp_tool(name="my-custom-tool", config_model=MyToolConfig)
@asynccontextmanager
async def my_tool_factory(config: MyToolConfig):
"""MCP工具工厂函数"""
# 初始化工具会话
session = MyToolSession(config)
try:
await session.initialize()
yield session
finally:
await session.cleanup()
2. 调用带工具的模型
在 analyze 或 generate_response 中使用 use_tools 参数。框架会自动处理整个调用流程。
from zhenxun.services.llm.api import analyze
from nonebot_plugin_alconna.uniseg import UniMessage
response = await analyze(
UniMessage("帮我查一下苹果公司的股价"),
use_tools=["query_stock_price"]
)
print(response.text) # 输出应为 "苹果公司(AAPL)的当前股价为175.5美元。" 或类似内容
处理多模态输入
本模块通过 UniMessage 和 LLMContentPart 完美支持多模态。
create_multimodal_message: 推荐的、用于从代码中便捷地创建多模态消息的函数。unimsg_to_llm_parts: 框架内部使用的核心转换函数,将UniMessage的各个段(文本、图片等)转换为LLMContentPart列表。
from zhenxun.services.llm import analyze
from zhenxun.services.llm.utils import create_multimodal_message
from pathlib import Path
# 从本地文件创建消息
message = create_multimodal_message(
text="请分析这张图片和这个视频。图片里是什么?视频里发生了什么?",
images=[Path("path/to/your/image.jpg")],
videos=[Path("path/to/your/video.mp4")]
)
response = await analyze(message, model="Gemini/gemini-1.5-pro")
print(response.text)
🔧 高级主题与扩展
模型与密钥管理
模块提供了一些工具函数来管理你的模型配置。
from zhenxun.services.llm.manager import (
list_available_models,
list_embedding_models,
set_global_default_model_name,
get_global_default_model_name,
get_key_usage_stats,
reset_key_status
)
from zhenxun.services.llm import clear_model_cache, get_cache_stats
# 列出所有在config.yaml中配置的可用模型
models = list_available_models()
print([m['full_name'] for m in models])
# 列出所有可用的嵌入模型
embedding_models = list_embedding_models()
print([m['full_name'] for m in embedding_models])
# 动态设置全局默认模型
success = set_global_default_model_name("GLM/glm-4-plus")
# 获取所有Key的使用统计
stats = await get_key_usage_stats()
print(stats)
# 重置'Gemini'提供商的所有Key
await reset_key_status("Gemini")
缓存管理
模块提供了模型实例缓存功能,可以提高性能并减少重复初始化的开销。
from zhenxun.services.llm import clear_model_cache, get_cache_stats
# 获取缓存统计信息
stats = get_cache_stats()
print(f"缓存大小: {stats['cache_size']}/{stats['max_cache_size']}")
print(f"缓存TTL: {stats['cache_ttl']}秒")
print(f"已缓存模型: {stats['cached_models']}")
# 清空模型缓存(在内存不足或需要强制重新初始化时使用)
clear_model_cache()
print("模型缓存已清空")
错误处理 (LLMException)
所有模块内的预期错误都会被包装成 LLMException,方便统一处理。
from zhenxun.services.llm import chat, LLMException, LLMErrorCode
try:
await chat("test", model="InvalidProvider/invalid_model")
except LLMException as e:
print(f"捕获到LLM异常: {e}")
print(f"错误码: {e.code}") # 例如 LLMErrorCode.MODEL_NOT_FOUND
print(f"用户友好提示: {e.user_friendly_message}")
自定义适配器 (Adapter)
如果你想支持一个新的、非 OpenAI 兼容的 LLM 服务,可以通过实现自己的适配器来完成。
-
创建适配器类: 继承
BaseAdapter并实现其抽象方法。# my_adapters/custom_adapter.py from zhenxun.services.llm.adapters import BaseAdapter, RequestData, ResponseData class MyCustomAdapter(BaseAdapter): @property def api_type(self) -> str: return "my_custom_api" @property def supported_api_types(self) -> list[str]: return ["my_custom_api"] # ... 实现 prepare_advanced_request, parse_response 等方法 -
注册适配器: 在你的插件初始化代码中注册你的适配器。
from zhenxun.services.llm.adapters import register_adapter from .my_adapters.custom_adapter import MyCustomAdapter register_adapter(MyCustomAdapter()) -
在
config.yaml中使用:AI: PROVIDERS: - name: MyAwesomeLLM api_key: "my-secret-key" api_type: "my_custom_api" # 关键!使用你注册的 api_type # ...
📚 API 快速参考
| 类/函数 | 主要用途 | 推荐场景 |
|---|---|---|
llm.chat() |
进行简单的、无状态的文本对话。 | 快速实现单轮问答。 |
llm.search() |
执行带网络搜索的问答。 | 需要最新信息或回答事实性问题时。 |
llm.code() |
请求模型执行代码。 | 计算、数据处理、代码生成等。 |
llm.pipeline_chat() |
将多个模型串联,处理复杂任务流。 | 需要多模型协作完成的任务,如“图生文再润色”。 |
llm.analyze() |
处理复杂的多模态输入 (UniMessage) 和工具调用。 |
插件中处理用户命令,需要解析图片、at、回复等复杂消息时。 |
llm.AI (类) |
管理一个有状态的、连续的对话会话。 | 需要实现上下文关联的连续对话机器人。 |
llm.get_model_instance() |
获取一个底层的、可直接控制的 LLMModel 实例。 |
需要对模型进行最精细控制的复杂或自定义场景。 |
llm.config.LLMGenerationConfig (类) |
定义模型生成的具体参数,如温度、最大Token等。 | 当需要微调模型输出风格或格式时。 |
llm.tools.tool_registry (实例) |
注册和管理可供LLM调用的函数工具。 | 当你想让LLM拥有与外部世界交互的能力时。 |
llm.embed() |
生成文本的嵌入向量表示。 | 语义搜索、相似度计算、文本聚类等。 |
llm.search_multimodal() |
执行带网络搜索的多模态问答。 | 需要基于图片、视频等多模态内容进行搜索时。 |
llm.analyze_multimodal() |
便捷的多模态分析函数。 | 直接分析文本、图片、视频、音频等多模态内容。 |
llm.AIConfig (类) |
AI会话的配置类,包含模型、温度等参数。 | 配置AI会话的行为和特性。 |
llm.clear_model_cache() |
清空模型实例缓存。 | 内存管理或强制重新初始化模型时。 |
llm.get_cache_stats() |
获取模型缓存的统计信息。 | 监控缓存使用情况和性能优化。 |
llm.list_embedding_models() |
列出所有可用的嵌入模型。 | 选择合适的嵌入模型进行向量化任务。 |
llm.config.CommonOverrides (类) |
提供常用的配置预设,如创意模式、精确模式等。 | 快速应用常见的模型配置组合。 |
llm.utils.create_multimodal_message |
便捷地从文本、图片、音视频等数据创建 UniMessage。 |
在代码中以编程方式构建多模态输入时。 |