大模型二 Agent入门实战(AI私厨)
一 需求分析
AI私厨是一个基于LangChain和多模态AI的食谱推荐应用。用户可以拍摄自家冰箱或厨房的食物照片,AI会自动识别图片中的食材,根据食材搜索相关食谱推荐给用户。
1.1 功能特性
- 📸 图片识别 - 上传食材图片,自动识别其中的食材
- 🔍 智能搜索 - 根据识别的食材搜索相关食谱
- 🍽️ 智能排序 - 按推荐度、难度、营养价值对食谱进行排序
- 💡 创意建议 - 当找不到合适食谱时,提供创意搭配建议
- 💬 对话交互 - 聊天式界面,支持图片上传 + 文本对话
1.2 预期效果
基本的聊天界面窗口,支持图片上传+文本对话:

上传图片,根据图片识别食材:

根据食材搜索食谱,并智能排序:

1.3 实现思路分析
定义一个基础Agent,核心就是模型(Model)和工具(Tool),我们从这两点入手:
- 模型:由于要实现多模态输入,所以必须用多模态模型,比如qwen3.5-plus
- 工具:需要联网搜索食谱,所以要用到web搜索工具,推荐Tavily
- 记忆:短期记忆我们暂时使用Sqlite来实现
剩下就是提示词了,这里我给大家准备了一份测试过的提示词:
system_prompt = “”"
你是一名私人厨师。收到用户提供的食材照片或清单后,请按以下流程操作:
1.识别和评估食材:若用户提供照片,首先辨识所有可见食材。基于食材的外观状态,评估其新鲜度与可用量,整理出一份“当前可用食材清单”。
2.智能食谱检索:优先调用 web_search 工具,以“可用食材清单”为核心关键词,查找可行菜谱。
3.多维度评估与排序:从营养价值和制作难度两个维度对检索到的候选食谱进行量化打分,并根据得分排序,制作简单且营养丰富的排名靠前。
4.结构化方案输出:把排序后的食谱整理为一份结构清晰的建议报告,要包含食谱信息、得分、推荐理由、食谱的参考图片,帮助用户快速做出决策。
请严格按照流程,优先调用 web_search 工具搜索食谱,搜索不到的情况下才能自己发挥。
“”"
接下来,就是组合这些东西,开发你的智能体了,赶紧动手试试吧!
二 功能模拟(jupyter)
我们先在jupyter将Agent的流程跑通。
2.1 配置
确保你的.env中有以下配置:
# .env
# 阿里百炼
DASHSCOPE_API_KEY=sk-913a82aa121f412aa9a8c8c7b22f7792
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
# web_search引擎
TAVILY_API_KEY=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
2.2 依赖
参考下面的依赖:
[project]
name = "food-recipe-recommender"
version = "0.1.0"
description = "AI-powered recipe recommender based on uploaded food images"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"langchain>=0.3.0",
"langchain-community>=0.3.0",
"langchain-openai>=0.2.0",
"langchain-core>=0.3.0",
"streamlit>=1.40.0",
"pillow>=11.0.0",
"python-dotenv>=1.0.0",
"tavily-python>=0.5.0",
"langchain-tavily>=0.1.0",
"fastapi>=0.109.0",
"uvicorn>=0.27.0",
"python-multipart>=0.0.6",
"alibabacloud-oss-v2>=1.2.4",
"langgraph-checkpoint-sqlite>=3.0.3",
]
[tool.uv]
dev-dependencies = [
"pytest>=8.0.0",
"black>=24.0.0",
]
2.3 加载配置
首先,我们要加载环境变量:
# 加载环境变量
from dotenv import load_dotenv
load_dotenv()
2.4 定义工具
然后,我们要定义工具:
from langchain_tavily import TavilySearch
# web搜索工具,使用tavily作为web搜索工具
web_search = TavilySearch(
max_results=5,
topic="general",
)
2.5 初始化模型
接着,初始化多模态模型:
from langchain.chat_models import init_chat_model
import os
model = init_chat_model(
model="qwen3.5-plus", # 模型名称,这里选择qwen3.5-plus,这是一个多模态模型
model_provider="openai",
base_url=os.getenv("DASHSCOPE_BASE_URL"),
api_key=os.getenv("DASHSCOPE_API_KEY")
)
2.6 记忆管理
然后,我们定义记忆管理的checkpointer:
from langgraph.checkpoint.sqlite import SqliteSaver
import sqlite3
# 连接sqlite
connection = sqlite3.connect("resources/personal_chief.db", check_same_thread=False)
# 初始化checkpointer
checkpointer = SqliteSaver(connection)
# 自动建表
checkpointer.setup()
2.7 初始化Agent
接下来,就是智能体了:
from langchain.agents import create_agent
system_prompt = """
你是一名私人厨师。收到用户提供的食材照片或清单后,请按以下流程操作:
1.识别和评估食材:若用户提供照片,首先辨识所有可见食材。基于食材的外观状态,评估其新鲜度与可用量,整理出一份“当前可用食材清单”。
2.智能食谱检索:优先调用 web_search 工具,以“可用食材清单”为核心关键词,查找可行菜谱。
3.多维度评估与排序:从营养价值和制作难度两个维度对检索到的候选食谱进行量化打分,并根据得分排序,制作简单且营养丰富的排名靠前。
4.结构化方案输出:把排序后的食谱整理为一份结构清晰的建议报告,要包含食谱信息、得分、推荐理由、食谱的参考图片,帮助用户快速做出决策。
请严格按照流程,优先调用 web_search 工具搜索食谱,搜索不到的情况下才能自己发挥。
"""
agent = create_agent(
model=model,
tools=[web_search],
system_prompt=system_prompt,
checkpointer=checkpointer
)
2.8 测试
我们在网上找到一张冰箱食物图片:

测试一下:
from langchain.messages import HumanMessage
# 准备多模态消息,图片是网络上的冰箱食物图片
multimodal_message = HumanMessage(
content=[
{"type": "image",
"url": "https://img.freepik.com/free-photo/arrangement-different-foods-organized-fridge_23-2149099882.jpg"},
{"type": "text", "text": "帮我看看这些食材能做些什么?"}
])
config = {"configurable": {"thread_id": "6"}}
response = agent.invoke({"messages": [multimodal_message]}, config)
打印:
# 友好打印
for message in response['messages']:
message.pretty_print()
结果:
================================ Human Message =================================
[{'type': 'image', 'url': 'https://img.freepik.com/free-photo/arrangement-different-foods-organized-fridge_23-2149099882.jpg'}, {'type': 'text', 'text': '帮我看看这些食材能做些什么?'}]
================================== Ai Message ==================================
这些食材非常丰富,包括了多种蔬菜、菌菇、鱼类和肉类,非常适合制作健康美味的餐食。我将根据这些食材,为您搜索可用的食谱,并提供创意搭配建议。同时,我会对每个食谱的营养价值和制作难度进行评分,并综合排序,为您提供最佳选择。
首先,我将分析这些食材,然后进行网络搜索,寻找适合的食谱。
Tool Calls:
tavily_search (call_5f30eac22b4b4f8c8b7927)
Call ID: call_5f30eac22b4b4f8c8b7927
Args:
query: 食谱 用蘑菇 西红柿 三文鱼 鸡胸肉 西兰花 生菜 红椒 胡萝卜 花椰菜
================================= Tool Message =================================
Name: tavily_search
{"query": "食谱 用蘑菇 西红柿 三文鱼 鸡胸肉 西兰花 生菜 红椒 胡萝卜 花椰菜", "follow_up_questions": null, "answer": null, "images": [], "results": [{"url": "https://www.facebook.com/groups/455719458197800/posts/%E9%B8%A1%E6%B1%A4%E9%A3%9F%E8%B0%B1-%E5%8E%9F%E6%96%99200%E5%85%8B%E9%B8%A1%E8%82%89%E8%A5%BF%E5%85%B0%E8%8A%B1%E8%8F%9C%E8%8A%B1%E8%83%A1%E8%90%9D%E5%8D%9C%E5%9C%9F%E8%B1%86%E6%89%80%E6%9C%89%E6%9D%90%E6%96%99%E9%83%BD%E6%A0%B9%E6%8D%AE%E5%8F%A3%E5%91%B3%E5%88%87%E7%89%87%E7%A3%A8%E7%A2%8E%E7%9A%84%E9%A6%99%E6%96%992%E7%93%A3%E5%A4%A7%E8%92%9C%E5%85%B6%E4%BB%96%E9%A6%99%E6%96%991%E6%B1%A4%E5%8C%99%E8%98%91%E8%8F%87%E6%B1%A4%E7%B2%891%E8%8C%B6%E5%8C%99%E7%9B%90%E5%B0%91%E8%AE%B8%E8%83%A1%E6%A4%92%E7%B2%89%E7%83%B9%E9%A5%AA%E6%96%B9%E6%B3%95%E5%B0%86%E9%B8%A1%E8%83%B8%E8%82%89%E7%9F%AD%E6%9A%82%E7%85%AE%E4%B8%80%E4%B8%8B%E7%84%B6%E5%90%8E%E5%8F%96%E5%87%BA/2224317858004609/", "title": "鸡汤食谱🌺 原料: 200克鸡肉西兰花菜花胡萝卜土豆所有材料 ...", "content": "磨碎的香料: 2瓣大蒜 其他香料: 1汤匙蘑菇汤粉 1茶匙盐 少许胡椒粉 烹饪方法: 将鸡胸肉短暂煮一下,然后取出并沥干。 将植物油加热,然后爆香蒜头,然后加水,", "score": 0.6437107, "raw_content": null}, {"url": "https://www.instagram.com/p/DRzSXVLjRjI/", "title": "西兰花、鸡胸肉、蒜、姜", "content": "做法超级简单: 1. 鸡胸肉切块,加入适量生抽、料酒、黑胡椒、盐、生粉,抓匀腌制15 分钟。 2. 西兰花切小朵,蒜切末,姜切片。 3. 锅中烧开水,加少许盐和油,放", "score": 0.5015387, "raw_content": null}, {"url": "https://cookpad.com/tw/%E6%90%9C%E5%B0%8B/%E8%A5%BF%E8%98%AD%E8%8A%B1%E4%B8%89%E6%96%87%E9%AD%9A", "title": "西蘭花三文魚料理與家常食譜", "content": "香焗紅椒三文魚炒飯 ... 三文魚一件 • 紅椒兩棵 • 西蘭花粒、蒜蓉、薑蓉、芝士碎各適量。 ... 油二湯匙、鹽2茶匙、蠔油一茶匙。", "score": 0.40387306, "raw_content": null}, {"url": "https://www.reddit.com/r/EatCheapAndHealthy/comments/136ppq6/im_marinating_some_chicken_breasts_this_week_for/?tl=zh-hans", "title": "这周我腌了一些鸡胸肉准备晚餐……我能搭配什么吃呢? ...", "content": "我把我的蔬菜(芦笋、西兰花、西葫芦、辣椒、蘑菇,我想大部分都可以)切好,拌上油、柠檬、大蒜、盐/胡椒,然后放进烤箱里,400度烤10-15分钟。简直是改变游戏", "score": 0.39333898, "raw_content": null}, {"url": "https://fsnep.ucdavis.edu/sites/g/files/dgvnsk2286/files/inline-files/02.%20Lesson%204%20Handout%201%20ChickenBroccoliAndRiceCasserole_Recipe_SCH.pdf", "title": "鸡肉西兰花饭", "content": "食谱来自从 Making Every Dollar Count curriculum 由 University of California Cooperative Extension California's CalFresh Healthy Living, with funding from the United States Department of Agriculture’s Supplemental Nutrition Assistance Program – USDA SNAP, produced this material. These institutions are equal opportunity providers and employers. For important nutrition information, visit www.CalFreshHealthyLiving.org. \\01.1 CURRICULA\\CURRICULA\\Curricula Print files\\Adult Curricula\\PSSC\\PSSC 2017-Current\\Lesson 4 Simplified Chinese Rev: 04/20 鸡肉西兰花饭 • 4 人分量 • 材料: • 1 磅去骨、去皮 鸡胸 • 1 勺油 • 1 青椒或甜椒 • 1 罐 (10.75 盎司) 奶油蘑菇汤、或蘑菇鸡肉 汤、或芹菜汤 • 1 杯未熟的即食糙米 • 1 杯水 • 1 包(10-12盎司)已切好的西兰花 • ½ 杯干酪粉(起司粉、芝士粉) • 适量盐及黑胡椒粉以作调味 做法: 1. 把青椒切成小块,约1/2 英寸厚。 3. 把鸡肉切成小块,约1/2 英寸厚。 5. 在锅中加入生鸡。用中火煮几分钟,直到煮熟为 止,或到中间不再呈粉红色的程度。 7. 在锅中加入青椒,洋葱,汤,米和水。 8. 从炉台移开。加上奶酪。加入盐和胡椒调味。 营养成分*: 每份含量: 总卡路里– 360; 总脂肪– 11 克; 饱和脂肪– 4 克; 钠– 690 毫克; 碳水化合物– 31 克; 膳食纤维– 5 克; 糖– 4 克; 蛋白质– 35 克; 维生素 A– 30%; 维生素 C– 120%; 钙– 15%; 铁– 15%. *以下分析使用了低钠奶油蘑 菇汤及切达干酪(切达起司、 车打芝士) 材料: • 菜板 • 菜刀 • 平底锅 • 锅铲 • 开罐器 • 量杯 • 奶酪刨丝器.", "score": 0.36283427, "raw_content": null}], "response_time": 1.0, "request_id": "18ed28fb-aa5d-4d28-8c7d-05fc5db4cf69"}
================================== Ai Message ==================================
根据您提供的食材,我为您找到了一些可用的食谱和创意搭配建议。以下是综合排序后的推荐:
### 1. **三文鱼西兰花烤盘料理**
- **食材**: 三文鱼、西兰花、红椒、蘑菇、胡萝卜
- **营养价值**: 高蛋白、富含Omega-3脂肪酸、维生素C和膳食纤维。
- **制作难度**: 低(只需腌制和烤制)
- **评分**: 营养价值 9/10,制作难度 3/10
- **食谱说明**: 将三文鱼用盐、黑胡椒和柠檬汁腌制15分钟,西兰花、红椒和蘑菇切块,与胡萝卜一起拌入橄榄油、蒜末和少许盐。将所有食材铺在烤盘上,放入预热至200°C的烤箱中烤15-20分钟,直到三文鱼熟透,蔬菜变软。
### 2. **鸡胸肉西兰花炒饭**
- **食材**: 鸡胸肉、西兰花、蘑菇、红椒、胡萝卜
- **营养价值**: 高蛋白、低脂肪,富含维生素和矿物质。
- **制作难度**: 中等(需要炒制和调味)
- **评分**: 营养价值 8/10,制作难度 5/10
- **食谱说明**: 鸡胸肉切丁,用生抽、料酒、黑胡椒腌制15分钟。西兰花切小朵,红椒和胡萝卜切丁,蘑菇切片。热锅加油,先炒鸡胸肉至变色,再加入蔬菜翻炒,最后加入米饭和少许酱油调味,炒匀即可。
### 3. **创意搭配:蘑菇鸡肉蔬菜炖锅**
- **食材**: 鸡胸肉、蘑菇、西兰花、红椒、胡萝卜、生菜
- **营养价值**: 营养均衡,富含植物纤维和优质蛋白。
- **制作难度**: 中等(需要炖煮)
- **评分**: 营养价值 8/10,制作难度 6/10
- **食谱说明**: 鸡胸肉切块,用盐、胡椒和蒜粉腌制。锅中加少许油,先炒香蒜末,再加入鸡肉翻炒至变色。加入切好的蘑菇、红椒、胡萝卜和西兰花,倒入适量高汤或水,小火炖煮15分钟。最后加入生菜,稍微翻炒即可。
### 4. **三文鱼蘑菇意面**
- **食材**: 三文鱼、蘑菇、西兰花、红椒、胡萝卜
- **营养价值**: 富含蛋白质和健康脂肪,适合健身人群。
- **制作难度**: 中等(需要煮意面和调味)
- **评分**: 营养价值 8/10,制作难度 5/10
- **食谱说明**: 意面煮熟备用。三文鱼切块,用盐、黑胡椒和柠檬汁腌制。蘑菇切片,红椒和胡萝卜切丁。热锅加油,先炒香蒜末,再加入蘑菇和蔬菜翻炒,加入少许奶油或牛奶,煮至浓稠。最后加入三文鱼和煮好的意面,拌匀即可。
### 5. **创意搭配:蔬菜鸡肉卷**
- **食材**: 鸡胸肉、西兰花、红椒、蘑菇、胡萝卜、生菜
- **营养价值**: 低热量、高纤维,适合减肥人群。
- **制作难度**: 中等(需要卷制和烤制)
- **评分**: 营养价值 7/10,制作难度 6/10
- **食谱说明**: 鸡胸肉切薄片,用盐、胡椒和酱油腌制。西兰花、红椒、蘑菇和胡萝卜切丝,与生菜一起铺在鸡胸肉上,卷成卷状,用牙签固定。放入烤箱200°C烤15分钟,直到鸡肉熟透,蔬菜变软。
这些食谱不仅充分利用了您现有的食材,还兼顾了营养均衡和制作的便捷性。希望您能享受这些美味的料理!如果有任何其他需求,随时告诉我。
继续询问:
response = agent.invoke(
{"messages": [HumanMessage(content="我喜欢第1道菜,可以说的更详细点吗?")]},
config
)
# 友好打印
response['messages'][-1].pretty_print()
结果:
================================== Ai Message ==================================
当然可以!既然您喜欢第1道菜——**三文鱼西兰花烤盘料理**,我会为您提供更详细的步骤、技巧和小贴士,确保您能轻松做出美味又健康的餐食!
---
## 🍽️ **三文鱼西兰花烤盘料理(详细版)**
### 📌 **食材清单**(根据您冰箱里的食材调整)
- 三文鱼:200-250克(约1-2块,根据个人喜好)
- 西兰花:1小颗(约200克,切小朵)
- 红椒:1个(切块或切条)
- 蘑菇:约100克(切片,如香菇、口蘑等)
- 胡萝卜:1根(切片或切丁,约100克)
- 橄榄油:2汤匙
- 蒜末:2瓣(可选,增加风味)
- 柠檬汁:1汤匙(可选,去腥提鲜)
- 盐:适量(约1/2茶匙)
- 黑胡椒:适量(约1/4茶匙,现磨更香)
- 新鲜香草(如迷迭香、百里香):少许(可选,提升香气)
---
## 🍳 **详细制作步骤**
### **1. 准备食材**
- **三文鱼**:用厨房纸吸干表面水分,用盐、黑胡椒和柠檬汁腌制15分钟(如果时间允许,可腌制30分钟,风味更佳)。
- **西兰花**:掰成小朵,用淡盐水浸泡5分钟,再冲洗干净,沥干水分。
- **红椒、胡萝卜、蘑菇**:分别切成均匀大小的块或片,确保烤制时受热均匀。
- **蒜末**:提前准备好,用于调味。
### **2. 调味蔬菜**
- 在一个大碗中,将西兰花、红椒、胡萝卜和蘑菇放入,加入1汤匙橄榄油、少许盐、黑胡椒和蒜末,搅拌均匀,让蔬菜充分吸收调味料。
### **3. 组装烤盘**
- 在烤盘上铺一层烘焙纸或刷一层薄薄的橄榄油,防止粘连。
- 将调味好的蔬菜均匀铺在烤盘底部。
- 将腌制好的三文鱼放在蔬菜上,尽量让三文鱼平铺,不要重叠。
- 如果喜欢,可以在三文鱼表面撒上少许新鲜香草(如迷迭香或百里香),增加香气。
### **4. 烘烤**
- **预热烤箱**:将烤箱预热至200°C(392°F)。
- **烤制时间**:将烤盘放入烤箱中层,烤15-20分钟。
- 如果喜欢三文鱼外焦里嫩,可以烤15分钟。
- 如果喜欢更熟透的口感,可以烤20分钟。
- **检查熟度**:用叉子轻轻戳三文鱼,如果鱼肉轻松散开,说明已经熟透。
### **5. 出炉与享用**
- 烤好后,从烤箱取出,稍微静置2-3分钟,让三文鱼的汁水重新分布。
- 可以搭配一小碗柠檬汁或蜂蜜芥末酱,增加风味。
- 搭配米饭、藜麦或全麦面包,营养更均衡!
---
## 📝 **小贴士**
1. **三文鱼的处理**:如果三文鱼是冷冻的,提前解冻,避免烤制时外焦内生。
2. **蔬菜的切法**:蔬菜切得越均匀,烤制时受热越均匀,口感更好。
3. **调味调整**:如果喜欢更浓郁的风味,可以在烤制前撒上少许芝士碎(如帕玛森芝士),烤制时融化,增加香气。
4. **搭配建议**:这道菜本身营养丰富,可以搭配一杯清爽的白葡萄酒或柠檬水,提升用餐体验。
---
## 📊 **营养与健康价值**
- **三文鱼**:富含Omega-3脂肪酸,有助于降低心血管疾病风险,同时提供优质蛋白。
- **西兰花**:富含维生素C、膳食纤维和抗氧化物质,有助于增强免疫力。
- **红椒和胡萝卜**:富含β-胡萝卜素和维生素A,对眼睛和皮肤健康有益。
- **蘑菇**:低热量、高纤维,富含维生素D和抗氧化成分。
- **整体搭配**:这道菜低脂、高蛋白、富含膳食纤维,适合健身、减脂或日常健康饮食。
---
## 🎯 **为什么推荐这道菜?**
- **制作简单**:只需腌制和烤制,无需复杂技巧。
- **营养均衡**:蛋白质、蔬菜、健康脂肪一应俱全。
- **适合家庭**:可以一次烤制多份,方便分餐或保存。
- **健康低卡**:橄榄油和香料调味,避免过多油脂和盐分。
---
如果您有任何特殊需求(比如素食、无麸质、低钠等),可以告诉我,我会为您调整食谱!希望您享受这道美味又健康的料理! 😊
可以发现,Agent具备记忆,接着前面的内容来回答。
测试通过!
三 LangSmith联调测试
LangChain的Agent底层是基于LangGraph实现的,而LangGraph提供了完整的后端部署功能,自带非常完善的API接口,无需我们额外处理。
同时,LangChain还提供了基于LangSmith的GUI控制台实现Agent的调试、监控、一键部署。
接下来我们就看看如何利用LangGraph在本地部署测试我们的Agent,并通过LangSmith做测试。
3.1 配置LangSmith
LangSmith提供了对Agent的GUI管理界面,而且还支持一键云部署功能。通常在测试阶段,建议大家在Agent中引入Simth,方便做测试和调试。
首先,我们要注册LangSmith,开通服务,生成API_KEY。
注册地址:https://smith.langchain.com/
注册成功后,登录,进入控制台,找到settings:

在settings页面找到API Keys菜单,创建自己的API_KEY:

千万要记住自己的API_KEY,不要弄丢了。
接着,我们无需额外安装依赖,只需要在项目的.env文件中添加配置即可:
# deepseek
DEEPSEEK_API_KEY=sk-5df6af828a04427da4d98fc53cebd63b
# aliyun dashscope
DASHSCOPE_API_KEY=sk-913a82aa121f412aa9a8c8c7b22f7792
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
# web_search引擎
TAVILY_API_KEY=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
# langsmith
LANGSMITH_API_KEY=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
LANGSMITH_TRACING=true
# project name
LANGSMITH_PROJECT=lc-course
3.2 开发Agent
首先,我们把刚才的代码集中到一个py文件中:

代码如下:
from langchain.chat_models import init_chat_model
from langchain_tavily import TavilySearch
from langchain.agents import create_agent
import os
# 1.加载环境变量
from dotenv import load_dotenv
load_dotenv()
# 2.web搜索工具,使用tavily作为web搜索工具
web_search = TavilySearch(
max_results=5,
topic="general"
)
# 3.多模态模型
model = init_chat_model(
model="qwen3.5-plus", # 模型名称,这里选择qwen3.5-plus,这是一个多模态模型,支持图片、文本、音频、视频
model_provider="openai",
base_url=os.getenv("DASHSCOPE_BASE_URL"),
api_key=os.getenv("DASHSCOPE_API_KEY")
)
# 4.Agent系统提示词
system_prompt = """
你是一名私人厨师。收到用户提供的食材照片或清单后,请按以下流程操作:
1.识别和评估食材:若用户提供照片,首先辨识所有可见食材。基于食材的外观状态,评估其新鲜度与可用量,整理出一份“当前可用食材清单”。
2.智能食谱检索:优先调用 web_search 工具,以“可用食材清单”为核心关键词,查找可行菜谱。
3.多维度评估与排序:从营养价值和制作难度两个维度对检索到的候选食谱进行量化打分,并根据得分排序,制作简单且营养丰富的排名靠前。
4.结构化方案输出:把排序后的食谱整理为一份结构清晰的建议报告,要包含食谱信息、得分、推荐理由、食谱的参考图片,帮助用户快速做出决策。
请严格按照流程,优先调用 web_search 工具搜索食谱,搜索不到的情况下才能自己发挥。
"""
# 5.创建Agent
agent = create_agent(
model=model, # 模型
tools=[web_search], # 工具
system_prompt=system_prompt # 系统提示词
)
注意
- LangGraph会自动托管Agent的记忆,因此代码中不用自己添加checkpointer!
- LangGraph自带Restful的API接口,我们只要定义好Agent就可以,其它不用管
3.3 本地部署
我们使用LangGraph命令行在本地部署,所以要先安装LangGraph的依赖。
使用uv安装:
uv add langgraph-cli[inmem]
然后,在项目根目录添加一个langgraph配置文件:

添加下面的内容:
{
"dependencies": ["."],
"graphs": {
"chief_agent": "./app/agents/personal_chief.py:agent"
},
"env": ".env"
}
注意:其中的agent配置格式为:
[Agent文件路径]:[Agent变量名]
例如,在我们的配置中:
- ./app/agents/personal_chief.py:就是文件路径
- agent:就是文件中定义的Agent名字
最后,点击左下角打开Pycharm终端:

使用LangGraph命令本地部署Agent:
uv run langgraph dev
效果:

看到这个,说明你的Agent已经在本地部署成功了!!
LangGraph提供了基于RestFull的完整的服务端API接口,可以访问http://127.0.0.1:2024/docs查看。接下来,你就可以自己开发前端,与这些接口对接了。
当然,LangGraph也支持Docker部署方案,可参考以下链接:https://docs.langchain.com/langsmith/deploy-with-control-plane#step-2-build-docker-image
3.4 LangSmith Studio测试
由于我们部署时配置了LangSmith,所以可以直接访问LangSmith提供的调试GUI界面:
https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
这里可以非常方便的调试我们的Agent,查看我们Agent的运行细节:

可以直接在界面中测试:

也可以查看详细的调用过程:

同时,LangSmith还提供了一键云部署功能,可以把Agent部署到云端:

但是要需要缴付昂贵的费用。。
所以,建议只在Agent测试阶段使用LangSmith吧~
四 实战开发
gent跑通了,但目前还存在几个问题:
- 目前的图片信息还是采用base64方式提交给模型,会占用大量内存,性能差
- 我们没有开发自己的前端,用户体验不好
接下来,我们就逐一解决这些问题。
在向模型提交多模态消息,比如:音频、视频、图片时,我们不建议直接发送文件数据(base64)给模型,这会大量占用内存和会话记忆。更常见的方案是:
- 先将多模态文件上传至通用的OSS服务,例如:阿里云OSS、腾讯云COS等
- 获取oss服务的文件url地址,组织多模态消息,发送给大模型
因此,我们需要单独开发一个文件上传的服务接口,让前端先上传好文件,再调用Agent.

我们的服务端需要具备以下接口:
- 对话接口:接收用户聊天消息,并调用Agent
- 会话管理接口:查询或删除会话历史
- 文件上传接口:调用OSS提供的客户端,实现文件上传授权,将来由前端完成文件上传,文件不经过服务器。
4.1 FastAPI服务端
首先,我们需要安装一些依赖,包括FastAPI和阿里云的OSS:
uv add fastapi alibabacloud-oss-v2
项目目录如下
app/
├── main.py # FastAPI 入口,配置路由和静态文件
│
├── agents/
│ └── personal_chief.py # AI 代理核心逻辑
│
├── api/
│ └── v1/
│ ├── chat.py # 对话 API
│ │ ├── POST /chat/stream 流式对话
│ │ ├── GET /chat/messages 获取历史
│ │ └── DELETE /chat/messages 清空历史
│ │
│ └── oss.py # OSS 上传签名 URL
│
├── models/
│ └── schemas.py # Pydantic 数据模型,请求/响应数据结构定义
│
├── common/
│ └── logger.py # 日志配置
│
└── static/ # Next.js 编译产出的静态网页
├── index.html # 前端入口
├── _next/ # Next.js 构建资源
└── ... # 其他静态资源
main.py作为程序入口:
import os
from fastapi import FastAPI
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from app.api.v1 import chat
from app.api.v1 import oss
from app.common.logger import setup_logging
# 初始化日志配置
setup_logging()
# 初始化FastAPI
app = FastAPI(
title="Personal Chief API",
description="私厨",
version="0.1.0"
)
# ...中间代码略...
if __name__ == "__main__":
import uvicorn
# 启动命令:python -m app.main
uvicorn.run("app.main:app", host="127.0.0.1", port=8001, reload=True)
直接运行main.py,访问:http://localhost:8001即可:

前端代码这里就不提供了,有需要的话评论区留言就可
4.2 OSS配置
虽然资料已经帮大家实现了oss的文件上传,但是大家需要自己去oss注册服务,并申请API_KEY
这里我们以阿里云OSS为例来说明
4.2.1 注册阿里云
注册地址:https://account.aliyun.com/login/login.htm?oauth_callback=https://oss.console.aliyun.com/index
注册登录成功后,访问链接:https://oss.console.aliyun.com/overview,即可看到oss控制台:

如果显示【尚未开通】,点击【立即开通】即可:

默认为按量付费,价格非常便宜,几乎可以忽略不计:

开通成功后,即可进入控制台页面:

4.2.2 申请API_KEY
访问链接:https://ram.console.aliyun.com/overview?activeTab=workflow,进入RAM访问控制页面:

点击:用户>创建用户,填写用户信息:

创建完成后,一定要记住你的AccessKey的ID和Secret:

然后,给新添加的用户《新增授权》:

在授权页面,给新用户添加oss的绝对控制权限:

4.2.3 开通OSS
访问链接:https://oss.console.aliyun.com/overview,进入oss控制台,选择创建Bucket:
填写bucket信息:

4.2.4 设置权限
目前,新建的Bucket还是无法访问的,是私有的。为了方便测试,这里我们暂时将其设置为公共读。
注意:
- 实际开发中oss中的图片应该设置为私有!不可对外暴露!!由额外的CDN服务对外暴露!
- 本例中,我们为了方便暂时将bucket设置为公共读,测试完毕后请及时关闭权限!
首先,进入Bucket管理页面:

进入具体的Bucket设置,关闭公共访问开关:

设置权限为公共读:

接着,我们要开启跨域访问权限:

点击《创建规则》,填写跨域规则:![[图片]](https://i-blog.csdnimg.cn/direct/03a2272703e648c49b365c59182b4257.png)
4.2.5 配置API_KEY
最后,我们需要把阿里云OSS的API_KEY配置到环境变量中,也就是项目的.env文件内,格式如下:
# 阿里OSS
OSS_ACCESS_KEY_ID=LTBI5tHzjC36KhCJfPqlbaCo
OSS_ACCESS_KEY_SECRET=aDPGBi1nIlYzcEmk5djWJGUv3w9Qkh
OSS_BUCKET=tmp9527
访问 http://localhost:8001,试试上传图片是否成功:

选择图片,可以看到预览:

点击发送按钮,上传成功应该能在聊天窗看到结果:

4.3 添加Checkpointer
由于上一节是基于LangGraph和LangSmith的部署,所以Agent并没有添加Checkpointer,由LangGraph自己处理。而现在既然要自定义Agent部署, 就必须自己添加Checkpointer了。
我们依然使用Sqlite作为存储方案,修改personal_chief.py文件,添加Checkpointer给Agent:
from langchain.chat_models import init_chat_model
from langchain_tavily import TavilySearch
from langchain.agents import create_agent
import os
from langgraph.checkpoint.sqlite import SqliteSaver
import sqlite3
# 1.加载环境变量
from dotenv import load_dotenv
load_dotenv()
# 2.web搜索工具,使用tavily作为web搜索工具
web_search = TavilySearch(
max_results=5,
topic="general"
)
# 3.多模态模型
model = init_chat_model(
model="qwen3.5-plus", # 模型名称,这里选择qwen3.5-plus,这是一个多模态模型,支持图片、文本、音频、视频
model_provider="openai",
base_url=os.getenv("DASHSCOPE_BASE_URL"),
api_key=os.getenv("DASHSCOPE_API_KEY")
)
# 4.初始化checkpointer
# 连接sqlite
connection = sqlite3.connect("../db/personal_chief.db", check_same_thread=False)
# 初始化checkpointer
checkpointer = SqliteSaver(connection)
# 自动建表
checkpointer.setup()
# 5.Agent系统提示词
system_prompt = """
你是一名私人厨师。收到用户提供的食材照片或清单后,请按以下流程操作:
1.识别和评估食材:若用户提供照片,首先辨识所有可见食材。基于食材的外观状态,评估其新鲜度与可用量,整理出一份“当前可用食材清单”。
2.智能食谱检索:优先调用 web_search 工具,以“可用食材清单”为核心关键词,查找可行菜谱。
3.多维度评估与排序:从营养价值和制作难度两个维度对检索到的候选食谱进行量化打分,并根据得分排序,制作简单且营养丰富的排名靠前。
4.结构化方案输出:把排序后的食谱整理为一份结构清晰的建议报告,要包含食谱信息、得分、推荐理由、食谱的参考图片,帮助用户快速做出决策。
请严格按照流程,优先调用 web_search 工具搜索食谱,搜索不到的情况下才能自己发挥。
"""
# 6.创建Agent
agent = create_agent(
model=model, # 模型
tools=[web_search], # 工具
checkpointer=checkpointer, # 记忆
system_prompt=system_prompt # 系统提示词
)
在app下创建一个db目录,用以存放Sqlite的db文件:

4.4 开发接口
目前在agents/personal_cheif.py文件中虽然已经开发了Agent,但是外界还是无法访问,我们需要定义Restful的接口供前端使用。
其中,在api/v1/chat.py中定义了Restful的接口,等待我们实现功能:
from fastapi import APIRouter
router = APIRouter()
@router.post("/chat/stream")
async def chat_endpoint(request: ChatRequest):
"""流式聊天接口"""
pass
@router.get("/chat/messages")
async def get_chat_messages(thread_id: str):
"""获取历史消息"""
pass
@router.delete("/chat/messages")
async def clear_chat_messages(thread_id: str):
"""清空历史消息"""
pass
4.4.1 功能实现
我们可以在agents/personal_cheif.py中基于agent开发所需的3个功能:
- 多模态聊天
- 获取会话历史
- 清空会话历史
agents/personal_cheif.py的完整代码如下:
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage, AIMessageChunk, AIMessage
from langchain_core.tools import tool
from langchain_tavily import TavilySearch
from langchain.agents import create_agent
from app.common.logger import logger
import os
from langgraph.checkpoint.sqlite import SqliteSaver
import sqlite3
# 加载环境变量
from dotenv import load_dotenv
load_dotenv()
# web搜索工具,使用tavily作为web搜索工具
tavily = TavilySearch(
max_results=5,
topic="general"
)
# 多模态模型
model = init_chat_model(
model="qwen3-omni-flash", # 模型名称,这里选择qwen3.5-plus,这是一个多模态模型,支持图片、文本、音频、视频
model_provider="openai",
base_url=os.getenv("DASHSCOPE_BASE_URL"),
api_key=os.getenv("DASHSCOPE_API_KEY")
)
# 初始化checkpointer
checkpointer = SqliteSaver(sqlite3.connect("db/personal_chief.db", check_same_thread=False))
# 自动建表
checkpointer.setup()
# Agent系统提示词
system_prompt = """
你是一名私人厨师。收到用户提供的食材照片或清单后,请按以下流程操作:
1.识别和评估食材:若用户提供照片,首先辨识所有可见食材。基于食材的外观状态,评估其新鲜度与可用量,整理出一份“当前可用食材清单”。
2.智能食谱检索:优先调用 web_search 工具,以“可用食材清单”为核心关键词,查找可行菜谱。
3.多维度评估与排序:从营养价值和制作难度两个维度对检索到的候选食谱进行量化打分,并根据得分排序,制作简单且营养丰富的排名靠前。
4.结构化方案输出:把排序后的食谱整理为一份结构清晰的建议报告,要包含食谱信息、得分、推荐理由、食谱的参考图片,帮助用户快速做出决策。
请严格按照流程,优先调用 web_search 工具搜索食谱,搜索不到的情况下才能自己发挥。
"""
# 创建代理
agent = create_agent(
model=model, # 模型
tools=[tavily], # 工具
checkpointer=checkpointer, # 记忆
system_prompt=system_prompt # 系统提示词
)
# 流式对话
async def search_recipes(prompt: str, image: str, thread_id: str):
"""调用agent搜索食谱"""
logger.info(f"[用户]: {prompt}, image: {image}, thread_id: {thread_id}")
try:
# 判断是否有图片,封装不同格式的消息
if not image or image.strip() == "":
message = HumanMessage(content=prompt)
else:
message = HumanMessage(content=[
{"type": "image", "url": image},
{"type": "text", "text": prompt}
])
# 流式调用Agent
for chunk, metadata in agent.stream(
{"messages": [message]},
{"configurable": {"thread_id": thread_id}},
stream_mode="messages"
):
if isinstance(chunk, AIMessageChunk) and chunk.content:
yield chunk.content
except Exception as e:
logger.error(f"\n[错误]: {str(e)}")
yield "信息检索失败,试试看手动输入食物列表?"
# 清空会话
def clear_messages(thread_id: str):
"""清空会话"""
logger.info(f"清空历史消息,thread_id: {thread_id}")
checkpointer.delete_thread(thread_id)
# 查询会话历史
def get_messages(thread_id: str) -> list[dict[str, str]]:
"""获取会话历史"""
logger.info(f"获取历史消息,thread_id: {thread_id}")
# 根据 thread_id 查询 checkpoint
checkpoint = checkpointer.get({"configurable": {"thread_id": thread_id}})
# 如果不存在,返回空列表
if not checkpoint:
return []
# 安全获取 messages
channel_values = checkpoint.get("channel_values")
if not channel_values:
return []
messages = channel_values.get("messages", [])
if not messages:
return []
# 转换消息格式
result = []
for msg in messages:
if not msg.content:
continue
if isinstance(msg, HumanMessage):
result.append({"role": "user", "content": msg.content})
elif isinstance(msg, AIMessage):
result.append({"role": "assistant", "content": msg.content})
return result
4.4.2 完善接口
然后,修改chat.py文件,导入agents.personal_cheif中的三个方法,完善接口:
from fastapi import APIRouter
from app.models.schemas import ChatRequest
from fastapi.responses import StreamingResponse
from app.agents.personal_chief import search_recipes, get_messages, clear_messages
router = APIRouter()
@router.post("/chat/stream")
async def chat_endpoint(request: ChatRequest):
"""流式对话"""
return StreamingResponse(
search_recipes(request.message, request.image_url, request.thread_id),
media_type="text/event-stream"
)
@router.get("/chat/messages")
async def get_chat_messages(thread_id: str):
"""获取历史消息"""
messages = get_messages(thread_id)
return {"messages": messages}
@router.delete("/chat/messages")
async def clear_chat_messages(thread_id: str):
"""清空历史消息"""
clear_messages(thread_id)
return {"success": True}
4.5 测试
访问http://localhost:8001,即可实现多模态聊天了:

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)