From 0a6a9ed09cc9021fc0ab371af1c77597c6743b85 Mon Sep 17 00:00:00 2001 From: z30057876 Date: Thu, 9 Oct 2025 15:13:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AE=BE=E8=AE=A1=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/call/convert.md | 166 +++++--------- design/call/empty.md | 299 +++++++++++++++++++++++++ design/call/llm.md | 31 ++- design/call/slot.md | 488 +++++++++++++++++++++++++++++++++++++++++ design/call/sql.md | 110 ++-------- design/call/summary.md | 71 +----- 6 files changed, 882 insertions(+), 283 deletions(-) create mode 100644 design/call/empty.md create mode 100644 design/call/slot.md diff --git a/design/call/convert.md b/design/call/convert.md index 6420d4af..ab309df1 100644 --- a/design/call/convert.md +++ b/design/call/convert.md @@ -5,6 +5,7 @@ Convert模块是欧拉助手框架中的一个核心工具,主要用于对生成的文字信息和原始数据进行格式化处理。该模块基于Jinja2模板引擎,支持灵活的模板语法,可以将各种数据转换为特定格式的文本或结构化数据,为系统中的数据展示和传递提供了强大的支持。 **主要功能特性:** + - 支持Jinja2模板语法的文本格式化 - 支持JSON数据的模板渲染和解析 - 提供多语言的工具名称和描述信息 @@ -28,13 +29,6 @@ apps/scheduler/call/convert/ `Convert` 类是模块的核心,继承自 `CoreCall` 基类,实现了模板转换的核心逻辑。 -```python -class Convert(CoreCall, input_model=ConvertInput, output_model=ConvertOutput): - """Convert 工具,用于对生成的文字信息和原始数据进行格式化""" - text_template: str | None = Field(description="自然语言信息的格式化模板,jinja2语法", default=None) - data_template: str | None = Field(description="原始数据的格式化模板,jinja2语法", default=None) -``` - ### 3.2 主要属性 | 属性名 | 类型 | 默认值 | 描述 | @@ -49,126 +43,76 @@ class Convert(CoreCall, input_model=ConvertInput, output_model=ConvertOutput): **功能描述**:提供Convert工具的名称和描述信息,支持多语言国际化。 **主要特点**: + - 支持中英文两种语言切换 - 返回标准的CallInfo对象,包含工具名称和功能描述 - 中文版本名称为"模板转换",英文版本名称为"Convert" - 描述信息说明了工具的核心功能:使用Jinja2语法格式化自然语言信息和原始数据 -```python -@classmethod -def info(cls, language: LanguageType = LanguageType.CHINESE) -> CallInfo: - """返回Call的名称和描述""" - i18n_info = { - LanguageType.CHINESE: CallInfo( - name="模板转换", - description="使用jinja2语法将自然语言信息和原始数据进行格式化。", - ), - LanguageType.ENGLISH: CallInfo( - name="Convert", - description="Use jinja2 syntax to format natural language information and original data.", - ), - } - return i18n_info[language] -``` +**实现逻辑**: + +1. 接收语言类型参数,默认为中文 +2. 根据语言类型返回对应的工具信息 +3. 中文环境下返回"模板转换"名称和中文描述 +4. 英文环境下返回"Convert"名称和英文描述 #### 3.3.2 _init方法 **功能描述**:初始化Convert工具,准备模板渲染所需的环境和变量。 **主要特点**: + - 继承自CoreCall基类并进行扩展 - 创建SandboxedEnvironment环境以安全地执行模板 - 收集和准备模板渲染所需的额外变量(如时间、历史记录、问题等) -```python -async def _init(self, call_vars: CallVars) -> ConvertInput: - """初始化工具""" - await super()._init(call_vars) - - self._history = call_vars.step_data - self._question = call_vars.question - self._env = SandboxedEnvironment( - loader=BaseLoader(), - autoescape=False, - trim_blocks=True, - lstrip_blocks=True, - ) - - # 获取当前时间 - time = datetime.now(tz=pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") - # 返回空的ConvertInput,因为输入数据来自上一步的输出 - self._extras = { - "time": time, - "history": self._history, - "question": self._question, - "background": self._sys_vars.background, - "ids": self._sys_vars.ids, - } - return ConvertInput( - text_template=self.text_template, - data_template=self.data_template, - extras=self._extras, - ) -``` +**实现逻辑**: + +1. 调用父类的初始化方法,完成基础设置 +2. 从调用变量中提取历史数据和问题信息 +3. 创建安全的Jinja2沙盒环境,配置模板处理选项 +4. 获取当前时间(使用亚洲/上海时区) +5. 构建扩展变量字典,包含: + - 当前时间 + - 历史记录数据 + - 用户问题 + - 系统背景信息 + - 相关ID信息 +6. 返回ConvertInput对象,包含模板内容和扩展变量 #### 3.3.3 _exec方法 **功能描述**:执行模板转换操作,处理文本模板和数据模板,并流式返回结果。 **主要特点**: + - 分别处理文本模板和数据模板 - 对模板渲染过程中的异常进行捕获和处理 - 支持流式输出,分别返回文本和数据两种类型的结果 -```python -async def _exec(self) -> AsyncGenerator[CallOutputChunk, None]: - """调用Convert工具""" - # 处理文本模板 - result_message = "" - if self.text_template is not None: - try: - text_template = self._env.from_string(self.text_template) - result_message = text_template.render(**self._extras) - except Exception as e: - raise CallError( - message=f"文本模板渲染错误: {e!s}", - data={ - "template": self.text_template, - "error": str(e), - }, - ) from e - else: - result_message = "未提供文本模板" - - # 处理数据模板 - result_data = {} - if self.data_template is not None: - try: - data_template = self._env.from_string(self.data_template) - rendered_data_str = data_template.render(**self._extras) - # 尝试解析为JSON对象 - result_data = json.loads(rendered_data_str) - except Exception as e: - raise CallError( - message=f"数据模板渲染错误: {e!s}", - data={ - "template": self.data_template, - "error": str(e), - }, - ) from e - else: - result_data = {"message": "未提供数据模板"} - - # 返回文本和数据两个部分 - yield CallOutputChunk( - type=CallOutputType.TEXT, - content=result_message, - ) - yield CallOutputChunk( - type=CallOutputType.DATA, - content=result_data, - ) -``` +**实现逻辑**: + +**文本模板处理:** + +1. 检查是否提供了文本模板 +2. 如果存在模板,使用Jinja2环境进行渲染 +3. 将扩展变量传递给模板进行渲染 +4. 捕获渲染异常并抛出详细的错误信息 +5. 如果未提供模板,返回默认提示信息 + +**数据模板处理:** + +1. 检查是否提供了数据模板 +2. 如果存在模板,先进行Jinja2渲染得到字符串结果 +3. 尝试将渲染结果解析为JSON对象 +4. 捕获渲染或解析异常并抛出详细错误信息 +5. 如果未提供模板,返回包含默认消息的对象 + +**结果输出:** + +1. 以流式方式返回文本类型的结果块 +2. 以流式方式返回数据类型的结果块 +3. 每个结果块包含对应的内容和类型标识 ## 4. 数据结构 @@ -321,13 +265,15 @@ sequenceDiagram ### 6.1 文本模板示例 **配置参数:** + ```json { "text_template": "用户的问题是:{{ question }}\n当前时间:{{ time }}\n历史步骤数:{{ history | length }}" } ``` -**输入数据(CallVars):** +**输入数据(CallVars):** + ```json { "question": "什么是欧拉助手?", @@ -336,8 +282,9 @@ sequenceDiagram } ``` -**输出结果(文本部分):** -``` +**输出结果(文本部分):** + +```text 用户的问题是:什么是欧拉助手? 当前时间:2023-01-01 12:00:00 历史步骤数:2 @@ -346,13 +293,15 @@ sequenceDiagram ### 6.2 数据模板示例 **配置参数:** + ```json { "data_template": "{\"question\": \"{{ question }}\", \"timestamp\": \"{{ time }}\", \"history_count\": {{ history | length }} }" } ``` -**输入数据(CallVars):** +**输入数据(CallVars):** + ```json { "question": "什么是欧拉助手?", @@ -361,7 +310,8 @@ sequenceDiagram } ``` -**输出结果(数据部分):** +**输出结果(数据部分):** + ```json { "question": "什么是欧拉助手?", @@ -389,4 +339,4 @@ Convert模块包含完善的错误处理机制,主要针对以下两种错误 4. **自定义过滤器扩展**:可以考虑扩展Jinja2环境,添加自定义过滤器,提供更多数据处理和格式化能力。 -5. **国际化支持增强**:当前的默认提示信息仅支持中文,可以考虑将其纳入多语言支持体系,根据系统语言自动切换。 \ No newline at end of file +5. **国际化支持增强**:当前的默认提示信息仅支持中文,可以考虑将其纳入多语言支持体系,根据系统语言自动切换。 diff --git a/design/call/empty.md b/design/call/empty.md new file mode 100644 index 00000000..94044672 --- /dev/null +++ b/design/call/empty.md @@ -0,0 +1,299 @@ +# Empty工具模块文档 + +## 概述 + +Empty工具是一个占位符工具,用于在工作流中提供空白节点功能。它不执行任何实际的操作,主要用于工作流设计中的占位、测试或作为流程控制节点。Empty工具是最简单的Call实现,展示了CoreCall框架的基本结构和生命周期。 + +## 功能特性 + +- **占位符功能**:提供空白节点,用于工作流占位 +- **多语言支持**:支持中文和英文两种语言 +- **最小化实现**:展示CoreCall框架的基本结构 +- **零副作用**:不执行任何实际操作,确保系统稳定性 +- **结构化数据**:基于Pydantic模型进行数据验证和序列化 + +## 核心组件 + +### 1. Empty类 + +Empty工具的核心实现类,继承自`CoreCall`基类,是所有Call实现中最简单的示例。 + +### 2. 主要属性 + +| 属性名 | 类型 | 默认值 | 描述 | +|--------|------|--------|------| +| `input_model` | type[DataBase] | DataBase | 输入模型类型 | +| `output_model` | type[DataBase] | DataBase | 输出模型类型 | +| `to_user` | bool | False | 是否将输出返回给用户 | +| `enable_filling` | bool | False | 是否需要进行自动参数填充 | + +### 3. 核心方法 + +- `info()`: 返回工具的多语言名称和描述 +- `instance()`: 创建工具实例(继承自CoreCall) +- `_init()`: 初始化工具输入 +- `_exec()`: 执行工具逻辑(空实现) +- `exec()`: 公共执行接口(继承自CoreCall) + +## 数据结构 + +Empty工具的数据结构非常简单,它使用DataBase作为输入和输出模型: + +```mermaid +classDiagram + class DataBase { + <> + +model_json_schema() dict + } + + class Empty { + +input_model: type[DataBase] + +output_model: type[DataBase] + +to_user: bool + +enable_filling: bool + +info() CallInfo + +instance() Self + +_init() DataBase + +_exec() AsyncGenerator + +exec() AsyncGenerator + } + + class CallInfo { + +name: str + +description: str + } + + class CallOutputChunk { + +type: CallOutputType + +content: str | dict + } + + Empty --> DataBase : 输入 + Empty --> DataBase : 输出 + Empty --> CallInfo : 返回 + Empty --> CallOutputChunk : 生成 +``` + +### 数据模型说明 + +- **DataBase**: 所有Call的输入基类,提供通用的数据验证和序列化功能 +- **CallInfo**: 包含工具名称和描述的信息类 +- **CallOutputChunk**: Call的输出块,包含类型和内容 +- **Empty**: 主要的工具类,使用DataBase作为输入和输出模型 + +### 数据流转关系 + +```mermaid +graph LR + A[CallVars] --> B[Empty工具] + B --> C[DataBase输入] + C --> D[空执行逻辑] + D --> E[CallOutputChunk输出] + + subgraph "输入数据" + A1[call_vars: 系统变量] + end + + subgraph "处理过程" + B1[初始化DataBase] + B2[空执行] + end + + subgraph "输出数据" + E1[type: DATA] + E2[content] + end + + A1 --> B1 + B1 --> B2 + B2 --> E1 + B2 --> E2 +``` + +## 工作流程 + +Empty工具的工作流程非常简单,主要展示Call的基本生命周期: + +```mermaid +graph TD + A[开始] --> B[接收CallVars] + B --> C[初始化DataBase] + C --> D[执行空逻辑] + D --> E[生成空输出] + E --> F[结束] + + subgraph "初始化阶段" + B1[_init方法] + B2[返回DataBase实例] + end + + subgraph "执行阶段" + D1[_exec方法] + D2[生成CallOutputChunk] + D3[type: DATA] + D4[content] + end + + B --> B1 + B1 --> B2 + B2 --> D1 + D1 --> D2 + D2 --> D3 + D3 --> D4 + D4 --> E +``` + +## 执行时序图 + +```mermaid +sequenceDiagram + participant E as StepExecutor + participant EMP as Empty + participant C as CoreCall + + E->>EMP: instance(executor, node) + EMP->>C: 继承CoreCall.instance() + C->>EMP: _set_input(executor) + EMP->>EMP: _init(call_vars) + EMP-->>C: 返回DataBase() + C->>EMP: 设置input属性 + + E->>EMP: exec(executor, input_data) + EMP->>C: 继承CoreCall.exec() + C->>EMP: _exec(input_data) + EMP->>EMP: 创建CallOutputChunk + EMP-->>C: 返回空输出 + C->>EMP: _after_exec(input_data) + C-->>E: 返回CallOutputChunk +``` + +## 核心实现 + +### 1. 类定义 + +```python +class Empty(CoreCall, input_model=DataBase, output_model=DataBase): + """空Call""" +``` + +Empty类继承自CoreCall,并指定输入和输出模型都为DataBase,这是最简单的配置。 + +### 2. 多语言信息 + +```python +@classmethod +def info(cls, language: LanguageType = LanguageType.CHINESE) -> CallInfo: + i18n_info = { + LanguageType.CHINESE: CallInfo(name="空白", description="空白节点,用于占位"), + LanguageType.ENGLISH: CallInfo(name="Empty", description="Empty node, used for placeholder"), + } + return i18n_info[language] +``` + +提供中英文两种语言的名称和描述信息。 + +### 3. 初始化方法 + +```python +async def _init(self, call_vars: CallVars) -> DataBase: + return DataBase() +``` + +返回一个空的DataBase实例,不进行任何处理。 + +### 4. 执行方法 + +```python +async def _exec(self, input_data: dict[str, Any]) -> AsyncGenerator[CallOutputChunk, None]: + output = CallOutputChunk(type=CallOutputType.DATA, content={}) + yield output +``` + +生成一个空的DATA类型输出块,内容为空字典。 + +## 使用示例 + +### 基本使用 + +```python +# 创建Empty工具实例 +empty_tool = await Empty.instance(executor, node) + +# 执行空操作 +async for chunk in empty_tool.exec(executor, input_data): + if chunk.type == CallOutputType.DATA: + print(f"输出内容: {chunk.content}") # 输出: {} +``` + +### 在工作流中使用 + +```python +# 工作流配置示例 +workflow_config = { + "nodes": [ + { + "id": "start", + "type": "start", + "name": "开始" + }, + { + "id": "placeholder", + "type": "Empty", + "name": "占位节点", + "description": "用于占位的空白节点" + }, + { + "id": "end", + "type": "end", + "name": "结束" + } + ], + "edges": [ + {"from": "start", "to": "placeholder"}, + {"from": "placeholder", "to": "end"} + ] +} +``` + +## 配置参数 + +| 参数 | 类型 | 默认值 | 描述 | +|------|------|--------|------| +| `input_model` | type[DataBase] | DataBase | 输入模型类型 | +| `output_model` | type[DataBase] | DataBase | 输出模型类型 | +| `to_user` | bool | False | 是否将输出返回给用户 | +| `enable_filling` | bool | False | 是否需要进行自动参数填充 | + +## 应用场景 + +### 1. 工作流占位 + +```mermaid +graph LR + A[开始] --> B[数据处理] + B --> C[空白占位] + C --> D[结果输出] + + style C fill:#f9f9f9,stroke:#333,stroke-width:2px +``` + +在工作流设计中使用Empty节点作为占位符,为未来的功能扩展预留位置。 + +### 2. 流程测试 + +在开发阶段使用Empty节点测试工作流的连接性和流程逻辑,而不执行实际的功能。 + +## 依赖关系 + +- `CoreCall`: 基础调用框架,提供通用的Call生命周期管理 +- `DataBase`: 基础数据模型,提供通用的数据验证和序列化功能 +- `CallInfo`: 工具信息模型,包含名称和描述 +- `CallOutputChunk`: 输出块模型,定义输出格式 +- `CallVars`: 系统变量模型,包含执行上下文信息 + +## 相关模块 + +- `apps/scheduler/call/core.py`: CoreCall基类实现 +- `apps/scheduler/call/empty.py`: Empty工具实现 +- `apps/schemas/scheduler.py`: 调度器相关Schema定义 +- `apps/schemas/enum_var.py`: 枚举类型定义 diff --git a/design/call/llm.md b/design/call/llm.md index 3ac42ae3..540cfa23 100644 --- a/design/call/llm.md +++ b/design/call/llm.md @@ -22,21 +22,20 @@ apps/scheduler/call/llm/ `LLM` 类是模块的核心,继承自 `CoreCall` 基类,实现了与大模型的交互逻辑。 -```python -class LLM(CoreCall, input_model=LLMInput, output_model=LLMOutput): - """大模型调用工具""" - # 配置参数 - to_user: bool = Field(default=True) - temperature: float = Field(description="大模型温度(随机化程度)", default=0.7) - step_history_size: int = Field(description="上下文信息中包含的步骤历史数量", default=3, ge=0, le=10) - history_length: int = Field(description="历史对话记录数量", default=0, ge=0) - system_prompt: str = Field(description="大模型系统提示词", default="You are a helpful assistant.") - user_prompt: str = Field(description="大模型用户提示词", default=LLM_DEFAULT_PROMPT) -``` +### 3.2 主要属性 + +| 属性名 | 类型 | 默认值 | 描述 | +|--------|------|--------|------| +| `to_user` | bool | True | 是否需要将输出返回给用户 | +| `temperature` | float | 0.7 | 大模型温度(随机化程度),控制输出的随机性 | +| `step_history_size` | int | 3 | 上下文信息中包含的步骤历史数量,范围0-10 | +| `history_length` | int | 0 | 历史对话记录数量,用于提供上下文信息 | +| `system_prompt` | str | "You are a helpful assistant." | 大模型系统提示词,定义AI的角色和行为 | +| `user_prompt` | str | LLM_DEFAULT_PROMPT | 大模型用户提示词模板,使用Jinja2语法 | -### 3.2 主要方法 +### 3.3 主要方法 -#### 3.2.1 info方法 +#### 3.3.1 info方法 **功能描述**:提供LLM工具的名称和描述信息,支持多语言国际化。 @@ -47,7 +46,7 @@ class LLM(CoreCall, input_model=LLMInput, output_model=LLMOutput): - 中文版本名称为"大模型",英文版本名称为"LLM" - 描述信息说明了工具的核心功能:使用指定提示词和上下文信息调用大模型 -#### 3.2.2 _prepare_message方法 +#### 3.3.2 _prepare_message方法 **功能描述**:准备输入给大模型的消息列表,是整个LLM调用流程的核心预处理方法。 @@ -63,7 +62,7 @@ class LLM(CoreCall, input_model=LLMInput, output_model=LLMOutput): **输出格式**:返回包含role和content字段的消息字典列表 -#### 3.2.3 _init方法 +#### 3.3.3 _init方法 **功能描述**:初始化LLM工具,准备调用所需的输入数据。 @@ -74,7 +73,7 @@ class LLM(CoreCall, input_model=LLMInput, output_model=LLMOutput): - 将消息列表封装为LLMInput对象 - 返回准备好的输入数据供后续执行使用 -#### 3.2.4 _exec方法 +#### 3.3.4 _exec方法 **功能描述**:执行实际的大模型调用,并以流式方式返回处理结果。 diff --git a/design/call/slot.md b/design/call/slot.md new file mode 100644 index 00000000..c738d943 --- /dev/null +++ b/design/call/slot.md @@ -0,0 +1,488 @@ +# Slot工具模块文档 + +## 概述 + +Slot工具是一个智能参数自动填充工具,它通过分析历史步骤数据、背景信息和用户问题,自动生成符合JSON Schema要求的参数对象。该工具支持两阶段填充策略:首先使用大语言模型进行初步填充,如果存在剩余参数则使用FunctionCall进行精确填充。 + +## 功能特性 + +- **智能参数填充**:基于历史步骤和背景信息自动填充工具参数 +- **两阶段填充策略**:LLM初步填充 + FunctionCall精确填充 +- **Schema验证**:支持JSON Schema验证和错误检测 +- **多语言支持**:支持中文和英文两种语言 +- **模板化提示词**:使用Jinja2模板引擎动态生成提示词 +- **流式输出**:支持实时流式输出填充结果 +- **结构化数据**:基于Pydantic模型进行数据验证和序列化 + +## 核心组件 + +### 1. Slot类 + +Slot工具的核心实现类,继承自`CoreCall`基类,负责参数自动填充的整个流程。 + +### 2. 主要属性 + +| 属性名 | 类型 | 默认值 | 描述 | +|--------|------|--------|------| +| `data` | dict[str, Any] | {} | 当前输入数据 | +| `current_schema` | dict[str, Any] | {} | 当前JSON Schema | +| `summary` | str | "" | 背景信息总结 | +| `facts` | list[str] | [] | 事实信息列表 | +| `step_num` | int | 1 | 历史步骤数 | + +### 3. 核心方法 + +- `info()`: 返回工具的多语言名称和描述 +- `instance()`: 创建工具实例 +- `_init()`: 初始化工具输入,处理历史数据和Schema +- `_exec()`: 执行参数填充逻辑 +- `_llm_slot_fill()`: 使用大语言模型填充参数 +- `_function_slot_fill()`: 使用FunctionCall填充剩余参数 + +## 数据结构 + +Slot工具涉及多个数据模型,它们之间的关系如下: + +```mermaid +classDiagram + class DataBase { + <> + +model_json_schema() dict + } + + class SlotInput { + +remaining_schema: dict + } + + class SlotOutput { + +slot_data: dict + +remaining_schema: dict + } + + class Slot { + +data: dict + +current_schema: dict + +summary: str + +facts: list + +step_num: int + +info() CallInfo + +instance() Self + +_init() SlotInput + +_exec() AsyncGenerator + +_llm_slot_fill() tuple + +_function_slot_fill() dict + } + + class SlotProcessor { + +_validator_cls: type + +_validator: Validator + +_schema: dict + +process_json() dict + +convert_json() dict + +check_json() dict + +add_null_to_basic_types() dict + } + + DataBase <|-- SlotInput : 继承 + DataBase <|-- SlotOutput : 继承 + Slot --> SlotInput : 输入 + Slot --> SlotOutput : 输出 + Slot --> SlotProcessor : 使用 + SlotProcessor --> SlotInput : 生成remaining_schema + SlotProcessor --> SlotOutput : 验证和转换数据 +``` + +### 数据模型说明 + +- **DataBase**: 所有Call的输入基类,提供通用的数据验证和序列化功能 +- **SlotInput**: 继承自DataBase,包含剩余需要填充的Schema信息 +- **SlotOutput**: 继承自DataBase,包含填充后的数据和剩余Schema +- **Slot**: 主要的工具类,负责参数填充的整个流程 +- **SlotProcessor**: 参数槽处理器,负责JSON Schema验证和数据转换 + +### 数据流转关系 + +```mermaid +graph LR + A[CallVars] --> B[Slot工具] + B --> C[SlotProcessor] + C --> D[SlotInput] + D --> E[LLM填充] + E --> F[FunctionCall填充] + F --> G[SlotOutput] + + subgraph "输入数据" + A1[question: 用户问题] + A2[step_data: 历史步骤数据] + A3[current_schema: JSON Schema] + A4[summary: 背景总结] + A5[facts: 事实信息] + end + + subgraph "处理过程" + B1[历史数据处理] + B2[Schema验证] + B3[LLM推理填充] + B4[FunctionCall精确填充] + B5[数据转换和验证] + end + + subgraph "输出数据" + G1[slot_data: 填充后的数据] + G2[remaining_schema: 剩余Schema] + end + + A1 --> B1 + A2 --> B1 + A3 --> B2 + A4 --> B3 + A5 --> B3 + B1 --> B2 + B2 --> B3 + B3 --> B4 + B4 --> B5 + B5 --> G1 + B5 --> G2 +``` + +## 提示词模板 + +Slot工具使用Jinja2模板引擎生成提示词,支持中英文两种语言。模板设计遵循以下原则: + +### 模板设计特点 + +- **结构化指令**:使用XML标签清晰分隔不同部分 +- **动态内容渲染**:通过Jinja2循环语法动态生成历史工具数据 +- **多语言适配**:根据系统语言自动选择合适的模板 +- **输出格式控制**:明确指定JSON输出要求和限制 + +### 提示词模板结构 + +```mermaid +graph TD + A[SLOT_GEN_PROMPT] --> B[instructions] + A --> C[example] + A --> D[context] + A --> E[question] + A --> F[tool_info] + A --> G[tool_call] + A --> H[output] + + B --> B1[任务说明] + B --> B2[要求列表] + B --> B3[输出约束] + + C --> C1[示例场景] + C --> C2[工具信息] + C --> C3[Schema结构] + C --> C4[期望输出] + + D --> D1[历史总结] + D --> D2[事实信息] + D --> D3[工具调用历史] + + E --> E1[用户问题] + + F --> F1[工具名称] + F --> F2[工具描述] + + G --> G1[JSON Schema] + + H --> H1[JSON对象输出] +``` + +### 模板核心要素 + +1. **任务说明**:明确要求生成符合JSON Schema的参数对象 +2. **数据优先级**:用户输入 > 背景信息 > 历史数据 +3. **格式约束**:严格按照JSON Schema输出,不编造字段 +4. **可选字段处理**:可省略可选字段 +5. **示例说明**:提供具体的使用示例 + +## 工作流程 + +Slot工具采用两阶段填充策略,确保参数填充的准确性和完整性: + +```mermaid +graph TD + A[开始] --> B[接收输入数据] + B --> C[初始化SlotProcessor] + C --> D[检查当前Schema] + D --> E{是否有剩余Schema?} + E -->|否| F[返回空结果] + E -->|是| G[第一阶段:LLM填充] + G --> H[解析LLM输出] + H --> I[数据转换] + I --> J[检查剩余Schema] + J --> K{仍有剩余Schema?} + K -->|否| L[输出最终结果] + K -->|是| M[第二阶段:FunctionCall填充] + M --> N[数据转换] + N --> O[最终Schema检查] + O --> L + L --> P[结束] + + subgraph "LLM填充阶段" + G1[创建Jinja2模板] + G2[渲染提示词] + G3[调用LLM] + G4[解析JSON响应] + end + + subgraph "FunctionCall填充阶段" + M1[构建对话上下文] + M2[调用JSON函数] + M3[获取结构化数据] + end + + G --> G1 + G1 --> G2 + G2 --> G3 + G3 --> G4 + G4 --> H + + M --> M1 + M1 --> M2 + M2 --> M3 + M3 --> N +``` + +## 执行时序图 + +```mermaid +sequenceDiagram + participant E as StepExecutor + participant S as Slot + participant SP as SlotProcessor + participant T as Jinja2Template + participant L as LLM + participant F as FunctionLLM + participant V as JSONValidator + + E->>S: instance(executor, node) + S->>S: _set_input(executor) + S->>S: _init(call_vars) + S->>SP: 创建SlotProcessor(schema) + SP->>SP: 初始化验证器 + SP->>S: 返回remaining_schema + + E->>S: exec(executor, input_data) + S->>S: _exec(input_data) + + alt 有剩余Schema + S->>T: 创建SandboxedEnvironment + S->>T: 选择语言模板 + S->>T: render(工具信息, Schema, 历史数据, 总结, 问题, 事实) + T-->>S: 生成完整提示词 + + S->>L: 调用LLM生成参数 + L-->>S: 流式返回JSON响应 + S->>F: process_response(answer) + F-->>S: 处理后的JSON字符串 + S->>V: json.loads(answer) + V-->>S: 解析的JSON数据 + + S->>SP: convert_json(slot_data) + SP-->>S: 转换后的数据 + S->>SP: check_json(slot_data) + SP-->>S: 剩余Schema + + alt 仍有剩余Schema + S->>F: _json(messages, schema) + F-->>S: 结构化JSON数据 + S->>SP: convert_json(slot_data) + SP-->>S: 转换后的数据 + S->>SP: check_json(slot_data) + SP-->>S: 最终剩余Schema + end + end + + S-->>E: 返回CallOutputChunk +``` + +## 核心算法 + +### 1. 两阶段填充策略 + +```mermaid +graph LR + A[原始Schema] --> B[LLM填充阶段] + B --> C[FunctionCall填充阶段] + C --> D[最终结果] + + B --> B1[生成自然语言提示词] + B --> B2[LLM推理生成JSON] + B --> B3[解析和验证JSON] + + C --> C1[构建结构化对话] + C --> C2[调用JSON生成函数] + C --> C3[获取精确JSON数据] + + D --> D1[slot_data: 填充数据] + D --> D2[remaining_schema: 剩余Schema] +``` + +### 2. Schema验证流程 + +```mermaid +graph TD + A[输入JSON数据] --> B[SlotProcessor.check_json] + B --> C[使用Draft7Validator验证] + C --> D{验证是否通过?} + D -->|通过| E[返回空Schema] + D -->|失败| F[提取验证错误] + F --> G[构建错误Schema模板] + G --> H[生成JSON Pointer路径] + H --> I[返回remaining_schema] + + subgraph "错误处理" + F1[遍历验证错误] + F2[提取字段路径] + F3[构建字段Schema] + F4[添加到required列表] + end + + F --> F1 + F1 --> F2 + F2 --> F3 + F3 --> F4 + F4 --> G +``` + +## 使用示例 + +### 基本使用 + +```python +# 创建Slot工具实例 +slot_tool = await Slot.instance(executor, node) + +# 执行参数填充 +async for chunk in slot_tool.exec(executor, input_data): + if chunk.type == CallOutputType.DATA: + slot_output = chunk.content + print(f"填充数据: {slot_output['slot_data']}") + print(f"剩余Schema: {slot_output['remaining_schema']}") +``` + +### 输入数据示例 + +```python +# Slot工具输入数据结构示例 +slot_input = SlotInput( + remaining_schema={ + "type": "object", + "properties": { + "city": { + "type": "string", + "description": "城市名称" + }, + "date": { + "type": "string", + "description": "查询日期" + } + }, + "required": ["city", "date"] + } +) + +# 上下文数据 +context_data = { + "data": {}, + "current_schema": {...}, + "summary": "用户询问天气信息", + "facts": ["用户对杭州天气感兴趣"], + "step_num": 1 +} +``` + +### 输出数据示例 + +```python +# Slot工具输出数据结构示例 +slot_output = SlotOutput( + slot_data={ + "city": "杭州", + "date": "明天" + }, + remaining_schema={} # 空表示所有参数已填充完成 +) +``` + +## 配置参数 + +| 参数 | 类型 | 默认值 | 描述 | +|------|------|--------|------| +| `data` | dict[str, Any] | {} | 当前输入数据 | +| `current_schema` | dict[str, Any] | {} | 当前JSON Schema | +| `summary` | str | "" | 背景信息总结 | +| `facts` | list[str] | [] | 事实信息列表 | +| `step_num` | int | 1 | 历史步骤数 | +| `to_user` | bool | False | 是否将输出返回给用户 | +| `enable_filling` | bool | False | 是否需要进行自动参数填充 | + +## 错误处理 + +Slot工具包含以下错误处理机制: + +### 1. JSON解析错误 + +- LLM输出格式不正确时的异常处理 +- 使用try-catch捕获JSON解析异常 +- 解析失败时返回空字典 + +### 2. Schema验证错误 + +- JSON Schema格式错误检测 +- 验证器初始化失败处理 +- 字段验证失败时的错误提取 + +### 3. 模板渲染错误 + +- Jinja2模板渲染异常处理 +- 变量未定义时的默认值处理 +- 模板语法错误检测 + +### 4. LLM调用异常 + +- 大模型调用失败处理 +- 网络超时和重试机制 +- 响应格式验证 + +## 性能与扩展性 + +### 性能考虑 + +Slot工具在性能方面进行了以下优化: + +- **两阶段填充策略**:优先使用LLM快速填充,必要时使用FunctionCall精确填充 +- **流式输出**:支持实时流式输出,提升用户体验 +- **模板缓存**:Jinja2模板环境复用,减少重复创建开销 +- **Schema验证优化**:使用高效的JSON Schema验证器 + +### 扩展性设计 + +Slot工具设计具有良好的扩展性: + +1. **多语言支持**:可轻松添加新的语言模板 +2. **Schema扩展**:支持自定义JSON Schema验证规则 +3. **填充策略**:可扩展更多填充策略和算法 +4. **数据转换**:支持自定义数据转换器 +5. **集成接口**:基于CoreCall基类,易于集成到调度系统 + +## 依赖关系 + +- `CoreCall`: 基础调用框架 +- `SlotProcessor`: 参数槽处理器,负责Schema验证和数据转换 +- `Jinja2`: 模板引擎,用于动态生成提示词 +- `Pydantic`: 数据验证和序列化 +- `FunctionLLM`: 大语言模型接口和JSON处理 +- `jsonschema`: JSON Schema验证库 +- `CallVars`: 调用变量和上下文信息 + +## 相关模块 + +- `apps/scheduler/slot/slot.py`: 核心SlotProcessor实现 +- `apps/scheduler/call/core.py`: CoreCall基类 +- `apps/llm/function.py`: FunctionLLM接口 +- `apps/schemas/scheduler.py`: 调度器相关Schema定义 diff --git a/design/call/sql.md b/design/call/sql.md index cfcce7c3..5e412801 100644 --- a/design/call/sql.md +++ b/design/call/sql.md @@ -2,14 +2,13 @@ ## 概述 -SQL模块是Euler Copilot框架中的一个核心调用工具,用于通过自然语言查询生成SQL语句并执行数据库操作。该模块支持多种数据库类型,包括MySQL、MongoDB、PostgreSQL和OpenGauss。 +SQL模块是openEuler Intelligence框架中的一个工具,用于通过将自然语言转换为SQL语句并执行数据库操作。该模块支持多种数据库类型,包括MySQL、MongoDB、PostgreSQL和openGauss。 ## 功能特性 -- **多数据库支持**: 支持MySQL、MongoDB、PostgreSQL、OpenGauss等多种数据库 +- **多数据库支持**: 支持MySQL、MongoDB、PostgreSQL、openGauss等多种数据库 - **自然语言转SQL**: 通过外置的Chat2DB工具API,将用户问题转换为SQL语句 - **异步执行**: 采用异步编程模式,支持流式输出 -- **错误处理**: 完善的异常处理和错误信息国际化 - **配置灵活**: 支持动态配置数据库连接参数 ## 类结构 @@ -40,14 +39,11 @@ classDiagram class SQLInput { +question: str - +Field(description="用户输入") } class SQLOutput { +result: list[dict[str, Any]] +sql: str - +Field(description="SQL工具的执行结果") - +Field(description="SQL语句") } DataBase <|-- SQLInput : 继承 @@ -113,40 +109,14 @@ sequenceDiagram ## 核心方法 -### info() 类方法 - -返回Call的名称和描述信息,支持中英文国际化。 - -```python -@classmethod -def info(cls, language: LanguageType = LanguageType.CHINESE) -> CallInfo: - """返回Call的名称和描述""" -``` - -### _init() 方法 - -初始化SQL工具,从CallVars中提取用户问题。 - -```python -async def _init(self, call_vars: CallVars) -> SQLInput: - """初始化SQL工具""" - return SQLInput(question=call_vars.question) -``` - -### _exec() 方法 - -执行SQL查询的核心方法,包含以下步骤: - -1. **数据验证**: 将输入数据转换为SQLInput对象 -2. **请求组装**: 构建发送给Chat2DB API的请求数据 -3. **API调用**: 异步调用Chat2DB的/sql/handler端点 -4. **结果处理**: 解析API返回的JSON数据 -5. **输出构建**: 创建SQLOutput对象并返回 - -```python -async def _exec(self, input_data: dict[str, Any]) -> AsyncGenerator[CallOutputChunk, None]: - """运行SQL工具, 支持MySQL, MongoDB, PostgreSQL, OpenGauss""" -``` +- `info()`:返回Call的名称和描述信息,支持中英文国际化。 +- `_init()`:初始化SQL工具,从CallVars中提取用户问题。 +- `_exec()`:执行SQL查询的核心方法,包含以下步骤: + 1. **数据验证**: 将输入数据转换为SQLInput对象 + 2. **请求组装**: 构建发送给Chat2DB API的请求数据 + 3. **API调用**: 异步调用Chat2DB的/sql/handler端点 + 4. **结果处理**: 解析API返回的JSON数据 + 5. **输出构建**: 创建SQLOutput对象并返回 ## API接口规范 @@ -184,30 +154,13 @@ Chat2DB API的响应数据结构: } ``` -## 错误处理 - -### 异常类型 +## 异常 - **CallError**: 自定义异常类,用于处理SQL查询失败的情况 - **httpx异常**: HTTP请求相关的异常 - **JSON解析异常**: API响应解析失败 -### 错误消息 - -支持中英文错误消息: - -```python -MESSAGE = { - "fail": { - LanguageType.CHINESE: "SQL查询错误:SQL语句执行失败!", - LanguageType.ENGLISH: "SQL query error: SQL statement execution failed!", - }, -} -``` - -## 配置要求 - -### 环境配置 +## 配置 需要在配置文件中设置Chat2DB API的URL: @@ -216,40 +169,9 @@ MESSAGE = { sql_url = "http://chat2db-api:8080" ``` -### 数据库配置 - -SQL工具支持以下数据库配置参数: - -- **数据库类型**: postgres, mysql, mongodb, opengauss -- **连接参数**: host, port, username, password, database -- **表名列表**: 可选的表名列表,用于限制查询范围 - ## 使用示例 -### 基本用法 - -```python -# 创建SQL工具实例 -sql_tool = SQL( - database_type="postgres", - host="localhost", - port=5432, - username="postgres", - password="password", - database="mydb", - table_name_list=["users", "orders"] -) - -# 执行查询 -input_data = {"question": "查询所有用户信息"} -async for chunk in sql_tool._exec(input_data): - if chunk.type == CallOutputType.DATA: - result = chunk.content - print(f"SQL语句: {result['sql']}") - print(f"查询结果: {result['result']}") -``` - -### 在流程中使用 +### 在Flow中使用 ```yaml steps: @@ -274,12 +196,6 @@ steps: - **异步处理**: 采用异步HTTP客户端(httpx.AsyncClient),支持流式输出,提高用户体验 - **日志记录**: 详细记录SQL语句、执行结果和风险等级,便于问题排查和性能监控 -### 扩展性 - -- **支持新的数据库类型**: 可以通过修改`database_type`字段支持新的数据库类型,前提是Chat2DB API支持该数据库 -- **自定义输出格式**: 可以通过继承`SQLOutput`类来扩展输出数据结构,添加更多元数据信息 -- **错误处理增强**: 可以在`_exec`方法中添加更细粒度的错误处理逻辑,针对不同类型的错误提供更具体的错误信息 - ### 安全考虑 - **SQL注入防护**: 依赖Chat2DB工具进行SQL注入防护,该工具会验证SQL语句的安全性、评估SQL执行的风险等级、提供风险提示信息 diff --git a/design/call/summary.md b/design/call/summary.md index 0a926b07..d24fa403 100644 --- a/design/call/summary.md +++ b/design/call/summary.md @@ -2,15 +2,7 @@ ## 概述 -Summary工具是一个用于理解对话上下文的智能工具,它通过分析对话记录和关键事实,生成简洁的背景总结,为后续对话提供上下文理解支持。 - -## 功能特性 - -- **上下文理解**:分析对话记录和关键事实,生成三句话以内的背景总结 -- **多语言支持**:支持中文和英文两种语言 -- **模板化提示词**:使用Jinja2模板引擎动态生成提示词 -- **流式输出**:支持实时流式输出总结内容 -- **结构化数据**:基于Pydantic模型进行数据验证和序列化 +Summary工具是一个用于理解对话上下文的Call,它通过分析对话记录和事实条目,生成背景总结,为后续Flow的上下文理解提供支持。 ## 核心组件 @@ -18,12 +10,11 @@ Summary工具是一个用于理解对话上下文的智能工具,它通过分 Summary工具的核心实现类,继承自`CoreCall`基类。 -```python -class Summary(CoreCall, input_model=DataBase, output_model=SummaryOutput): - """总结工具""" - - context: ExecutorBackground = Field(description="对话上下文") -``` +### 2. 主要属性 + +| 属性名 | 类型 | 默认值 | 描述 | +|--------|------|--------|------| +| `context` | ExecutorBackground | - | 对话上下文信息,包含对话记录、关键事实等 | **主要方法:** @@ -31,9 +22,8 @@ class Summary(CoreCall, input_model=DataBase, output_model=SummaryOutput): - `instance()`: 创建工具实例 - `_init()`: 初始化工具输入 - `_exec()`: 执行总结生成逻辑 -- `exec()`: 公共执行接口 -### 2. 数据结构 +### 3. 数据结构 Summary工具涉及多个数据模型,它们之间的关系如下: @@ -46,16 +36,12 @@ classDiagram class SummaryOutput { +summary: str - +Field(description="对问答上下文的总结内容") } class ExecutorBackground { +num: int +conversation: list[dict[str, str]] +facts: list[str] - +Field(description="对话记录最大数量", default=0) - +Field(description="对话记录", default=[]) - +Field(description="当前Executor的背景信息", default=[]) } class Summary { @@ -79,7 +65,6 @@ classDiagram - **DataBase**: 所有Call的输入基类,提供通用的数据验证和序列化功能 - **SummaryOutput**: 继承自DataBase,包含总结内容的输出模型 - **ExecutorBackground**: 执行器背景信息,包含对话记录和关键事实 -- **Summary**: 主要的工具类,使用ExecutorBackground作为上下文,输出SummaryOutput #### 数据流转关系 @@ -112,7 +97,7 @@ graph LR C1 --> D ``` -### 3. 提示词模板 +### 4. 提示词模板 Summary工具使用Jinja2模板引擎生成提示词,支持中英文两种语言。模板设计遵循以下原则: @@ -121,8 +106,6 @@ Summary工具使用Jinja2模板引擎生成提示词,支持中英文两种语 - **多语言适配**:根据系统语言自动选择合适的模板 - **输出格式控制**:明确指定输出要求和限制 -#### 提示词模板设计 - Summary工具提供中英文两种语言的提示词模板,两种模板在结构和功能上保持一致,仅在语言表述上有所差异。模板设计包含以下核心要素: 1. **任务说明**:明确要求生成三句话背景总结,用于后续对话的上下文理解 @@ -130,14 +113,6 @@ Summary工具提供中英文两种语言的提示词模板,两种模板在结 3. **格式约束**:限制输出长度(少于3句话,少于300个字),不包含XML标签 4. **数据源标识**:清晰标记对话记录和关键事实的来源,使用XML标签进行结构化组织 -模板使用Jinja2语法进行动态渲染: - -- 通过循环语法动态生成对话记录,每个对话项包含角色和内容信息 -- 关键事实以列表形式呈现,支持多行显示 -- 根据系统语言自动选择合适的模板版本 - -这种设计确保了多语言环境下的正确显示和一致的用户体验。 - ## 工作流程 ```mermaid @@ -221,16 +196,7 @@ graph LR ## 使用示例 -### 基本使用 - -```python -# 创建Summary工具实例 -summary_tool = await Summary.instance(executor, node) - -# 执行总结生成 -async for chunk in summary_tool.exec(executor, input_data): - print(chunk.content) # 输出总结内容 -``` +Summary工具是系统内置的隐藏工具,不可由用户直接使用。 ### 上下文数据示例 @@ -267,25 +233,6 @@ Summary工具包含以下错误处理机制: 2. **模板渲染错误**:Jinja2模板渲染异常处理 3. **LLM调用异常**:大模型调用失败处理 -## 性能与扩展性 - -### 性能考虑 - -Summary工具在性能方面进行了以下优化: - -- **流式输出**:支持实时流式输出,提升用户体验 -- **模板缓存**:Jinja2模板环境复用,减少重复创建开销 -- **内存优化**:及时释放不需要的中间数据 - -### 扩展性设计 - -Summary工具设计具有良好的扩展性: - -1. **多语言支持**:可轻松添加新的语言模板 -2. **模板定制**:支持自定义提示词模板 -3. **输出格式**:可扩展输出数据结构 -4. **集成接口**:基于CoreCall基类,易于集成到调度系统 - ## 依赖关系 - `CoreCall`: 基础调用框架 -- Gitee