fix: LLM 智能填单解析失败修复 — 支持截断 JSON 自动修复和错误日志
- _extract_json 增加截断修复:LLM 返回不完整 JSON 时尝试截断到最后 一个 } 逐层闭合,避免因响应截断直接报错 - safe_parse 增加 logger.warning 日志:异常不再静默吞掉,打印完整 traceback 便于排查 - parse/safe_parse 增加 model 参数:从 settings.llm_parse_model 读取 不再硬编码 qwen-plus - .env.example 补充 LLM_PARSE_MODEL 和 LLM_PARSE_API_URL 配置说明 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
272d97488d
commit
2c70b6a8f6
@ -63,6 +63,18 @@ ALIYUN_AI_ACCESS_KEY_SECRET=xxx
|
||||
|
||||
# LLM 解析 API Key(DashScope 通义千问)
|
||||
LLM_PARSE_API_KEY=
|
||||
# LLM 模型名称(默认 qwen-plus)
|
||||
LLM_PARSE_MODEL=qwen-plus
|
||||
# LLM API 地址(默认 dashscope 兼容模式)
|
||||
LLM_PARSE_API_URL=https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions
|
||||
# OCR 模型名称(使用默认模型时填 default)
|
||||
ALIYUN_OCR_MODEL=default
|
||||
# OCR 服务自定义端点地址(留空则使用默认端点)
|
||||
ALIYUN_OCR_ENDPOINT=
|
||||
# OCR 服务请求路径(留空则使用默认路径)
|
||||
ALIYUN_OCR_PATH=
|
||||
# OCR 应用码(部分 OCR 服务需要此配置)
|
||||
ALIYUN_OCR_APPCODE=
|
||||
|
||||
# ==================== 物流轨迹查询 ====================
|
||||
|
||||
|
||||
@ -17,11 +17,14 @@
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from decimal import Decimal
|
||||
from difflib import SequenceMatcher
|
||||
from urllib import error, parse, request
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@ -400,7 +403,8 @@ OCR 已提取的信息:
|
||||
|
||||
def parse(self, text: str, product_groups: list[dict],
|
||||
api_key: str, api_url: str,
|
||||
ocr_context: dict | None = None) -> dict:
|
||||
ocr_context: dict | None = None,
|
||||
model: str = "qwen-plus") -> dict:
|
||||
"""调用 LLM 解析订单文本,返回结构化订单数据。
|
||||
|
||||
参数:
|
||||
@ -432,7 +436,7 @@ OCR 已提取的信息:
|
||||
system_prompt = self.TEXT_SYSTEM_PROMPT.format(product_hints=product_hints)
|
||||
|
||||
payload = json.dumps({
|
||||
"model": "qwen-plus",
|
||||
"model": model,
|
||||
"messages": [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": f"请解析以下订单内容:\n\n{text}"},
|
||||
@ -457,7 +461,8 @@ OCR 已提取的信息:
|
||||
def _extract_json(self, text: str) -> dict:
|
||||
"""从 LLM 响应文本中提取 JSON 内容。
|
||||
|
||||
处理 LLM 可能包裹在 markdown 代码块中的情况。
|
||||
处理 LLM 可能包裹在 markdown 代码块中的情况,
|
||||
以及 LLM 响应被截断导致 JSON 不完整的常见场景。
|
||||
|
||||
参数:
|
||||
text: LLM 原始响应文本。
|
||||
@ -469,11 +474,23 @@ OCR 已提取的信息:
|
||||
if text.startswith("```"):
|
||||
text = text.split("\n", 1)[1]
|
||||
text = text.rsplit("```", 1)[0]
|
||||
return json.loads(text.strip())
|
||||
text = text.strip()
|
||||
try:
|
||||
return json.loads(text)
|
||||
except json.JSONDecodeError:
|
||||
# LLM 响应可能被截断,尝试截断到最后一个完整 } 修复
|
||||
last_brace = text.rfind("}")
|
||||
while last_brace > 0:
|
||||
try:
|
||||
return json.loads(text[:last_brace + 1])
|
||||
except json.JSONDecodeError:
|
||||
last_brace = text.rfind("}", 0, last_brace - 1)
|
||||
raise
|
||||
|
||||
def safe_parse(self, text: str, product_groups: list[dict],
|
||||
api_key: str, api_url: str,
|
||||
ocr_context: dict | None = None) -> dict | None:
|
||||
ocr_context: dict | None = None,
|
||||
model: str = "qwen-plus") -> dict | None:
|
||||
"""安全版解析入口,异常时返回 None 而非抛出异常。
|
||||
|
||||
参数:
|
||||
@ -482,13 +499,15 @@ OCR 已提取的信息:
|
||||
api_key: LLM API 访问密钥。
|
||||
api_url: LLM API 地址。
|
||||
ocr_context: 可选的 OCR 上下文。
|
||||
model: LLM 模型名称。
|
||||
|
||||
返回:
|
||||
解析后的订单字典,失败时返回 None。
|
||||
"""
|
||||
try:
|
||||
return self.parse(text, product_groups, api_key, api_url, ocr_context)
|
||||
return self.parse(text, product_groups, api_key, api_url, ocr_context, model=model)
|
||||
except Exception:
|
||||
logger.warning("[LLM] 解析失败", exc_info=True)
|
||||
return None
|
||||
|
||||
|
||||
@ -986,6 +1005,7 @@ class AIService:
|
||||
settings.llm_parse_api_key or settings.aliyun_ai_access_key_id,
|
||||
settings.llm_parse_api_url,
|
||||
ocr_context=ocr_context,
|
||||
model=settings.llm_parse_model,
|
||||
)
|
||||
|
||||
# 5. 合并
|
||||
|
||||
Loading…
Reference in New Issue
Block a user