自建向量数据库的食材营养知识库(可连DIFY)

自建向量数据库的食材营养知识库(可连DIFY) 🥗

用AI的智慧,解锁食材的营养密码

1. 项目概述 🚀

这个项目是为了构建一个能够帮助AI更好理解食材营养成分的知识库。通过这个知识库,AI可以对各种菜谱的食材进行分析,提供有价值的营养信息和建议。

虽然是个小项目,但麻雀虽小五脏俱全!从数据获取、处理、向量化到查询系统,一应俱全!这简直就是一个微型版的向量知识库全栈开发流程。

2. 系统架构 🏗️

在这里插入图片描述

3. 数据处理流程 🔄

在这里插入图片描述

4. 查询流程设计 🔍

在这里插入图片描述

5. 代码结构与关键功能 💻

5.1 核心文件

  • process_data.py: 数据处理和向量数据库构建
  • external_kb_api.py: API服务和查询处理
  • test_search.py: 测试和演示脚本
  • config.py: 配置文件

5.2 数据处理代码分析

process_data.py 是整个项目的基础,负责从原始数据到向量数据库的转换:

# 加载并预处理数据
df = load_data(str(DATA_FILE))
df = preprocess_data(df)

# 创建食品描述向量 
vectors = create_food_vectors(df, SILICONFLOW_API_KEY)

# 保存向量数据库
save_vector_db(df, vectors, DB_DIR)

食材向量生成过程:

def create_food_vectors(df, api_key: str) -> np.ndarray:
    food_descriptions = df['食品描述'].tolist()
    vectors = []
    
    # 调用API将文本向量化
    for desc in food_descriptions:
        try:
            response = requests.post(
                'https://api.siliconflow.cn/v1/embeddings',
                headers=headers,
                json={
                    'model': 'BAAI/bge-large-zh-v1.5',
                    'input': desc,
                    'encoding_format': 'float'
                }
            )
            
            if response.status_code == 200:
                vector = response.json()['data'][0]['embedding']
                vectors.append(vector)
            else:
                # 失败处理
                vectors.append(np.zeros(VECTOR_DIMENSION))
        except Exception:
            # 异常处理
            vectors.append(np.zeros(VECTOR_DIMENSION))
    
    return np.array(vectors)

5.3 智能解析食材列表

为了实现对菜谱中多种食材的分解和匹配,我们实现了食材解析器:

def parse_ingredients(query):
    """解析食材列表,支持JSON字符串或普通文本输入"""
    try:
        # 尝试解析为JSON
        ingredients = json.loads(query)
        if isinstance(ingredients, list):
            return [item.get('name', '') for item in ingredients if item.get('name')]
        elif isinstance(ingredients, dict):
            return [ingredients.get('name', '')] if ingredients.get('name') else []
    except json.JSONDecodeError:
        # 如果不是JSON,假设是普通文本
        return [query]

5.4 向量相似度匹配

对单个食材的相似度计算和匹配:

def search_single_ingredient(query: str, top_k: int, score_threshold: float, metadata_condition=None):
    # 获取查询向量
    query_vector = get_query_vector(query)
    
    # 计算相似度
    similarities = []
    for i, vec in enumerate(vectors):
        similarity = 1 - cosine(query_vector, vec)  # 余弦相似度
        similarities.append((i, similarity))
    
    # 排序并筛选结果
    similarities.sort(key=lambda x: x[1], reverse=True)
    
    # 应用过滤器并返回结果
    # ...

6. 实现挑战与解决方案 🛠️

6.1 数据来源问题

挑战: 原计划的中文食材数据源无法访问
解决方案: 转而使用USDA数据并进行翻译,实现了数据的本地化

6.2 查询文本太长导致API错误

挑战: 测试时发现查询文本太长导致413错误
解决方案: 重构测试代码,只发送食材列表作为查询内容

# 修改前
"query": """{ 整个菜谱JSON }"""

# 修改后
"query": json.dumps(recipe_data["ingredient"])

6.3 中文匹配精度问题

挑战: 中文词汇如"豆子"与"豆干"、"干面粉"容易混淆
解决方案: 引入食材名称匹配记录,方便后续分析和优化匹配算法

result_item = {
    "metadata": record["metadata"],
    "score": float(score),
    "title": record["title"],
    "content": record["content"],
    "ingredient_name": query  # 记录匹配的食材名称
}

7. 使用演示 🎮

测试脚本设计了三种测试场景:

  1. 基本食材搜索测试:
recipe_data = {
    "name": "青椒炒香干",
    "ingredient": [
        {"name": "香干", "quantity": "8小块"},
        {"name": "青椒", "quantity": "5个"},
        # ...其他食材
    ]
}
  1. 带营养元数据条件的搜索测试:
metadata_condition = {
    "logical_operator": "and",
    "conditions": [
        {
            "name": ["蛋白质"],
            "comparison_operator": ">",
            "value": "15"
        }
    ]
}
  1. 错误处理测试:
    • 测试错误的API密钥
    • 测试错误的知识库ID

8. 未来优化方向 🔮

  1. 数据扩充:

    • 爬取中文食材营养数据
    • 增加更多食材种类
  2. 匹配算法优化:

    • 引入食材分类体系
    • 优化中文语义匹配
  3. 功能扩展:

    • 添加营养分析功能
    • 实现菜品健康评分
    • 整合食材替代建议

9. 总结:程序员的碎碎念 🎭

搭建这个食材营养知识库的过程,就像是在做一道"营养大杂烩"——材料不多,但五味俱全。

数据量只有可怜的350条,对于动辄上万种食材的烹饪世界来说,简直就是沧海一粟。我们的匹配系统现在的智商大概只有5岁,看到"干"字就分不清是"豆干"还是"面粉干"。

不过话说回来,从无到有总是第一步。这个小系统虽然简陋,但五脏俱全,为未来的迭代打下了基础。就像我们做菜一样,先有个锅,才能炒出花来嘛!

写代码如同做菜,配方虽简单,但关键在于用心。下次我们一定会端出更丰盛的"营养知识大餐"!😋

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值