L3-1、掌控多轮对话的节奏 -Prompt 结构与上下文管理全攻略
一、多轮对话中的上下文挑战与常见问题
在与大语言模型(LLM)进行多轮对话时,我们常常面临以下挑战:
- 上下文丢失:模型"遗忘"之前提到的信息
- 指代不明:难以理解代词指向的内容
- 话题漂移:对话逐渐偏离最初目标
- 信息过载:上下文窗口限制导致早期信息被截断
- 一致性问题:模型回答前后矛盾
这些问题会导致用户体验下降,特别是在开发对话型应用时尤为明显。
二、结构化设计:初始化、提问、跟进、总结
高效的多轮对话需要清晰的结构设计,可以参考以下四段式结构:
1. 初始化阶段
设定对话基调与规则:
initial_prompt = """
你是一位金融顾问专家。请遵循以下规则:
- 提供专业、准确的金融建议
- 使用简洁明了的语言解释复杂概念
- 需要更多信息时,主动询问
- 避免讨论非金融相关话题
"""
2. 提问阶段
清晰明确地表达需求:
question = """
我有30万元的闲置资金,希望投资获得稳定收益,
风险承受能力中等,计划3-5年后用于子女教育。
请推荐合适的投资组合方案。
"""
3. 跟进阶段
针对回答深入探讨,澄清疑惑:
follow_up = """
关于你提到的ETF投资,我想了解:
1. 有哪些具体的低波动ETF推荐?
2. 这些ETF的历史收益率大约是多少?
3. 投资ETF与购买指数型基金相比有什么优势?
"""
4. 总结阶段
对对话内容进行归纳与确认:
summary_prompt = """
请总结我们讨论的投资方案要点:
1. 适合我的资产配置比例
2. 推荐的具体投资产品
3. 需要注意的风险因素
4. 建议的定期检视与调整频率
"""
三、上下文引用技巧:变量记忆、前文重提、内容引用
变量记忆
在应用程序中使用变量存储关键信息:
import streamlit as st
# 初始化会话状态
if 'user_info' not in st.session_state:
st.session_state.user_info = {
'risk_tolerance': None,
'investment_amount': None,
'time_horizon': None,
'financial_goals': []
}
# 收集用户信息
st.title("智能投资顾问")
investment_amount = st.number_input("投资金额(元)", min_value=0, step=10000)
if investment_amount > 0:
st.session_state.user_info['investment_amount'] = investment_amount
risk_options = ["保守", "中等", "激进"]
risk_tolerance = st.select_slider("风险承受能力", options=risk_options)
st.session_state.user_info['risk_tolerance'] = risk_tolerance
time_horizon = st.slider("投资时间范围(年)", 1, 30, 5)
st.session_state.user_info['time_horizon'] = time_horizon
goals = st.multiselect("投资目标",
["退休规划", "子女教育", "购房", "旅行", "财务自由"])
st.session_state.user_info['financial_goals'] = goals
# 构建上下文提示
if st.button("获取投资建议"):
context_prompt = f"""
基于以下用户信息提供投资建议:
- 投资金额: {st.session_state.user_info['investment_amount']}元
- 风险承受能力: {st.session_state.user_info['risk_tolerance']}
- 投资期限: {st.session_state.user_info['time_horizon']}年
- 投资目标: {', '.join(st.session_state.user_info['financial_goals'])}
"""
st.write("正在生成投资建议...")
# 这里调用AI模型API,将context_prompt发送给模型
前文重提
在新问题中引用之前的讨论内容:
if 'conversation_history' not in st.session_state:
st.session_state.conversation_history = []
user_input = st.text_input("您的问题:")
if user_input and st.button("发送"):
st.session_state.conversation_history.append({"role": "user", "content": user_input})
# 构建包含历史记录的提示
full_prompt = "以下是我们之前的对话内容:\n\n"
for message in st.session_state.conversation_history:
prefix = "用户: " if message["role"] == "user" else "助手: "
full_prompt += prefix + message["content"] + "\n\n"
full_prompt += "请基于上述对话记录回答我的问题。"
# 调用AI模型API,传入full_prompt
# response = call_ai_api(full_prompt)
# 显示响应并添加到历史记录
# st.write("AI回复:", response)
# st.session_state.conversation_history.append({"role": "assistant", "content": response})
内容引用
允许用户和AI明确引用之前提到的特定内容:
st.subheader("对话历史")
for i, message in enumerate(st.session_state.conversation_history):
role = "用户" if message["role"] == "user" else "AI助手"
with st.expander(f"{role} ({i+1})"):
st.write(message["content"])
if message["role"] == "assistant":
if st.button(f"引用这条回复 #{i+1}", key=f"ref_{i}"):
ref_text = f"关于你在回复#{i+1}中提到的'{message['content'][:30]}...',"
st.session_state.reference_text = ref_text
st.experimental_rerun()
# 在用户输入框预填引用文本
reference_placeholder = ""
if 'reference_text' in st.session_state:
reference_placeholder = st.session_state.reference_text
user_input = st.text_input("您的问题:", value=reference_placeholder)
四、信息遗忘与"记住"的策略实现(含示例)
为了解决LLM的"遗忘"问题,我们可以采用以下策略:
1. 总结记忆 + 细节按需检索
import streamlit as st
from langchain.memory import ConversationSummaryMemory
from langchain.llms import OpenAI
st.title("具备记忆能力的AI助手")
# 初始化记忆组件
if 'memory' not in st.session_state:
st.session_state.memory = ConversationSummaryMemory(
llm=OpenAI(temperature=0),
max_token_limit=100
)
# 显示当前对话摘要
if st.checkbox("显示对话摘要"):
summary = st.session_state.memory.buffer
st.info(f"当前对话摘要:\n{summary}")
# 用户输入
user_input = st.text_input("您的问题:")
if user_input and st.button("发送"):
# 从记忆中获取摘要
memory_summary = st.session_state.memory.buffer
# 构建提示
prompt = f"""
以下是我们对话的摘要:
{memory_summary}
用户的新问题是:{user_input}
请基于以上上下文回答问题。
"""
# 这里调用AI API获取回答
# response = call_ai_api(prompt)
response = "这是AI的示例回答"
# 更新记忆
st.session_state.memory.save_context(
{"input": user_input},
{"output": response}
)
# 显示回答
st.write("AI回复:", response)
2. 关键信息提取与状态追踪
import streamlit as st
import json
st.title("信息提取与状态追踪示例")
# 初始化状态
if 'entity_memory' not in st.session_state:
st.session_state.entity_memory = {
"user_preferences": {},
"discussed_topics": [],
"action_items": []
}
# 分栏布局
col1, col2 = st.columns([2, 1])
with col1:
st.subheader("对话界面")
user_input = st.text_input("您的问题或指令:")
if user_input and st.button("发送"):
# 模拟发送给AI并获取回复
ai_response = "这是AI的模拟回复"
# 模拟信息提取过程
extraction_prompt = f"""
从以下对话中提取关键信息:
用户: {user_input}
AI: {ai_response}
提取以下类别的信息(JSON格式):
1. 用户偏好
2. 讨论的主题
3. 需要跟进的事项
"""
# 模拟AI提取的信息(实际应用中应调用AI API)
extracted_info = {
"user_preferences": {"喜欢的编程语言": "Python"},
"discussed_topics": ["AI记忆机制"],
"action_items": ["研究LangChain的记忆组件"]
}
# 更新存储的信息
for category, items in extracted_info.items():
if isinstance(items, dict):
st.session_state.entity_memory[category].update(items)
elif isinstance(items, list):
st.session_state.entity_memory[category].extend(items)
# 显示对话
st.write("用户:", user_input)
st.write("AI:", ai_response)
with col2:
st.subheader("已提取的信息")
st.write("用户偏好:")
st.json(st.session_state.entity_memory["user_preferences"])
st.write("已讨论主题:")
st.write(", ".join(set(st.session_state.entity_memory["discussed_topics"])))
st.write("待办事项:")
for item in set(st.session_state.entity_memory["action_items"]):
st.checkbox(item, key=f"todo_{item}")
3. 记忆/对话重置功能
st.sidebar.title("对话控制")
if st.sidebar.button("清除记忆"):
if 'entity_memory' in st.session_state:
st.session_state.entity_memory = {
"user_preferences": {},
"discussed_topics": [],
"action_items": []
}
if 'conversation_history' in st.session_state:
st.session_state.conversation_history = []
if 'memory' in st.session_state:
st.session_state.memory.clear()
st.sidebar.success("已重置所有记忆和对话历史!")
memory_type = st.sidebar.radio(
"记忆类型",
["完整历史", "摘要记忆", "关键信息提取"]
)
st.sidebar.info(f"当前使用: {memory_type}")
五、实战演示:对话型 AI 模板与提示优化建议
全功能对话助手示例
import streamlit as st
import uuid
import time
# 设置页面
st.set_page_config(page_title="高级对话助手", layout="wide")
# 初始化会话状态
if 'conversation_id' not in st.session_state:
st.session_state.conversation_id = str(uuid.uuid4())
if 'messages' not in st.session_state:
st.session_state.messages = []
if 'memory_mode' not in st.session_state:
st.session_state.memory_mode = "完整记忆"
if 'context_items' not in st.session_state:
st.session_state.context_items = {}
# 侧边栏控制
st.sidebar.title("对话设置")
assistant_role = st.sidebar.selectbox(
"选择助手角色",
["通用助手", "技术导师", "写作教练", "金融顾问"]
)
st.sidebar.divider()
memory_mode = st.sidebar.radio(
"记忆模式",
["完整记忆", "摘要记忆", "有限回合(最近N轮)"]
)
st.session_state.memory_mode = memory_mode
if memory_mode == "有限回合(最近N轮)":
memory_turns = st.sidebar.slider("保留最近几轮对话", 1, 10, 3)
st.sidebar.divider()
st.sidebar.subheader("对话上下文")
new_context_key = st.sidebar.text_input("添加上下文项(键)")
new_context_value = st.sidebar.text_area("值")
if new_context_key and new_context_value and st.sidebar.button("添加到上下文"):
st.session_state.context_items[new_context_key] = new_context_value
st.sidebar.success(f"已添加 '{new_context_key}' 到上下文")
# 显示和管理上下文项
if st.session_state.context_items:
st.sidebar.divider()
st.sidebar.subheader("当前上下文项")
for key in list(st.session_state.context_items.keys()):
if st.sidebar.checkbox(key, True, key=f"ctx_{key}"):
pass # 保持选中
else:
del st.session_state.context_items[key] # 取消选中则移除
# 重置对话
if st.sidebar.button("开始新对话"):
st.session_state.messages = []
st.session_state.conversation_id = str(uuid.uuid4())
st.sidebar.success("已创建新对话!")
# 主界面
st.title("高级对话助手")
st.caption(f"对话ID: {st.session_state.conversation_id} | 角色: {assistant_role} | 记忆模式: {memory_mode}")
# 显示对话历史
for i, message in enumerate(st.session_state.messages):
role = " 用户" if message["role"] == "user" else " 助手"
with st.chat_message(message["role"]):
st.write(message["content"])
# 为每条消息添加引用按钮
if st.button(f"引用", key=f"ref_msg_{i}"):
quote_text = f'引用: "{message["content"][:50]}..."'
st.session_state.quote_text = quote_text
# 引用文本预填充
input_placeholder = ""
if 'quote_text' in st.session_state:
input_placeholder = st.session_state.quote_text
# 使用后清除,避免重复
del st.session_state.quote_text
# 用户输入
user_input = st.chat_input("输入您的问题...", value=input_placeholder)
if user_input:
# 添加用户消息
st.session_state.messages.append({"role": "user", "content": user_input})
# 在UI中显示用户消息
with st.chat_message("user"):
st.write(user_input)
# 构建发送给AI的上下文
prompt_context = ""
# 添加角色设定
role_descriptions = {
"通用助手": "你是一位乐于助人的AI助手,能回答各种问题。",
"技术导师": "你是一位编程专家,擅长解释技术概念并帮助解决代码问题。",
"写作教练": "你是一位写作教练,帮助用户提升写作技巧,提供有建设性的反馈。",
"金融顾问": "你是一位金融顾问,提供个人理财和投资建议。"
}
prompt_context += f"## 角色\n{role_descriptions[assistant_role]}\n\n"
# 添加记忆上下文
prompt_context += "## 对话历史\n"
if memory_mode == "完整记忆":
# 包含所有历史消息
history_messages = st.session_state.messages[:-1] # 除去最新用户消息
elif memory_mode == "摘要记忆":
# 这里应该调用AI生成摘要,为简化示例,只保留第一条和最近几条
history_messages = [st.session_state.messages[0]] if len(st.session_state.messages) > 1 else []
history_messages += st.session_state.messages[-3:-1] if len(st.session_state.messages) > 2 else []
else: # 有限回合
# 保留最近N轮
start_idx = max(0, len(st.session_state.messages) - 1 - memory_turns*2)
history_messages = st.session_state.messages[start_idx:-1]
for msg in history_messages:
role_label = "用户" if msg["role"] == "user" else "助手"
prompt_context += f"{role_label}: {msg['content']}\n\n"
# 添加用户上下文项
if st.session_state.context_items:
prompt_context += "## 用户上下文\n"
for key, value in st.session_state.context_items.items():
prompt_context += f"{key}: {value}\n"
# 添加最新的用户问题
prompt_context += f"\n## 当前问题\n{user_input}\n"
# 在实际应用中,这里应该调用AI API
# ai_response = call_ai_api(prompt_context)
# 模拟AI响应
with st.chat_message("assistant"):
message_placeholder = st.empty()
full_response = ""
# 模拟打字效果
simulated_response = "这是一个模拟的AI回复,展示了多轮对话中的上下文管理。在实际应用中,这里会连接到OpenAI、Azure OpenAI或其他LLM提供商的API。"
for chunk in simulated_response.split():
full_response += chunk + " "
time.sleep(0.05)
message_placeholder.write(full_response + "▌")
message_placeholder.write(full_response)
# 保存AI响应到历史记录
st.session_state.messages.append({"role": "assistant", "content": full_response})
# 显示调试信息
if st.sidebar.checkbox("显示调试信息"):
st.sidebar.subheader("完整提示构建")
st.sidebar.code(prompt_context)
提示优化建议
明确角色与期望:为AI助手定义清晰的角色和行为准则
使用标记分隔上下文区域:
## 角色定义
你是... ## 历史信息
... ## 当前输入
...
增加元指令:
在回答前,请先考虑:
1. 我是否有足够信息回答这个问题?
2. 用户可能有什么隐含需求?
3. 我应该以什么格式展示回答?
指定回复格式:
请使用以下格式回答用户问题:
- 简短总结(1-2句)
- 详细解释(2-3段)
- 推荐行动(若适用)
优化提示的演进:通过A/B测试和用户反馈持续优化提示模板
通过结合这些技术,你可以显著提升多轮对话的质量和用户体验,有效应对上下文管理的挑战。
这篇博客介绍了多轮对话中上下文管理的关键技术与实践策略,并通过Streamlit示例展示了具体实现方法。掌握这些技巧,你将能够构建更智能、更自然的对话式AI应用。
L3-1、掌控多轮对话的节奏 -Prompt 结构与上下文管理全攻略的更多相关文章
- android屏幕适配的全攻略3-动态获取手机屏幕宽高及动态设置控件宽高
1.获取手机屏幕宽高: DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetr ...
- [转]使用C#开发ActiveX控件全攻略
前言: 这段时间因为工作的需要,研究了一下ActiveX控件.总结如下: 先说说ActiveX的基本概念. 根据微软权威的软件开发指南MSDN(Microsoft Developer Network) ...
- WPF知识点全攻略05- XAML内容控件
此处简单列举出布局控件外,其他常用的控件: Window:WPF窗口 UserControl:用户控件 Page:页 Frame:用来浏览Page页 Border:嵌套控件,提供边框和背景. Butt ...
- PNG透明窗体全攻略(控件不透明)
http://blog.csdn.net/riklin/article/details/4417247 看好了,这是XP系统,未装.net.我的Photoshop学的不太好,把玻璃片弄的太透了些,如果 ...
- TED:如何掌控你的自由时间以及让自己变得更好,这样就能看到爱情应有的样子
TED:如何掌控你的自由时间以及让自己变得更好,这样就能看到爱情应有的样子 一.<如何掌控你的自由时间> (1)时间管理的传统思维:守时和节省零散的时间.演讲者认为这个观点已经彻底落后. ...
- 掌控(control) 方法记录
掌控(control) 题面描述 公元\(2044\)年,人类进入了宇宙纪元.L国有\(n\)个星球,分别编号为\(1\)到\(n\),每一星球上有一个球长.有些球长十分强大,可以管理或掌控其他星球的 ...
- ACM对时间掌控力和日积月累的习惯的意义
马云说,要想创业成功,不是要知道现在什么东西最火,而是要清楚的知道十年以后什么东西最火.这就意味着,你对时间掌控力,至少要有十年. 但是仔细回想一下自己的学生时代,自己对时间的把握是怎样的?有些人只能 ...
- IQ一个人的智力和对科学知识的理解掌握程度。 EQ对环境和个人情绪的掌控和对团队关系的运作能力。 AQ挫折商 一个人面对困境时减除自己的压力、渡过难关的能力。
IQ: Intelligence Quotient 智商 一个人的智力和对科学知识的理解掌握程度. EQ: Emotional Quotient 情商 一个人对环境和个人情绪的掌控和对团队关系的运作能 ...
- 4星|《行为设计学:掌控关键决策》:影响决策质量的四大思维陷阱及WRAP应对法
行为设计学:掌控关键决策 两位作者认为,有四大思维陷阱让人做出错误的决策:思维狭隘.证实倾向.短期情绪.过度自信.两位作者提出WRAP决策流程来应对:Widen your options(拓宽选择空间 ...
- CIO需加强对战略管理层面的掌控-精华篇
当代CIO面临提升信息化作用的新机遇.CIO在企业中,不能满足于职能性的技术支撑角色,要找到新的着力点,以发挥信息化在全局战略中的作用,把信息化力量聚焦于做强做优,提高国际竞争力上来,成为企业不可或缺 ...
随机推荐
- 【FAQ】HarmonyOS SDK 闭源开放能力 —Push Kit(9)
1.问题描述: 通过push token向鸿蒙手机推送一条通知,收到通知后,通知右侧不展示图片. 解决方案: 检查一下是否存在图片风控:https://developer.huawei.com/con ...
- Python装饰器:套层壳我变得更强了!
Python装饰器:套层壳我变得更强了 Python装饰器:套层壳我变得更强了 关于作用域和闭包可以聊点什么? 什么是作用域 什么是闭包 装饰器:套层壳我变得更强了 参考资料 昨天阅读了<Pyt ...
- js回忆录(1) -- 变量,null 和 undefined
变量:这个东西不同的高度的人看法不一样,甚至不同领域的人的看法也不一样,当初上机组的时候依稀记得老师说这个寄存器那个锁存器什么的,然后根据高低电位就变成了二进制认识的0和1了,当然了具体细节本博主大人 ...
- 最新版 Proteus 8.15 Professional 图文安装教程(附安装包)
前言 大家好,我是梁国庆. Proteus 是世界上唯一将电路仿真软件.PCB设计软件和虚拟模型仿真软件三合一的设计平台. 本篇博主将手把手带领大家安装最新版 Proteus 8.15. 若图片加载超 ...
- windows goland go exec "gcc": executable file not found in %PATH%
问题 windows 本地缺少 gcc 编译器 解决方案 下载安装使用 MinGW-w64 第一种 https://winlibs.com/#download-release 下载后解压到磁盘中,然后 ...
- rot-偏移,ascii,md5爆破
题目: 破解下面的密文: 83 89 78 84 45 86 96 45 115 121 110 116 136 132 132 132 108 128 117 118 134 110 123 111 ...
- Docker镜像(image)详解
如果曾经做过 VM 管理员,则可以把 Docker 镜像理解为 VM 模板,VM 模板就像停止运行的 VM,而 Docker 镜像就像停止运行的容器:而作为一名研发人员,则可以将镜像理解为类(Clas ...
- 【Git】在 Eclipse 中使用 Git
在 Eclipse 中使用 Git Eclipse 中默认自带了 Git 插件,通过点击 Help→About Eclipse IDE 可以查看 1 全局配置 1.1 配置用户名和邮箱 点击 Wind ...
- 必须添加对程序集"System.Core"的引用
异常波浪线 解决办法 <system.web> <compilation> <assemblies> <add assembly="System.C ...
- 🎀B站-网页优化插件BewlyBewly
简介 一个开源的B站网页优化浏览器插件,对B站网页进行了调整和优化,页面更具视觉吸引力和用户友好性. 源码 https://github.com/BewlyBewly/BewlyBewly 支持 插件 ...