跳到主要内容

AI 分析

概述

AI 分析是 Evatar 的核心智能能力。每张上传的截图都会自动进入分析管线 (pipeline),由 LLM 进行多模态分析,提取结构化信息包括应用名称、内容分类、用户意图、摘要、实体和置信度。

分析管线流程

分析字段

LLM 返回结构化 JSON,包含以下字段:

字段类型说明示例
app_nameString截图来源应用名称"微信", "支付宝", "12306"
content_categoryString内容分类"chat", "webpage", "finance", "notification"
intentString用户意图"reminder", "research", "reference", "note", "ignore"
relevanceString相关性等级"high", "medium", "low"
summaryString中文摘要 (2-3 句话)"用户在微信中与张三讨论了明天的会议安排"
entitiesArray提取的实体列表[{"type":"人名","value":"张三"}, {"type":"日期","value":"明天"}]
confidenceFloat置信度 (0.0-1.0)0.85

内容分类 (content_category)

分类说明
chat聊天记录截图
webpage网页内容
notification系统通知
social_media社交媒体
finance金融/支付信息
education教育/学习内容
shopping购物/电商
entertainment娱乐内容
tool工具类应用
other其他

意图分类 (intent)

意图触发条件
reminder包含明确时间/日期/截止时间
research知识/教程/研报/招标文件
reference聊天记录中有人名和具体内容、支付/转账信息
note一般性记录
ignore锁屏、壁纸、广告、无意义截图

实体类型 (entities)

LLM 会从截图中尽量多地提取以下类型的实体:

实体类型说明
人名联系人、发送者、乘车人等
公司企业、机构名称
金额价格、支付金额、工资
日期各种日期表达
时间各种时间表达
地点地点、地址
车次火车车次号
航班航班号
电话电话号码
链接URL
股票股票代码/名称
项目项目名称

LLM System Prompt

分析使用的 System Prompt 定义在 services/llm.py 中:

SYSTEM_PROMPT = """你是一个截图分析助手。分析手机截图内容,返回结构化JSON。

严格按此JSON格式返回,不要返回其他内容:
{
"app_name": "应用名称",
"content_category": "chat / webpage / notification / ...",
"intent": "reminder / research / reference / note / ignore",
"relevance": "high / medium / low",
"summary": "用中文总结截图核心内容,2-3句话",
"entities": [
{"type": "人名/公司/金额/...", "value": "具体值"}
],
"confidence": 0.0到1.0
}
"""

相关性过滤

分析完成后,系统会根据 relevanceconfidence 判断是否值得提取记忆:

# services/pipeline.py
relevance = parsed.get("relevance", "high")
confidence = parsed.get("confidence", 1)
if not (relevance == "low" and confidence < 0.3):
# 提取记忆
await extract_memories_from_text(mem_text, "photo", str(photo_id), ...)

低相关性截图(如锁屏、壁纸、广告)会被标记为 relevance=lowconfidence<0.3,这些截图仍会保存分析结果,但不会触发记忆提取,减少噪声。

图片处理

上传的图片在发送给 LLM 前会进行预处理:

# services/llm.py - encode_image_base64()
img = Image.open(image_path)
if img.width > 2048 or img.height > 2048:
img.thumbnail((2048, 2048), Image.Resampling.LANCZOS)
# 重新编码为 JPEG/PNG
img.save(buf, format=save_fmt, quality=85)
b64 = base64.b64encode(buf.getvalue()).decode("utf-8")
  • 超过 2048px 的图片会被缩放至 2048x2048 以内
  • 使用 LANCZOS 重采样算法保持质量
  • JPEG 质量设为 85

记忆提取

分析完成后,如果截图不是低相关性,系统会自动从分析结果中提取记忆:

mem_text = f"截图应用:{parsed.get('app_name','')} 分类:{parsed.get('content_category','')} "
f"摘要:{parsed.get('summary','')} 实体:{parsed.get('entities','')}"
await extract_memories_from_text(mem_text, "photo", str(photo_id), photo.device_id, db)

重试机制

分析任务使用指数退避重试,最多 3 次:

# services/pipeline.py - _safe_process()
for attempt in range(3):
try:
await process_photo(photo_id)
return
except _UNRECOVERABLE as e:
# 不可恢复错误直接放弃
return
except Exception as e:
if attempt < 2:
wait = 2 ** attempt # 1s, 2s
await asyncio.sleep(wait)

不可恢复的错误(如 FileNotFoundErrorValueError)会直接放弃重试。

意图推理触发

每累计完成 3 张截图的分析,系统会自动触发一次意图推理周期:

# services/pipeline.py
_REASONING_TRIGGER_EVERY = 3

def _on_analysis_done(task):
with _counter_lock:
global _analysis_counter
_analysis_counter += 1
if _analysis_counter >= _REASONING_TRIGGER_EVERY:
_analysis_counter = 0
trigger = True
if trigger:
asyncio.create_task(_trigger_reasoning())

幂等性

分析任务是幂等的,已完成的截图不会重复分析:

if analysis.status == AnalysisStatus.DONE:
logger.info(f"Photo {photo_id} already analyzed, skipping")
return

错误处理

分析失败时,错误信息会被记录到数据库中:

analysis.status = AnalysisStatus.ERROR
analysis.error_message = error_msg[:500]
analysis.completed_at = datetime.now(timezone.utc)

LLM 调用返回的错误会经过格式化处理,提取有意义的错误信息:

error_msg = format_llm_error(e)

分析状态流转

状态说明
pending等待分析
processing正在分析中
done分析完成
error分析失败 (可重试)