Просмотр исходного кода

多模型支持(通过配置项指定)

jiaqiang 2 дней назад
Родитель
Сommit
efef526511

+ 5 - 4
llmops/agents/data_stardard.py

@@ -42,11 +42,11 @@ class SafeJsonOutputParser(JsonOutputParser):
 
 # --- 核心 Parser ---
 class TransactionParserAgent:
-    def __init__(self, api_key: str, multimodal_api_url: str, base_url: str = "https://api.deepseek.com"):
+    def __init__(self, api_key: str, multimodal_api_url: str, base_url: str = "https://api.deepseek.com", model_name: str = "deepseek-chat"):
         # 1. 初始化 LangChain ChatOpenAI 客户端
         # DeepSeek 完全兼容 OpenAI 接口,使用 ChatOpenAI 是标准做法
         self.llm = ChatOpenAI(
-            model="deepseek-chat",
+            model=model_name,
             api_key=api_key,
             base_url=base_url,
             temperature=0.1,
@@ -384,14 +384,15 @@ JSON Array:
 
 
 
-async def data_standize(api_key: str, base_url: str, multimodal_api_url: str, input_file_path: str) -> dict:
+async def data_standardize(api_key: str, base_url: str, model_name: str, multimodal_api_url: str, input_file_path: str) -> dict:
     """
     数据标准化入口方法
     """
     # 创建Agent
     agent = TransactionParserAgent(
-        api_key="sk-8634dbc2866540c4b6003bb5733f23d8",
+        api_key=api_key,
         base_url=base_url,
+        model_name=model_name,
         multimodal_api_url=multimodal_api_url
     )
     # 执行标准化处理

+ 27 - 18
llmops/agents/outline_agent.py

@@ -69,16 +69,17 @@ class ReportOutline(BaseModel):
 class OutlineGeneratorAgent:
     """大纲生成智能体:将报告需求转化为结构化大纲"""
 
-    def __init__(self, api_key: str, base_url: str = "https://api.deepseek.com"):
+    def __init__(self, api_key: str, base_url: str = "https://api.deepseek.com", model_name: str = "deepseek-chat"):
         """
         初始化大纲生成Agent
 
         Args:
             api_key: DeepSeek API密钥
             base_url: DeepSeek API基础URL
+            model_name: 模型名称
         """
         self.llm = ChatOpenAI(
-            model="deepseek-chat",
+            model=model_name,
             api_key=api_key,
             base_url=base_url,
             temperature=0.1
@@ -488,19 +489,20 @@ class OutlineGeneratorAgent:
         """
         try:
             keyword_prompt = ChatPromptTemplate.from_messages([
-                ("system", """你是一个专业的关键词提取专家,需要从用户查询中提取关键的分析指标和业务术语。
-
-请分析查询内容,识别出用户关心的核心指标、分析维度和业务概念。
-
-返回格式:
-请以逗号分隔的关键词列表形式返回,不要其他解释。
-
-示例:
-收入分析, 支出统计, 交易对手, 时间趋势, 占比分析"""),
-                ("human", """用户查询:{question}
-行业背景:{industry}
+                ("system", """
+                    你是一个专业的关键词提取专家,需要从用户查询中提取关键的分析指标和业务术语。
+                    请分析查询内容,识别出用户关心的核心指标、分析维度和业务概念。
+                    
+                    返回格式:
+                    请以逗号分隔的关键词列表形式返回,不要其他解释。
+                    
+                    示例:
+                    收入分析, 支出统计, 交易对手, 时间趋势, 占比分析"""),
+                ("human", """
+                    用户查询:{question}
+                    行业背景:{industry}
 
-请提取这个查询中的关键分析指标和业务术语。""")
+                    请提取这个查询中的关键分析指标和业务术语。""")
             ])
 
             chain = keyword_prompt | self.llm
@@ -510,8 +512,12 @@ class OutlineGeneratorAgent:
             })
 
             keywords_text = result.content.strip()
+            import re
+            # 1️⃣ 去 <think>...</think>
+            text = re.sub(r"<think>.*?</think>", "", keywords_text, flags=re.S).strip()
+
             # 按逗号分割并清理空白
-            keywords = [kw.strip() for kw in keywords_text.split(',') if kw.strip()]
+            keywords = [kw.strip() for kw in text.split(',') if kw.strip()]
 
             print(f"🔍 提取到查询关键词: {keywords}")
             return keywords
@@ -864,7 +870,8 @@ class OutlineGeneratorAgent:
                 如果未找到匹配:返回空字符串 ""
                 
                 只返回知识ID或空字符串,不要其他解释。"""),
-                            ("human", """指标信息:
+            ("human", """
+                指标信息:
                 名称:{metric_name}
                 描述:{metric_description}
                 
@@ -915,7 +922,7 @@ class OutlineGeneratorAgent:
             return ""
 
 
-async def generate_report_outline(question: str, industry: str, sample_data: List[Dict[str, Any]], api_key: str, max_retries: int = 3, retry_delay: float = 2.0) -> ReportOutline:
+async def generate_report_outline(question: str, industry: str, sample_data: List[Dict[str, Any]], api_key: str, base_url: str, model_name: str, max_retries: int = 3, retry_delay: float = 2.0) -> ReportOutline:
     """
     生成报告大纲的主函数,支持重试机制
 
@@ -924,6 +931,8 @@ async def generate_report_outline(question: str, industry: str, sample_data: Lis
         industry: 行业
         sample_data: 数据样本
         api_key: API密钥
+        base_url: LLM base url
+        model_name: LLM model name
         max_retries: 最大重试次数,默认3次
         retry_delay: 重试间隔时间(秒),默认2秒
 
@@ -933,7 +942,7 @@ async def generate_report_outline(question: str, industry: str, sample_data: Lis
     import asyncio
     import time
 
-    agent = OutlineGeneratorAgent(api_key)
+    agent = OutlineGeneratorAgent(api_key=api_key, base_url=base_url, model_name=model_name)
 
     print(f"📝 开始生成报告大纲(最多重试 {max_retries} 次)...")
 

+ 7 - 4
llmops/agents/planning_agent.py

@@ -67,16 +67,17 @@ def normalize_requirements(req: Any) -> Optional[Dict[str, Any]]:
 class PlanningAgent:
     """规划智能体:负责状态分析和决策制定"""
 
-    def __init__(self, api_key: str, base_url: str = "https://api.deepseek.com"):
+    def __init__(self, api_key: str, base_url: str = "https://api.deepseek.com", model_name: str = "deepseek-chat"):
         """
         初始化规划Agent
 
         Args:
             api_key: DeepSeek API密钥
             base_url: DeepSeek API基础URL
+            model_name: 模型名称
         """
         self.llm = ChatOpenAI(
-            model="deepseek-chat",
+            model=model_name,
             api_key=api_key,
             base_url=base_url,
             temperature=0.1
@@ -349,7 +350,7 @@ def analyze_current_state(state: Dict[str, Any]) -> Dict[str, Any]:
 
 
 async def plan_next_action(question: str, industry: str, current_state: Dict[str, Any],
-                           api_key: str) -> PlanningDecision:
+                           api_key: str, base_url: str, model_name: str) -> PlanningDecision:
     """
     规划下一步行动的主函数
 
@@ -357,11 +358,13 @@ async def plan_next_action(question: str, industry: str, current_state: Dict[str
         question: 用户查询
         current_state: 当前状态
         api_key: API密钥
+        base_url: LLM base_url
+        model_name: LLM model name
 
     Returns:
         规划决策结果
     """
-    agent = PlanningAgent(api_key)
+    agent = PlanningAgent(api_key, base_url, model_name)
 
     try:
         decision = await agent.make_decision(question, industry, current_state)

+ 21 - 12
llmops/complete_agent_flow_rule.py

@@ -48,22 +48,24 @@ from llmops.agents.rules_engine_metric_calculation_agent import RulesEngineMetri
 from llmops.agents.data_manager import DataManager
 import os
 from llmops.agents.data_classify_agent import data_classify
-from llmops.config import DEEPSEEK_API_KEY, multimodal_api_url
-from llmops.agents.data_stardard import data_standize
+from llmops.config import DEEPSEEK_API_KEY, multimodal_api_url, LLM_API_KEY, LLM_BASE_URL, LLM_MODEL_NAME
+from llmops.agents.data_stardard import data_standardize
 
 class CompleteAgentFlow:
     """完整的智能体工作流"""
 
-    def __init__(self, api_key: str, base_url: str = "https://api.deepseek.com"):
+    def __init__(self, api_key: str, base_url: str = "https://api.deepseek.com", model_name: str = "deepseek-chat"):
         """
         初始化完整的工作流
 
         Args:
             api_key: DeepSeek API密钥
             base_url: DeepSeek API基础URL
+            model_name: 模型名称
         """
         self.api_key = api_key
         self.base_url = base_url
+        self.model_name = model_name
 
         # 初始规则引擎智能体
         self.rules_engine_agent = RulesEngineMetricCalculationAgent(api_key, base_url)
@@ -187,7 +189,9 @@ class CompleteAgentFlow:
                 question=state["question"],
                 industry=state["industry"],
                 current_state=state,
-                api_key=self.api_key
+                api_key=self.api_key,
+                base_url=self.base_url,
+                model_name=self.model_name
             )
 
             # 更新状态
@@ -225,6 +229,8 @@ class CompleteAgentFlow:
                 industry=state["industry"],
                 sample_data=state["data_set"][:3],  # 使用前3个样本
                 api_key=self.api_key,
+                base_url=self.base_url,
+                model_name=self.model_name,
                 max_retries=3,  # 最多重试5次
                 retry_delay=3.0  # 每次重试间隔3秒
             )
@@ -287,9 +293,10 @@ class CompleteAgentFlow:
             print("📝 正在对数据进行标准化处理...")
 
             # 数据标准化处理
-            result = await data_standize(
+            result = await data_standardize(
                 api_key=self.api_key,
                 base_url=self.base_url,
+                model_name=self.model_name,
                 multimodal_api_url=multimodal_api_url,
                 input_file_path=state["original_file_path"]
             )
@@ -675,7 +682,7 @@ async def run_complete_agent_flow(question: str, industry: str, data: List[Dict[
 
 
 # 便捷函数
-async def run_flow(question: str, industry: str, original_file_path: str, api_key: str, session_id: str = None, use_rules_engine_only: bool = False, use_traditional_engine_only: bool = False) -> Dict[str, Any]:
+async def run_flow(question: str, industry: str, original_file_path: str, api_key: str, base_url: str, model_name: str, session_id: str = None, use_rules_engine_only: bool = False, use_traditional_engine_only: bool = False) -> Dict[str, Any]:
     """
     运行完整智能体工作流的便捷函数
 
@@ -684,6 +691,8 @@ async def run_flow(question: str, industry: str, original_file_path: str, api_ke
         data: 数据集
         original_file_path: 原始文件路径(pdf/img/csv)
         api_key: API密钥
+        base_url: LLM base url
+        model_name: LLM model name
         session_id: 会话ID
         use_rules_engine_only: 是否只使用规则引擎指标计算
         use_traditional_engine_only: 是否只使用传统引擎指标计算
@@ -691,7 +700,7 @@ async def run_flow(question: str, industry: str, original_file_path: str, api_ke
     Returns:
         工作流结果
     """
-    workflow = CompleteAgentFlow(api_key)
+    workflow = CompleteAgentFlow(api_key, base_url, model_name)
     return await workflow.run_workflow(question, industry, original_file_path, session_id, use_rules_engine_only, use_traditional_engine_only)
 
 
@@ -709,10 +718,6 @@ async def main():
     print("🚀 执行CompleteAgentFlow系统测试")
     print("=" * 50)
 
-    if not DEEPSEEK_API_KEY:
-        print("❌ 未找到API密钥")
-        return
-
     # 行业
     industry = "农业"
 
@@ -721,12 +726,16 @@ async def main():
     curr_dir = os.path.dirname(os.path.abspath(__file__))
     file_path = os.path.join(curr_dir, "..", "data_files", file_name)
 
+    print(f"使用LLM:{LLM_MODEL_NAME}")
+
     # 执行测试
     result = await run_flow(
         question="请生成一份详细的农业经营贷流水分析报告,需要包含:1.总收入和总支出统计 2.收入笔数和支出笔数 3.各类型收入支出占比分析 4.交易对手收入支出TOP3排名 5.按月份的收入支出趋势分析 6.账户数量和交易时间范围统计 7.资金流入流出月度统计等全面指标",
         industry = industry,
         original_file_path=file_path,
-        api_key=DEEPSEEK_API_KEY,
+        api_key=LLM_API_KEY,
+        base_url=LLM_BASE_URL,
+        model_name=LLM_MODEL_NAME,
         session_id="direct-test"
     )
 

+ 1 - 2
llmops/config.py

@@ -34,7 +34,6 @@ load_dotenv()
 # API密钥配置 - 优先从环境变量读取,支持通过.env文件配置
 DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
 if not DEEPSEEK_API_KEY:
-    print(f"从环境变量中获取 DEEPSEEK_API_KEY 失败,使用默认值")
     DEEPSEEK_API_KEY = "sk-d9526c1f01dc488d9aae9624ce4bba14"
 
 
@@ -116,7 +115,7 @@ qwen3_32B_model = {
 deepseek_v3_model = {
     "name": "deepseek-chat",
     "api_key": DEEPSEEK_API_KEY,
-    "base_url": DEEPSEEK_BASE_URL
+    "base_url": "https://api.deepseek.com"
 }