From 1633e2c48c12a081a6a6cfb22dcb381c37beefd6 Mon Sep 17 00:00:00 2001 From: z30057876 Date: Sat, 8 Feb 2025 19:48:09 +0800 Subject: [PATCH 1/2] =?UTF-8?q?Prompt=E5=92=8C=E6=A8=A1=E5=9E=8B=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E9=80=82=E9=85=8DDeepseek=EF=BC=881=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/config.py | 16 ++-- apps/constants.py | 7 ++ apps/entities/enum.py | 9 ++ apps/llm/function.py | 74 +++++++++++++--- apps/llm/patterns/domain.py | 59 ++++--------- apps/llm/patterns/executor.py | 39 +++------ apps/llm/patterns/facts.py | 46 +++------- apps/llm/patterns/recommend.py | 101 ++++++---------------- apps/llm/patterns/select.py | 53 ++++++------ apps/llm/reasoning.py | 153 +++++++++++++++++---------------- assets/.env.example | 21 ++--- requirements.txt | 1 - 12 files changed, 263 insertions(+), 316 deletions(-) diff --git a/apps/common/config.py b/apps/common/config.py index fcbeded2..8f487357 100644 --- a/apps/common/config.py +++ b/apps/common/config.py @@ -71,25 +71,19 @@ class ConfigModel(BaseModel): HALF_KEY1: str = Field(description="Half key 1") HALF_KEY2: str = Field(description="Half key 2") HALF_KEY3: str = Field(description="Half key 3") - # 模型类型 - MODEL: str = Field(description="选择的模型类型", default="openai") # OpenAI API LLM_KEY: Optional[str] = Field(description="OpenAI API 密钥", default=None) LLM_URL: Optional[str] = Field(description="OpenAI API URL地址", default=None) LLM_MODEL: Optional[str] = Field(description="OpenAI API 模型名", default=None) - # 星火大模型 - SPARK_APP_ID: Optional[str] = Field(description="星火大模型API 应用名", default=None) - SPARK_API_KEY: Optional[str] = Field(description="星火大模型API 密钥名", default=None) - SPARK_API_SECRET: Optional[str] = Field(description="星火大模型API 密钥值", default=None) - SPARK_API_URL: Optional[str] = Field(description="星火大模型API URL地址", default=None) - SPARK_LLM_DOMAIN: Optional[str] = Field(description="星火大模型API 领域名", default=None) - # 参数猜解 - SCHEDULER_BACKEND: Optional[str] = Field(description="参数猜解后端", default=None) + LLM_MAX_TOKENS: int = Field(description="OpenAI API 最大Token数", default=8192) + LLM_TEMPERATURE: float = Field(description="OpenAI API 温度", default=0.7) + # 参数提取 + SCHEDULER_TYPE: Optional[str] = Field(description="参数猜解后端", default=None) SCHEDULER_MODEL: Optional[str] = Field(description="参数猜解模型名", default=None) SCHEDULER_URL: Optional[str] = Field(description="参数猜解 URL地址", default=None) SCHEDULER_API_KEY: Optional[str] = Field(description="参数猜解 API密钥", default=None) SCHEDULER_MAX_TOKENS: int = Field(description="参数猜解最大Token数", default=8192) - SCHEDULER_TEMPERATURE: float = Field(description="参数猜解温度", default=0.07) + SCHEDULER_TEMPERATURE: float = Field(description="参数猜解温度", default=0.7) # 插件位置 PLUGIN_DIR: Optional[str] = Field(description="插件路径", default=None) # SQL接口路径 diff --git a/apps/constants.py b/apps/constants.py index 87ed23bc..39d2dfaa 100644 --- a/apps/constants.py +++ b/apps/constants.py @@ -14,3 +14,10 @@ MAX_API_RESPONSE_LENGTH = 4096 MAX_SCHEDULER_HISTORY_SIZE = 3 LOGGER = logging.getLogger("gunicorn.error") + +REASONING_BEGIN_TOKEN = [ + "", +] +REASONING_END_TOKEN = [ + "", +] diff --git a/apps/entities/enum.py b/apps/entities/enum.py index 8f93213e..fcc521a3 100644 --- a/apps/entities/enum.py +++ b/apps/entities/enum.py @@ -55,3 +55,12 @@ class EventType(str, Enum): STEP_OUTPUT = "step.output" FLOW_STOP = "flow.stop" DONE = "done" + + +class LLMType(str, Enum): + """大模型类型""" + + OPENAI = "openai" + VLLM = "vllm" + OLLAMA = "ollama" + SGLANG = "sglang" diff --git a/apps/llm/function.py b/apps/llm/function.py index a98d5973..a86155c6 100644 --- a/apps/llm/function.py +++ b/apps/llm/function.py @@ -1,4 +1,4 @@ -"""用于FunctionCall的大模型 +"""FunctionCall的大模型调用 Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. """ @@ -12,6 +12,7 @@ from asyncer import asyncify from sglang.lang.chat_template import get_chat_template from apps.common.config import config +from apps.constants import REASONING_BEGIN_TOKEN, REASONING_END_TOKEN from apps.scheduler.json_schema import build_regex_from_schema @@ -28,18 +29,30 @@ class FunctionLLM: - vllm """ if config["SCHEDULER_BACKEND"] == "sglang": - self._client = sglang.RuntimeEndpoint(config["SCHEDULER_URL"], api_key=config["SCHEDULER_API_KEY"]) + if not config["SCHEDULER_API_KEY"]: + self._client = sglang.RuntimeEndpoint(config["SCHEDULER_URL"]) + else: + self._client = sglang.RuntimeEndpoint(config["SCHEDULER_URL"], api_key=config["SCHEDULER_API_KEY"]) self._client.chat_template = get_chat_template("chatml") sglang.set_default_backend(self._client) - if config["SCHEDULER_BACKEND"] == "vllm": - self._client = openai.AsyncOpenAI( - base_url=config["SCHEDULER_URL"], - api_key=config["SCHEDULER_API_KEY"], - ) + if config["SCHEDULER_BACKEND"] == "vllm" or config["SCHEDULER_BACKEND"] == "openai": + if not config["SCHEDULER_API_KEY"]: + self._client = openai.AsyncOpenAI(base_url=config["SCHEDULER_URL"]) + else: + self._client = openai.AsyncOpenAI( + base_url=config["SCHEDULER_URL"], + api_key=config["SCHEDULER_API_KEY"], + ) if config["SCHEDULER_BACKEND"] == "ollama": - self._client = ollama.AsyncClient( - host=config["SCHEDULER_URL"], - ) + if not config["SCHEDULER_API_KEY"]: + self._client = ollama.AsyncClient(host=config["SCHEDULER_URL"]) + else: + self._client = ollama.AsyncClient( + host=config["SCHEDULER_URL"], + headers={ + "Authorization": f"Bearer {config['SCHEDULER_API_KEY']}", + }, + ) @staticmethod @sglang.function @@ -104,6 +117,47 @@ class FunctionLLM: return result + async def _call_openai(self, messages: list[dict[str, Any]], schema: dict[str, Any], max_tokens: int, temperature: float) -> str: + """调用openai模型生成JSON + + :param messages: 历史消息列表 + :param schema: 输出JSON Schema + :param max_tokens: 最大Token长度 + :param temperature: 大模型温度 + :return: 生成的JSON + """ + model = config["SCHEDULER_MODEL"] + if not model: + err_msg = "未设置FuntionCall所用模型!" + raise ValueError(err_msg) + + param = { + "model": model, + "messages": messages, + "max_tokens": max_tokens, + "temperature": temperature, + } + + if schema: + tool_data = { + "type": "function", + "function": { + "name": "output", + "description": "Call the function to get the output", + "parameters": schema, + }, + } + param["tools"] = [tool_data] + param["tool_choice"] = "required" + + response = await self._client.chat.completions.create(**param) # type: ignore[] + try: + ans = response.choices[0].message.tool_calls[0].function.arguments or "" + except IndexError: + ans = "" + return ans + + async def _call_ollama(self, messages: list[dict[str, Any]], schema: dict[str, Any], max_tokens: int, temperature: float) -> str: """调用ollama模型生成JSON diff --git a/apps/llm/patterns/domain.py b/apps/llm/patterns/domain.py index e2623bd8..91238973 100644 --- a/apps/llm/patterns/domain.py +++ b/apps/llm/patterns/domain.py @@ -12,47 +12,25 @@ from apps.llm.reasoning import ReasoningLLM class Domain(CorePattern): """从问答中提取领域信息""" - system_prompt: str = r""" - Your task is: Extract feature tags and categories from given conversations. - Tags and categories will be used in a recommendation system to offer search keywords to users. + system_prompt: str = "" + """系统提示词(暂不使用)""" - Conversations will be given between "" and "" tags. - - EXAMPLE 1 - - CONVERSATION: - - User: What is the weather in Beijing? - Assistant: It is sunny in Beijing. - - - OUTPUT: - Beijing, weather - END OF EXAMPLE 1 - - - EXAMPLE 2 - - CONVERSATION: - - User: Check CVEs on host 1 from 2024-01-01 to 2024-01-07. - Assistant: There are 3 CVEs on host 1 from 2024-01-01 to 2024-01-07, including CVE-2024-0001, CVE-2024-0002, and CVE-2024-0003. - + user_prompt: str = r""" + 根据对话上文,提取推荐系统所需的关键词标签,要求: + 1. 实体名词、技术术语、时间范围、地点、产品等关键信息均可作为关键词标签 + 2. 至少一个关键词与对话的话题有关 + 3. 标签需精简,不得重复,不得超过10个字 - OUTPUT: - CVE, host 1, Cybersecurity + ==示例== + 样例对话: + 用户:北京天气如何? + 助手:北京今天晴。 - END OF EXAMPLE 2 - """ - """系统提示词""" + 样例输出: + ["北京", "天气"] + ==结束示例== - user_prompt: str = r""" - CONVERSATION: - - {conversation} - - - OUTPUT: + 输出结果: """ """用户提示词""" @@ -75,10 +53,9 @@ class Domain(CorePattern): async def generate(self, task_id: str, **kwargs) -> list[str]: # noqa: ANN003 """从问答中提取领域信息""" - messages = [ - {"role": "system", "content": self.system_prompt}, - {"role": "user", "content": self.user_prompt.format(conversation=kwargs["conversation"])}, - ] + messages = [{"role": "system", "content": self.system_prompt}] + messages += kwargs["conversation"] + messages += [{"role": "user", "content": self.user_prompt}] result = "" async for chunk in ReasoningLLM().call(task_id, messages, streaming=False): diff --git a/apps/llm/patterns/executor.py b/apps/llm/patterns/executor.py index 5f39200c..726d0f1f 100644 --- a/apps/llm/patterns/executor.py +++ b/apps/llm/patterns/executor.py @@ -70,40 +70,21 @@ class ExecutorThought(CorePattern): class ExecutorBackground(CorePattern): """使用大模型进行生成Executor初始背景""" - system_prompt: str = r""" - 你是一位专门负责总结和分析对话的AI助手。你的任务是: - 1. 理解用户与AI之间的对话内容 - 2. 分析提供的关键事实列表 - 3. 结合之前的思考生成一个简洁但全面的背景总结 - 4. 确保总结包含对话中的重要信息点和关键概念 - 请用清晰、专业的语言输出总结,同时注意呈现预先考虑过的思考内容。 - """ + system_prompt: str = r"" """系统提示词""" user_prompt: str = r""" - 请分析以下内容: - - 1. 之前的思考: - - {thought} - - - 2. 对话记录(包含用户和AI的对话,在标签中): - - {conversation} - - - 3. 关键事实(在标签中): - + 根据对话上文,生成一个完整的背景总结。这个总结将用于后续对话的上下文理解。 + 生成总结的要求如下: + 1. 突出重要信息点,例如时间、地点、人物、事件等。 + 2. 下面给出的事实条目若与历史记录有关,则可以在生成总结时作为已知信息。 + 3. 确保信息准确性,不得编造信息。 + 4. 总结应少于1000个字。 + + 关键事实(在标签中): {facts} - - 请基于以上信息,生成一个完整的背景总结。这个总结将用于后续对话的上下文理解。 - 要求: - - 突出重要信息点 - - 保持逻辑连贯性 - - 确保信息准确性 - 请开始总结。 + 开始生成: """ """用户提示词""" diff --git a/apps/llm/patterns/facts.py b/apps/llm/patterns/facts.py index 8b1d0cf4..f665aa8d 100644 --- a/apps/llm/patterns/facts.py +++ b/apps/llm/patterns/facts.py @@ -10,10 +10,12 @@ from apps.llm.reasoning import ReasoningLLM class Facts(CorePattern): """事实提取""" - system_prompt: str = r""" - 你是一个信息提取助手,擅长从用户提供的个人信息中准确提取出偏好、关系、实体等有用信息,并将其进行归纳和整理。 - 你的任务是:从给出的对话中提取关键信息,并将它们组织成独一无二的、易于理解的事实。对话将以JSON格式给出,其中“question”为用户的输入,“answer”为回答。 - 以下是您需要关注的信息类型以及有关如何处理输入数据的详细说明。 + system_prompt: str = "" + """系统提示词(暂不使用)""" + + user_prompt: str = r""" + 从对话上文中提取关键信息,并将它们组织成独一无二的、易于理解的事实,包含用户偏好、关系、实体等有用信息。 + 以下是需要关注的信息类型以及有关如何处理输入数据的详细说明。 **你需要关注的信息类型** 1. 实体:对话中涉及到的实体。例如:姓名、地点、组织、事件等。 @@ -32,43 +34,19 @@ class Facts(CorePattern): } ``` - **样例** - EXAMPLE 1 - { - "question": "杭州西湖有哪些景点?", - "answer": "杭州西湖是中国浙江省杭州市的一个著名景点,以其美丽的自然风光和丰富的文化遗产而闻名。西湖周围有许多著名的景点,包括著名的苏堤、白堤、断桥、三潭印月等。西湖以其清澈的湖水和周围的山脉而著名,是中国最著名的湖泊之一。" - } + **输出格式示例** + 样例对话: + 用户:杭州西湖有哪些景点? + 助手:杭州西湖是中国浙江省杭州市的一个著名景点,以其美丽的自然风光和丰富的文化遗产而闻名。西湖周围有许多著名的景点,包括著名的苏堤、白堤、断桥、三潭印月等。西湖以其清澈的湖水和周围的山脉而著名,是中国最著名的湖泊之一。 - 事实信息: + 样例输出: ```json { "facts": ["杭州西湖有苏堤、白堤、断桥、三潭印月等景点"] } ``` - END OF EXAMPLE 1 - - EXAMPLE 2 - { - "question": "开放原子基金会是什么?", - "answer": "开放原子基金会(OpenAtom Foundation)是一个非营利性组织,旨在推动开源生态的发展。它由阿里巴巴、华为、腾讯等多家知名科技公司共同发起,致力于构建一个开放、协作、共享的开源社区。" - } - - 事实信息: - ```json - { - "facts": ["开放原子基金会是一个非营利性组织,旨在推动开源生态的发展", "开放原子基金会由阿里巴巴、华为、腾讯等多家知名科技公司共同发起"] - } - ``` - - END OF EXAMPLE 2 - """ - """系统提示词""" - - user_prompt: str = r""" - {message_json_str} - - 事实信息: + 输出结果: """ """用户提示词""" diff --git a/apps/llm/patterns/recommend.py b/apps/llm/patterns/recommend.py index b6b1e945..fd1e2d1d 100644 --- a/apps/llm/patterns/recommend.py +++ b/apps/llm/patterns/recommend.py @@ -11,98 +11,47 @@ from apps.llm.reasoning import ReasoningLLM class Recommend(CorePattern): """使用大模型进行推荐问题生成""" - system_prompt: str = r""" - 你是智能助手,负责分析问答历史并预测用户问题。 - - **任务说明:** - - 根据背景信息、工具描述和用户倾向预测问题。 - - **信息说明:** - - [Empty]标识空信息,如“背景信息: [Empty]”表示当前无背景信息。 - - 背景信息含最近1条完整问答信息及最多4条历史提问信息。 + system_prompt: str = "" + """系统提示词""" - **要求:** - 1. 用用户口吻生成问题。 - 2. 优先使用工具描述进行预测,特别是与背景或倾向无关时。 - 3. 工具描述为空时,依据背景和倾向预测。 - 4. 生成的应为疑问句或祈使句,时间限制为30字。 - 5. 避免输出非必要信息。 - 6. 新生成的问题不得与“已展示问题”或“用户历史提问”重复或相似。 + user_prompt: str = r""" + 根据对话上文、工具描述和用户倾向,生成预测问题。 - **示例:** + 信息说明: + - [Empty]标识空信息,如“工具描述: [Empty]”表示当前未使用工具。 + - 历史提问信息为背景参考作用,最多提供4条。 - EXAMPLE 1 - ## 工具描述 - 调用API,查询天气数据 + 生成时需要遵循的要求: + 1. 从用户角度生成预测问题。 + 2. 预测问题应为疑问句或祈使句,必须少于30字。 + 3. 预测问题应优先贴合工具描述,特别是工具描述与背景或倾向无关时。 + 5. 预测问题必须精简,不得输出非必要信息。 + 6. 预测问题不得与“用户历史提问”重复或相似。 - ## 背景信息 - ### 用户历史提问 - Question 1: 简单介绍杭州 - Question 2: 杭州有哪些著名景点 + ==示例== + 工具描述:调用API,查询天气数据 - ### 最近1轮问答 - Question: 帮我查询今天的杭州天气数据 - Answer: 杭州今天晴,气温20度,空气质量优。 + 用户历史提问: + - 简单介绍杭州 + - 杭州有哪些著名景点 - ## 用户倾向 + 用户倾向: ['旅游', '美食'] - ## 已展示问题 - 杭州有什么好吃的? - - ## 预测问题 + 生成的预测问题: 杭州西湖景区的门票价格是多少? - END OF EXAMPLE 1 - - EXAMPLE 2 - ## 工具描述 - [Empty] - - ## 背景信息 - ### 用户历史提问 - [Empty] - - ### 最近1轮问答 - Question: 帮我查询上周的销售数据 - Answer: 上周的销售数据如下: - 星期一:1000 - 星期二:1200 - 星期三:1100 - 星期四:1300 - 星期五:1400 + ==结束示例== - ## 用户倾向 - ['销售', '数据分析'] - ## 已展示问题 - [Empty] + 工具描述:{action_description} - ## 预测问题 - 帮我分析上周的销售数据趋势 - END OF EXAMPLE 2 - - Let's begin. - """ - """系统提示词""" - - user_prompt: str = r""" - ## 工具描述 - {action_description} - - ## 背景信息 - ### 用户历史提问 + 用户历史提问: {history_questions} - ### 最近1轮问答 - {recent_question} - - ## 用户倾向 + 用户倾向: {user_preference} - ## 已展示问题 - {shown_questions} - - ## 预测问题 + 生成的预测问题: """ """用户提示词""" diff --git a/apps/llm/patterns/select.py b/apps/llm/patterns/select.py index f7bb3284..58baa7c5 100644 --- a/apps/llm/patterns/select.py +++ b/apps/llm/patterns/select.py @@ -15,47 +15,42 @@ from apps.llm.reasoning import ReasoningLLM class Select(CorePattern): """通过投票选择最佳答案""" - system_prompt: str = r""" - Your task is: select the best option from the list of available options. The option should be able to answer \ - the question and be inferred from the context and the output. + system_prompt: str = r"" + """系统提示词""" - EXAMPLE - Question: 使用天气API,查询明天杭州的天气信息 + user_prompt: str = r""" + 根据历史对话(包括工具调用结果)和用户问题,从给出的选项列表中,选出最符合要求的那一项。 + 在输出之前,请先思考,并使用“”标签给出思考过程。 - Context: 人类首先询问了杭州有什么美食,之后询问了杭州有什么知名旅游景点。 + ==样例== + 用户问题: 使用天气API,查询明天杭州的天气信息 - Output: `{}` + 选项列表: + - [API] 请求特定API,获得返回的JSON数据 + - [SQL] 查询数据库,获得数据库表中的数据 - The available options are: - - API: 请求特定API,获得返回的JSON数据 - - SQL: 查询数据库,获得数据库表中的数据 + + API 工具可以通过 API 来获取外部数据,而天气信息可能就存储在外部数据中,由于用户说明中明确提到了天气 API 的使用,因此应该优先使用 API 工具。\ + SQL 工具用于从数据库中获取信息,考虑到天气数据的可变性和动态性,不太可能存储在数据库中,因此 SQL 工具的优先级相对较低,\ + 最佳选择似乎是“API:请求特定 API,获取返回的 JSON 数据”。 + - Let's think step by step. API tools can retrieve external data through the use of APIs, and weather \ - information may be stored in external data. As the user instructions explicitly mentioned the use of the weather API, \ - the API tool should be prioritized. SQL tools are used to retrieve information from databases. Given the variable \ - and dynamic nature of weather data, it is unlikely to be stored in a database. Therefore, the priority of \ - SQL tools is relatively low. The best option seems to be "API: request a specific API, get the \ - returned JSON data". - END OF EXAMPLE + 最符合要求的选项是: + API + ==结束样例== - Let's begin. - """ - """系统提示词""" + 用户问题: {question} - user_prompt: str = r""" - Question: {question} - - Context: {background} - - Output: `{data}` - - The available options are: + 选项列表: {choice_list} - Let's think step by step. + 思考: + + 让我们一步一步思考。 """ """用户提示词""" + slot_schema: ClassVar[dict[str, Any]] = { "type": "object", "properties": { diff --git a/apps/llm/reasoning.py b/apps/llm/reasoning.py index a0446c5a..568735e4 100644 --- a/apps/llm/reasoning.py +++ b/apps/llm/reasoning.py @@ -1,69 +1,36 @@ -"""推理/生成大模型调用 +"""问答大模型调用 Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved. """ from collections.abc import AsyncGenerator +from typing import Optional import tiktoken -from langchain_core.messages import ChatMessage as LangchainChatMessage -from langchain_openai import ChatOpenAI -from sparkai.llm.llm import ChatSparkLLM -from sparkai.messages import ChatMessage as SparkChatMessage +from openai import AsyncOpenAI from apps.common.config import config from apps.common.singleton import Singleton +from apps.constants import REASONING_BEGIN_TOKEN, REASONING_END_TOKEN from apps.manager.task import TaskManager class ReasoningLLM(metaclass=Singleton): - """调用用于推理/生成的大模型""" + """调用用于问答的大模型""" _encoder = tiktoken.get_encoding("cl100k_base") def __init__(self) -> None: """判断配置文件里用了哪种大模型;初始化大模型客户端""" - if config["MODEL"] == "openai": - self._client = ChatOpenAI( - api_key=config["LLM_KEY"], + if not config["LLM_KEY"]: + self._client = AsyncOpenAI( base_url=config["LLM_URL"], - model=config["LLM_MODEL"], - tiktoken_model_name="cl100k_base", - streaming=True, ) - elif config["MODEL"] == "spark": - self._client = ChatSparkLLM( - spark_app_id=config["SPARK_APP_ID"], - spark_api_key=config["SPARK_API_KEY"], - spark_api_secret=config["SPARK_API_SECRET"], - spark_api_url=config["SPARK_API_URL"], - spark_llm_domain=config["SPARK_LLM_DOMAIN"], - request_timeout=600, - streaming=True, - ) - else: - err = "暂不支持此种大模型API" - raise NotImplementedError(err) - - - @staticmethod - def _construct_openai_message(messages: list[dict[str, str]]) -> list[LangchainChatMessage]: - """模型类型为OpenAI API时:构造消息列表 - - :param messages: 原始的消息,形如`{"role": "xxx", "content": "xxx"}` - :returns: 构造后的消息内容 - """ - return [LangchainChatMessage(content=msg["content"], role=msg["role"]) for msg in messages] - - - @staticmethod - def _construct_spark_message(messages: list[dict[str, str]]) -> list[SparkChatMessage]: - """当模型类型为星火(星火SDK时),构造消息 - - :param messages: 原始的消息,形如`{"role": "xxx", "content": "xxx"}` - :return: 构造后的消息内容 - """ - return [SparkChatMessage(content=msg["content"], role=msg["role"]) for msg in messages] + return + self._client = AsyncOpenAI( + api_key=config["LLM_KEY"], + base_url=config["LLM_URL"], + ) def _calculate_token_length(self, messages: list[dict[str, str]], *, pure_text: bool = False) -> int: """使用ChatGPT的cl100k tokenizer,估算Token消耗量""" @@ -76,36 +43,78 @@ class ReasoningLLM(metaclass=Singleton): return result + def _validate_messages(self, messages: list[dict[str, str]]) -> list[dict[str, str]]: + """验证消息格式是否正确""" + if messages[0]["role"] != "system": + # 添加默认系统消息 + messages.insert(0, {"role": "system", "content": "You are a helpful assistant."}) - async def call(self, task_id: str, messages: list[dict[str, str]], - max_tokens: int = 8192, temperature: float = 0.07, *, streaming: bool = True) -> AsyncGenerator[str, None]: - """调用大模型,分为流式和非流式两种 + if messages[-1]["role"] != "user": + err = f"消息格式错误,最后一个消息必须是用户消息:{messages[-1]}" + raise ValueError(err) - :param task_id: 任务ID - :param messages: 原始消息 - :param streaming: 是否启用流式输出 - :param max_tokens: 最大Token数 - :param temperature: 模型温度(随机化程度) - """ - input_tokens = self._calculate_token_length(messages) + return messages - if config["MODEL"] == "openai": - msg_list = self._construct_openai_message(messages) - elif config["MODEL"] == "spark": - msg_list = self._construct_spark_message(messages) - else: - err = "暂不支持此种大模型API" - raise NotImplementedError(err) - - if streaming: - result = "" - async for chunk in self._client.astream(msg_list, max_tokens=max_tokens, temperature=temperature): # type: ignore[arg-type] - yield str(chunk.content) - result += str(chunk.content) - else: - result = await self._client.ainvoke(msg_list, max_tokens=max_tokens, temperature=temperature) # type: ignore[arg-type] - yield str(result.content) - result = str(result.content) + async def call(self, task_id: str, messages: list[dict[str, str]], # noqa: C901, PLR0912 + max_tokens: Optional[int] = None, temperature: Optional[float] = None, + *, streaming: bool = True) -> AsyncGenerator[str, None]: + """调用大模型,分为流式和非流式两种""" + input_tokens = self._calculate_token_length(messages) + try: + + msg_list = self._validate_messages(messages) + except ValueError as e: + err = f"消息格式错误:{e}" + raise ValueError(err) from e + + if max_tokens is None: + max_tokens = config["LLM_MAX_TOKENS"] + if temperature is None: + temperature = config["LLM_TEMPERATURE"] + + stream = await self._client.chat.completions.create( + model=config["LLM_MODEL"], + messages=msg_list, # type: ignore[] + max_tokens=max_tokens, + temperature=temperature, + stream=True, + ) # type: ignore[] + + result = "" + + async for chunk in stream: + content = chunk.choices[0].delta.content or "" + reason = "" + if hasattr(chunk.choices[0].delta, "reasoning_content"): + reason = chunk.choices[0].delta.reasoning_content or "" + + if reason: + if "" not in result: + reason = "" + reason + result += reason + if streaming: + yield reason + continue + else: + if "" in result and "" not in result: + result += "" + if streaming: + yield "" + + for token in REASONING_BEGIN_TOKEN: + if token in content: + content = content.replace(token, "") + + for token in REASONING_END_TOKEN: + if token in content: + content = content.replace(token, "") + + result += content + if streaming: + yield content + + if not streaming: + yield result output_tokens = self._calculate_token_length([{"role": "assistant", "content": result}], pure_text=True) await TaskManager.update_token_summary(task_id, input_tokens, output_tokens) diff --git a/assets/.env.example b/assets/.env.example index ccfc158f..931d9c99 100644 --- a/assets/.env.example +++ b/assets/.env.example @@ -74,26 +74,21 @@ HALF_KEY1= HALF_KEY2= HALF_KEY3= -# LLM -MODEL= -## Spark -SPARK_APP_ID= -SPARK_API_KEY= -SPARK_API_SECRET= -SPARK_API_URL= -SPARK_LLM_DOMAIN= -## OpenAI Compatible +# OpenAI接口(用于问答) +LLM_TYPE= LLM_URL= LLM_KEY= -LLM_MODEL_NAME= +LLM_MODEL= +LLM_MAX_TOKENS=8192 +LLM_TEMPERATURE=0.7 -# 调度 -SCHEDULER_BACKEND= +# 小模型接口(用于参数提取等程序功能) +SCHEDULER_TYPE= SCHEDULER_MODEL= SCHEDULER_URL= SCHEDULER_API_KEY= SCHEDULER_MAX_TOKENS=8192 -SCHEDULER_TEMPERATURE=0.07 +SCHEDULER_TEMPERATURE=0.7 # 插件 PLUGIN_DIR= diff --git a/requirements.txt b/requirements.txt index 5cbab4b8..862b3629 100644 --- a/requirements.txt +++ b/requirements.txt @@ -43,7 +43,6 @@ redis==5.2.0 requests==2.32.3 sglang==0.4.0.post1 sortedcontainers==2.4.0 -spark-ai-python==0.4.5 sqlalchemy==2.0.35 starlette==0.41.2 tiktoken==0.8.0 -- Gitee From 57f052ada06d65c57b0bf029e0b05f4811f4c254 Mon Sep 17 00:00:00 2001 From: z30057876 Date: Sun, 9 Feb 2025 19:50:09 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=9B=B4=E6=96=B0database=20chart?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/configs/mongo/healthcheck.sh | 15 -- deploy/chart/databases/configs/pgsql/init.sql | 4 - .../templates/minio/minio-ingress.yaml | 19 --- .../templates/minio/minio-secret.yaml | 10 -- .../templates/minio/minio-service.yaml | 24 ---- .../{minio-pvc.yaml => minio-storage.yaml} | 5 +- .../{minio-deployment.yaml => minio.yaml} | 67 +++++++-- .../templates/mongo/mongo-config.yaml | 23 +++ .../templates/mongo/mongo-secret.yaml | 12 -- .../templates/mongo/mongo-service.yaml | 17 --- .../{mongo-pvc.yaml => mongo-storage.yaml} | 6 +- .../{mongo-deployment.yaml => mongo.yaml} | 46 ++++-- .../templates/pgsql/pgsql-config.yaml | 13 ++ .../templates/pgsql/pgsql-secret.yaml | 11 -- .../templates/pgsql/pgsql-service.yaml | 17 --- .../{pgsql-pvc.yaml => pgsql-storage.yaml} | 5 +- .../{pgsql-deployment.yaml => pgsql.yaml} | 47 ++++-- .../templates/redis/redis-secret.yaml | 10 -- .../templates/redis/redis-service.yaml | 17 --- .../{redis-deployment.yaml => redis.yaml} | 42 ++++-- deploy/chart/databases/templates/secrets.yaml | 16 +++ deploy/chart/databases/values.yaml | 135 +++++++----------- 22 files changed, 259 insertions(+), 302 deletions(-) delete mode 100644 deploy/chart/databases/configs/mongo/healthcheck.sh delete mode 100644 deploy/chart/databases/configs/pgsql/init.sql delete mode 100644 deploy/chart/databases/templates/minio/minio-ingress.yaml delete mode 100644 deploy/chart/databases/templates/minio/minio-secret.yaml delete mode 100644 deploy/chart/databases/templates/minio/minio-service.yaml rename deploy/chart/databases/templates/minio/{minio-pvc.yaml => minio-storage.yaml} (62%) rename deploy/chart/databases/templates/minio/{minio-deployment.yaml => minio.yaml} (46%) create mode 100644 deploy/chart/databases/templates/mongo/mongo-config.yaml delete mode 100644 deploy/chart/databases/templates/mongo/mongo-secret.yaml delete mode 100644 deploy/chart/databases/templates/mongo/mongo-service.yaml rename deploy/chart/databases/templates/mongo/{mongo-pvc.yaml => mongo-storage.yaml} (62%) rename deploy/chart/databases/templates/mongo/{mongo-deployment.yaml => mongo.yaml} (63%) create mode 100644 deploy/chart/databases/templates/pgsql/pgsql-config.yaml delete mode 100644 deploy/chart/databases/templates/pgsql/pgsql-secret.yaml delete mode 100644 deploy/chart/databases/templates/pgsql/pgsql-service.yaml rename deploy/chart/databases/templates/pgsql/{pgsql-pvc.yaml => pgsql-storage.yaml} (62%) rename deploy/chart/databases/templates/pgsql/{pgsql-deployment.yaml => pgsql.yaml} (53%) delete mode 100644 deploy/chart/databases/templates/redis/redis-secret.yaml delete mode 100644 deploy/chart/databases/templates/redis/redis-service.yaml rename deploy/chart/databases/templates/redis/{redis-deployment.yaml => redis.yaml} (52%) create mode 100644 deploy/chart/databases/templates/secrets.yaml diff --git a/deploy/chart/databases/configs/mongo/healthcheck.sh b/deploy/chart/databases/configs/mongo/healthcheck.sh deleted file mode 100644 index 299d945b..00000000 --- a/deploy/chart/databases/configs/mongo/healthcheck.sh +++ /dev/null @@ -1,15 +0,0 @@ -#! /bin/bash - -if mongosh --quiet --eval "rs.status().ok" -u ${MONGO_INITDB_ROOT_USERNAME} -p ${MONGO_INITDB_ROOT_PASSWORD} &> /dev/null; then - echo "MongoDB集群状态正常" - exit 0 -else - echo "初始化MongoDB集群" - if ! mongosh --quiet --eval 'rs.initiate({_id: "rs0", members: [{ _id: 0, host: "127.0.0.1:27017" }]});' -u ${MONGO_INITDB_ROOT_USERNAME} -p ${MONGO_INITDB_ROOT_PASSWORD} &> /dev/null; then - echo "初始化MongoDB集群失败!" - exit 1 - fi - echo "初始化MongoDB集群成功!" - exit 0 -fi - \ No newline at end of file diff --git a/deploy/chart/databases/configs/pgsql/init.sql b/deploy/chart/databases/configs/pgsql/init.sql deleted file mode 100644 index 85fba6ef..00000000 --- a/deploy/chart/databases/configs/pgsql/init.sql +++ /dev/null @@ -1,4 +0,0 @@ -CREATE EXTENSION zhparser; -CREATE EXTENSION vector; -CREATE TEXT SEARCH CONFIGURATION zhparser (PARSER = zhparser); -ALTER TEXT SEARCH CONFIGURATION zhparser ADD MAPPING FOR n,v,a,i,e,l WITH simple; \ No newline at end of file diff --git a/deploy/chart/databases/templates/minio/minio-ingress.yaml b/deploy/chart/databases/templates/minio/minio-ingress.yaml deleted file mode 100644 index be64c6c8..00000000 --- a/deploy/chart/databases/templates/minio/minio-ingress.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if .Values.databases.minio.ingress.enabled }} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: minio-ingress-{{ .Release.Name }} - namespace: {{ .Release.Namespace }} -spec: - rules: - - host: {{ .Values.databases.minio.ingress.domain }} - http: - paths: - - path: {{ .Values.databases.minio.ingress.prefix }} - pathType: Prefix - backend: - service: - name: minio-service-{{ .Release.Name }} - port: - number: 9001 -{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/minio/minio-secret.yaml b/deploy/chart/databases/templates/minio/minio-secret.yaml deleted file mode 100644 index d62b215c..00000000 --- a/deploy/chart/databases/templates/minio/minio-secret.yaml +++ /dev/null @@ -1,10 +0,0 @@ -{{- if .Values.databases.minio.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: minio-secret-{{ .Release.Name }} - namespace: {{ .Release.Namespace }} -type: Opaque -stringData: - minio-password: {{ .Values.databases.minio.password }} -{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/minio/minio-service.yaml b/deploy/chart/databases/templates/minio/minio-service.yaml deleted file mode 100644 index a528fbfd..00000000 --- a/deploy/chart/databases/templates/minio/minio-service.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- if .Values.databases.minio.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: minio-service-{{ .Release.Name }} - namespace: {{ .Release.Namespace }} -spec: - type: {{ .Values.databases.minio.service.type }} - selector: - app: minio-{{ .Release.Name }} - ports: - - name: minio-data - port: 9000 - targetPort: 9000 - {{- if (and (eq .Values.databases.minio.service.type "NodePort") .Values.databases.minio.service.dataNodePort) }} - nodePort: {{ .Values.databases.minio.service.dataNodePort }} - {{- end }} - - name: minio-console - port: 9001 - targetPort: 9001 - {{- if (and (eq .Values.databases.minio.service.type "NodePort") .Values.databases.minio.service.consoleNodePort) }} - nodePort: {{ .Values.databases.minio.service.consoleNodePort }} - {{- end }} -{{- end }} diff --git a/deploy/chart/databases/templates/minio/minio-pvc.yaml b/deploy/chart/databases/templates/minio/minio-storage.yaml similarity index 62% rename from deploy/chart/databases/templates/minio/minio-pvc.yaml rename to deploy/chart/databases/templates/minio/minio-storage.yaml index 69ab0706..aa5061d8 100644 --- a/deploy/chart/databases/templates/minio/minio-pvc.yaml +++ b/deploy/chart/databases/templates/minio/minio-storage.yaml @@ -2,14 +2,15 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: minio-pvc-{{ .Release.Name }} + name: minio-storage namespace: {{ .Release.Namespace }} annotations: helm.sh/resource-policy: keep spec: + storageClassName: {{ default "local-path" .Values.globals.storageClass }} accessModes: - ReadWriteOnce resources: requests: - storage: {{ .Values.databases.minio.persistentVolumeSize }} + storage: {{ default "10Gi" .Values.storage.minio }} {{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/minio/minio-deployment.yaml b/deploy/chart/databases/templates/minio/minio.yaml similarity index 46% rename from deploy/chart/databases/templates/minio/minio-deployment.yaml rename to deploy/chart/databases/templates/minio/minio.yaml index 72818696..ab616c7d 100644 --- a/deploy/chart/databases/templates/minio/minio-deployment.yaml +++ b/deploy/chart/databases/templates/minio/minio.yaml @@ -1,26 +1,66 @@ {{- if .Values.databases.minio.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: minio-service + namespace: {{ .Release.Namespace }} +spec: + type: {{ default "ClusterIP" .Values.databases.minio.service.type }} + selector: + app: minio + ports: + - name: minio-data + port: 9000 + targetPort: 9000 + nodePort: {{ default nil .Values.databases.minio.service.dataNodePort }} + - name: minio-console + port: 9001 + targetPort: 9001 + nodePort: {{ default nil .Values.databases.minio.service.consoleNodePort }} + +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: minio-ingress + namespace: {{ .Release.Namespace }} +spec: + rules: + - host: {{ default "minio.eulercopilot.local" .Values.domain.minioConsole }} + http: + paths: + - path: {{ default "/" .Values.databases.minio.ingress.prefix }} + pathType: Prefix + backend: + service: + name: minio-service + port: + number: 9001 + +--- apiVersion: apps/v1 kind: Deployment metadata: - name: minio-deploy-{{ .Release.Name }} + name: minio-deploy namespace: {{ .Release.Namespace }} labels: - app: minio-{{ .Release.Name }} + app: minio spec: - replicas: {{ .Values.globals.replicaCount }} + replicas: {{ default 1 .Values.globals.replicaCount }} selector: matchLabels: - app: minio-{{ .Release.Name }} + app: minio template: metadata: labels: - app: minio-{{ .Release.Name }} + app: minio spec: automountServiceAccountToken: false containers: - name: minio - image: "{{if ne ( .Values.databases.minio.image.registry | toString ) ""}}{{ .Values.databases.minio.image.registry }}{{ else }}{{ .Values.globals.imageRegistry }}{{ end }}/{{ .Values.databases.minio.image.name }}:{{ .Values.databases.minio.image.tag | toString }}" - imagePullPolicy: {{ if ne ( .Values.databases.minio.image.imagePullPolicy | toString ) "" }}{{ .Values.databases.minio.image.imagePullPolicy }}{{ else }}{{ .Values.globals.imagePullPolicy }}{{ end }} + image: {{ default "hub.oepkgs.net/neocopilot/minio:empty" .Values.databases.minio.image }} + imagePullPolicy: {{ default "IfNotPresent" .Values.globals.imagePullPolicy }} args: - "server" - "/data" @@ -49,18 +89,19 @@ spec: - name: MINIO_ROOT_PASSWORD valueFrom: secretKeyRef: - name: minio-secret-{{ .Release.Name }} + name: euler-copilot-database key: minio-password volumeMounts: - mountPath: "/data" name: minio-data resources: - {{- toYaml .Values.databases.minio.resources | nindent 12 }} + requests: + cpu: 0.25 + memory: 256Mi + limits: + {{- toYaml .Values.databases.minio.resourceLimits | nindent 14 }} volumes: - name: minio-data persistentVolumeClaim: - claimName: minio-pvc-{{ .Release.Name }} - - name: minio-init - secret: - secretName: minio-secret-{{ .Release.Name }} + claimName: minio-storage {{- end }} diff --git a/deploy/chart/databases/templates/mongo/mongo-config.yaml b/deploy/chart/databases/templates/mongo/mongo-config.yaml new file mode 100644 index 00000000..1dba95d1 --- /dev/null +++ b/deploy/chart/databases/templates/mongo/mongo-config.yaml @@ -0,0 +1,23 @@ +{{- if .Values.databases.mongo.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: mongo-config + namespace: {{ .Release.Namespace }} +data: + healthcheck.sh: | + #! /bin/bash + + if mongosh --quiet --eval "rs.status().ok" -u ${MONGO_INITDB_ROOT_USERNAME} -p ${MONGO_INITDB_ROOT_PASSWORD} &> /dev/null; then + echo "MongoDB集群状态正常" + exit 0 + else + echo "初始化MongoDB集群" + if ! mongosh --quiet --eval 'rs.initiate({_id: "rs0", members: [{ _id: 0, host: "127.0.0.1:27017" }]});' -u ${MONGO_INITDB_ROOT_USERNAME} -p ${MONGO_INITDB_ROOT_PASSWORD} &> /dev/null; then + echo "初始化MongoDB集群失败!" + exit 1 + fi + echo "初始化MongoDB集群成功!" + exit 0 + fi +{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/mongo/mongo-secret.yaml b/deploy/chart/databases/templates/mongo/mongo-secret.yaml deleted file mode 100644 index 62bb2675..00000000 --- a/deploy/chart/databases/templates/mongo/mongo-secret.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.databases.mongo.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: mongo-secret-{{ .Release.Name }} - namespace: {{ .Release.Namespace }} -type: Opaque -stringData: - mongo-password: {{ .Values.databases.mongo.password }} - healthcheck.sh: | -{{ tpl (.Files.Get "configs/mongo/healthcheck.sh") . | indent 4 }} -{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/mongo/mongo-service.yaml b/deploy/chart/databases/templates/mongo/mongo-service.yaml deleted file mode 100644 index 9e758c73..00000000 --- a/deploy/chart/databases/templates/mongo/mongo-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- if .Values.databases.mongo.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: mongo-db-{{ .Release.Name }} - namespace: {{ .Release.Namespace }} -spec: - type: {{ .Values.databases.mongo.service.type }} - selector: - app: mongo-{{ .Release.Name }} - ports: - - port: 27017 - targetPort: 27017 - {{- if (and (eq .Values.databases.mongo.service.type "NodePort") .Values.databases.mongo.service.nodePort) }} - nodePort: {{ .Values.databases.mongo.service.nodePort }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/mongo/mongo-pvc.yaml b/deploy/chart/databases/templates/mongo/mongo-storage.yaml similarity index 62% rename from deploy/chart/databases/templates/mongo/mongo-pvc.yaml rename to deploy/chart/databases/templates/mongo/mongo-storage.yaml index 8cecc5dd..0adcab70 100644 --- a/deploy/chart/databases/templates/mongo/mongo-pvc.yaml +++ b/deploy/chart/databases/templates/mongo/mongo-storage.yaml @@ -2,15 +2,15 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: mongo-pvc-{{ .Release.Name }} + name: mongo-storage namespace: {{ .Release.Namespace }} annotations: helm.sh/resource-policy: keep spec: + storageClassName: {{ default "local-path" .Values.globals.storageClass }} accessModes: - ReadWriteOnce - storageClassName: local-path resources: requests: - storage: {{ .Values.databases.mongo.persistentVolumeSize }} + storage: {{ default "10Gi" .Values.storage.mongo }} {{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/mongo/mongo-deployment.yaml b/deploy/chart/databases/templates/mongo/mongo.yaml similarity index 63% rename from deploy/chart/databases/templates/mongo/mongo-deployment.yaml rename to deploy/chart/databases/templates/mongo/mongo.yaml index 842ea499..46dbdd8e 100644 --- a/deploy/chart/databases/templates/mongo/mongo-deployment.yaml +++ b/deploy/chart/databases/templates/mongo/mongo.yaml @@ -1,28 +1,42 @@ {{- if .Values.databases.mongo.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: mongo-db + namespace: {{ .Release.Namespace }} +spec: + type: {{ default "ClusterIP" .Values.databases.mongo.service.type }} + selector: + app: mongo + ports: + - port: 27017 + targetPort: 27017 + nodePort: {{ default nil .Values.databases.mongo.service.nodePort }} + +--- apiVersion: apps/v1 kind: Deployment metadata: - name: mongo-deploy-{{ .Release.Name }} + name: mongo-deploy namespace: {{ .Release.Namespace }} labels: - app: mongo-{{ .Release.Name }} + app: mongo spec: - replicas: {{ .Values.globals.replicaCount }} + replicas: {{ default 1 .Values.globals.replicaCount }} selector: matchLabels: - app: mongo-{{ .Release.Name }} + app: mongo template: metadata: - annotations: - checksum/secret: {{ include (print $.Template.BasePath "/mongo/mongo-secret.yaml") . | sha256sum }} labels: - app: mongo-{{ .Release.Name }} + app: mongo spec: automountServiceAccountToken: false containers: - name: mongo - image: "{{ if ne (.Values.databases.mongo.image.registry | toString ) "" }}{{ .Values.databases.mongo.image.registry }}{{ else }}{{ .Values.globals.imageRegistry }}{{ end }}/{{ .Values.databases.mongo.image.name }}:{{ .Values.databases.mongo.image.tag | toString }}" - imagePullPolicy: {{ if ne (.Values.databases.mongo.image.imagePullPolicy | toString) "" }}{{ .Values.databases.mongo.image.imagePullPolicy }}{{ else }}{{ .Values.globals.imagePullPolicy }}{{ end }} + image: {{ default "hub.oepkgs.net/neocopilot/mongo:7.0.16-x86" .Values.databases.mongo.image }} + imagePullPolicy: {{ default "IfNotPresent" .Values.globals.imagePullPolicy }} command: - bash - -c @@ -59,7 +73,7 @@ spec: - name: MONGO_INITDB_ROOT_PASSWORD valueFrom: secretKeyRef: - name: mongo-secret-{{ .Release.Name }} + name: euler-copilot-database key: mongo-password - name: MONGO_INITDB_DATABASE value: euler_copilot @@ -70,13 +84,17 @@ spec: name: mongo-init subPath: healthcheck.sh resources: - {{- toYaml .Values.databases.mongo.resources | nindent 12 }} + requests: + cpu: 0.25 + memory: 256Mi + limits: + {{- toYaml .Values.databases.mongo.resourceLimits | nindent 14 }} restartPolicy: Always volumes: - name: mongo-data persistentVolumeClaim: - claimName: mongo-pvc-{{ .Release.Name }} + claimName: mongo-storage - name: mongo-init - secret: - secretName: mongo-secret-{{ .Release.Name }} + configMap: + name: mongo-config {{- end }} diff --git a/deploy/chart/databases/templates/pgsql/pgsql-config.yaml b/deploy/chart/databases/templates/pgsql/pgsql-config.yaml new file mode 100644 index 00000000..9c7c4d66 --- /dev/null +++ b/deploy/chart/databases/templates/pgsql/pgsql-config.yaml @@ -0,0 +1,13 @@ +{{- if .Values.databases.pgsql.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: pgsql-config + namespace: {{ .Release.Namespace }} +data: + init.sql: | + CREATE EXTENSION zhparser; + CREATE EXTENSION vector; + CREATE TEXT SEARCH CONFIGURATION zhparser (PARSER = zhparser); + ALTER TEXT SEARCH CONFIGURATION zhparser ADD MAPPING FOR n,v,a,i,e,l WITH simple; +{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/pgsql/pgsql-secret.yaml b/deploy/chart/databases/templates/pgsql/pgsql-secret.yaml deleted file mode 100644 index 387a2b66..00000000 --- a/deploy/chart/databases/templates/pgsql/pgsql-secret.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- if .Values.databases.pgsql.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: pgsql-secret-{{ .Release.Name }} - namespace: {{ .Release.Namespace }} -type: Opaque -stringData: - init.sql: -{{ tpl (.Files.Get "configs/pgsql/init.sql") . | indent 4 }} -{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/pgsql/pgsql-service.yaml b/deploy/chart/databases/templates/pgsql/pgsql-service.yaml deleted file mode 100644 index 7c0e000e..00000000 --- a/deploy/chart/databases/templates/pgsql/pgsql-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- if .Values.databases.pgsql.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: pgsql-db-{{ .Release.Name }} - namespace: {{ .Release.Namespace }} -spec: - type: {{ .Values.databases.pgsql.service.type }} - selector: - app: pgsql-{{ .Release.Name }} - ports: - - port: 5432 - targetPort: 5432 - {{- if (and (eq .Values.databases.pgsql.service.type "NodePort") .Values.databases.pgsql.service.nodePort) }} - nodePort: {{ .Values.databases.pgsql.service.nodePort }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/pgsql/pgsql-pvc.yaml b/deploy/chart/databases/templates/pgsql/pgsql-storage.yaml similarity index 62% rename from deploy/chart/databases/templates/pgsql/pgsql-pvc.yaml rename to deploy/chart/databases/templates/pgsql/pgsql-storage.yaml index f3fcfc87..ca72ea10 100644 --- a/deploy/chart/databases/templates/pgsql/pgsql-pvc.yaml +++ b/deploy/chart/databases/templates/pgsql/pgsql-storage.yaml @@ -2,14 +2,15 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: pgsql-pvc-{{ .Release.Name }} + name: pgsql-storage namespace: {{ .Release.Namespace }} annotations: helm.sh/resource-policy: keep spec: + storageClassName: {{ default "local-path" .Values.globals.storageClass }} accessModes: - ReadWriteOnce resources: requests: - storage: {{ .Values.databases.pgsql.persistentVolumeSize }} + storage: {{ default "10Gi" .Values.storage.pgsql }} {{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/pgsql/pgsql-deployment.yaml b/deploy/chart/databases/templates/pgsql/pgsql.yaml similarity index 53% rename from deploy/chart/databases/templates/pgsql/pgsql-deployment.yaml rename to deploy/chart/databases/templates/pgsql/pgsql.yaml index df8cee79..3ade7ee1 100644 --- a/deploy/chart/databases/templates/pgsql/pgsql-deployment.yaml +++ b/deploy/chart/databases/templates/pgsql/pgsql.yaml @@ -1,26 +1,42 @@ {{- if .Values.databases.pgsql.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: pgsql-db + namespace: {{ .Release.Namespace }} +spec: + type: {{ default "ClusterIP" .Values.databases.pgsql.service.type }} + selector: + app: pgsql + ports: + - port: 5432 + targetPort: 5432 + nodePort: {{ default nil .Values.databases.pgsql.service.nodePort }} + +--- apiVersion: apps/v1 kind: Deployment metadata: - name: pgsql-deploy-{{ .Release.Name }} + name: pgsql-deploy namespace: {{ .Release.Namespace }} labels: - app: pgsql-{{ .Release.Name }} + app: pgsql spec: - replicas: {{ .Values.globals.replicaCount }} + replicas: {{ default 1 .Values.globals.replicaCount }} selector: matchLabels: - app: pgsql-{{ .Release.Name }} + app: pgsql template: metadata: labels: - app: pgsql-{{ .Release.Name }} + app: pgsql spec: automountServiceAccountToken: false containers: - name: pgsql - image: "{{if ne ( .Values.databases.pgsql.image.registry | toString ) ""}}{{ .Values.databases.pgsql.image.registry }}{{ else }}{{ .Values.globals.imageRegistry }}{{ end }}/{{ .Values.databases.pgsql.image.name }}:{{ .Values.databases.pgsql.image.tag | toString }}" - imagePullPolicy: {{ if ne ( .Values.databases.pgsql.image.imagePullPolicy | toString ) "" }}{{ .Values.databases.pgsql.image.imagePullPolicy }}{{ else }}{{ .Values.globals.imagePullPolicy }}{{ end }} + image: {{ default "hub.oepkgs.net/neocopilot/pgsql-empty:pg16" .Values.databases.pgsql.image }} + imagePullPolicy: {{ default "IfNotPresent" .Values.globals.imagePullPolicy }} ports: - containerPort: 5432 protocol: TCP @@ -40,7 +56,10 @@ spec: - name: POSTGRES_USER value: "postgres" - name: POSTGRES_PASSWORD - value: "{{ .Values.databases.pgsql.password }}" + valueFrom: + secretKeyRef: + name: euler-copilot-database + key: pgsql-password volumeMounts: - mountPath: /var/lib/postgresql/data name: pgsql-data @@ -48,12 +67,16 @@ spec: name: pgsql-init subPath: init.sql resources: - {{- toYaml .Values.databases.pgsql.resources | nindent 12 }} + requests: + cpu: 0.25 + memory: 256Mi + limits: + {{- toYaml .Values.databases.pgsql.resourceLimits | nindent 14 }} volumes: - name: pgsql-data persistentVolumeClaim: - claimName: pgsql-pvc-{{ .Release.Name }} + claimName: pgsql-storage - name: pgsql-init - secret: - secretName: pgsql-secret-{{ .Release.Name }} + configMap: + name: pgsql-config {{- end }} diff --git a/deploy/chart/databases/templates/redis/redis-secret.yaml b/deploy/chart/databases/templates/redis/redis-secret.yaml deleted file mode 100644 index 41d859f6..00000000 --- a/deploy/chart/databases/templates/redis/redis-secret.yaml +++ /dev/null @@ -1,10 +0,0 @@ -{{- if .Values.databases.redis.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: redis-secret-{{ .Release.Name }} - namespace: {{ .Release.Namespace }} -type: Opaque -stringData: - redis-password: {{ .Values.databases.redis.password }} -{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/redis/redis-service.yaml b/deploy/chart/databases/templates/redis/redis-service.yaml deleted file mode 100644 index db37dbfb..00000000 --- a/deploy/chart/databases/templates/redis/redis-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- if .Values.databases.redis.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: redis-db-{{ .Release.Name }} - namespace: {{ .Release.Namespace }} -spec: - type: {{ .Values.databases.redis.service.type }} - selector: - app: redis-{{ .Release.Name }} - ports: - - port: 6379 - targetPort: 6379 - {{- if (and (eq .Values.databases.redis.service.type "NodePort") .Values.databases.redis.service.nodePort) }} - nodePort: {{ .Values.databases.redis.service.nodePort }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/templates/redis/redis-deployment.yaml b/deploy/chart/databases/templates/redis/redis.yaml similarity index 52% rename from deploy/chart/databases/templates/redis/redis-deployment.yaml rename to deploy/chart/databases/templates/redis/redis.yaml index 8994bdb6..6c1ab951 100644 --- a/deploy/chart/databases/templates/redis/redis-deployment.yaml +++ b/deploy/chart/databases/templates/redis/redis.yaml @@ -1,28 +1,42 @@ {{- if .Values.databases.redis.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: redis-db + namespace: {{ .Release.Namespace }} +spec: + type: {{ default "ClusterIP" .Values.databases.redis.service.type }} + selector: + app: redis + ports: + - port: 6379 + targetPort: 6379 + nodePort: {{ default nil .Values.databases.redis.service.nodePort }} + +--- apiVersion: apps/v1 kind: Deployment metadata: - name: redis-deploy-{{ .Release.Name }} + name: redis-deploy namespace: {{ .Release.Namespace }} labels: - app: redis-{{ .Release.Name }} + app: redis spec: - replicas: {{ .Values.globals.replicaCount }} + replicas: {{ default 1 .Values.globals.replicaCount }} selector: matchLabels: - app: redis-{{ .Release.Name }} + app: redis template: metadata: - annotations: - checksum/secret: {{ include (print $.Template.BasePath "/redis/redis-secret.yaml") . | sha256sum }} labels: - app: redis-{{ .Release.Name }} + app: redis spec: automountServiceAccountToken: false containers: - name: redis - image: "{{ if ne (.Values.databases.redis.image.registry | toString) "" }}{{ .Values.databases.redis.image.registry }}{{ else }}{{ .Values.globals.imageRegistry }}{{ end }}/{{ .Values.databases.redis.image.name }}:{{ .Values.databases.redis.image.tag | toString }}" - imagePullPolicy: {{ if ne (.Values.databases.redis.image.imagePullPolicy | toString ) "" }}{{ .Values.databases.redis.image.imagePullPolicy }}{{ else }}{{ .Values.globals.imagePullPolicy }}{{ end }} + image: {{ default "hub.oepkgs.net/neocopilot/redis:7.4-alpine" .Values.databases.redis.image }} + imagePullPolicy: {{ default "IfNotPresent" .Values.globals.imagePullPolicy }} command: - redis-server - --requirepass $(REDIS_PASSWORD) @@ -44,15 +58,17 @@ spec: - name: REDIS_PASSWORD valueFrom: secretKeyRef: - name: redis-secret-{{ .Release.Name }} + name: euler-copilot-database key: redis-password volumeMounts: - mountPath: /tmp name: redis-tmp - securityContext: - readOnlyRootFilesystem: {{ .Values.databases.redis.readOnly }} resources: - {{- toYaml .Values.databases.redis.resources | nindent 12 }} + requests: + cpu: 0.1 + memory: 64Mi + limits: + {{- toYaml .Values.databases.redis.resourceLimits | nindent 14 }} restartPolicy: Always volumes: - name: redis-tmp diff --git a/deploy/chart/databases/templates/secrets.yaml b/deploy/chart/databases/templates/secrets.yaml new file mode 100644 index 00000000..5dff217d --- /dev/null +++ b/deploy/chart/databases/templates/secrets.yaml @@ -0,0 +1,16 @@ +{{- $databaseSecret := (lookup "v1" "Secret" .Release.Namespace "euler-copilot-database") }} +{{- if not $databaseSecret}} +apiVersion: v1 +kind: Secret +metadata: + name: euler-copilot-database + namespace: {{ .Release.Namespace }} + annotations: + helm.sh/resource-policy: keep +type: Opaque +stringData: + redis-password: {{ randAlphaNum 20 }} + mongo-password: {{ randAlphaNum 20 }} + minio-password: {{ randAlphaNum 20 }} + pgsql-password: {{ randAlphaNum 20 }} +{{- end }} \ No newline at end of file diff --git a/deploy/chart/databases/values.yaml b/deploy/chart/databases/values.yaml index 6efd901f..f4d14091 100644 --- a/deploy/chart/databases/values.yaml +++ b/deploy/chart/databases/values.yaml @@ -1,127 +1,88 @@ # 全局设置 globals: - # [必填] 部署副本数 - replicaCount: 1 - # [必填] 镜像仓库 - imageRegistry: "hub.oepkgs.net/neocopilot" - # [必填] 镜像拉取策略 - imagePullPolicy: IfNotPresent + # 部署副本数,默认为1 + replicaCount: + # 镜像拉取策略,默认为IfNotPresent + imagePullPolicy: + # 存储类,默认为local-path + storageClass: + +# 存储设置 +storage: + # MinIO存储大小,默认为10GB + minio: + # MongoDB存储大小,默认为10GB + mongo: + # 向量数据库存储大小,默认为10GB + pgsql: + +# 域名设置 +domain: + # 需要修改为MinIO Console绑定的域名。单节点部署时,服务基于Host进行区分,无法使用IP地址 + minioConsole: databases: minio: # [必填] 是否部署MinIO实例 enabled: true - # 镜像设置 + # 镜像设置:默认为hub.oepkgs.net/neocopilot/minio:empty + # 镜像版本:["empty", "empty-arm"] image: - # 镜像仓库。留空则使用全局设置。 - registry: "" - # [必填] 镜像名 - name: "minio" - # [必填] 镜像标签, 为empty或empty-arm - tag: "empty" - # 拉取策略。留空则使用全局设置。 - imagePullPolicy: "" # 性能限制设置 - resources: {} - # [必填] 容器根目录只读 - readOnly: false - # [必填] PersistentVolume大小设置 - persistentVolumeSize: 20Gi - # [必填] 密码设置 - password: "admin123" + resourceLimits: {} # Service设置 service: - # [必填] Service类型,ClusterIP或NodePort - type: ClusterIP - # 当类型为nodePort时,填写MinIO数据端口对应的主机的端口号 - dataNodePort: "" - # 当类型为nodePort时,填写MinIO控制台对应的主机的端口号 - consoleNodePort: "" + # Service类型,例如NodePort + type: + # 当类型为NodePort时,填写MinIO数据端口对应的主机的端口号 + dataNodePort: + # 当类型为NodePort时,填写MinIO控制台对应的主机的端口号 + consoleNodePort: # Ingress设置 ingress: # [必填] 是否暴露MinIO的Console enabled: true - # [必填] 部署域名 - # 需要修改为MinIO Console绑定的域名。单节点部署时,服务基于Host进行区分,无法使用IP地址 - domain: "" # Ingress URL前缀 prefix: / mongo: # [必填] 是否部署MySQL数据库实例 enabled: true - # 镜像设置 + # 镜像设置;默认为hub.oepkgs.net/neocopilot/mongo:7.0.16-x86 + # 镜像版本: ["7.0.16-x86", "7.0.16-arm"] image: - # 镜像仓库。留空则使用全局设置。 - registry: "" - # [必填] 镜像名 - name: mongo - # [必填] 镜像标签,为7.0.16-x86或7.0.16-arm - tag: "7.0.16-x86" - # 拉取策略。留空则使用全局设置。 - imagePullPolicy: "" # 性能限制设置 - resources: {} - # [必填] 容器根目录只读 - readOnly: false - # [必填] PersistentVolume大小设置 - persistentVolumeSize: 10Gi - # [必填] 密码设置 - password: "admin123" + resourceLimits: {} # Service设置 service: - # [必填] Service类型,ClusterIP或NodePort - type: ClusterIP + # [必填] Service类型,例如NodePort + type: # 当类型为nodePort时,填写主机的端口号 - nodePort: "" + nodePort: redis: # [必填] 是否部署Redis实例 enabled: true - # 镜像设置 + # 镜像设置,默认为hub.oepkgs.net/neocopilot/redis:7.4-alpine + # 镜像版本: ["7.4-alpine", "7.4-alpine-arm"] image: - # 镜像仓库。留空则使用全局设置。 - registry: "" - # [必填] 镜像名 - name: redis - # [必填] 镜像标签,为7.4-alpine或7.4-alpine-arm - tag: 7.4-alpine - # 拉取策略。留空则使用全局设置 - imagePullPolicy: "" # 性能限制设置 - resources: {} - # [必填] 容器根目录只读 - readOnly: false - # [必填] 密码设置 - password: "admin123" + resourceLimits: {} # Service设置 service: - # [必填] Service类型,ClusterIP或NodePort - type: ClusterIP + # Service类型,如NodePort + type: # 当类型为nodePort时,填写主机的端口号 - nodePort: "" + nodePort: pgsql: # [必填] 是否部署PostgreSQL实例 enabled: true - # 镜像设置 + # 镜像设置,默认为hub.oepkgsnet/neocopilot/pgsql-empty:pg16 + # 镜像版本: ["pg16", "pg16-arm"] image: - # 镜像仓库。留空则使用全局设置。 - registry: "" - # [必填] 镜像名 - name: pgsql-empty - # [必填] 镜像标签,为pg16或pg16-arm - tag: pg16 - # 拉取策略。留空则使用全局设置。 - imagePullPolicy: "" # 性能限制设置 - resources: {} - # [必填] 容器根目录只读 - readOnly: false - # [必填] Volume大小设置 - persistentVolumeSize: 10Gi + resourceLimits: {} # Service设置 service: - # [必填] Service类型,ClusterIP或NodePort - type: ClusterIP - # 当类型为nodePort时,填写主机的端口号 - nodePort: "" - # [必填] 密码设置 - password: "admin123" + # Service类型,如NodePort + type: + # 当类型为NodePort时,填写主机的端口号 + nodePort: -- Gitee