构建智能旅游推荐:ollama-python用户行为分析
构建智能旅游推荐:ollama-python用户行为分析
【免费下载链接】ollama-python 项目地址: https://gitcode.com/GitHub_Trending/ol/ollama-python
你是否还在为旅游推荐系统的同质化问题困扰?当用户输入"推荐适合家庭的海滨度假地"时,传统系统往往返回千篇一律的热门景点列表。本文将展示如何利用ollama-python构建基于用户行为分析的智能旅游推荐系统,通过对话历史追踪、行为特征提取和实时数据融合,实现真正个性化的旅行建议。读完本文你将掌握:
- 使用ollama对话历史API构建用户行为档案
- 通过嵌入向量(Embedding)量化用户偏好特征
- 结合结构化输出与工具调用实现推荐逻辑
- 完整的旅游推荐系统架构与代码实现
系统架构设计
智能旅游推荐系统需要解决三个核心问题:用户行为数据的有效收集、偏好特征的精准提取、以及动态推荐逻辑的实现。基于ollama-python构建的系统架构如下:
技术栈选型
| 功能模块 | ollama-python核心API | 辅助技术 |
|---|---|---|
| 对话历史追踪 | chat(messages=[]) |
Python列表/JSON文件 |
| 用户偏好提取 | generate(format='json') |
JSON Schema验证 |
| 行为特征量化 | embed(model='all-minilm') |
余弦相似度计算 |
| 外部数据集成 | tools=[Tool()] |
景点信息API/天气服务 |
| 异步处理 | AsyncClient() |
aiohttp/asyncio |
用户行为数据收集
对话历史追踪实现
用户与推荐系统的每一次交互都蕴含潜在需求,通过ollama-python的对话历史管理可以完整记录交互过程:
from ollama import Client
import json
from datetime import datetime
class UserBehaviorTracker:
def __init__(self, model="llama3.2"):
self.client = Client()
self.user_history = []
self.behavior_log = []
def track_interaction(self, user_input):
# 追加用户输入到对话历史
self.user_history.append({"role": "user", "content": user_input})
# 获取模型响应
response = self.client.chat(
model="llama3.2",
messages=self.user_history,
stream=False
)
# 记录助手响应
assistant_msg = response["message"]["content"]
self.user_history.append({"role": "assistant", "content": assistant_msg})
# 记录行为日志(包含时间戳和交互类型)
self.behavior_log.append({
"timestamp": datetime.now().isoformat(),
"user_input": user_input,
"intent": self._classify_intent(user_input),
"response_time": response["total_duration"] / 1e9 # 转换为秒
})
return assistant_msg
def _classify_intent(self, user_input):
# 使用结构化输出解析用户意图
schema = {
"type": "object",
"properties": {
"intent": {"type": "string", "enum": ["查询", "推荐", "比较", "预订", "闲聊"]},
"destination": {"type": "string"},
"travel_type": {"type": "string", "enum": ["家庭", "情侣", "独自", "朋友"]},
"budget": {"type": "number"}
}
}
response = self.client.generate(
model="llama3.2",
prompt=f"解析用户查询意图: {user_input}",
format={"type": "json", "schema": schema}
)
return json.loads(response["response"])
这段代码实现了基本的用户行为追踪功能,包括:
- 完整对话历史记录
- 交互意图自动分类
- 响应时间统计
- 结构化数据提取
多模态行为数据采集
现代旅游推荐需要处理多种类型的用户输入,ollama-python支持图像理解功能,可以分析用户上传的旅行照片来推断偏好:
from ollama import generate
import base64
from PIL import Image
import io
def analyze_travel_photo(image_path):
# 读取并编码图像
with open(image_path, "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
# 定义图像分析结果的结构化输出
schema = {
"type": "object",
"properties": {
"scene_type": {"type": "string", "enum": ["海滩", "山脉", "城市", "古迹", "自然公园"]},
"activities": {"type": "array", "items": {"type": "string"}},
"crowd_level": {"type": "string", "enum": ["安静", "适中", "热闹"]},
"architecture_style": {"type": "string"}
}
}
response = generate(
model="llava", # 多模态模型
prompt="分析这张旅行照片,描述场景类型、可能的活动和环境特征",
images=[image_data],
format={"type": "json", "schema": schema}
)
return json.loads(response["response"])
通过图像分析,系统可以获取用户过去旅行偏好的视觉线索,例如喜欢海滩还是山地、偏好自然景观还是城市建筑等,这些信息对于构建全面的用户画像至关重要。
用户偏好特征提取
行为嵌入向量生成
将用户行为转化为数值向量是实现个性化推荐的关键步骤。ollama-python的embed API可以将文本形式的用户行为记录转化为高维向量:
from ollama import embed
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
class UserPreferenceEmbedder:
def __init__(self, model="all-minilm"):
self.model = model
self.user_embeddings = {} # 存储用户历史行为嵌入
def embed_behavior(self, user_id, behavior_texts):
"""将用户行为文本转化为嵌入向量"""
# 如果是列表,直接处理;如果是单文本,转为列表
if isinstance(behavior_texts, str):
behavior_texts = [behavior_texts]
response = embed(
model=self.model,
input=behavior_texts
)
embeddings = np.array(response["embeddings"])
# 存储用户嵌入向量(取平均作为用户当前偏好向量)
if user_id in self.user_embeddings:
self.user_embeddings[user_id] = np.vstack(
[self.user_embeddings[user_id], embeddings]
).mean(axis=0)
else:
self.user_embeddings[user_id] = embeddings.mean(axis=0)
return self.user_embeddings[user_id]
def compare_preferences(self, user_id1, user_id2):
"""比较两个用户的偏好相似度"""
if user_id1 not in self.user_embeddings or user_id2 not in self.user_embeddings:
return 0.0
return cosine_similarity(
self.user_embeddings[user_id1].reshape(1, -1),
self.user_embeddings[user_id2].reshape(1, -1)
)[0][0]
这个嵌入向量生成器可以:
- 将用户文本行为记录转化为数值向量
- 动态更新用户偏好特征
- 计算用户间偏好相似度
- 支持批量处理行为数据
推荐算法实现
基于嵌入向量的内容推荐
利用用户行为嵌入向量,我们可以实现基础的内容推荐功能:
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
class TravelRecommender:
def __init__(self, embedder,景点数据库):
self.embedder = embedder # 前面定义的UserPreferenceEmbedder实例
self.景点数据库 = 景点数据库 # 包含景点描述的DataFrame
self._precompute_destination_embeddings()
def _precompute_destination_embeddings(self):
"""预计算所有景点的嵌入向量"""
# 提取景点描述文本
descriptions = self.景点数据库["description"].tolist()
# 批量生成嵌入向量
response = embed(
model="all-minilm",
input=descriptions
)
# 存储景点嵌入向量
self.景点数据库["embedding"] = list(response["embeddings"])
def recommend_destinations(self, user_id, top_n=5, filter_criteria=None):
"""基于用户偏好推荐景点"""
if user_id not in self.embedder.user_embeddings:
return []
user_embedding = self.embedder.user_embeddings[user_id]
# 计算用户与每个景点的相似度
self.景点数据库["similarity"] = self.景点数据库["embedding"].apply(
lambda x: cosine_similarity([user_embedding], [x])[0][0]
)
# 应用过滤条件
filtered = self.景点数据库
if filter_criteria:
for key, value in filter_criteria.items():
filtered = filtered[filtered[key] == value]
# 返回相似度最高的top_n个景点
recommendations = filtered.sort_values("similarity", ascending=False).head(top_n)
return recommendations[["name", "location", "rating", "similarity"]].to_dict("records")
这个基础推荐器的工作流程是:
- 预计算所有景点的嵌入向量
- 获取用户当前偏好嵌入向量
- 计算余弦相似度匹配最佳景点
- 应用过滤条件(如预算、旅行类型)
- 返回排序后的推荐结果
结合工具调用的增强推荐
真实世界的旅游推荐需要实时数据支持,ollama-python的工具调用功能可以整合外部API:
from ollama import Client
import requests
import json
class EnhancedTravelRecommender(TravelRecommender):
def __init__(self, embedder,景点数据库, api_keys):
super().__init__(embedder,景点数据库)
self.client = Client()
self.api_keys = api_keys # 存储外部API密钥
# 定义可用工具
self.tools = [
{
"name": "get_weather",
"description": "获取指定地点的天气预报",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "城市名称"},
"days": {"type": "integer", "description": "预报天数", "default": 7}
},
"required": ["location"]
}
},
{
"name": "get_attraction_details",
"description": "获取景点详细信息和实时人流数据",
"parameters": {
"type": "object",
"properties": {
"attraction_id": {"type": "string", "description": "景点ID"},
"date": {"type": "string", "description": "访问日期,格式YYYY-MM-DD"}
},
"required": ["attraction_id", "date"]
}
}
]
def get_weather(self, location, days=7):
"""调用天气API获取预报"""
url = f"http://api.weatherapi.com/v1/forecast.json?key={self.api_keys['weather']}&q={location}&days={days}"
response = requests.get(url)
return response.json()
def get_attraction_details(self, attraction_id, date):
"""调用景点信息API获取详情"""
url = f"https://api.tripadvisor.com/api/partner/attractions/{attraction_id}/details"
headers = {"Authorization": f"OAuth {self.api_keys['tripadvisor']}"}
params = {"date": date}
response = requests.get(url, headers=headers, params=params)
return response.json()
def intelligent_recommend(self, user_id, travel_dates, party_size):
"""智能推荐流程,结合工具调用"""
# 1. 获取基础推荐
base_recommendations = self.recommend_destinations(user_id)
# 2. 准备系统提示
system_prompt = f"""你是一个智能旅游推荐助手。基于以下初步推荐和用户信息,
结合实时数据为用户提供最佳旅行建议。用户计划在{travel_dates}出行,同行{party_size}人。
初步推荐: {base_recommendations}
请考虑:
1. 各目的地的天气情况是否适合旅行
2. 景点在旅行日期的人流预测
3. 是否需要调整推荐顺序或增加新目的地
4. 提供具体的行程安排建议
"""
# 3. 开始带工具调用的对话
messages = [{"role": "system", "content": system_prompt}]
while True:
response = self.client.chat(
model="llama3.2",
messages=messages,
tools=self.tools,
stream=False
)
# 将模型响应添加到对话历史
messages.append(response["message"])
# 检查是否需要调用工具
if not response["message"].get("tool_calls"):
break
# 处理工具调用
for tool_call in response["message"]["tool_calls"]:
function_name = tool_call["function"]["name"]
arguments = json.loads(tool_call["function"]["arguments"])
# 调用相应函数
if function_name == "get_weather":
result = self.get_weather(**arguments)
elif function_name == "get_attraction_details":
result = self.get_attraction_details(**arguments)
else:
result = {"error": "未知工具"}
# 将工具调用结果添加到对话历史
messages.append({
"role": "tool",
"content": json.dumps(result),
"tool_name": function_name
})
return response["message"]["content"]
这个增强推荐器增加了以下能力:
- 调用外部API获取实时天气数据
- 获取景点实时人流和可用性信息
- 基于多轮工具调用动态优化推荐结果
- 考虑旅行日期和同行人数等具体因素
完整系统实现
数据准备
首先准备一个简单的景点数据库:
# 准备景点数据库
景点数据库 = pd.DataFrame([
{
"name": "三亚亚龙湾",
"location": "海南",
"description": "中国最美的海滩之一,适合家庭度假,有清澈的海水和细腻的沙滩",
"rating": 4.8,
"price_level": "中高",
"travel_type": "家庭,情侣",
"activities": "游泳,日光浴,水上运动"
},
{
"name": "张家界国家森林公园",
"location": "湖南",
"description": "壮观的砂岩峰林地貌,适合徒步和自然景观爱好者",
"rating": 4.9,
"price_level": "中等",
"travel_type": "独自,朋友",
"activities": "徒步,摄影,观景"
},
{
"name": "北京故宫",
"location": "北京",
"description": "中国明清两代皇家宫殿,历史文化底蕴深厚",
"rating": 4.7,
"price_level": "中等",
"travel_type": "家庭,独自",
"activities": "观光,文化体验,摄影"
},
{
"name": "丽江古城",
"location": "云南",
"description": "保存完好的历史文化古城,有独特的民族文化",
"rating": 4.6,
"price_level": "中等",
"travel_type": "情侣,朋友",
"activities": "观光,购物,美食,文化体验"
},
{
"name": "桂林漓江",
"location": "广西",
"description": "以喀斯特地貌闻名的河流景观,适合乘船游览",
"rating": 4.8,
"price_level": "中等",
"travel_type": "家庭,情侣,朋友",
"activities": "乘船游览,摄影,徒步"
}
])
系统集成
# 初始化组件
embedder = UserPreferenceEmbedder()
基础推荐器 = TravelRecommender(embedder, 景点数据库)
# API密钥配置(实际应用中应使用环境变量)
api_keys = {
"weather": "your_weather_api_key",
"tripadvisor": "your_tripadvisor_api_key"
}
增强推荐器 = EnhancedTravelRecommender(embedder, 景点数据库, api_keys)
# 用户交互示例
tracker = UserBehaviorTracker()
user_id = "user_123"
# 模拟用户交互
user_inputs = [
"你好,我计划下个月去旅行",
"我想找一个适合家庭的海滨度假地",
"我们有2个小孩,预算中等",
"想了解一下三亚怎么样?",
"有什么好玩的景点推荐吗?",
"天气怎么样?需要带什么衣服?"
]
for input_text in user_inputs:
print(f"用户: {input_text}")
response = tracker.track_interaction(input_text)
# 记录用户行为到嵌入向量
embedder.embed_behavior(user_id, input_text)
print(f"系统: {response}\n")
# 生成最终推荐
print("===== 个性化旅行推荐 =====")
print(增强推荐器.intelligent_recommend(
user_id="user_123",
travel_dates="2025-07-10至2025-07-17",
party_size=4
))
系统优化与评估
性能优化策略
为了提升推荐系统性能,可以实施以下优化:
class OptimizedTravelRecommender(EnhancedTravelRecommender):
def __init__(self, embedder,
【免费下载链接】ollama-python 项目地址: https://gitcode.com/GitHub_Trending/ol/ollama-python
更多推荐


所有评论(0)