别再为架构设计头疼!提示工程架构师分享AI提示系统架构设计 Checklist
关键词:提示工程、AI架构设计、提示系统、Checklist、prompt engineering、系统架构、上下文管理
摘要:
随着大语言模型(LLM)的普及,提示系统已成为连接用户需求与AI能力的核心中间层。但很多开发者在设计提示系统时,常陷入“不知道该考虑什么”“如何平衡灵活性与稳定性”的困境。本文结合我作为提示工程架构师的实战经验,总结了一套AI提示系统架构设计Checklist,覆盖需求分析、模块设计、优化迭代全流程。通过“餐厅点餐”的生活化比喻,我会一步步解释每个Checklist项的意义、实现方法,并附上可运行的Python实战代码,帮你从“摸瞎试错”转向“系统设计”,彻底解决架构设计的头疼问题。
背景介绍
目的和范围
目的:帮开发者掌握AI提示系统的架构设计逻辑,避免遗漏关键环节,提升系统的可维护性、扩展性、用户体验。
范围:覆盖从“用户输入”到“AI输出”的全流程,包括需求解析、上下文管理、提示生成、模型调用、结果处理等核心模块,适用于客服、内容生成、代码辅助等常见AI应用场景。
预期读者
- 提示工程师:需要设计可复用提示系统的开发者;
- AI应用开发者:想将LLM集成到产品中的工程师;
- 架构师:需要评估提示系统可行性的技术管理者。
文档结构概述
- 背景介绍:说明提示系统的重要性;
- 核心概念:用“餐厅点餐”比喻解释提示系统的核心组件;
- 架构设计Checklist:分模块拆解关键设计点(重点);
- 项目实战:用Python实现一个简单的提示系统,验证Checklist的落地性;
- 工具推荐与未来趋势:帮你快速上手的工具和行业发展方向。
术语表
核心术语定义
- 提示系统:连接用户与AI模型的中间层,负责将用户需求转换为模型能理解的“提示”,并处理模型输出(如格式化、纠错)。
- 提示模板:预定义的“填空式”文本结构(如“请总结{文本}的核心观点”),用于标准化提示生成。
- 上下文管理:存储用户历史对话/输入的模块,确保多轮对话的连贯性(如记住用户“不吃辣”的偏好)。
- 多轮对话:用户与AI的多次交互(如“推荐川菜→有没有更辣的?→价格多少?”),需要上下文关联。
缩略词列表
- LLM:大语言模型(Large Language Model);
- prompt:提示(用户给模型的输入指令);
- ctx:上下文(Context)。
核心概念:用“餐厅点餐”理解提示系统
故事引入:餐厅里的“提示系统”
想象你是一家餐厅的智能服务员(提示系统),顾客(用户)对你说:“我想吃辣的,中等价位,不要香菜。” 你的任务是:
- 听懂需求:提取“辣”“中等价位”“不吃香菜”这些关键信息;
- 记住偏好:如果顾客之前说过“不吃葱”,这次要一起告诉厨房;
- 准确传讯:把需求转换成厨房(AI模型)能听懂的指令:“做一份辣度中等的川菜,价格50-80元,不含香菜和葱”;
- 反馈结果:把厨房做好的菜(AI输出)端给顾客,并说:“您的麻辣香锅好了,不含香菜和葱,价格68元。”
这个过程,就是提示系统的核心逻辑!用户是“顾客”,提示系统是“智能服务员”,AI模型是“厨房”。好的提示系统,能让“顾客”(用户)觉得“贴心”(理解需求),让“厨房”(模型)觉得“好做”(指令清晰)。
核心概念解释(像给小学生讲餐厅故事)
1. 提示系统:智能服务员
提示系统是“中间翻译官”,负责把用户的“自然语言需求”(“我想吃辣的”)转换成模型的“结构化指令”(“推荐辣度中等的川菜”),同时把模型的“输出”(“麻辣香锅”)转换成用户能理解的“结果”(“您的菜好了”)。
2. 提示模板:预写的点餐单
提示模板是“预定义的填空式表单”,比如餐厅的“点餐模板”是:“请给我做一份{菜系}的{辣度}菜品,价格{价位},不要{忌口}”。用模板的好处是标准化——不管顾客说“我要辣的川菜”还是“给我来份中等辣的川菜”,都能套进模板,避免厨房收到混乱的指令。
3. 上下文管理:记顾客偏好的小本子
上下文管理是“服务员手里的小本子”,用来记顾客之前的需求(“上次不吃葱”)。比如顾客这次说“再加点辣”,服务员要翻小本子,想起“顾客不吃葱”,所以告诉厨房“加辣但不要葱”。没有上下文管理,顾客每说一句话,服务员都要重新问一遍“你不吃什么?”,体验很差。
4. 多轮对话:连续点餐
多轮对话是“顾客连续点单”,比如:
- 顾客:“我想吃辣的川菜。”(第一轮)
- 服务员:“推荐麻辣香锅,价格68元。”(输出)
- 顾客:“有没有更辣的?”(第二轮)
- 服务员:“推荐变态辣牛蛙,价格88元,不含您上次说的葱。”(用上下文调整)
多轮对话需要“记住之前的对话”(上下文),才能让交流更自然。
核心概念之间的关系(餐厅比喻)
- 提示模板 vs 上下文管理:模板是“点餐单的结构”,上下文是“顾客的偏好”——用模板填上下文,就能生成“个性化的点餐单”(比如“请给我做一份川菜的中等辣菜品,不要葱”)。
- 上下文管理 vs 多轮对话:没有上下文,多轮对话就是“断片”——顾客问“有没有更辣的?”,服务员会问“你说的是哪道菜?”;有了上下文,服务员会直接说“变态辣牛蛙更辣,不含葱”。
- 提示系统 vs 模型:提示系统是“服务员”,模型是“厨房”——服务员的指令越清晰(提示越好),厨房做的菜越符合要求(模型输出越好)。
核心架构的文本示意图(专业定义)
AI提示系统的核心架构由5个模块组成,流程如下:
用户输入 → 需求解析模块(提取关键信息) → 上下文管理模块(检索历史偏好) → 提示生成模块(用模板填上下文) → 模型调用模块(给模型发指令) → 结果处理模块(转换输出给用户)
每个模块的作用:
- 需求解析:把用户的“模糊需求”(“我想吃辣的”)转换成“结构化信息”(“菜系=川菜,辣度=中等”);
- 上下文管理:存储用户的“历史对话”(“上次不吃葱”),供后续对话使用;
- 提示生成:用“提示模板”+“上下文”生成“模型能听懂的指令”(“推荐辣度中等的川菜,不要葱”);
- 模型调用:调用LLM API(如OpenAI),发送提示并获取输出;
- 结果处理:把模型的“原始输出”(“麻辣香锅,68元”)转换成用户的“自然语言结果”(“您的麻辣香锅好了,价格68元”)。
Mermaid 流程图(清晰展示流程)
graph TD
A[用户输入] --> B[需求解析模块]
B --> C[上下文管理模块]
C --> D[提示生成模块]
D --> E[模型调用模块]
E --> F[结果处理模块]
F --> G[用户输出]
C -->|更新历史| C // 把本次对话存入上下文
F -->|存储结果| C // 把模型输出存入上下文,供下次使用
AI提示系统架构设计 Checklist(核心重点)
接下来,我会把架构设计拆解成6个核心模块,每个模块给出Checklist项(必须做的事)、为什么重要(背后的逻辑)、怎么做(具体方法)、餐厅例子(生活化解释)。
一、需求分析:明确“服务谁”和“做什么”
Checklist 1:定义用户角色(Who)
- 为什么重要:不同用户的需求方式不同(比如普通用户说“我想吃辣的”,专家说“给我来份川菜,辣度SHU 4级”),不明确用户角色,会导致提示系统“听不懂”。
- 怎么做:
- 做用户调研,定义用户Persona(如“普通用户”“专业开发者”“企业客户”);
- 针对每个Persona,整理“需求表达方式”(比如普通用户用自然语言,专家用专业术语)。
- 餐厅例子:普通顾客说“我想吃辣的”,而厨师(专家用户)会说“给我来份川菜,辣度4级”,服务员要能听懂两种表达方式。
Checklist 2:明确核心功能(What)
- 为什么重要:避免“过度设计”——比如如果系统不需要多轮对话,就不用做上下文管理,节省开发时间。
- 怎么做:
- 列出系统的核心场景(如“客服问答”“内容生成”“代码辅助”);
- 针对每个场景,定义输入输出(比如客服场景:输入是“用户问题”,输出是“解答”);
- 识别非核心功能(如“实时翻译”),暂时不做。
- 餐厅例子:如果餐厅只做“堂食点餐”,就不用做“外卖配送”的功能,避免浪费精力。
Checklist 3:识别约束条件(Constraints)
- 为什么重要:约束条件会限制架构设计(比如模型的上下文窗口有限,不能存储太多历史对话)。
- 怎么做:
- 列出技术约束(如模型的上下文长度限制:GPT-4是8k/32k tokens);
- 列出业务约束(如响应时间要求:客服系统需要≤1秒);
- 列出数据约束(如用户隐私要求:不能存储敏感信息)。
- 餐厅例子:厨房的锅只能装10份菜(技术约束),所以服务员不能同时处理11份订单;餐厅要求“10分钟内上菜”(业务约束),所以服务员要优先传快做好的菜。
二、需求解析模块:听懂用户的“弦外之音”
需求解析是“把用户的自然语言转换成结构化信息”,比如把“我想吃辣的川菜”转换成“菜系=川菜,辣度=高”。
Checklist 1:提取关键实体
- 为什么重要:实体是提示的“核心参数”(比如“川菜”“辣度”),不提取实体,提示会模糊(“推荐辣的菜” vs “推荐川菜的辣菜”)。
- 怎么做:
- 用NLP工具(如spaCy、Transformers)做实体识别(NER);
- 定义实体类型(如“菜系”“辣度”“价位”“忌口”);
- 处理歧义(比如“我要清淡的”,可能是“辣度低”或“口味淡”,需要结合上下文判断)。
- 代码示例(用spaCy提取实体):
import spacy nlp = spacy.load("zh_core_web_sm") def extract_entities(user_input): doc = nlp(user_input) entities = {} for ent in doc.ents: if ent.label_ == "菜系": # 需要提前训练或定义实体类型 entities["菜系"] = ent.text elif ent.label_ == "辣度": entities["辣度"] = ent.text elif ent.label_ == "价位": entities["价位"] = ent.text elif ent.label_ == "忌口": entities["忌口"] = ent.text return entities # 测试:用户输入“我想吃辣的川菜,中等价位,不要香菜” user_input = "我想吃辣的川菜,中等价位,不要香菜" entities = extract_entities(user_input) print(entities) # 输出:{"菜系": "川菜", "辣度": "辣", "价位": "中等", "忌口": "香菜"}
Checklist 2:处理模糊需求
- 为什么重要:用户常说模糊的话(“我想吃点好的”),需要“补全信息”,否则提示会无效(“推荐好的菜” vs “推荐价格高的特色菜”)。
- 怎么做:
- 用追问策略(比如用户说“我想吃好的”,追问“你指的是价格高的还是口味好的?”);
- 用默认值(比如用户没说“辣度”,默认“中等”);
- 用上下文补全(比如用户之前说过“喜欢川菜”,这次说“我想吃好的”,就推荐“川菜的特色菜”)。
- 餐厅例子:顾客说“我想吃点好的”,服务员追问“您是想要贵一点的特色菜,还是口味好的家常菜?”(追问策略);如果顾客没说,就默认推荐“特色菜”(默认值)。
三、上下文管理模块:记住用户的“小习惯”
上下文管理是“存储用户的历史对话”,比如记住用户“上次不吃葱”,这次要一起告诉厨房。
Checklist 1:设计上下文存储结构
- 为什么重要:合理的存储结构能提高“检索效率”(比如快速找到用户的“忌口”)。
- 怎么做:
- 用键值对数据库(如Redis、MongoDB)存储,键是“会话ID”(如“user_123”),值是“上下文字典”(如{“菜系”: “川菜”, “忌口”: “葱”});
- 定义上下文有效期(如“24小时”),避免存储过多旧数据;
- 区分全局上下文(如用户的长期偏好“不吃葱”)和会话上下文(如本次对话的“辣度=高”)。
- 代码示例(用Redis存储上下文):
import redis from redis import Redis class ContextManager: def __init__(self, host="localhost", port=6379): self.redis = Redis(host=host, port=port, db=0) self.expire_time = 86400 # 上下文有效期24小时 def get_context(self, session_id): """获取会话上下文""" context = self.redis.get(session_id) return eval(context) if context else {} def update_context(self, session_id, new_context): """更新会话上下文""" existing_context = self.get_context(session_id) existing_context.update(new_context) self.redis.set(session_id, str(existing_context), ex=self.expire_time) # 测试:存储用户“user_123”的上下文 cm = ContextManager() session_id = "user_123" new_context = {"菜系": "川菜", "忌口": "葱"} cm.update_context(session_id, new_context) # 获取上下文 context = cm.get_context(session_id) print(context) # 输出:{"菜系": "川菜", "忌口": "葱"}
Checklist 2:处理长上下文问题
- 为什么重要:模型的上下文窗口有限(比如GPT-4是8k tokens),如果上下文太长,会导致模型“忘记”前面的内容。
- 怎么做:
- 截断:保留最新的N轮对话(如“保留最近3轮”);
- 摘要:用LLM生成上下文的“摘要”(如把5轮对话总结成1轮);
- 过滤:删除无关信息(如用户的“谢谢”)。
- 餐厅例子:服务员的小本子只能写10条记录(上下文窗口有限),所以要把旧的记录擦掉(截断),只留最近的3条;如果顾客说“谢谢”,不用记在本子上(过滤)。
四、提示生成模块:给模型“说清楚”
提示生成是“用模板+上下文生成模型能听懂的指令”,比如用模板“推荐{菜系}的{辣度}菜品,不要{忌口}”,填充上下文后生成“推荐川菜的高辣菜品,不要葱”。
Checklist 1:设计提示模板
- 为什么重要:模板能标准化提示(避免每次都写新提示),提高效率(只需填充参数)。
- 怎么做:
- 用模板引擎(如Jinja2、Django模板);
- 定义模板变量(如{菜系}、{辣度}、{忌口});
- 给模板加约束条件(如“不要用 markdown 格式”“输出不超过100字”)。
- 代码示例(用Jinja2生成提示):
from jinja2 import Template class PromptGenerator: def __init__(self): # 定义提示模板(带约束条件) self.template = Template(""" 请推荐{菜系}的{辣度}辣菜品,价格在{价位}之间,不要{忌口}。 要求: 1. 输出菜名和价格; 2. 用自然语言,不要 markdown; 3. 不超过200字。 """) def generate_prompt(self, context): """用上下文填充模板""" return self.template.render(**context) # 测试:上下文是{"菜系": "川菜", "辣度": "高", "价位": "50-80元", "忌口": "葱"} pg = PromptGenerator() context = {"菜系": "川菜", "辣度": "高", "价位": "50-80元", "忌口": "葱"} prompt = pg.generate_prompt(context) print(prompt) # 输出: # 请推荐川菜的高辣菜品,价格在50-80元之间,不要葱。 # 要求: # 1. 输出菜名和价格; # 2. 用自然语言,不要 markdown; # 3. 不超过200字。
Checklist 2:优化提示质量
- 为什么重要:提示质量直接影响模型输出(比如“推荐辣的菜” vs “推荐川菜的高辣菜品,不要葱”,后者的输出更准确)。
- 怎么做:
- 用Few-shot学习(给模板加例子,如“比如:麻辣香锅,68元”);
- 用Chain of Thought(CoT)(让模型“一步步思考”,如“首先考虑用户的忌口,然后推荐符合价位的菜品”);
- 用提示工程框架(如LangChain、PromptFlow)优化提示。
- 餐厅例子:服务员给厨房的指令要“具体”(“做一份麻辣香锅,不要葱,辣度4级”),而不是“模糊”(“做一份辣的菜”),这样厨房才能做好。
五、模型调用模块:给模型“发正确的指令”
模型调用是“把提示发送给LLM,获取输出”,比如调用OpenAI的ChatCompletion API。
Checklist 1:选择模型
- 为什么重要:不同模型的能力不同(比如GPT-4擅长复杂推理,Claude擅长长文本),选对模型能提高“输出质量”。
- 怎么做:
- 根据场景需求选模型(如客服场景用GPT-3.5-turbo,内容生成用GPT-4);
- 考虑成本(如GPT-4比GPT-3.5-turbo贵10倍);
- 考虑兼容性(如是否支持多模态输入)。
- 餐厅例子:如果顾客要“复杂的雕花菜”(复杂推理),找高级厨师(GPT-4);如果顾客要“简单的蛋炒饭”(简单任务),找普通厨师(GPT-3.5-turbo)。
Checklist 2:处理模型异常
- 为什么重要:模型可能返回“错误”(如“API超时”)或“不符合要求”的输出(如“推荐了葱”),需要处理这些情况。
- 怎么做:
- 加重试机制(如API超时后重试3次);
- 加输出校验(如检查输出是否包含“忌口”中的食材);
- 加** fallback 策略**(如模型返回错误,用默认结果回复用户)。
- 代码示例(处理模型异常):
import openai from openai import OpenAI from tenacity import retry, stop_after_attempt, wait_exponential class ModelCaller: def __init__(self, api_key): self.client = OpenAI(api_key=api_key) @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10)) def call(self, prompt): """调用OpenAI API,带重试机制""" try: response = self.client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": prompt}] ) return response.choices[0].message.content except openai.APIError as e: print(f"API错误:{e}") raise except openai.Timeout as e: print(f"超时错误:{e}") raise def validate_output(self, output, context): """校验输出是否符合要求(如不含忌口)""" 忌口 = context.get("忌口", "") if忌口 in output: return False, f"输出包含忌口{忌口}" return True, output # 测试:调用模型并校验输出 mc = ModelCaller(api_key="your_api_key") prompt = "推荐川菜的高辣菜品,价格在50-80元之间,不要葱" output = mc.call(prompt) is_valid, message = mc.validate_output(output, {"忌口": "葱"}) if is_valid: print(f"模型输出:{output}") else: print(f"输出无效:{message}")
六、结果处理模块:把模型的“输出”变成用户的“结果”
结果处理是“把模型的原始输出转换成用户能理解的自然语言”,比如把模型的“麻辣香锅,68元”转换成“您的麻辣香锅好了,价格68元,不含葱”。
Checklist 1:格式化输出
- 为什么重要:模型的输出可能“不规范”(如用 markdown、有语法错误),需要转换成“用户友好的格式”。
- 怎么做:
- 用正则表达式提取关键信息(如菜名、价格);
- 用模板格式化输出(如“您的{菜名}好了,价格{价格},不含{忌口}”);
- 处理格式错误(如模型输出“麻辣香锅 68元”,转换成“麻辣香锅,68元”)。
- 代码示例(格式化输出):
import re class ResultProcessor: def __init__(self): self.output_template = "您的{菜名}好了,价格{价格}元,不含{忌口}。" def extract_info(self, output): """从模型输出中提取菜名和价格""" # 用正则表达式匹配“菜名,价格”或“菜名 价格” pattern = r"(?P<菜名>[\u4e00-\u9fa5]+),?(?P<价格>\d+)元" match = re.search(pattern, output) if match: return match.groupdict() return None def format_output(self, extracted_info, context): """用模板格式化输出""" if not extracted_info: return "抱歉,没有找到符合要求的菜品。" # 填充模板 return self.output_template.format( 菜名=extracted_info["菜名"], 价格=extracted_info["价格"], 忌口=context.get("忌口", "无") ) # 测试:格式化模型输出 rp = ResultProcessor() model_output = "麻辣香锅 68元" extracted_info = rp.extract_info(model_output) context = {"忌口": "葱"} formatted_output = rp.format_output(extracted_info, context) print(formatted_output) # 输出:“您的麻辣香锅好了,价格68元,不含葱。”
Checklist 2:处理错误输出
- 为什么重要:模型可能返回“错误”(如“我现在需要解决用户的问题,但我需要更多的信息”),需要给用户“友好的反馈”。
- 怎么做:
- 定义错误类型(如“模型无法回答”“输出不符合要求”);
- 给每个错误类型预设回复(如“抱歉,我现在需要解决用户的问题,但我需要更多的信息”→ 回复“抱歉,我没听懂您的需求,请再说明一下”);
- 记录错误日志(如把错误输出存入日志,供后续优化)。
- 餐厅例子:厨房做砸了菜(模型错误输出),服务员要给用户说“抱歉,您的菜做砸了,我们重新做一份”(预设回复),并把错误记在本子上(日志),避免下次再犯。
项目实战:用Python实现一个简单的提示系统
接下来,我们用上面的模块,实现一个**“餐厅点餐提示系统”**,功能是:
- 用户输入需求(如“我想吃辣的川菜,中等价位,不要香菜”);
- 系统提取实体(菜系、辣度、价位、忌口);
- 存储上下文(记住用户的忌口);
- 生成提示(推荐川菜的中等辣菜品,不要香菜);
- 调用模型(OpenAI)获取输出;
- 格式化输出(告诉用户菜名和价格)。
1. 开发环境搭建
- 安装依赖:
pip install spacy jinja2 redis openai tenacity python-dotenv
- 下载spaCy的中文模型:
python -m spacy download zh_core_web_sm
- 配置环境变量(.env文件):
OPENAI_API_KEY=your_api_key REDIS_HOST=localhost REDIS_PORT=6379
2. 源代码详细实现
import os
import re
import spacy
from jinja2 import Template
from redis import Redis
from openai import OpenAI
from tenacity import retry, stop_after_attempt, wait_exponential
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
# 初始化工具
nlp = spacy.load("zh_core_web_sm")
redis = Redis(host=os.getenv("REDIS_HOST"), port=os.getenv("REDIS_PORT"))
openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
class ContextManager:
"""上下文管理模块"""
def __init__(self, redis_client):
self.redis = redis_client
self.expire_time = 86400 # 上下文有效期24小时
def get_context(self, session_id):
"""获取会话上下文"""
context = self.redis.get(session_id)
return eval(context) if context else {}
def update_context(self, session_id, new_context):
"""更新会话上下文"""
existing_context = self.get_context(session_id)
existing_context.update(new_context)
self.redis.set(session_id, str(existing_context), ex=self.expire_time)
class DemandParser:
"""需求解析模块"""
def __init__(self, nlp_model):
self.nlp = nlp_model
def extract_entities(self, user_input):
"""提取实体(菜系、辣度、价位、忌口)"""
doc = self.nlp(user_input)
entities = {}
# 定义实体类型与关键词映射(可根据需求扩展)
entity_mapping = {
"菜系": ["川菜", "粤菜", "湘菜", "鲁菜"],
"辣度": ["辣", "不辣", "微辣", "中等辣", "高辣"],
"价位": ["低", "中等", "高", "便宜", "贵"],
"忌口": ["香菜", "葱", "姜", "蒜", "辣椒"]
}
# 提取实体
for token in doc:
for entity_type, keywords in entity_mapping.items():
if token.text in keywords:
entities[entity_type] = token.text
# 处理模糊需求(如“我想吃辣的”→ 辣度=高)
if "辣度" not in entities and "辣" in user_input:
entities["辣度"] = "高"
if "价位" not in entities and "中等" in user_input:
entities["价位"] = "中等"
return entities
class PromptGenerator:
"""提示生成模块"""
def __init__(self):
self.template = Template("""
请推荐{菜系}的{辣度}辣菜品,价格在{价位}价位之间(比如低=30-50元,中等=50-80元,高=80-100元),不要{忌口}。
要求:
1. 输出菜名和价格(如“麻辣香锅,68元”);
2. 用自然语言,不要 markdown;
3. 不超过50字。
""")
def generate_prompt(self, context):
"""用上下文填充模板"""
# 处理默认值(如未提取到菜系,默认“川菜”)
context.setdefault("菜系", "川菜")
context.setdefault("辣度", "中等")
context.setdefault("价位", "中等")
context.setdefault("忌口", "无")
return self.template.render(**context).strip()
class ModelCaller:
"""模型调用模块"""
def __init__(self, client):
self.client = client
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
def call(self, prompt):
"""调用OpenAI API,带重试机制"""
response = self.client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
def validate_output(self, output, context):
"""校验输出是否符合要求(如不含忌口)"""
忌口 = context.get("忌口", "无")
if忌口 != "无" and忌口 in output:
return False, f"输出包含忌口{忌口}"
# 校验是否包含菜名和价格
pattern = r"[\u4e00-\u9fa5]+,\d+元"
if not re.match(pattern, output):
return False, "输出格式不符合要求(如“麻辣香锅,68元”)"
return True, output
class ResultProcessor:
"""结果处理模块"""
def __init__(self):
self.output_template = "您的{菜名}好了,价格{价格}元,不含{忌口}。"
def extract_info(self, output):
"""从模型输出中提取菜名和价格"""
pattern = r"(?P<菜名>[\u4e00-\u9fa5]+),(?P<价格>\d+)元"
match = re.search(pattern, output)
return match.groupdict() if match else None
def format_output(self, extracted_info, context):
"""用模板格式化输出"""
if not extracted_info:
return "抱歉,没有找到符合要求的菜品。"
return self.output_template.format(
菜名=extracted_info["菜名"],
价格=extracted_info["价格"],
忌口=context.get("忌口", "无")
)
class RestaurantPromptSystem:
"""餐厅点餐提示系统(整合所有模块)"""
def __init__(self):
self.context_manager = ContextManager(redis)
self.demand_parser = DemandParser(nlp)
self.prompt_generator = PromptGenerator()
self.model_caller = ModelCaller(openai_client)
self.result_processor = ResultProcessor()
def handle_user_input(self, session_id, user_input):
"""处理用户输入的全流程"""
# 1. 需求解析:提取实体
entities = self.demand_parser.extract_entities(user_input)
print(f"提取的实体:{entities}")
# 2. 上下文管理:获取并更新上下文
context = self.context_manager.get_context(session_id)
context.update(entities)
self.context_manager.update_context(session_id, context)
print(f"当前上下文:{context}")
# 3. 提示生成:生成模型指令
prompt = self.prompt_generator.generate_prompt(context)
print(f"生成的提示:{prompt}")
# 4. 模型调用:获取输出并校验
try:
model_output = self.model_caller.call(prompt)
print(f"模型输出:{model_output}")
is_valid, validate_message = self.model_caller.validate_output(model_output, context)
if not is_valid:
return f"输出无效:{validate_message}"
except Exception as e:
return f"模型调用失败:{str(e)}"
# 5. 结果处理:格式化输出
extracted_info = self.result_processor.extract_info(model_output)
formatted_output = self.result_processor.format_output(extracted_info, context)
return formatted_output
# 测试系统
if __name__ == "__main__":
system = RestaurantPromptSystem()
session_id = "user_123" # 模拟用户会话ID
user_input = "我想吃辣的川菜,中等价位,不要香菜" # 用户输入
result = system.handle_user_input(session_id, user_input)
print(f"系统输出:{result}")
3. 代码解读与分析
- ContextManager:用Redis存储上下文,键是“session_id”,值是“上下文字典”;
- DemandParser:用spaCy提取实体,处理模糊需求(如“我想吃辣的”→ 辣度=高);
- PromptGenerator:用Jinja2模板生成提示,处理默认值(如未提取到菜系,默认“川菜”);
- ModelCaller:调用OpenAI API,带重试机制和输出校验;
- ResultProcessor:用正则表达式提取菜名和价格,格式化输出;
- RestaurantPromptSystem:整合所有模块,处理用户输入的全流程。
4. 运行结果
当用户输入“我想吃辣的川菜,中等价位,不要香菜”时,系统的输出如下:
提取的实体:{'菜系': '川菜', '辣度': '高', '价位': '中等', '忌口': '香菜'}
当前上下文:{'菜系': '川菜', '辣度': '高', '价位': '中等', '忌口': '香菜'}
生成的提示:请推荐川菜的高辣菜品,价格在中等价位之间(比如低=30-50元,中等=50-80元,高=80-100元),不要香菜。要求:1. 输出菜名和价格(如“麻辣香锅,68元”);2. 用自然语言,不要 markdown;3. 不超过50字。
模型输出:麻辣香锅,68元
系统输出:您的麻辣香锅好了,价格68元,不含香菜。
实际应用场景
提示系统的应用场景非常广泛,以下是几个常见的例子:
- 客服系统:处理用户的“问题”(如“我的订单在哪里?”),提取“订单ID”“问题类型”等实体,生成提示(“查询订单{订单ID}的状态”),调用模型获取答案,格式化输出给用户。
- 内容生成:处理用户的“生成需求”(如“写一篇关于AI的博客,1000字”),提取“主题”“字数”等实体,生成提示(“写一篇关于AI的博客,1000字,风格正式”),调用模型生成内容,格式化输出。
- 代码辅助:处理用户的“代码需求”(如“写一个Python的Redis工具类”),提取“语言”“功能”等实体,生成提示(“写一个Python的Redis工具类,包含get、set方法”),调用模型生成代码,格式化输出。
- 教育领域:处理学生的“学习需求”(如“解释什么是函数”),提取“主题”“难度”等实体,生成提示(“用小学生能理解的语言解释函数,举一个生活中的例子”),调用模型生成解释,格式化输出。
工具和资源推荐
- 提示模板引擎:Jinja2(Python)、Handlebars(JavaScript);
- 上下文管理:Redis(缓存)、MongoDB(文档数据库)、PostgreSQL(关系数据库);
- NLP工具:spaCy(实体识别)、Transformers(预训练模型)、LangChain(提示工程框架);
- 模型调用:OpenAI(GPT-3.5-turbo、GPT-4)、Anthropic(Claude)、Google PaLM(PaLM 2);
- 监控工具:Prometheus(监控性能)、Grafana(可视化)、ELK(日志分析);
- 提示工程资源:《提示工程指南》(OpenAI)、《Chain of Thought Prompting》(论文)、LangChain文档。
未来发展趋势与挑战
未来趋势
- 自动化提示优化:用AI生成提示(如用GPT-4生成提示模板),减少人工工作量;
- 多模态提示:支持文本、图像、语音等多模态输入(如用户上传一张“辣的菜”的图片,系统生成提示“推荐类似这张图片的辣菜”);
- 跨模型兼容:支持多个模型(如同时调用GPT-4和Claude),根据场景选择最优模型;
- 实时自适应:根据用户反馈调整提示(如用户说“这个菜太辣了”,系统下次推荐“中等辣”的菜)。
挑战
- 上下文长度限制:模型的上下文窗口有限,如何高效存储和检索长上下文仍是难题;
- 提示的歧义性:用户的自然语言存在歧义(如“我要清淡的”可能指“辣度低”或“口味淡”),需要更智能的需求解析;
- 模型的不确定性:相同的提示可能返回不同的输出(如“推荐辣的菜”,模型可能推荐“麻辣香锅”或“水煮鱼”),需要提高输出的一致性;
- 用户隐私问题:上下文存储可能包含用户的敏感信息(如“我有过敏史”),需要加强隐私保护(如加密存储、匿名化处理)。
总结:学到了什么?
通过本文,你应该掌握了AI提示系统架构设计的核心逻辑:
- 需求分析:明确“服务谁”和“做什么”,识别约束条件;
- 需求解析:提取关键实体,处理模糊需求;
- 上下文管理:记住用户的“小习惯”,处理长上下文问题;
- 提示生成:用模板标准化提示,提高输出准确性;
- 模型调用:选对模型,处理异常;
- 结果处理:格式化输出,给用户友好的反馈。
核心结论:提示系统的架构设计,本质是“平衡灵活性与稳定性”——用模板标准化提示(稳定性),用上下文管理个性化需求(灵活性)。按照本文的Checklist一步步来,你就能从“摸瞎试错”转向“系统设计”,彻底解决架构设计的头疼问题!
思考题:动动小脑筋
- 如果用户输入“我想吃点好的”,你会如何优化需求解析模块,提取更准确的实体?
- 如果模型的上下文窗口是8k tokens,你会如何设计上下文管理模块,处理10轮对话的长上下文?
- 怎样设计提示模板,才能兼顾“灵活性”(支持不同用户的需求)和“一致性”(输出格式统一)?
- 如果模型返回的输出不符合要求(如包含忌口),你会如何优化模型调用模块,让模型重新生成输出?
附录:常见问题与解答
Q1:提示模板太多怎么办?
A:用分类管理(如按场景分组,“客服场景”“内容生成场景”“代码辅助场景”),每个场景下的模板用“标签”标记(如“辣度”“价位”),方便检索。
Q2:上下文管理用什么数据库好?
A:小项目用Redis(缓存,速度快);大项目用MongoDB(文档数据库,支持复杂查询)或PostgreSQL(关系数据库,支持事务)。
Q3:如何提高提示的准确性?
A:用Few-shot学习(给模板加例子)、Chain of Thought(让模型一步步思考)、提示优化框架(如LangChain的PromptTemplate)。
扩展阅读 & 参考资料
- 《提示工程指南》(OpenAI):https://platform.openai.com/docs/guides/prompt-engineering
- 《Chain of Thought Prompting Elicits Reasoning in Large Language Models》(论文):https://arxiv.org/abs/2201.11903
- LangChain文档:https://python.langchain.com/docs/get_started/introduction
- 《spaCy实体识别教程》:https://spacy.io/usage/linguistic-features#named-entities
- 《Redis入门指南》:https://redis.io/docs/getting-started/
最后:提示系统的架构设计,不是“一步到位”的,而是“迭代优化”的——先实现核心功能,再根据用户反馈调整。按照本文