Эх сурвалжийг харах

feat: 优化 Qwen3 NER 提取支持

改进:
- 默认模型改为 qwen3:4b(中文能力强,参数轻量)
- Prompt 简化并添加 /no_think 指令避免 thinking 输出
- 解析响应时移除 <think>...</think> 标签
- 超时时间增加到 180 秒(适配 CPU 推理)

使用方式:
NER_MODEL=ollama OLLAMA_MODEL=qwen3:4b \
  uvicorn app.main:app --host 0.0.0.0 --port 8001
何文松 1 сар өмнө
parent
commit
bcee925f09

+ 10 - 19
python-services/ner-service/.env.example

@@ -5,43 +5,34 @@
 # ============================================
 # 可选值: rule / ollama
 # - rule: 基于规则的简单 NER(开发测试用,速度快但准确率低)
-# - ollama: 使用本地 Ollama LLM(推荐生产环境,准确率高)
+# - ollama: 使用本地 Ollama LLM(准确率高,需要算力
 NER_MODEL=ollama
 
 # ============================================
-# Ollama 配置(当 NER_MODEL=ollama 时使用)
+# Ollama 配置
 # ============================================
 # Ollama 服务地址
 OLLAMA_URL=http://localhost:11434
 
-# 使用的模型(推荐)
-# 通用 LLM 模式:
-#   - qwen2.5:7b(推荐中文,能力最强)
-#   - qwen2.5:14b(更强,需要更多显存)
-# UniversalNER 专用模式:
-#   - zeffmuks/universal-ner(NER 专用模型,速度快)
-OLLAMA_MODEL=zeffmuks/universal-ner
+# 使用的模型
+# - qwen3:4b(推荐,中文能力强,4B 参数较轻量)
+# - qwen3:8b(更强,需要更多内存)
+# - qwen2.5:7b(备选)
+OLLAMA_MODEL=qwen3:4b
 
-# 请求超时时间(秒)
-OLLAMA_TIMEOUT=120
+# 请求超时时间(秒,CPU 模式需要更长)
+OLLAMA_TIMEOUT=180
 
 # ============================================
 # 文本分块配置(长文本处理)
 # ============================================
-# 每个分块的最大字符数
 CHUNK_SIZE=2000
-
-# 分块重叠字符数(避免实体被截断)
 CHUNK_OVERLAP=200
 
 # ============================================
-# 日志配置
+# 日志和服务配置
 # ============================================
 LOG_LEVEL=INFO
-
-# ============================================
-# 服务配置
-# ============================================
 HOST=0.0.0.0
 PORT=8001
 DEBUG=false

+ 2 - 2
python-services/ner-service/app/config.py

@@ -26,8 +26,8 @@ class Settings(BaseSettings):
     
     # Ollama 配置(用于 ollama 模式)
     ollama_url: str = "http://localhost:11434"
-    ollama_model: str = "qwen2.5:7b"  # 推荐中文 NER 使用 qwen2.5
-    ollama_timeout: int = 120  # 秒
+    ollama_model: str = "qwen3:4b"  # 推荐中文 NER 使用 qwen3
+    ollama_timeout: int = 180  # 秒(CPU 模式需要更长时间)
     
     # UniversalNER 专用配置(当 ollama_model 包含 'universal-ner' 时自动启用)
     # 模型名: zeffmuks/universal-ner

+ 18 - 27
python-services/ner-service/app/services/ollama_service.py

@@ -76,38 +76,26 @@ class OllamaService:
         types = entity_types or settings.entity_types
         types_desc = ", ".join(types)
         
-        prompt = f"""你是一个专业的命名实体识别(NER)系统。请从以下文本中提取实体。
+        prompt = f"""/no_think
+你是一个专业的命名实体识别(NER)系统。请从以下文本中提取实体,直接输出JSON,不要解释。
 
-## 任务要求
-1. 识别以下类型的实体: {types_desc}
-2. 每个实体需要包含: 名称(name)、类型(type)、在文本中的起始位置(charStart)和结束位置(charEnd)
-3. 只提取明确的、有意义的实体,避免提取过于泛化的词汇
-4. 严格按照 JSON 格式输出
+## 实体类型: {types_desc}
+- PERSON: 人名
+- ORG: 机构/公司
+- LOC: 地点
+- DATE: 日期
+- NUMBER: 数值(带单位)
+- DEVICE: 设备仪器
+- PROJECT: 项目/工程
+- METHOD: 方法/标准
 
-## 实体类型说明
-- PERSON: 人名(如:张三、李经理)
-- ORG: 机构/组织/公司(如:成都检测公司、环保局)
-- LOC: 地点/地址(如:成都市、高新区)
-- DATE: 日期时间(如:2024年5月15日、2024-05-15)
-- NUMBER: 带单位的数值(如:50分贝、100万元)
-- DEVICE: 设备仪器(如:噪音检测仪、分析仪器)
-- PROJECT: 项目/工程(如:环境监测项目、XX工程)
-- METHOD: 方法/标准(如:GB/T 12345、检测方法)
+## 输出格式(严格JSON,不要其他内容):
+{{"entities": [{{"name": "实体名", "type": "类型", "charStart": 0, "charEnd": 0}}]}}
 
-## 输出格式
-请严格按以下 JSON 格式输出,不要包含其他内容:
-```json
-{{
-  "entities": [
-    {{"name": "实体名称", "type": "实体类型", "charStart": 起始位置, "charEnd": 结束位置}}
-  ]
-}}
-```
-
-## 待处理文本
+## 文本:
 {text}
 
-## 提取结果
+## JSON结果:
 """
         return prompt
     
@@ -150,6 +138,9 @@ class OllamaService:
         entities = []
         
         try:
+            # Qwen3 可能有 thinking 模式,需要移除 <think>...</think> 部分
+            response = re.sub(r'<think>[\s\S]*?</think>', '', response)
+            
             # 尝试提取 JSON 部分
             json_match = re.search(r'\{[\s\S]*\}', response)
             if not json_match: