Browse Source

clean_agent

丁云鹏 1 week ago
parent
commit
d5f55879ef
5 changed files with 171 additions and 14 deletions
  1. 36 0
      database/db.py
  2. 41 0
      database/models.py
  3. 15 12
      gemini.py
  4. 2 2
      prompt/evaluation.md
  5. 77 0
      prompt/extraction.md

+ 36 - 0
database/db.py

@@ -0,0 +1,36 @@
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker, declarative_base
+from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
+import os
+from dotenv import load_dotenv
+
+# 加载环境变量
+load_dotenv()
+
+# 数据库连接配置
+DATABASE_URL = os.getenv(
+    "DATABASE_URL", 
+    "mysql+pymysql://wqsd:wqsd@2025@rm-bp13g3ra2f59q49xs.mysql.rds.aliyuncs.com:3306/ai_knowledge?charset=utf8&connect_timeout=30&read_timeout=30&write_timeout=30"
+)
+
+# 创建同步引擎和会话
+engine = create_engine(
+    DATABASE_URL,
+    pool_size=10,
+    max_overflow=20,
+    pool_timeout=30,
+    echo=False  # 设为True可查看SQL日志
+)
+
+SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
+
+# 声明基类
+Base = declarative_base()
+
+# 获取数据库会话的依赖函数
+def get_db():
+    db = SessionLocal()
+    try:
+        yield db
+    finally:
+        db.close()

+ 41 - 0
database/models.py

@@ -0,0 +1,41 @@
+from sqlalchemy import Column, Integer, String, DateTime, Text, BigInteger
+from datetime import datetime
+from .db import Base
+
+
+class KnowledgeParsingContent(Base):
+    __tablename__ = 'knowledge_parsing_content'
+    __table_args__ = {
+        'comment': '内容解析表'
+    }
+    
+    id = Column(BigInteger, primary_key=True, autoincrement=True)
+    content_id = Column(String(128), nullable=False)
+    request_id = Column(String(128), nullable=False)
+    task_id = Column(BigInteger, nullable=False)
+    parsing_data = Column(Text, comment='结构化数据')
+    create_time = Column(DateTime, default=datetime.now)
+    status = Column(Integer, default=0, comment='0: 未开始,1:处理中 2: 处理完成 3:处理失败')
+    indentify_data = Column(Text, comment='理解的数据')
+    
+    def __repr__(self):
+        return f"<KnowledgeParsingContent(id={self.id}, content_id={self.content_id}, status={self.status})>"
+
+class KnowledgeExtractionContent(Base):
+    __tablename__ = 'knowledge_extraction_content'
+    __table_args__ = (
+        Index('idx_request_id', 'request_id'),  # 创建索引
+        {'comment': '内容抽取表'}
+    )
+    
+    id = Column(BigInteger, primary_key=True, autoincrement=True)
+    request_id = Column(String(128), nullable=False)
+    parsing_id = Column(BigInteger, nullable=False)
+    score = Column(Integer, default=-1)
+    reason = Column(Text, comment='打分原因')
+    data = Column(Text, comment='结构化数据')
+    create_at = Column(DateTime, default=datetime.now)
+    status = Column(Integer, default=0, comment='0: 未开始,1:处理中 2: 处理完成 3:处理失败')
+    
+    def __repr__(self):
+        return f"<KnowledgeExtractionContent(id={self.id}, request_id={self.request_id}, status={self.status})>"

+ 15 - 12
gemini.py

@@ -29,22 +29,18 @@ class GeminiProcessor:
         self.model = genai.GenerativeModel('gemini-2.5-flash')
     
     def process(self, content: Any, system_prompt: str) -> Dict[str, Any]:
-        """
-        处理内容结构化
-        
-        Args:
-            content: 要处理的内容
-            system_prompt: 系统提示词
-            
-        Returns:
-            处理结果
-        """
+
         try:
             # 构建完整的提示词
             full_prompt = f"{system_prompt}\n\n内容:{json.dumps(content, ensure_ascii=False)}"
             
             # 调用 Gemini API
-            response = self.model.generate_content(full_prompt)
+            response = self.model.generate_content(
+                contents=content,
+                config=types.GenerateContentConfig(
+                    system_instruction=system_prompt
+                )
+            )
             
             # 尝试解析 JSON 响应
             try:
@@ -55,4 +51,11 @@ class GeminiProcessor:
                 return {"result": response.text, "raw_response": response.text}
                 
         except Exception as e:
-            return {"error": str(e), "content": content} 
+            return {"error": str(e), "content": content} 
+            
+    def batch_process(self, contents: list, system_prompt: str) -> list:
+        results = []
+        for content in contents:
+            result = self.process(content, system_prompt)
+            results.append(result)
+        return results

+ 2 - 2
prompt/evaluate.md → prompt/evaluation.md

@@ -37,8 +37,8 @@
 这是一个你需要学习的范例:
 
 **输入:**
-- **Query:** "宠物类目的选题方法"
-- **Content:** "本文将介绍宠物狗的十大可爱瞬间,以及如何给它们拍摄有趣的照片,吸引社交媒体上的关注。我们将分享构图技巧和后期处理方法。"
+- **query_word:** "宠物类目的选题方法"
+- **content:** "本文将介绍宠物狗的十大可爱瞬间,以及如何给它们拍摄有趣的照片,吸引社交媒体上的关注。我们将分享构图技巧和后期处理方法。"
 
 **理想输出:**
 ```json

+ 77 - 0
prompt/extraction.md

@@ -0,0 +1,77 @@
+# Prompt: 知识库内容清洗与原文提取
+
+## 你的角色 (Role)
+你是一个“知识库内容分析师”,具备极高的准确性、对无关信息的零容忍,以及对动态主题的快速适应能力。
+
+## 任务目标 (Goal)
+你的核心任务是对给定的原始数据进行深度清洗,并根据一个特定的“查询意图”(Query),从清洗后的文本中精准提取出所有与该意图直接相关的原文片段。这些提取出的原文片段将用于构建高质量的知识库。
+
+## 背景信息 (Context)
+你处理的知识库内容领域和主题是动态的,完全由用户提供的“查询意图”来决定。你需要根据Query词来理解当前任务所需的知识背景。
+
+## 输入 (Input)
+当接收任务时,你会收到一个JSON对象作为输入,其中包含两部分:
+1.  **query_word:** 对应本次任务的“查询意图”,即一个清晰、具体的搜索词或问题。
+2.  **content:** 对应本次任务的“原始数据”,即一段未经处理的Markdown格式文本。
+
+JSON输入结构示例:
+```json
+{
+    "query_word": "你的查询词",
+    "content": "你的Markdown格式原始数据"
+}
+```
+
+## 输出要求 (Output)
+你需要返回一个JSON对象。
+1.  **格式 (Format):** JSON对象应包含一个键`"extracted_data"`,其值为清洗后、且与“查询意图”直接相关的纯文本内容。提取出的原文片段应拼接在一起,形成一个连续的文本流,段落之间保留自然换行。
+2.  **边界情况处理 (Edge Case):** 如果在原始数据中经过清洗和筛选后,未找到任何与“查询意图”直接相关的内容,则`"extracted_data"`键的值必须是字符串`"未找到相关信息"`。
+
+JSON输出结构示例:
+```json
+{
+    "extracted_data": "清洗后且与Query意图相关的纯文本内容"
+}
+```
+或在未找到内容时:
+```json
+{
+    "extracted_data": "未找到相关信息"
+}
+```
+
+## 约束条件 (Constraints)
+1.  **内容完整性:** 你不能对原文内容进行任何总结、改写、简化或添加额外信息。所有提取的都必须是原始文本的精确片段。
+2.  **严格清洗:** 在判断相关性之前,必须严格执行以下数据清洗规则:
+    *   **Markdown 格式标记去除:**
+        *   标题符号 (`#`, `##`, `###` 等)
+        *   加粗/斜体标记 (`**bold**`, `*italic*`, `_italic_`)
+        *   代码块标记 (```` ` ``, ``` `)
+        *   列表标记 (`-`, `*`, `1.`, `.` 等)
+        *   引用块标记 (`>`)
+        *   分割线 (`---`, `***` 等)
+        *   链接语法:保留链接文本,但去除URL部分 (`[链接文本](URL)` -> `链接文本`)
+        *   图片语法:彻底去除图片引用 (`![alt文本](URL)`)
+    *   **结构性噪音去除:**
+        *   页眉/页脚信息
+        *   目录/大纲列表
+        *   导航菜单/侧边栏内容
+        *   版权声明/免责声明等法律或标准文本
+        *   广告、促销或其他非知识性推广信息
+    *   **非文本或冗余内容去除:**
+        *   代码块内容:去除整个代码块及其内部文本。
+        *   特殊字符和符号:去除非标准、乱码字符或连续的无意义符号(如`[大笑R]`, `[氛围感R]`等表情符号或应用特定标记)。
+        *   过多空白符:将连续的多个空格、换行符、制表符压缩为单个空格或自然换行。
+        *   重复内容:识别并去除完全重复的段落或句子。
+        *   评论区内容:若有,需去除。
+3.  **精确相关性:** 只有与“查询意图”直接相关的文本片段才应被保留。任何与意图完全不相关的内容,即使在清洗后仍然存在,也应被过滤掉。
+
+## 工作流程 (Workflow)
+请严格按照以下步骤完成任务:
+1.  **分析Query:** 首先,从输入的JSON对象中提取`query_word`,并仔细分析和透彻理解其含义,明确本次任务需要提取的核心信息和主题方向。
+2.  **预处理数据:** 接着,从输入的JSON对象中提取`content`(原始Markdown文本),并逐行或逐段地通读。严格按照上述“约束条件”中定义的所有“数据清洗规则”,对文本进行预处理。在这一步,只关注格式和结构性噪音的去除,不进行相关性判断。
+3.  **判断相关性:** 然后,在清洗后的文本中,逐句(或根据上下文判断,逐小段)地分析每个文本单元。判断该文本单元是否与第一步中理解的“查询意图”直接相关。
+4.  **整合输出:**
+    *   将所有判断为“直接相关”的、未经任何修改的原文片段,按照其在原始文本中的先后顺序,拼接成一个纯文本流。
+    *   将此纯文本流作为`"extracted_data"`键的值,构建最终的JSON输出。
+    *   如果经过以上步骤,最终没有找到任何直接相关的原文片段,则构建JSON输出为`{"extracted_data": "未找到相关信息"}`。