告别健身计划制定难题:AI健身教练LLM系统全攻略
你还在为这些健身问题烦恼吗?
每次制定健身计划都要花3小时查资料?健身房请私教费用高昂且效果参差不齐?尝试过10种健身App却找不到适合自己的方案?随着人工智能(AI)技术的飞速发展,大型语言模型(LLM,Large Language Model)正在彻底改变健身指导的方式。本文将带你构建一个个性化AI健身教练系统,通过LLM技术实现基于用户身体数据、健身目标和偏好的智能计划生成,解决传统健身指导的痛点问题。
读完本文你将获得:
- 基于LLM的健身计划生成系统完整架构设计
- 个性化健身数据采集与处理的技术方案(附代码实现)
- 健身专业知识图谱构建与LLM知识注入方法
- 多模态健身指导生成(文本计划+动作演示)的实现
- 完整的系统部署与优化指南(含Colab可运行代码)
一、AI健身教练系统架构设计
1.1 系统核心组件与数据流
一个完整的AI健身教练LLM系统包含五大核心模块,形成从数据采集到计划生成的闭环:
关键数据流说明:
- 用户输入数据:身体指标(身高、体重、体脂率)、健身目标(增肌/减脂/塑形)、可用设备、时间限制、伤病史等
- 处理后数据:结构化的用户画像向量(User Profile Vector)、目标分类标签、约束条件编码
- 输出数据:周期训练计划(每周拆分)、单次训练方案(动作序列、组数、次数)、营养建议、动作演示链接
1.2 技术选型与架构对比
| 架构类型 | 技术栈 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|---|
| 基础LLM调用 | GPT-4 API + 提示词工程 | 开发速度快、零部署成本 | 数据隐私风险、API费用高 | 快速原型验证 |
| 开源LLM微调 | LLaMA-2-7B + LoRA | 数据本地处理、可定制性强 | 需要GPU资源、调参复杂 | 企业级部署 |
| RAG增强LLM | Mistral-7B + Chroma | 知识更新灵活、专业度高 | 向量库维护成本、检索精度依赖 | 专业领域应用 |
| 多模态LLM | Llava-13B | 直接理解动作图像、视频 | 计算资源需求高 | 动作纠正功能 |
推荐架构:对于个人开发者和中小型应用,采用"开源LLM微调+RAG增强"的混合架构,平衡成本、隐私和专业度。基础模型选用Llama-2-7B-Chat,通过LoRA方法在健身专业数据集上微调,同时构建健身知识图谱实现实时知识更新。
1.3 系统性能指标与评估标准
为确保AI健身教练系统的实用性,需要关注以下关键指标:
- 计划个性化程度:用户特征匹配准确率(目标、身体条件、偏好)
- 专业正确性:运动生理学原则符合度(由健身专家评估)
- 用户依从性:计划完成率、用户留存率
- 效果达成率:用户目标实现百分比(如减脂5%、增肌3kg)
- 系统响应时间:计划生成延迟(目标<3秒)
- 安全建议覆盖率:针对用户伤病史的动作规避率
二、用户数据采集与预处理
2.1 健身相关数据采集方案
全面准确的用户数据是生成个性化计划的基础。系统需要采集三类核心数据:
基础身体数据:
# 用户身体数据采集表单(Python实现)
class FitnessProfileForm:
def __init__(self):
self.basic_info = {
"age": None,
"gender": None, # "male", "female", "other"
"height": None, # cm
"weight": None, # kg
"body_fat": None, # percentage
"resting_heart_rate": None # bpm
}
self.fitness_goals = {
"primary_goal": None, # "muscle_gain", "fat_loss", "endurance", "flexibility"
"secondary_goals": [],
"target_date": None, # 目标完成日期
"specific_target": None # 如"减5kg体重"
}
self.availability = {
"weekly_training_days": None,
"average_session_duration": None, # minutes
"preferred_time": None # "morning", "afternoon", "evening"
}
# 更多数据字段...
def validate_data(self):
"""验证数据合理性,如体重范围、训练天数等"""
errors = []
if self.basic_info["weight"] and (self.basic_info["weight"] < 30 or self.basic_info["weight"] > 250):
errors.append("体重数据异常,请检查输入")
if self.availability["weekly_training_days"] and (self.availability["weekly_training_days"] < 1 or self.availability["weekly_training_days"] > 7):
errors.append("每周训练天数必须在1-7天之间")
return errors
健身经验与偏好数据:
- 训练经验水平(初学者/中级/高级)
- 过往训练经历(如有)
- 偏好的训练类型(力量训练/有氧运动/功能性训练)
- 可用健身设备(无设备/哑铃/杠铃/综合器械)
- 不喜欢的动作或训练方式
健康状况数据:
- 现有伤病情况(如膝盖不适、腰部旧伤)
- 慢性疾病史(如高血压、糖尿病)
- 药物使用情况(可能影响训练的药物)
- 饮食限制(素食/过敏食物等)
2.2 数据预处理与特征工程
原始用户数据需要经过处理转换为LLM可理解的特征表示:
import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler, OneHotEncoder
class FitnessDataProcessor:
def __init__(self):
# 初始化数据处理器
self.scaler = StandardScaler()
self.encoder = OneHotEncoder(sparse_output=False)
# 预定义特征列
self.numeric_features = ["age", "height", "weight", "body_fat", "weekly_training_days", "session_duration"]
self.categorical_features = ["gender", "experience_level", "primary_goal", "equipment_access"]
def process_numeric_features(self, df):
"""处理数值型特征:标准化"""
numeric_data = df[self.numeric_features].fillna(df[self.numeric_features].median())
return self.scaler.fit_transform(numeric_data)
def process_categorical_features(self, df):
"""处理分类型特征:独热编码"""
categorical_data = df[self.categorical_features].fillna("unknown")
return self.encoder.fit_transform(categorical_data)
def create_user_profile_vector(self, user_data):
"""创建用户画像向量"""
# 转换为DataFrame
df = pd.DataFrame([user_data])
# 处理不同类型特征
numeric_features = self.process_numeric_features(df)
categorical_features = self.process_categorical_features(df)
# 合并特征
user_vector = np.hstack([numeric_features, categorical_features])
return user_vector
def encode_constraints(self, constraints):
"""编码约束条件(如伤病史、时间限制)"""
# 将约束条件转换为LLM可理解的文本描述
constraint_text = "Constraints: "
if constraints.get("injuries"):
constraint_text += f"Has injuries: {', '.join(constraints['injuries'])}. Avoid exercises that strain these areas. "
if constraints.get("time_limit"):
constraint_text += f"Maximum session duration: {constraints['time_limit']} minutes. "
if constraints.get("equipment_limitations"):
constraint_text += f"Available equipment: {', '.join(constraints['equipment_limitations'])}. "
return constraint_text
2.3 数据存储与隐私保护
用户健身数据包含敏感个人信息,需要安全存储:
import sqlite3
import hashlib
import json
from datetime import datetime
class FitnessDataStore:
def __init__(self, db_path="fitness_coach.db"):
self.conn = sqlite3.connect(db_path)
self._create_tables()
def _create_tables(self):
"""创建数据库表结构"""
cursor = self.conn.cursor()
# 用户表(存储基本信息)
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
user_id TEXT PRIMARY KEY,
username TEXT,
created_at DATETIME,
last_login DATETIME
)
''')
# 用户数据加密存储表
cursor.execute('''
CREATE TABLE IF NOT EXISTS user_data (
user_id TEXT PRIMARY KEY,
encrypted_profile BLOB,
last_updated DATETIME,
FOREIGN KEY(user_id) REFERENCES users(user_id)
)
''')
# 训练计划表
cursor.execute('''
CREATE TABLE IF NOT EXISTS training_plans (
plan_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id TEXT,
plan_data TEXT,
created_at DATETIME,
is_active BOOLEAN,
FOREIGN KEY(user_id) REFERENCES users(user_id)
)
''')
self.conn.commit()
def _encrypt_data(self, data, key):
"""加密用户敏感数据"""
# 实际应用中应使用更安全的加密算法
import cryptography
from cryptography.fernet import Fernet
cipher_suite = Fernet(key)
return cipher_suite.encrypt(json.dumps(data).encode())
def _decrypt_data(self, encrypted_data, key):
"""解密用户敏感数据"""
from cryptography.fernet import Fernet
cipher_suite = Fernet(key)
return json.loads(cipher_suite.decrypt(encrypted_data).decode())
def save_user_profile(self, user_id, profile_data, encryption_key):
"""保存加密的用户资料"""
encrypted_data = self._encrypt_data(profile_data, encryption_key)
cursor = self.conn.cursor()
cursor.execute('''
INSERT OR REPLACE INTO user_data (user_id, encrypted_profile, last_updated)
VALUES (?, ?, ?)
''', (user_id, encrypted_data, datetime.now()))
self.conn.commit()
def get_user_profile(self, user_id, encryption_key):
"""获取解密的用户资料"""
cursor = self.conn.cursor()
cursor.execute('''
SELECT encrypted_profile FROM user_data WHERE user_id = ?
''', (user_id,))
result = cursor.fetchone()
if result:
return self._decrypt_data(result[0], encryption_key)
return None
def save_training_plan(self, user_id, plan_data):
"""保存生成的训练计划"""
cursor = self.conn.cursor()
# 先将当前活跃计划设为非活跃
cursor.execute('''
UPDATE training_plans SET is_active = 0 WHERE user_id = ? AND is_active = 1
''', (user_id,))
# 保存新计划
cursor.execute('''
INSERT INTO training_plans (user_id, plan_data, created_at, is_active)
VALUES (?, ?, ?, 1)
''', (user_id, json.dumps(plan_data), datetime.now()))
self.conn.commit()
二、健身知识图谱构建与RAG系统实现
2.1 健身领域知识图谱设计
构建专业的健身知识图谱是确保LLM给出科学建议的关键:
2.2 知识数据采集与处理
从专业健身资源中提取结构化知识:
import requests
from bs4 import BeautifulSoup
import json
import re
from tqdm import tqdm
class FitnessKnowledgeScraper:
def __init__(self):
self.exercise_data = []
self.muscle_groups = set()
self.equipment_types = set()
def clean_text(self, text):
"""清理文本数据"""
text = re.sub(r'\s+', ' ', text)
text = text.strip()
return text
def scrape_exercise_details(self, url):
"""从健身网站抓取动作详情"""
try:
response = requests.get(url, timeout=10)
soup = BeautifulSoup(response.text, 'html.parser')
# 提取基本信息
name = soup.find('h1', class_='exercise-name').text.strip()
muscle_groups = [mg.text.strip() for mg in soup.find_all('span', class_='muscle-group')]
difficulty = soup.find('div', class_='difficulty-rating').text.strip()
equipment = [eq.text.strip() for eq in soup.find_all('div', class_='equipment-item')]
# 提取动作说明
instructions = []
for step in soup.find_all('li', class_='instruction-step'):
instructions.append(self.clean_text(step.text))
# 提取注意事项
tips = []
for tip in soup.find_all('div', class_='safety-tip'):
tips.append(self.clean_text(tip.text))
# 更新全局集合
for mg in muscle_groups:
self.muscle_groups.add(mg)
for eq in equipment:
self.equipment_types.add(eq)
return {
'name': name,
'muscle_groups': muscle_groups,
'difficulty': difficulty,
'equipment': equipment,
'instructions': instructions,
'tips': tips,
'source_url': url
}
except Exception as e:
print(f"Error scraping {url}: {e}")
return None
def scrape_exercise_list(self, base_url, max_pages=5):
"""抓取动作列表页"""
all_exercises = []
for page in tqdm(range(1, max_pages+1)):
url = f"{base_url}?page={page}"
try:
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
exercise_links = soup.find_all('a', class_='exercise-link')
for link in exercise_links:
exercise_url = link['href']
# 确保是绝对URL
if not exercise_url.startswith('http'):
exercise_url = f"https://example.com{exercise_url}"
exercise_data = self.scrape_exercise_details(exercise_url)
if exercise_data:
all_exercises.append(exercise_data)
except Exception as e:
print(f"Error scraping list page {page}: {e}")
continue
self.exercise_data = all_exercises
return all_exercises
def save_knowledge_data(self, output_file):
"""保存知识数据到JSON文件"""
knowledge_base = {
'exercises': self.exercise_data,
'muscle_groups': list(self.muscle_groups),
'equipment_types': list(self.equipment_types),
'last_updated': datetime.now().isoformat()
}
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(knowledge_base, f, ensure_ascii=False, indent=2)
return knowledge_base
2.3 向量数据库构建与检索实现
使用Chroma构建健身知识向量数据库:
import chromadb
from chromadb.utils import embedding_functions
import json
import uuid
class FitnessKnowledgeVectorDB:
def __init__(self, persist_directory="./fitness_knowledge_db"):
# 初始化Chroma客户端
self.client = chromadb.PersistentClient(path=persist_directory)
# 使用开源嵌入模型
self.embedding_func = embedding_functions.SentenceTransformerEmbeddingFunction(
model_name="all-MiniLM-L6-v2"
)
# 创建或获取集合
self.collection = self.client.get_or_create_collection(
name="fitness_knowledge",
embedding_function=self.embedding_func,
metadata={"hnsw:space": "cosine"}
)
def load_knowledge_data(self, knowledge_file):
"""从JSON文件加载知识数据"""
with open(knowledge_file, 'r', encoding='utf-8') as f:
return json.load(f)
def add_exercises_to_db(self, exercises):
"""将动作数据添加到向量数据库"""
documents = []
metadatas = []
ids = []
for exercise in exercises:
# 创建文档内容
doc_content = f"Exercise: {exercise['name']}\n"
doc_content += f"Muscle Groups: {', '.join(exercise['muscle_groups'])}\n"
doc_content += f"Difficulty: {exercise['difficulty']}\n"
doc_content += f"Equipment: {', '.join(exercise['equipment'])}\n"
doc_content += "Instructions:\n"
for i, step in enumerate(exercise['instructions'], 1):
doc_content += f"{i}. {step}\n"
doc_content += "Tips:\n"
for tip in exercise['tips']:
doc_content += f"- {tip}\n"
documents.append(doc_content)
metadatas.append({
"type": "exercise",
"name": exercise['name'],
"muscle_groups": exercise['muscle_groups'],
"difficulty": exercise['difficulty'],
"equipment": exercise['equipment']
})
ids.append(f"exercise_{uuid.uuid4().hex[:8]}")
# 批量添加到数据库
if documents:
self.collection.add(
documents=documents,
metadatas=metadatas,
ids=ids
)
print(f"Added {len(documents)} exercises to vector database")
def query_relevant_exercises(self, query, muscle_group=None, equipment=None, limit=5):
"""查询相关动作"""
# 构建查询条件
where = {}
if muscle_group:
where["muscle_groups"] = {"$in": [muscle_group]}
if equipment:
where["equipment"] = {"$in": [equipment]}
# 执行查询
results = self.collection.query(
query_texts=[query],
where=where,
n_results=limit,
include=["documents", "metadatas", "distances"]
)
return results
def get_exercise_by_name(self, name):
"""按名称查找动作"""
results = self.collection.query(
where={"name": name},
n_results=1,
include=["documents", "metadatas"]
)
if results['documents'] and len(results['documents'][0]) > 0:
return {
"document": results['documents'][0][0],
"metadata": results['metadatas'][0][0]
}
return None
2.4 RAG增强LLM回答生成
实现检索增强生成,让LLM结合健身专业知识回答问题:
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
import torch
class RAGFitnessCoach:
def __init__(self, vector_db, model_name="lmsys/vicuna-7b-v1.5"):
self.vector_db = vector_db
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map="auto",
torch_dtype=torch.float16
)
self.generator = pipeline(
"text-generation",
model=self.model,
tokenizer=self.tokenizer,
max_new_tokens=1024,
temperature=0.7,
top_p=0.95,
repetition_penalty=1.15
)
def retrieve_context(self, user_query, user_profile):
"""检索相关知识上下文"""
# 基于用户目标和身体数据生成检索查询
target_muscle_groups = self._determine_target_muscles(user_profile)
available_equipment = user_profile.get("availability", {}).get("equipment_access", [])
# 构建检索查询
retrieval_queries = []
for muscle_group in target_muscle_groups[:2]: # 主要目标肌群
retrieval_queries.append(f"Best exercises for {muscle_group} with {', '.join(available_equipment)} equipment")
# 执行多次检索
context_documents = []
for query in retrieval_queries:
results = self.vector_db.query_relevant_exercises(
query=query,
muscle_group=muscle_group,
equipment=available_equipment,
limit=3
)
context_documents.extend(results['documents'][0])
# 去重上下文
unique_contexts = list({doc: doc for doc in context_documents}.values())
return "\n\n".join(unique_contexts)
def _determine_target_muscles(self, user_profile):
"""基于用户目标确定目标肌群"""
primary_goal = user_profile.get("fitness_goals", {}).get("primary_goal", "general_fitness")
# 目标-肌群映射
goal_muscle_map = {
"muscle_gain": ["chest", "back", "legs", "shoulders", "arms"],
"fat_loss": ["full_body", "core", "cardio"],
"strength": ["legs", "back", "chest"],
"toning": ["core", "arms", "glutes", "legs"],
"flexibility": ["full_body", "back", "legs", "shoulders"]
}
return goal_muscle_map.get(primary_goal, ["full_body"])
def generate_workout_plan(self, user_profile, user_query=None):
"""生成完整训练计划"""
# 获取用户数据
user_context = f"""User Profile:
Age: {user_profile.get('basic_info', {}).get('age', 'unknown')}
Gender: {user_profile.get('basic_info', {}).get('gender', 'unknown')}
Fitness Level: {user_profile.get('experience', {}).get('level', 'beginner')}
Primary Goal: {user_profile.get('fitness_goals', {}).get('primary_goal', 'general_fitness')}
Available Equipment: {', '.join(user_profile.get('availability', {}).get('equipment_access', ['bodyweight']))}
Weekly Training Days: {user_profile.get('availability', {}).get('weekly_training_days', 3)}
Session Duration: {user_profile.get('availability', {}).get('average_session_duration', 45)} minutes
Injuries/Constraints: {', '.join(user_profile.get('health', {}).get('injuries', ['none']))}
"""
# 获取知识上下文
knowledge_context = self.retrieve_context(
user_query=user_query or "Generate a personalized workout plan",
user_profile=user_profile
)
# 构建提示词
prompt = f"""You are a certified personal trainer and fitness expert. Create a personalized workout plan based on the user profile and exercise knowledge provided.
{knowledge_context}
{user_context}
INSTRUCTIONS:
1. Create a weekly workout split appropriate for the user's experience level and weekly training days.
2. For each training day, provide:
- Focus muscle groups
- Warm-up routine (5-10 minutes)
- Main exercises (4-6 exercises) with sets, reps, and rest periods
- Cool-down/stretching (5 minutes)
3. Ensure exercises are suitable for the available equipment and avoid movements that could aggravate injuries.
4. Include progression suggestions for each exercise.
5. Add nutrition and recovery tips relevant to the user's primary goal.
6. Format the plan in clear markdown with headings, tables, and bullet points for readability.
WORKOUT PLAN:"""
# 生成计划
response = self.generator(prompt)[0]['generated_text']
# 提取生成的计划部分(去除提示词)
plan_start = response.find("WORKOUT PLAN:") + len("WORKOUT PLAN:")
workout_plan = response[plan_start:].strip()
return workout_plan
三、系统部署与优化
3.1 轻量化部署方案
使用Gradio构建Web界面,实现本地部署:
import gradio as gr
import json
import uuid
from fitness_data_processor import FitnessDataProcessor
from rag_fitness_coach import RAGFitnessCoach
from fitness_vector_db import FitnessKnowledgeVectorDB
# 初始化系统组件
vector_db = FitnessKnowledgeVectorDB()
# 加载知识数据(实际应用中应提前构建)
# vector_db.add_exercises_to_db(vector_db.load_knowledge_data("fitness_knowledge.json")['exercises'])
coach = RAGFitnessCoach(vector_db)
data_processor = FitnessDataProcessor()
# 用户会话存储
user_sessions = {}
def create_user_session():
"""创建新用户会话"""
user_id = str(uuid.uuid4())
user_sessions[user_id] = {
"profile": {},
"plans": [],
"history": []
}
return user_id
def save_user_profile(user_id, age, gender, weight, height, experience_level,
primary_goal, weekly_days, session_duration, equipment, injuries):
"""保存用户资料"""
if user_id not in user_sessions:
user_id = create_user_session()
# 构建用户资料
user_profile = {
"basic_info": {
"age": int(age),
"gender": gender,
"weight": float(weight),
"height": float(height)
},
"experience": {
"level": experience_level
},
"fitness_goals": {
"primary_goal": primary_goal
},
"availability": {
"weekly_training_days": int(weekly_days),
"average_session_duration": int(session_duration),
"equipment_access": equipment.split(",") if equipment else []
},
"health": {
"injuries": injuries.split(",") if injuries else []
}
}
user_sessions[user_id]["profile"] = user_profile
return user_id, "Profile saved successfully! Click 'Generate Workout Plan' to create your personalized plan."
def generate_workout_plan(user_id):
"""生成训练计划"""
if user_id not in user_sessions or not user_sessions[user_id]["profile"]:
return "Please complete your profile first!"
user_profile = user_sessions[user_id]["profile"]
try:
plan = coach.generate_workout_plan(user_profile)
user_sessions[user_id]["plans"].append(plan)
return plan
except Exception as e:
return f"Error generating plan: {str(e)}"
# 创建Gradio界面
with gr.Blocks(title="AI Fitness Coach") as demo:
gr.Markdown("# 🤖 AI Fitness Coach LLM")
gr.Markdown("Personalized workout plans generated by AI with fitness expertise")
# 隐藏的用户ID存储
user_id = gr.State("")
with gr.Tab("User Profile"):
with gr.Row():
with gr.Column(scale=1):
age = gr.Number(label="Age", value=30, minimum=18, maximum=100)
gender = gr.Dropdown(label="Gender", choices=["male", "female", "other"], value="male")
weight = gr.Number(label="Weight (kg)", value=70, minimum=30, maximum=200)
height = gr.Number(label="Height (cm)", value=175, minimum=100, maximum=250)
with gr.Column(scale=1):
experience_level = gr.Dropdown(
label="Experience Level",
choices=["beginner", "intermediate", "advanced"],
value="beginner"
)
primary_goal = gr.Dropdown(
label="Primary Goal",
choices=["muscle_gain", "fat_loss", "strength", "toning", "flexibility"],
value="muscle_gain"
)
weekly_days = gr.Slider(label="Weekly Training Days", minimum=1, maximum=7, value=4, step=1)
session_duration = gr.Slider(label="Session Duration (minutes)", minimum=20, maximum=120, value=60, step=5)
with gr.Row():
equipment = gr.Textbox(label="Available Equipment (comma separated, e.g. dumbbells, bench)", value="dumbbells, bench")
injuries = gr.Textbox(label="Injuries/Constraints (comma separated, e.g. knee pain, back injury)", value="none")
with gr.Row():
save_btn = gr.Button("Save Profile")
save_status = gr.Textbox(label="Status", interactive=False)
with gr.Tab("Workout Plan"):
generate_btn = gr.Button("Generate Workout Plan")
plan_output = gr.Markdown(label="Your Personalized Workout Plan")
# 设置事件处理
save_btn.click(
fn=save_user_profile,
inputs=[user_id, age, gender, weight, height, experience_level, primary_goal, weekly_days, session_duration, equipment, injuries],
outputs=[user_id, save_status]
)
generate_btn.click(
fn=generate_workout_plan,
inputs=[user_id],
outputs=[plan_output]
)
# 启动应用
if __name__ == "__main__":
demo.launch(share=True)
3.2 性能优化策略
针对LLM模型推理速度慢的问题,实施以下优化:
# 模型量化与优化示例
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
def load_optimized_model(model_name="lmsys/vicuna-7b-v1.5"):
"""加载量化优化的模型,减少内存占用并提高推理速度"""
# 4位量化配置
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16
)
# 加载模型
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
low_cpu_mem_usage=True
)
# 加载tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
return model, tokenizer
# 推理缓存实现
from functools import lru_cache
class InferenceCache:
def __init__(self, max_size=100):
self.cache = {}
self.max_size = max_size
def generate_cache_key(self, user_profile, query):
"""生成缓存键"""
# 提取用户资料中的关键参数
key_params = {
"level": user_profile.get("experience", {}).get("level"),
"goal": user_profile.get("fitness_goals", {}).get("primary_goal"),
"equipment": tuple(sorted(user_profile.get("availability", {}).get("equipment_access", []))),
"days": user_profile.get("availability", {}).get("weekly_training_days")
}
# 结合查询生成键
return (frozenset(key_params.items()), query)
def get_cached_result(self, user_profile, query):
"""获取缓存结果"""
key = self.generate_cache_key(user_profile, query)
return self.cache.get(key)
def cache_result(self, user_profile, query, result):
"""缓存结果"""
key = self.generate_cache_key(user_profile, query)
# 控制缓存大小
if len(self.cache) >= self.max_size:
# LRU淘汰策略(简单实现)
oldest_key = next(iter(self.cache.keys()))
del self.cache[oldest_key]
self.cache[key] = result
3.3 评估与改进
构建评估指标体系,持续改进系统:
class FitnessPlanEvaluator:
def __init__(self, knowledge_db):
self.knowledge_db = knowledge_db
# 健身专业规则库
self.exercise_rules = {
"overtraining_risk": {
"pattern": r"([A-Za-z\s]+muscle group)[^.]*trained more than 2 days in a row",
"severity": "high"
},
"equipment_mismatch": {
"pattern": r"requires ([A-Za-z\s]+equipment)[^.]*but user has ([A-Za-z\s]+equipment)",
"severity": "high"
},
"difficulty_inappropriate": {
"pattern": r"beginner level[^.]*advanced exercise",
"severity": "medium"
}
}
def evaluate_plan_safety(self, workout_plan, user_profile):
"""评估计划安全性"""
issues = []
# 检查过度训练风险
muscle_groups = self._extract_muscle_groups(workout_plan)
for muscle, days in muscle_groups.items():
if len(days) > 2 and len(set(days)) < len(days): # 连续训练同一肌群
issues.append({
"type": "overtraining_risk",
"description": f"Muscle group '{muscle}' trained on consecutive days: {', '.join(days)}",
"severity": "high"
})
# 检查伤病史冲突
user_injuries = user_profile.get('health', {}).get('injuries', [])
if user_injuries and user_injuries[0].lower() != "none":
risky_exercises = self._find_risky_exercises(workout_plan, user_injuries)
for exercise in risky_exercises:
issues.append({
"type": "injury_risk",
"description": f"Exercise '{exercise}' may aggravate injury: {', '.join(user_injuries)}",
"severity": "critical"
})
return issues
def evaluate_plan_effectiveness(self, workout_plan, user_profile):
"""评估计划有效性"""
primary_goal = user_profile.get('fitness_goals', {}).get('primary_goal', 'general_fitness')
evaluation = {
"goal_alignment": self._check_goal_alignment(workout_plan, primary_goal),
"volume_appropriate": self._check_volume_appropriateness(workout_plan, user_profile),
"exercise_balance": self._check_exercise_balance(workout_plan)
}
return evaluation
def suggest_improvements(self, issues, effectiveness):
"""生成改进建议"""
suggestions = []
if effectiveness["goal_alignment"] < 0.7:
suggestions.append("Increase exercises targeting your primary goal muscles.")
if effectiveness["volume_appropriate"] < 0.6:
suggestions.append("Adjust training volume to match your fitness level.")
for issue in issues:
if issue["type"] == "overtraining_risk":
suggestions.append(f"Rearrange training split to allow 48 hours recovery for {issue['description'].split("'")[1]}.")
elif issue["type"] == "equipment_mismatch":
equipment_needed = issue["description"].split("'")[1]
equipment_available = issue["description"].split("'")[3]
suggestions.append(f"Replace exercises requiring {equipment_needed} with alternatives using {equipment_available}.")
return suggestions
def _extract_muscle_groups(self, workout_plan):
"""提取训练计划中的肌群"""
# 实现从计划文本中提取肌群和训练日的逻辑
# 简化实现...
return {"chest": ["Monday", "Wednesday", "Friday"], "back": ["Monday", "Thursday"]}
def _find_risky_exercises(self, workout_plan, injuries):
"""查找可能加重伤病的动作"""
# 实现基于伤病史查找风险动作的逻辑
# 简化实现...
return ["bench press", "deep squats"] if "knee" in injuries else []
四、总结与未来展望
基于LLM的个性化健身教练系统通过结合专业健身知识和AI技术,解决了传统健身指导的个性化不足、成本高和专业性有限等问题。本文详细介绍了系统架构设计、数据处理流程、知识图谱构建和RAG增强方法,并提供了完整的实现代码。
该系统的核心优势在于:
- 高度个性化:基于用户身体数据、目标和偏好生成计划
- 科学专业:通过知识图谱确保建议符合运动生理学原理
- 灵活适应:根据用户反馈和进步动态调整训练计划
- 成本效益:一次部署可服务大量用户,降低健身指导门槛
未来发展方向:
- 多模态交互:结合计算机视觉实现动作纠正功能
- 可穿戴设备集成:实时采集运动数据优化训练计划
- 社区功能:用户计划分享与教练点评系统
- 长期健康管理:整合饮食、睡眠等生活方式因素
通过本文提供的技术方案,你可以构建一个功能完备的AI健身教练系统,为用户提供专业、个性化的健身指导。无论是作为独立应用还是现有健身平台的增强功能,该系统都能显著提升用户的健身体验和效果。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



