Files
zhenxun_bot/zhenxun/services/ai/core/options.py
T
0b32d69c9c ♻️ refactor(tools): 重构工具装饰器系统并优化沙箱与文档注释 (#2147)
* ♻️ refactor(ai): 重构 AI 服务模块并完善文档注释

- 【重构】统一清理并优化所有 AI 服务模块文件的导入语句,将其移至文件顶部
- 【重构】重构 `hooks.py` 中的 `Hooks` 派发逻辑,使用通用管道函数消除重复代码,并引入 `HookPoint` 描述符
- 【重构】重构工具装饰器实现,新增 `toolkit` 类装饰器,优化 `BaseToolkit` 配置合并与前缀处理
- 【功能】Docker 沙箱容器创建时支持自动注入系统代理环境变量并配置 `ExtraHosts`
- 【功能】Jupyter 服务启动前自动清理旧进程并初始化临时目录权限
- 【修复】优化 Pydantic 结构化输出校验失败时的错误信息提取,提供更详细的字段级错误反馈
- 【修复】在 `api.py` 中避免将 `ModelRetry` 和 `ControlFlowExit` 异常错误地包装为 `LLMException`
- 【文档】为 AI 服务、沙箱、工具链、工作流等核心模块补充完整的 Docstring 和类型注释

* 📝 docs(ai): 补全核心模块文档注释并清理冗余代码

- 补全 `run/context`、`run/hooks` 和 `tools/engine/registry` 中类与方法的中文文档注释
- 清理 `tools/providers/builtin/sandbox` 中未使用的 `PythonPluginProtocol` 协议及相关导入
- 规范化部分代码的格式与尾随逗号

* ♻️ refactor!(flow): 重构 Task 为 AgentTask 并优化工作流元数据定义

- 【Breaking Change】将 `Task` 重命名为 `AgentTask` 以避免命名冲突
- 更新 Agent、Team、Workflow 等模块中的类型声明与相关逻辑
- 引入 `AutoNodeMeta` 强类型元数据,替换工作流装饰器中的裸字典定义
- 将 `StepMeta`、`ConditionMeta` 和 `RouterMeta` 统一移动至 `types.py`
- 优化 `RunnableNode` 对上游 `AgentTask` 的处理与拼接逻辑
- 调整团队协作策略中 `FinishAction` 的返回值为完整结果对象

* ♻️ refactor(workflow): 移除人工确认机制并重构错误策略

- 移除工作流节点的人工确认(HITL)与挂起继续机制
- 删除 `auto` 自动化工作流及相关装饰器文件
- 将错误处理策略类从 `types.py` 拆分并移动到新文件 `policies.py`
- 优化节点执行失败时的异常信息格式化输出
- 移除 `WorkflowRunResult` 和 `StepOutput` 中与挂起相关的状态字段

* 🚨 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>
2026-07-05 11:47:21 +08:00

420 lines
15 KiB
Python

"""
AI 模块配置数据域类型定义
"""
from __future__ import annotations
from collections.abc import Callable
from enum import Enum
from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar
from pydantic import BaseModel, ConfigDict, Field
from zhenxun.utils.pydantic_compat import model_copy, model_dump, model_validate
if TYPE_CHECKING:
from zhenxun.services.ai.llm.builder import IntentBuilder
T = TypeVar("T")
class ResponseFormat(Enum):
"""响应格式枚举"""
TEXT = "text"
JSON = "json"
MULTIMODAL = "multimodal"
class StructuredOutputStrategy(str, Enum):
"""结构化输出策略"""
NATIVE = "native"
"""使用原生 API (如 OpenAI json_object/json_schema, Gemini mime_type)"""
TOOL_CALL = "tool_call"
"""构造虚假工具调用来强制输出结构化数据 (适用于指令跟随弱但工具调用强的模型)"""
PROMPT = "prompt"
"""仅在 Prompt 中追加 Schema 说明,依赖文本补全"""
class EmbeddingTaskType(str, Enum):
"""
文本嵌入任务类型 (对应 Gemini embedding 模型的 task_type 参数)
"""
RETRIEVAL_QUERY = "RETRIEVAL_QUERY"
"""指定给定的文本是搜索/检索设置中的查询 (Query)。"""
RETRIEVAL_DOCUMENT = "RETRIEVAL_DOCUMENT"
"""指定给定的文本是被搜索语料库中的文档 (Document)。"""
SEMANTIC_SIMILARITY = "SEMANTIC_SIMILARITY"
"""指定文本将用于语义文本相似度 (STS) 计算。"""
CLASSIFICATION = "CLASSIFICATION"
"""指定嵌入向量将用于文本分类任务。"""
CLUSTERING = "CLUSTERING"
"""指定嵌入向量将用于聚类任务。"""
QUESTION_ANSWERING = "QUESTION_ANSWERING"
"""指定文本将用于问答任务。"""
FACT_VERIFICATION = "FACT_VERIFICATION"
"""指定文本将用于事实核查任务。"""
class BaseOutputDefinition(Generic[T]):
"""声明式结构化输出基类"""
type_: type[T]
class ToolOutput(BaseOutputDefinition[T]):
"""工具输出标记:使用强制工具调用 (Tool Call) 结束任务并返回指定结构"""
name: str | None = None
description: str | None = None
strict: bool | None = None
def __init__(
self,
type_: type[T],
name: str | None = None,
description: str | None = None,
strict: bool | None = None,
):
self.type_ = type_
self.name = name
self.description = description
self.strict = strict
class ReasoningEffort(str, Enum):
"""推理努力程度枚举"""
NONE = "NONE"
"""不开启推理思考"""
MINIMAL = "MINIMAL"
"""极低推理努力,追求最快响应"""
LOW = "LOW"
"""较低推理努力"""
MEDIUM = "MEDIUM"
"""中等推理努力(通常是默认值)"""
HIGH = "HIGH"
"""高推理努力"""
XHIGH = "XHIGH"
"""极高推理努力"""
MAX = "MAX"
"""最大推理努力 (如 GLM / DeepSeek)"""
class ImageAspectRatio(str, Enum):
"""图像宽高比枚举"""
SQUARE = "1:1"
"""正方形"""
LANDSCAPE_16_9 = "16:9"
"""横向宽屏 16:9"""
PORTRAIT_9_16 = "9:16"
"""竖向全屏 9:16"""
LANDSCAPE_4_3 = "4:3"
"""横向标准 4:3"""
PORTRAIT_3_4 = "3:4"
"""竖向标准 3:4"""
LANDSCAPE_3_2 = "3:2"
"""横向 3:2"""
PORTRAIT_2_3 = "2:3"
"""竖向 2:3"""
class ImageResolution(str, Enum):
"""图像分辨率/质量枚举"""
STANDARD = "STANDARD"
"""标准分辨率"""
HD = "HD"
"""高清分辨率"""
class CommonLLMConfig(BaseModel):
"""三大厂商通用基础生成参数"""
temperature: float | None = Field(default=None, ge=0.0, le=2.0)
"""采样温度。较高的值会使输出更加随机,较低的值会使其更加集中和确定。"""
max_tokens: int | None = Field(default=None, gt=0)
"""聊天完成时生成的最大 Token 数。"""
top_p: float | None = Field(default=None, ge=0.0, le=1.0)
"""核采样 (Nucleus sampling) 概率阈值。"""
top_k: int | None = Field(default=None, gt=0)
"""仅从概率最高的前 K 个 Token 中采样 (并非所有模型支持)。"""
frequency_penalty: float | None = Field(default=None, ge=-2.0, le=2.0)
"""频率惩罚。正值根据新 Token 在文本中的现有频率对其进行惩罚,
降低模型逐字重复同一行的可能性。"""
presence_penalty: float | None = Field(default=None, ge=-2.0, le=2.0)
"""存在惩罚。正值根据新 Token 到目前为止是否出现在文本中对其进行惩罚,
增加模型谈论新主题的可能性。"""
repetition_penalty: float | None = Field(default=None, ge=0.0, le=2.0)
"""重复惩罚系数 (部分非 OpenAI 兼容模型独有)。"""
stop: list[str] | str | None = Field(default=None)
"""API 停止生成后续 Token 的停止词序列。"""
reasoning_effort: ReasoningEffort | str | None = Field(default=None)
"""跨厂商统一的思考/推理等级意图(如 'low', 'high', 'max')。
具体映射由底层的 Adapter 执行。"""
class OutputFormatConfig(BaseModel):
"""输出格式与结构化控制"""
response_format: ResponseFormat | dict[str, Any] | None = Field(default=None)
"""响应格式类型 (枚举或字典形式的 json_schema 对象)。"""
response_mime_type: str | None = Field(default=None)
"""指定 MIME 类型 (如 application/json),主要用于 Gemini。"""
response_schema: dict[str, Any] | None = Field(default=None)
"""JSON Schema 字典,用于强制约束模型返回的 JSON 结构。"""
response_modalities: list[str] | None = Field(default=None)
"""允许的响应模态 (如 ["TEXT", "IMAGE"]),主要用于 Gemini。"""
structured_output_strategy: StructuredOutputStrategy | str | None = Field(
default=None
)
"""结构化输出所采用的内部策略。"""
class ToolCallConfig(BaseModel):
"""工具调用统一策略配置"""
mode: Literal["AUTO", "ANY", "NONE"] = Field(default="AUTO")
"""工具调用模式 (AUTO: 自动, ANY: 强制至少调一个, NONE: 禁用)。"""
allowed_function_names: list[str] | None = Field(default=None)
"""允许被调用的特定函数名称白名单。"""
include_server_side_tool_invocations: bool | None = Field(default=None)
"""是否包含服务端侧的工具调用日志流转 (主要用于 Gemini)。"""
class BaseProviderOption(BaseModel):
"""厂商配置逃生舱基类"""
model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow") # type: ignore
class OpenAIOptions(BaseProviderOption):
"""OpenAI 专属特权参数 (适配 Responses API)"""
store: bool | None = Field(default=None)
"""是否允许服务端留存本次请求的选项记录"""
metadata: dict[str, str] | None = Field(default=None)
"""附加在请求上的自定义元数据"""
class GeminiOptions(BaseProviderOption):
"""Gemini 专属特权参数"""
include_thoughts: bool | None = Field(default=None)
"""是否在最终响应中包含模型的内部思考过程 (Thoughts)"""
safety_settings: dict[str, str] | None = Field(default=None)
"""Gemini 专有的各个维度的安全过滤阈值配置"""
retrieval_config: dict[str, Any] | None = Field(default=None)
"""检索定位配置,如 LBS 经纬度信息,配合 Google Maps 工具使用"""
class DeepSeekOptions(BaseProviderOption):
"""DeepSeek 专属特权参数"""
thinking: bool | None = Field(default=None)
"""是否强制开启或关闭 R1 模型的思维链过程"""
class OpenAITTSOptions(BaseProviderOption):
"""OpenAI TTS 专属特权参数"""
voice_id: str | None = Field(default=None)
"""专属的音色 ID 配置"""
class GeminiTTSOptions(BaseProviderOption):
"""Gemini TTS 专属特权参数"""
voice_id: str | None = Field(default=None)
"""专属的音色 ID 配置"""
multi_speaker: bool | None = Field(default=None)
"""是否开启多说话人模式"""
second_voice: str | None = Field(default=None)
"""多说话人模式下的第二音色名称"""
class MiniMaxTTSOptions(BaseProviderOption):
"""MiniMax TTS 专属特权参数 (控制极度精细)"""
voice_id: str | None = Field(default=None)
"""专属的音色 ID 配置"""
vol: float | None = Field(default=None, gt=0.0, le=10.0)
"""音量,范围 (0, 10]"""
pitch: int | None = Field(default=None, ge=-12, le=12)
"""语调,范围 [-12, 12]"""
emotion: (
Literal[
"happy",
"sad",
"angry",
"fearful",
"disgusted",
"surprised",
"calm",
"fluent",
"whisper",
]
| None
) = Field(default=None)
"""情感控制"""
timbre_weights: list[dict[str, Any]] | None = Field(default=None)
"""音色混合权重 (最多4种)"""
pronunciation_dict: dict[str, list[str]] | None = Field(default=None)
"""自定义发音字典 (如: {"tone": ["处理/(chu3)(li3)"]})"""
class MiMoTTSOptions(BaseProviderOption):
"""MiMo TTS 专属特权参数"""
voice_id: str | None = Field(default=None)
"""专属的音色 ID 配置"""
class MediaGenerationConfig(BaseModel):
"""多模态媒体生成/优化的全局配置"""
aspect_ratio: ImageAspectRatio | str | None = Field(default=None)
"""生成的图像/视频宽高比 (如 '16:9')"""
resolution: str | None = Field(default=None)
"""生成的图像/视频分辨率 (如 '1K', '4K' 或 '1024x1024')"""
quality: Literal["low", "medium", "high", "standard", "hd"] | None = Field(
default=None
)
"""渲染质量及细节丰富水平"""
class TTSConfig(BaseModel):
"""文本转语音 (TTS) 全局配置"""
response_format: Literal["mp3", "wav", "pcm", "flac", "opus", "aac"] = Field(
default="mp3"
)
"""输出音频格式"""
speed: float = Field(default=1.0, ge=0.25, le=4.0)
"""语速 (通用映射)"""
openai_options: OpenAITTSOptions = Field(default_factory=OpenAITTSOptions)
"""OpenAI 厂商专属请求参数集"""
gemini_options: GeminiTTSOptions = Field(default_factory=GeminiTTSOptions)
"""Gemini 厂商专属请求参数集"""
minimax_options: MiniMaxTTSOptions = Field(default_factory=MiniMaxTTSOptions)
"""MiniMax 厂商专属请求参数集"""
mimo_options: MiMoTTSOptions = Field(default_factory=MiMoTTSOptions)
"""MiMo 厂商专属请求参数集"""
custom_kwargs: dict[str, Any] = Field(default_factory=dict)
"""兜底逃生舱,包含的键值对将直接透传至顶层请求体中 (可用于缓存 TTL)"""
model_config = ConfigDict(arbitrary_types_allowed=True)
class GenerationConfig(BaseModel):
"""
现代化 LLM 生成基座 (Intent-Driven Base)。
隔离通用参数与厂商私有参数,彻底终结"上帝类"。
"""
common: CommonLLMConfig = Field(default_factory=CommonLLMConfig)
"""大模型生成核心通用配置项"""
output: OutputFormatConfig = Field(default_factory=OutputFormatConfig)
"""输出格式与约束控制配置项"""
tools: ToolCallConfig = Field(default_factory=ToolCallConfig)
"""工具调用策略与函数声明配置项"""
media: MediaGenerationConfig = Field(default_factory=MediaGenerationConfig)
"""多媒体生成相关配置项"""
openai_options: OpenAIOptions = Field(default_factory=OpenAIOptions)
"""OpenAI 厂商专属请求参数集"""
gemini_options: GeminiOptions = Field(default_factory=GeminiOptions)
"""Gemini 厂商专属请求参数集"""
deepseek_options: DeepSeekOptions = Field(default_factory=DeepSeekOptions)
"""DeepSeek 厂商专属请求参数集"""
enable_caching: bool | None = Field(default=None)
"""是否在此次生成中开启上下文缓存 (Context Caching)"""
custom_kwargs: dict[str, Any] = Field(default_factory=dict)
"""兜底逃生舱,包含的键值对将直接透传至顶层请求体中"""
validation_policy: dict[str, Any] | None = Field(default=None)
"""自定义验证策略字典"""
response_validator: Callable[[Any], None] | None = Field(default=None)
"""针对原始返回对象的自定义回调验证器"""
model_config = ConfigDict(arbitrary_types_allowed=True)
@classmethod
def builder(cls) -> "IntentBuilder":
from zhenxun.services.ai.llm.builder import IntentBuilder
return IntentBuilder()
def to_dict(self) -> dict[str, Any]:
return model_dump(self, exclude_none=True)
def merge_with(self, other: "GenerationConfig | None") -> "GenerationConfig":
"""深度合并两个配置,实现配置的无损叠加"""
if not other:
return model_copy(self, deep=True)
base_dump = model_dump(self, exclude_none=True)
other_dump = model_dump(other, exclude_none=True)
def deep_merge(d1: dict, d2: dict) -> dict:
res = d1.copy()
for k, v in d2.items():
if isinstance(v, dict) and k in res and isinstance(res[k], dict):
res[k] = deep_merge(res[k], v)
else:
res[k] = v
return res
merged_dump = deep_merge(base_dump, other_dump)
return model_validate(GenerationConfig, merged_dump)
class LLMEmbeddingConfig(BaseModel):
"""Embedding 专用配置"""
task_type: str | None = Field(default=None)
"""生成意图的任务类型,参考 EmbeddingTaskType (主要用于 Gemini 和 Jina)"""
output_dimensionality: int | None = Field(default=None)
"""请求模型强制输出(或截断)的较低维度数,实现维度压缩"""
title: str | None = Field(default=None)
"""提供该文档的标题以供底层优化。仅在 task_type 为 RETRIEVAL_DOCUMENT 时有效。"""
encoding_format: str | None = Field(default="float")
"""向量数据在响应中的编码格式 (通常为 float 或 base64)"""
multimodal: bool | list[str] = Field(default=False)
"""是否允许多模态向量化。False 表示纯文本(极速安全);True 表示全部放行;
也可传入 ['image', 'text'] 细粒度控制。"""
custom_kwargs: dict[str, Any] = Field(default_factory=dict)
"""兜底逃生舱,包含的键值对将直接透传至顶层请求体中 (可用于缓存 TTL)"""
model_config = ConfigDict(arbitrary_types_allowed=True)
__all__ = [
"BaseProviderOption",
"CommonLLMConfig",
"EmbeddingTaskType",
"GeminiOptions",
"GeminiTTSOptions",
"GenerationConfig",
"ImageAspectRatio",
"ImageResolution",
"LLMEmbeddingConfig",
"MiMoTTSOptions",
"MiniMaxTTSOptions",
"OpenAIOptions",
"OpenAITTSOptions",
"OutputFormatConfig",
"ReasoningEffort",
"ResponseFormat",
"StructuredOutputStrategy",
"TTSConfig",
"ToolCallConfig",
"ToolOutput",
]