# 💡 Summary
# 🧩 Cues
# 🪞Notes
各方案的风险分析
## 1. 标签方案的Bad Cases
输入:"早上去西湖,下午去灵隐寺"
期望:"早上去<poi>西湖</poi>,下午去<poi>灵隐寺</poi>"
可能的错误:
```Java
❌ "早上去<poi>西湖,下午去灵隐寺</poi>" # 标签未闭合/错位
❌ "早上去<poi>西湖<poi>,下午去</poi>灵隐寺" # 嵌套混乱
❌ "早上去<poi西湖</poi>" # 标签格式错误
```
问题:LLM生成的标签容易出错,解析复杂,一旦出错整个文本可能无法解析。
## 2. Offset方案的Bad Cases
文本:"Day 1:早上去西湖散步"
错误offset:`{"text": "西湖", "start": 8, "end": 10}`
实际正确:start=9, end=11
结果:`text[8:10]= "去西" ❌ # 划词错位!`
问题:offset一旦错误,用户看到的高亮/点击会错位,体验很差。
## 推荐的容错方案 🎯
采用"Offset + 自动验证 + 降级匹配"三层防护:
```Java
@dataclass
class EntityMention:
text: str # 原词(必需)
type: str # city/poi
start: int # 主定位方式
end: int
context: str # 备用定位方式(包含原词+前后文)
```
## 前端使用时的容错逻辑
```Java
def safe_highlight(full_text, entity):
# 1️⃣ 优先使用offset(快速精确)
extracted = full_text[entity.start:entity.end]
if extracted == entity.text:
return {"start": entity.start, "end": entity.end, "valid": True}
# 2️⃣ Offset不匹配,使用context验证
if entity.context in full_text:
# 在context中找到原词的相对位置
ctx_pos = full_text.find(entity.context)
word_pos_in_ctx = entity.context.find(entity.text)
corrected_start = ctx_pos + word_pos_in_ctx
return {
"start": corrected_start,
"end": corrected_start + len(entity.text),
"valid": True,
"corrected": True # 标记为修正过的
}
# 3️⃣ 降级到全文搜索(contains)
pos = full_text.find(entity.text)
if pos >= 0:
return {"start": pos, "end": pos + len(entity.text), "valid": True, "fallback": True}
return {"valid": False} # 无法定位,放弃该实体
```
为什么这个方案最优?
方案 优点 缺点 容错性
纯标签 简单直观 LLM易出错,解析脆弱 ⭐
纯Offset 精确高效 无容错,一错就错位 ⭐⭐
纯Contains 最简单 多次出现时无法区分 ⭐⭐
Offset+验证+降级 精确+容错 数据结构稍复杂 ⭐⭐⭐⭐⭐
```