
---

# 🚀 Zhenxun LLM 服务模块

本模块是一个功能强大、高度可扩展的统一大语言模型（LLM）服务框架。它旨在将各种不同的 LLM 提供商（如 OpenAI、Gemini、智谱AI等）的 API 封装在一个统一、易于使用的接口之后，让开发者可以无缝切换和使用不同的模型，同时支持多模态输入、工具调用、智能重试和缓存等高级功能。

## 目录

- [🚀 Zhenxun LLM 服务模块](#-zhenxun-llm-服务模块)
  - [目录](#目录)
  - [✨ 核心特性](#-核心特性)
  - [🧠 核心概念](#-核心概念)
  - [🛠️ 安装与配置](#️-安装与配置)
    - [服务提供商配置 (`config.yaml`)](#服务提供商配置-configyaml)
    - [MCP 工具配置 (`mcp_tools.json`)](#mcp-工具配置-mcp_toolsjson)
  - [📘 使用指南](#-使用指南)
    - [**等级1: 便捷函数** - 最快速的调用方式](#等级1-便捷函数---最快速的调用方式)
    - [**等级2: `AI` 会话类** - 管理有状态的对话](#等级2-ai-会话类---管理有状态的对话)
    - [**等级3: 直接模型控制** - `get_model_instance`](#等级3-直接模型控制---get_model_instance)
  - [🌟 功能深度剖析](#-功能深度剖析)
    - [精细化控制模型生成 (`LLMGenerationConfig` 与 `CommonOverrides`)](#精细化控制模型生成-llmgenerationconfig-与-commonoverrides)
    - [赋予模型能力：工具使用 (Function Calling)](#赋予模型能力工具使用-function-calling)
      - [1. 注册工具](#1-注册工具)
        - [函数工具注册](#函数工具注册)
        - [MCP工具注册](#mcp工具注册)
      - [2. 调用带工具的模型](#2-调用带工具的模型)
    - [处理多模态输入](#处理多模态输入)
  - [🔧 高级主题与扩展](#-高级主题与扩展)
    - [模型与密钥管理](#模型与密钥管理)
    - [缓存管理](#缓存管理)
    - [错误处理 (`LLMException`)](#错误处理-llmexception)
    - [自定义适配器 (Adapter)](#自定义适配器-adapter)
  - [📚 API 快速参考](#-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` 部分。

```yaml
# /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 协议启动的外部工具服务。如果文件不存在，系统会自动创建一个包含示例的默认文件。

```json
{
  "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` 包的顶层，为你处理了所有的底层细节。

```python
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` 类是你的最佳选择。

```python
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` 语句来优雅地管理模型实例的生命周期。

```python
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()` 等，能极大地简化配置过程。

```python
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` 装饰器注册一个简单的函数工具。

```python
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工具。

```python
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` 参数。框架会自动处理整个调用流程。

```python
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` 列表。

```python
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)
```

## 🔧 高级主题与扩展

### 模型与密钥管理

模块提供了一些工具函数来管理你的模型配置。

```python
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")
```

### 缓存管理

模块提供了模型实例缓存功能，可以提高性能并减少重复初始化的开销。

```python
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`，方便统一处理。

```python
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 服务，可以通过实现自己的适配器来完成。

1.  **创建适配器类**: 继承 `BaseAdapter` 并实现其抽象方法。

    ```python
    # 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 等方法
    ```

2.  **注册适配器**: 在你的插件初始化代码中注册你的适配器。

    ```python
    from zhenxun.services.llm.adapters import register_adapter
    from .my_adapters.custom_adapter import MyCustomAdapter
    
    register_adapter(MyCustomAdapter())
    ```

3.  **在 `config.yaml` 中使用**:

    ```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`。                    | 在代码中以编程方式构建多模态输入时。                         |