我们晚上在京东App上通过京言AI助手点外卖为具体场景,重新走一遍四个模块(LLM、工具、记忆、规划)的协同循环。假设京东App内置了一个智能助手(类似“京言AI助手”),用户对助手说:
“
“晚上想吃点辣的,不要太油,从京东外卖上帮我选一家附近的店,直接下单。”
下面就是完整的执行过程,对应你给出的那个典型循环(理解 → 规划 → 读记忆 → 调工具 → 存记忆 → 回复)。
1. LLM 接收并理解用户指令
- 原始输入:自然语言,包含意图(点外卖)、约束条件(辣、不油)、平台限定(京东外卖)、动作(选店并下单)。
- LLM 做的事:
- 识别关键词:
晚上(时间暗示)、辣的(口味偏好)、不要太油(健康约束)、京东外卖(指定工具)、直接下单(执行动作)。 - 明确缺失信息:用户当前位置、具体店铺、菜品、付款方式(但这些可能从记忆中获得)。
- 输出结构化意图:
{ action: "order_food", cuisine: "spicy", oil_level: "low", platform: "JD_Food", auto_confirm: true }
- 识别关键词:
2. 规划模块分解任务
规划模块根据当前状态(已有意图、缺失信息)生成一个可动态调整的执行计划。典型计划如下:
| 步骤 | 动作 | 所需模块 | 说明 |
|---|---|---|---|
| 1 | 读取用户长期记忆 | 记忆 | 获取默认地址、历史口味偏好、常用支付方式 |
| 2 | 获取实时位置(若记忆中无地址或用户移动了) | 工具 | 调用京东App的GPS定位接口 |
| 3 | 查询京东外卖API,获取附近餐厅及菜品 | 工具 | 传入位置、关键词“辣 低油”,返回候选列表 |
| 4 | 让LLM评估候选结果,选择最佳餐厅和菜品 | LLM | 结合“辣但不油”约束和记忆中的历史评分 |
| 5 | 调用下单API | 工具 | 传入餐厅、菜品、地址、支付方式 |
| 6 | 将订单信息写入长期记忆 | 记忆 | 记录本次消费,用于未来推荐 |
| 7 | 生成自然语言回复 | LLM | 告知用户下单结果 |
“
注意:如果步骤4发现没有完全匹配的,规划模块会插入一个重规划子任务(例如放宽“不油”为“中等油量”或换一家店)。
3. 记忆模块提供上下文
在步骤1执行时,记忆模块被查询。它分为两部分:
- 短期记忆(本次会话):
- 用户刚刚说的“晚上、辣的、不要太油”。
- 尚未完成的下单操作状态。
- 长期记忆(跨会话存储,通常用向量数据库或键值表):
default_address: “北京市朝阳区XX小区12号楼302”payment_method: “京东白条”food_history: [ { date: “2025-10-01”, item: “麻辣香锅(少油)”, liked: true }, { date: “2025-10-05”, item: “辣子鸡”, feedback: “油太大” } ]preferred_cuisine: “川菜”, “湘菜”
记忆模块将这些信息返回给LLM和规划器,供后续步骤使用。
4. LLM 决定调用工具(第一次:查询外卖)
LLM 读取短期记忆中的计划步骤3:需要调用 京东外卖查询工具。
- 工具名称:
search_jd_food - 参数:
{
"location": "北京市朝阳区XX小区12号楼302",
"keywords": ["辣", "少油"],
"radius_km": 3,
"max_results": 5
} - 工具返回结果(存短期记忆):
[
{ "store": "川西坝子·少油麻辣香锅", "distance": "800m", "rating": 4.8, "dishes": [
{"name": "招牌少油香锅", "spicy": true, "oil_level": "low", "price": 38},
{"name": "微辣牛肉卷", "spicy": true, "oil_level": "medium", "price": 32}
]},
{ "store": "湘遇·低油菜馆", "distance": "1.2km", "rating": 4.6, "dishes": [
{"name": "少油小炒黄牛肉", "spicy": true, "oil_level": "low", "price": 45}
]},
{ "store": "辣么火·传统川菜", "distance": "900m", "rating": 4.5, "dishes": [
{"name": "水煮鱼", "spicy": true, "oil_level": "high", "price": 68}
]}
]
5. LLM 结合记忆进行推理和选择
LLM 现在拥有:
- 用户约束:辣、不油
- 长期记忆:用户喜欢“少油麻辣香锅”,讨厌“油大”的菜(辣子鸡反馈)
- 短期记忆:三家候选店铺及菜品油量标注
LLM 的思维链推理(可视为内部提示):
“
“辣么火的水煮鱼油量高,排除。湘遇的低油小炒黄牛肉符合要求,但距离稍远。川西坝子的招牌少油香锅距离近、评分高,且用户历史记录中对‘麻辣香锅(少油)’点赞,因此优先选择川西坝子的招牌少油香锅。”
最终选择:
- 店铺:川西坝子·少油麻辣香锅
- 菜品:招牌少油香锅(微辣,少油)
- 数量:1份
- 价格:38元 + 配送费 5元 = 43元
6. LLM 再次决定调用工具(第二次:执行下单)
规划模块步骤5要求调用 下单工具。LLM 生成调用参数(部分来自记忆):
{
"tool": "place_jd_food_order",
"params": {
"store_id": "JD_FOOD_7823",
"dish": "招牌少油香锅",
"quantity": 1,
"address": "北京市朝阳区XX小区12号楼302",
"payment": "京东白条",
"special_requests": "少油,微辣"
}
}
工具调用京东外卖的真实API,返回订单结果:
{
"order_id": "JD202610160001",
"total_amount": 43.00,
"estimated_delivery_time": "19:45",
"status": "success"
}
7. 记忆更新与最终回复
- 短期记忆:记录本次会话的订单号、金额、预计送达时间。
- 长期记忆更新:追加一条历史记录
{ date: "2026-10-16 19:00", item: "招牌少油香锅", liked: true, from_store: "川西坝子" },增强用户偏好向量。 - LLM 生成最终回复:““已按你‘辣但不油’的要求,在京东外卖上找到附近的‘川西坝子·少油麻辣香锅’店,为你下单了一份招牌少油香锅(微辣、少油),共计43元,使用京东白条支付。预计今晚7:45送达至XX小区12号楼302。订单号JD202610160001。如需更改,请尽快告诉我。”
协同流程对照表(点外卖 vs 机票例子)
| 步骤 | 机票例子 | 京东点外卖例子 |
|---|---|---|
| LLM 接收指令 | “查明天北京到上海机票,总结表格” | “晚上想吃辣的不要太油,京东外卖选店下单” |
| 规划分解 | ①查票 ②获取 ③总结 | ①读记忆 ②定位 ③查外卖 ④评估 ⑤下单 ⑥存记忆 ⑦回复 |
| 从记忆读取 | “喜欢早班机” | 默认地址、支付方式、历史喜欢“少油麻辣香锅” |
| 第一次调工具 | 机票查询API | 京东外卖搜索API(传入位置+辣+低油) |
| 工具结果存入短期记忆 | 航班列表 | 候选店铺+菜品油量标注 |
| LLM 决策 | 选择早班机并制表 | 根据历史偏好和油量选择“川西坝子少油香锅” |
| 第二次调工具 | (无,直接总结) | 京东外卖下单API |
| 最终回复 | 表格形式的航班信息 | 订单确认+送达时间 |
关键差异与启发
- 多轮工具调用:点外卖需要至少两次工具调用(查询 + 下单),机票例子只需一次查询。
- 条件分支:点外卖中如果查询结果没有低油辣菜,规划模块会插入“放宽油量限制”或“换关键词”的重试。
- 长期记忆的动态更新:下单后立即更新偏好,形成个性化循环。
- 京东App特有约束:工具调用必须遵循京东API的鉴权、地址格式、支付方式等,这需要LLM严格按schema生成参数。
下面给出一个基于 LangChain 的伪代码实现,演示如何用 LLM + 工具 + 记忆 + 规划 完成“在京东JoyAI上点外卖”任务。
环境准备(伪代码假设)
# 导入 LangChain 相关组件
from langchain.agents import initialize_agent, Tool, AgentType
from langchain.memory import ConversationBufferMemory, VectorStoreRetrieverMemory
from langchain.llms import OpenAI # 假设使用 OpenAI 模型,可替换为任何 LLM
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.callbacks import StdOutCallbackHandler
import json
from datetime import datetime
# 模拟京东外卖 API 函数 ------------------------------------------------
def get_user_location():
"""模拟获取用户当前 GPS 位置或默认地址"""
# 实际会调用京东 App 的定位接口
return"北京市朝阳区XX小区12号楼302"
def search_jd_food(location, keywords, radius_km=3):
"""模拟京东外卖搜索接口"""
# 参数示例:location="北京市朝阳区XX小区...", keywords="辣 少油"
mock_results = [
{
"store": "川西坝子·少油麻辣香锅",
"distance_km": 0.8,
"rating": 4.8,
"dishes": [
{"name": "招牌少油香锅", "spicy": True, "oil_level": "low", "price": 38},
{"name": "微辣牛肉卷", "spicy": True, "oil_level": "medium", "price": 32}
]
},
{
"store": "湘遇·低油菜馆",
"distance_km": 1.2,
"rating": 4.6,
"dishes": [
{"name": "少油小炒黄牛肉", "spicy": True, "oil_level": "low", "price": 45}
]
},
{
"store": "辣么火·传统川菜",
"distance_km": 0.9,
"rating": 4.5,
"dishes": [
{"name": "水煮鱼", "spicy": True, "oil_level": "high", "price": 68}
]
}
]
return mock_results
def place_jd_food_order(store_id, dish_name, quantity, address, payment_method, special_requests=""):
"""模拟京东外卖下单接口"""
# 实际会调用京东下单 API,这里返回模拟订单结果
order_id = f"JD{datetime.now().strftime('%Y%m%d%H%M%S')}"
total_amount = 43.00# 示例金额
estimated_time = "19:45"
return {
"order_id": order_id,
"total_amount": total_amount,
"estimated_delivery_time": estimated_time,
"status": "success"
}
定义工具(Tools)
将模拟 API 包装成 LangChain 的 Tool 对象,供 LLM 调用。
# 工具1:获取用户位置
def get_location_tool_func(_):
return get_user_location()
location_tool = Tool(
name="GetUserLocation",
func=get_location_tool_func,
description="获取用户当前默认地址。输入可以为空字符串。"
)
# 工具2:搜索京东外卖
def search_food_tool_func(query: str) -> str:
"""query 格式: "location|keywords" 例如 '北京市...|辣 少油'"""
parts = query.split("|")
location = parts[0] if len(parts) > 0else get_user_location()
keywords = parts[1] if len(parts) > 1else"辣 不油"
results = search_jd_food(location, keywords)
return json.dumps(results, ensure_ascii=False)
search_tool = Tool(
name="SearchJDFood",
func=search_food_tool_func,
description="搜索京东外卖餐厅和菜品。输入格式: '地址|关键词',例如 '北京市朝阳区XX小区|辣 少油'"
)
# 工具3:下单
def place_order_tool_func(order_json: str) -> str:
"""order_json 包含 store_id, dish_name, quantity, address, payment_method, special_requests"""
data = json.loads(order_json)
result = place_jd_food_order(
store_id=data["store_id"],
dish_name=data["dish_name"],
quantity=data.get("quantity", 1),
address=data["address"],
payment_method=data["payment_method"],
special_requests=data.get("special_requests", "")
)
return json.dumps(result, ensure_ascii=False)
order_tool = Tool(
name="PlaceJDFoodOrder",
func=place_order_tool_func,
description="在京东外卖下单。输入格式为 JSON: {'store_id':..., 'dish_name':..., 'quantity':1, 'address':..., 'payment_method':..., 'special_requests':...}"
)
tools = [location_tool, search_tool, order_tool]
记忆模块(Memory)
我们需要 短期记忆(保存当前会话上下文)和 长期记忆(保存用户偏好)。
这里简化演示:使用 ConversationBufferMemory 作为短期记忆,另外用一个简单的字典模拟长期记忆(实际可用向量数据库)。
# 短期记忆:存储最近对话及工具调用结果
short_memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True,
output_key="output"
)
# 长期记忆:模拟用户偏好(实际可用 Chroma/Pinecone)
long_term_memory = {
"default_address": "北京市朝阳区XX小区12号楼302",
"payment_method": "京东白条",
"food_history": [
{"date": "2025-10-01", "item": "麻辣香锅(少油)", "liked": True},
{"date": "2025-10-05", "item": "辣子鸡", "feedback": "油太大"}
],
"preferred_cuisine": ["川菜", "湘菜"]
}
# 一个简单的检索函数,将长期记忆注入到 prompt 中
def get_long_term_context(user_query: str) -> str:
# 实际根据 query 向量检索,这里直接返回整个偏好
returnf"用户长期偏好:默认地址 {long_term_memory['default_address']},支付方式 {long_term_memory['payment_method']}," \
f"历史喜欢的菜:{long_term_memory['food_history'][0]['item']},讨厌油大的食物。"
规划模块(Planning)
LangChain 的 initialize_agent 默认使用 ReAct 风格的 Agent,它本身就具备简单的规划能力(通过 LLM 生成 Thought/Action/Observation 循环)。
若需要更复杂的多步规划,可以自定义 AgentExecutor 或使用 PlanAndExecuteAgent。这里我们使用标准 zero-shot-react-description Agent,它的规划隐含在推理步骤中。
为了凸显“规划”,我们写一个显式的规划提示来引导 LLM 按步骤执行,并让 Agent 遵循该规划。
# 自定义规划提示模板
planning_prompt = PromptTemplate(
input_variables=["input", "agent_scratchpad", "chat_history", "long_term_context"],
template="""
你是一个京东外卖助手。你需要按照以下规划步骤执行用户的请求:
【规划步骤】
1. 如果用户没有明确给出地址,先调用 GetUserLocation 工具获取默认地址(从长期记忆获取也可以)。
2. 调用 SearchJDFood 工具,使用地址和“辣 少油”作为关键词,获取附近餐厅列表。
3. 分析搜索结果,结合用户的长期偏好(尤其是讨厌油太大的食物),选择最符合“辣但不油”的餐厅和菜品。
4. 调用 PlaceJDFoodOrder 工具,传入选中的餐厅ID、菜品名、地址、支付方式(从长期记忆获取)等。
5. 返回订单确认信息给用户。
用户长期偏好:
{long_term_context}
当前对话历史:
{chat_history}
用户最新指令:{input}
{agent_scratchpad}
"""
)
# 初始化 LLM(以 OpenAI 为例,实际可用任何模型)
llm = OpenAI(temperature=0, model_name="gpt-4")
# 创建 Agent
agent = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
memory=short_memory,
agent_kwargs={
"system_message": planning_prompt.template # 注入规划模板
},
verbose=True, # 打印推理过程
handle_parsing_errors=True
)
执行主流程
def run_jd_food_agent(user_input: str):
# 1. 获取长期记忆上下文
long_context = get_long_term_context(user_input)
# 2. 将长期记忆注入到 agent 的额外参数中(简单方式:拼接到输入)
# 实际可以通过 callback 或 memory 的额外字段实现
full_input = f"{user_input}\n\n【长期记忆信息】{long_context}"
# 3. 调用 Agent 执行
response = agent.run(full_input)
# 4. 执行后,根据结果更新长期记忆(例如记录本次点的菜)
# 这里简单示例:从 response 中提取订单信息,更新 food_history
if"订单号"in response:
new_record = {"date": datetime.now().strftime("%Y-%m-%d %H:%M"), "item": "招牌少油香锅", "liked": True}
long_term_memory["food_history"].append(new_record)
print("长期记忆已更新")
return response
# 模拟用户输入
user_query = "晚上想吃辣的,不要太油,帮我从京东外卖上选一家附近的店直接下单"
result = run_jd_food_agent(user_query)
print("\n=== 最终回复 ===\n", result)
模拟运行输出(Agent 的推理日志)
由于是伪代码,我们模拟一下 Agent 内部产生的 Thought/Action/Observation 序列:
> Entering new AgentExecutor chain...
Thought: 用户要求晚上点辣且不油的外卖。我需要先获得用户地址,然后搜索京东外卖,再选择符合要求的餐厅下单。
Action: GetUserLocation
Action Input: ""
Observation: 北京市朝阳区XX小区12号楼302
Thought: 地址已获得。现在需要搜索京东外卖,关键词为“辣 少油”。
Action: SearchJDFood
Action Input: "北京市朝阳区XX小区12号楼302|辣 少油"
Observation: [{"store": "川西坝子·少油麻辣香锅", "dishes": [{"name": "招牌少油香锅", "oil_level": "low"}...]}, ...]
Thought: 搜索结果中有三家店。根据长期记忆,用户讨厌油大的食物,且历史喜欢麻辣香锅(少油)。川西坝子的招牌少油香锅完全满足“辣且低油”,距离最近,评分最高。因此选择这家店和这个菜品。
Action: PlaceJDFoodOrder
Action Input: {"store_id": "川西坝子·少油麻辣香锅", "dish_name": "招牌少油香锅", "quantity": 1, "address": "北京市朝阳区XX小区12号楼302", "payment_method": "京东白条", "special_requests": "少油,微辣"}
Observation: {"order_id": "JD20261016190001", "total_amount": 43.0, "estimated_delivery_time": "19:45", "status": "success"}
Thought: 下单成功,我已获得订单信息。现在回复用户。
Final Answer: 已按你“辣但不油”的要求,在京东外卖上找到附近的“川西坝子·少油麻辣香锅”店,为你下单了一份招牌少油香锅(微辣、少油),共计43元,使用京东白条支付。预计今晚7:45送达至XX小区12号楼302。订单号JD20261016190001。如需更改,请尽快告诉我。
> Finished chain.
长期记忆已更新
=== 最终回复 ===
已按你“辣但不油”的要求...
关键点解释
- LLM:OpenAI 模型(或任何兼容模型)作为推理核心。
- 工具:三个自定义工具分别对应定位、搜索、下单。每个工具都有清晰的描述,Agent 知道何时调用。
- 记忆:
- 短期:
ConversationBufferMemory记录对话历史,保证多轮交互。 - 长期:简单字典存储用户偏好,并在每次请求时注入到 prompt;执行结束后更新。
- 短期:
- 规划:通过自定义 prompt 模板,明确写出了规划步骤(1→2→3→4→5),Agent 会按照这个顺序思考,但实际执行时仍依赖于 ReAct 的 Thought/Action 循环,不会机械执行——LLM 会根据观察动态调整(例如如果搜索结果不理想,可能重新搜索)。
这种实现方式已经足够模拟“点外卖”场景下的协同工作。
声明:来自程序员千羽,仅代表创作者观点。链接:https://eyangzhen.com/8592.html