MCP构建AI应用学习笔记(8)
·
MCP Chatbot 增强:提示功能引导交互,资源功能补充价值
一、为什么需要提示与资源功能?—— 解决 “用户不会用、答案不够全” 的痛点
前序开发的 MCP Chatbot 虽能基于引用服务器生成答案,但在实际使用中仍面临两大核心问题:
- 用户交互门槛高:新手用户不知道 “该问什么”(如 HR Chatbot 用户可能不清楚 “年假政策”“社保补缴” 等可提问方向),或提问表述模糊(如 “请假流程” 未说明是 “年假” 还是 “病假”),导致检索结果偏差、答案不准确;
- 答案延伸价值不足:Chatbot 仅返回问题答案,用户若需要 “进一步操作”(如根据年假政策下载申请表格)或 “相关知识”(如请假流程对应的系统入口),需额外咨询或搜索,体验不连贯。
提示功能与资源功能的核心价值,正是通过 “主动引导交互” 和 “补充关联资源”,让 Chatbot 从 “被动回答” 升级为 “主动辅助”:
- 提示功能:在用户交互的关键节点(如首次使用、提问模糊、检索无结果时),提供 “该问什么”“怎么问” 的引导,降低使用门槛;
- 资源功能:在答案中关联 “操作工具”“参考文档”“系统入口” 等资源,让用户获取答案后能直接完成后续动作,提升 Chatbot 的实用价值。
二、提示功能设计:分场景、无打扰、可配置
提示功能需遵循 “场景化触发、不打断主流程、用户可关闭” 三大原则,按用户交互阶段分为三类核心提示,均以 “组件化” 方式融入 MCP 架构(新增PromptGuideComponent,属于处理层,与输入层、检索组件协同)。
1. 提示功能的核心类型与应用场景
| 提示类型 | 触发场景 | 核心目标 | 示例效果 |
|---|---|---|---|
| 引导式提示 | 用户首次使用 Chatbot、或 30 秒未输入提问 | 告诉用户 “可提问的方向”,激发交互 | “您可咨询:年假申请天数、社保补缴流程、入职材料准备等问题” |
| 纠错式提示 | 用户提问表述模糊(如 “请假怎么弄”)、关键词缺失 | 引导用户补充信息,提升检索准确性 | “为了更精准回答,请说明您咨询的是‘年假’‘病假’还是‘事假’?” |
| 示例式提示 | 用户检索无结果(如 “未找到‘探亲假’相关知识”) | 提供 “正确提问示例”,降低试错成本 | “未找到相关内容,您可尝试提问:‘探亲假有多少天?’‘探亲假申请需要哪些材料?’” |
2. 提示组件的设计与实现(MCP 处理层新增组件)
PromptGuideComponent组件需支持 “场景判断、提示生成、触发控制” 三大能力,且接口需与 MCP 现有组件兼容(输入含session_id“用户行为”“当前上下文”,输出为 “提示文本 + 是否显示”)。
核心代码实现
python
运行
# MCP处理层:提示引导组件(mcp_core/process/prompt_guide.py)
from datetime import datetime
from typing import Dict, Optional
class PromptGuideComponent:
def __init__(self, config: Dict = None):
# 配置提示触发规则(可外部传入,支持自定义)
self.config = config or {
"guide_delay": 30, # 引导式提示触发延迟(秒):用户未输入时
"vague_threshold": 0.5, # 纠错式提示触发阈值:问题语义清晰度低于0.5
"no_result_prompts": [ # 检索无结果时的示例提示列表
"您可尝试提问:‘{topic}有多少天?’",
"您可补充细节,如‘{topic}申请需要哪些材料?’"
]
}
# 记录用户行为(会话ID→最后交互时间、提问历史)
self.user_behavior = {}
def update_behavior(self, session_id: str, action: str):
"""更新用户行为记录(用于判断提示触发时机)"""
if session_id not in self.user_behavior:
self.user_behavior[session_id] = {
"last_interact_time": datetime.now(),
"question_history": []
}
if action == "input_question":
self.user_behavior[session_id]["last_interact_time"] = datetime.now()
self.user_behavior[session_id]["question_history"].append(action)
elif action == "open_chat":
self.user_behavior[session_id]["last_interact_time"] = datetime.now()
def judge_scene(self, session_id: str, current_question: Optional[str] = None, retrieval_result: Dict = None) -> str:
"""判断当前场景,返回对应的提示类型(guide/error/example/none)"""
user_behavior = self.user_behavior.get(session_id, {})
current_time = datetime.now()
# 1. 判断是否触发“引导式提示”(首次打开/长时间未输入)
if not user_behavior or len(user_behavior.get("question_history", [])) == 0:
return "guide" # 首次使用
time_diff = (current_time - user_behavior["last_interact_time"]).total_seconds()
if time_diff >= self.config["guide_delay"] and not current_question:
return "guide" # 长时间未输入
# 2. 判断是否触发“纠错式提示”(提问模糊)
if current_question and self._is_vague_question(current_question):
return "error"
# 3. 判断是否触发“示例式提示”(检索无结果)
if retrieval_result and retrieval_result["status"] == "success" and len(retrieval_result["data"].get("references", [])) == 0:
return "example"
# 无提示触发
return "none"
def generate_prompt(self, prompt_type: str, current_question: Optional[str] = None) -> Dict:
"""根据提示类型生成提示文本,返回标准化格式(符合MCP组件输出接口)"""
if prompt_type == "none":
return {"show_prompt": False, "prompt_text": "", "prompt_type": "none"}
# 1. 引导式提示(按场景动态生成,示例以HR Chatbot为例)
if prompt_type == "guide":
guide_text = "欢迎使用HR助手!您可咨询以下方向的问题:\n" \
"- 假期政策:年假天数、请假流程、审批权限\n" \
"- 社保福利:社保缴纳标准、补缴流程、公积金提取\n" \
"- 入职离职:入职材料准备、离职手续办理、薪资结算"
return {
"show_prompt": True,
"prompt_text": guide_text,
"prompt_type": "guide",
"operable": False # 不可交互,仅展示
}
# 2. 纠错式提示(根据模糊问题补充引导)
if prompt_type == "error":
vague_topics = self._extract_vague_topics(current_question) # 提取模糊主题(如“请假”)
error_text = f"您提到的‘{vague_topics}’表述较模糊,为了精准回答,请补充说明:\n" \
"- 若咨询假期:请说明是‘年假’‘病假’‘事假’还是‘探亲假’\n" \
"- 若咨询流程:请说明是‘申请’‘审批’还是‘撤销’"
return {
"show_prompt": True,
"prompt_text": error_text,
"prompt_type": "error",
"operable": True, # 可交互,用户可直接补充内容
"suggested_inputs": ["年假申请流程", "病假审批权限"] # 可点击的建议输入
}
# 3. 示例式提示(根据无结果问题生成示例)
if prompt_type == "example":
topic = self._extract_topic_from_question(current_question) # 提取问题主题(如“探亲假”)
examples = [fmt.format(topic=topic) for fmt in self.config["no_result_prompts"]]
example_text = f"未找到‘{topic}’相关内容,您可尝试以下提问方式:\n" + "\n".join([f"- {ex}" for ex in examples])
return {
"show_prompt": True,
"prompt_text": example_text,
"prompt_type": "example",
"operable": True,
"suggested_inputs": examples # 示例可直接点击提交
}
# 辅助方法:判断问题是否模糊(简化实现,实际可结合NLP工具)
def _is_vague_question(self, question: str) -> bool:
vague_keywords = ["怎么弄", "流程", "怎么申请", "怎么办理"]
# 若问题含模糊关键词且无具体主题(如“请假流程”有主题,“流程怎么弄”无主题)
has_vague_keyword = any(kw in question for kw in vague_keywords)
has_specific_topic = any(topic in question for topic in ["年假", "病假", "社保", "公积金"])
return has_vague_keyword and not has_specific_topic
# 辅助方法:提取模糊问题的主题
def _extract_vague_topics(self, question: str) -> str:
if "请假" in question:
return "请假相关"
if "社保" in question or "公积金" in question:
return "社保/公积金相关"
return "相关业务"
# 辅助方法:从无结果问题中提取主题
def _extract_topic_from_question(self, question: str) -> str:
for topic in ["年假", "病假", "事假", "探亲假", "社保", "公积金"]:
if topic in question:
return topic
return "您咨询的业务"
三、资源功能设计:关联场景、精准推送、可复用
资源功能的核心是为 Chatbot 提供 “可管理、可关联、可推送” 的辅助资源库(如操作指南、下载链接、系统入口),让答案不仅 “解答问题”,还能 “提供后续行动支持”。该功能通过新增ResourceManagerComponent(存储层管理资源,输出层推送资源)实现,与现有引用服务器、会话管理组件协同。
1. 资源功能的核心价值与模块划分
| 核心价值 | 解决的实际问题 | 典型应用场景 |
|---|---|---|
| 答案延伸 | 用户获取答案后需额外搜索 “操作工具”(如请假申请表) | HR Chatbot 回答 “年假申请流程” 时,推送 “年假申请表下载链接” |
| 操作引导 | 用户知道政策但不知道 “在哪操作”(如社保查询) | 回答 “社保缴费查询” 时,推送 “企业社保查询系统入口” |
| 知识补充 | 用户需要 “更详细的参考文档”(如完整员工手册) | 回答 “加班工资计算” 时,推送 “《薪酬管理办法》完整文档” |
资源功能分为两大模块:
- 资源管理模块:负责资源的 “新增、分类、更新、权限控制”,支持按 “业务场景”(如年假、社保)、“资源类型”(如文档、链接、表格)分类存储,资源信息包含
resource_id(唯一标识)、scene_keywords(关联场景关键词)、content(资源内容 / 链接)、permission(访问权限); - 资源推送模块:负责 “根据用户提问场景匹配资源”,并将资源融入答案输出,支持 “自动推送”(如匹配到场景则默认推送)和 “手动触发”(如用户点击 “查看更多资源”)。
2. 资源组件的设计与实现(MCP 存储层 + 输出层新增组件)
(1)资源管理组件(存储层:ResourceManagerComponent)
python
运行
# MCP存储层:资源管理组件(mcp_core/storage/resource_manager.py)
from typing import List, Dict, Optional
class ResourceManagerComponent:
def __init__(self, storage_type: str = "local", db_path: str = "mcp_resources.db"):
self.storage_type = storage_type # 支持local(本地JSON)或db(数据库)
self.db_path = db_path
# 初始化资源库(实际场景从存储加载,此处模拟)
self.resources = self._load_resources()
# 加载资源(模拟从本地文件加载)
def _load_resources(self) -> List[Dict]:
if self.storage_type == "local":
return [
{
"resource_id": "res_001",
"scene_keywords": ["年假申请", "年假流程", "年假审批"], # 关联的提问场景关键词
"resource_type": "file_download", # 资源类型:文件下载
"content": "http://server/files/年假申请表.xlsx", # 下载链接
"name": "年假申请表(2024版)",
"permission": "all", # 所有用户可访问
"update_time": "2024-01-15"
},
{
"resource_id": "res_002",
"scene_keywords": ["社保查询", "社保缴费", "社保记录"],
"resource_type": "system_link", # 系统入口链接
"content": "http://server/systems/insurance-query",
"name": "企业社保查询系统",
"permission": "all",
"update_time": "2024-03-20"
},
{
"resource_id": "res_003",
"scene_keywords": ["薪酬计算", "加班工资", "绩效工资"],
"resource_type": "document", # 参考文档
"content": "《薪酬管理办法》完整文档:http://server/docs/salary-policy.pdf",
"name": "薪酬管理办法(含加班工资计算标准)",
"permission": "all",
"update_time": "2024-02-10"
}
]
# 数据库存储逻辑(省略,与之前对话存储组件逻辑一致)
return []
# 新增/更新资源(管理员接口)
def add_or_update_resource(self, resource: Dict) -> Dict:
# 校验资源必填字段
required_fields = ["resource_id", "scene_keywords", "resource_type", "content", "name", "permission"]
if not all(field in resource for field in required_fields):
return {"status": "failed", "error": "资源缺少必填字段"}
# 检查是否已存在该资源(存在则更新,不存在则新增)
existing_idx = next((i for i, res in enumerate(self.resources) if res["resource_id"] == resource["resource_id"]), None)
if existing_idx is not None:
self.resources[existing_idx] = resource
else:
self.resources.append(resource)
# 保存到存储(本地/数据库,省略)
self._save_resources()
return {"status": "success", "data": {"resource_id": resource["resource_id"]}}
# 根据用户提问场景匹配资源(核心方法,供Chatbot调用)
def match_resources(self, user_question: str, session_id: str) -> List[Dict]:
# 1. 校验用户权限(根据session_id获取用户角色,省略)
user_permission = "all" # 简化:默认所有用户有all权限
# 2. 提取问题中的场景关键词(如“年假申请”)
question_keywords = self._extract_question_keywords(user_question)
# 3. 匹配资源(场景关键词重叠度≥1,且权限符合)
matched_resources = []
for res in self.resources:
# 计算场景关键词重叠度
overlap = len(set(question_keywords) & set(res["scene_keywords"]))
if overlap >= 1 and res["permission"] == user_permission:
# 补充资源展示格式
res["display_text"] = self._format_resource_display(res)
matched_resources.append(res)
# 4. 按“更新时间降序”排序(优先推送最新资源)
matched_resources.sort(key=lambda x: x["update_time"], reverse=True)
return matched_resources[:2] # 最多推送2条,避免资源冗余
# 辅助方法:提取问题关键词(简化实现)
def _extract_question_keywords(self, question: str) -> List[str]:
# 预设场景关键词库(实际可结合NLP工具提取)
all_scene_keywords = ["年假申请", "年假流程", "社保查询", "社保缴费", "薪酬计算", "加班工资"]
return [kw for kw in all_scene_keywords if kw in question]
# 辅助方法:格式化资源展示文本(用于融入答案)
def _format_resource_display(self, resource: Dict) -> str:
if resource["resource_type"] == "file_download":
return f"【可下载文件】{resource['name']}:{resource['content']}(更新时间:{resource['update_time']})"
elif resource["resource_type"] == "system_link":
return f"【系统入口】{resource['name']}:{resource['content']}(点击直接访问)"
elif resource["resource_type"] == "document":
return f"【参考文档】{resource['name']}:{resource['content']}(含详细说明)"
return f"【相关资源】{resource['name']}:{resource['content']}"
# 辅助方法:保存资源到存储(省略)
def _save_resources(self):
pass
(2)资源推送组件(输出层:ResourcePusherComponent)
python
运行
# MCP输出层:资源推送组件(mcp_core/output/resource_pusher.py)
from typing import List, Dict
class ResourcePusherComponent:
def __init__(self, resource_manager: "ResourceManagerComponent"):
self.resource_manager = resource_manager # 依赖资源管理组件
self.push_strategy = "auto" # 推送策略:auto(自动)/manual(手动)
# 生成资源推送文本(融入答案末尾)
def generate_resource_text(self, user_question: str, session_id: str) -> str:
if self.push_strategy != "auto":
return "" # 手动策略需用户点击触发,不自动推送
# 1. 匹配资源
matched_resources = self.resource_manager.match_resources(user_question, session_id)
if not matched_resources:
return ""
# 2. 格式化资源文本(避免冗余,最多2条)
resource_text = "\n\n【相关辅助资源】\n"
for idx, res in enumerate(matched_resources, 1):
resource_text += f"{idx}. {res['display_text']}\n"
# 3. 补充手动触发提示(如需更多资源可点击)
resource_text += "\n若需查看更多相关资源,可点击【获取更多资源】按钮。"
return resource_text
# 手动触发资源推送(用户点击“获取更多资源”时调用)
def manual_push(self, user_question: str, session_id: str) -> List[Dict]:
matched_resources = self.resource_manager.match_resources(user_question, session_id)
# 返回结构化资源列表(供前端展示为卡片/列表)
return [
{
"resource_id": res["resource_id"],
"name": res["name"],
"type": res["resource_type"],
"content": res["content"],
"update_time": res["update_time"],
"display_text": res["display_text"]
}
for res in matched_resources
]
四、整合提示与资源功能到 MCP Chatbot:遵循 “模块化衔接” 原则
提示与资源功能需作为独立组件融入现有 MCP 架构,不破坏原有分层逻辑,核心整合点在 “处理层”(提示场景判断)和 “输出层”(资源推送),整体流程如下:
plaintext
[用户提问] → [输入层:文本清洗] → [处理层:
1. PromptGuideComponent判断提示场景→生成提示
2. ReferenceRetriever检索外部知识
3. LLMCaller生成基础答案
] → [输出层:
1. ResourcePusherComponent匹配并推送资源
2. 整合“提示+基础答案+资源”为最终输出
] → [用户界面:展示结果+提示(如需)]
1. 核心整合代码(修改 Chatbot 提问处理逻辑)
python
运行
# 整合提示与资源功能的Chatbot核心逻辑
from mcp_core.process import LLMCaller, ReferenceRetriever, PromptGuideComponent
from mcp_core.storage import ResourceManagerComponent
from mcp_core.output import ResourcePusherComponent
from mcp_core.process.context_manager import ContextManager
# 初始化新增组件
prompt_guide = PromptGuideComponent() # 提示组件
resource_manager = ResourceManagerComponent() # 资源管理组件
resource_pusher = ResourcePusherComponent(resource_manager=resource_manager) # 资源推送组件
# 初始化原有组件(保持不变)
llm_caller = LLMCaller(model="gpt-4o", api_key="your-api-key", params={"temperature": 0.2})
ref_retriever = ReferenceRetriever(reference_server_url="http://127.0.0.1:8001")
context_manager = ContextManager(max_history=5)
def handle_user_question_enhanced(session_id: str, user_question: str = None) -> Dict:
# 步骤1:更新用户行为(用于提示场景判断)
if user_question:
prompt_guide.update_behavior(session_id=session_id, action="input_question")
else:
prompt_guide.update_behavior(session_id=session_id, action="open_chat") # 仅打开未输入
# 步骤2:生成提示(判断是否需要提示)
# 若有用户提问,先检索引用服务器(用于示例提示判断);若无提问,仅判断引导提示
retrieval_result = None
if user_question:
retrieval_result = ref_retriever.retrieve(
session_id=session_id,
user_question=user_question,
retrieval_params={"top_k": 2, "knowledge_base_ids": ["hr_base"]}
)
# 判断提示场景并生成提示
prompt_scene = prompt_guide.judge_scene(
session_id=session_id,
current_question=user_question,
retrieval_result=retrieval_result
)
prompt_data = prompt_guide.generate_prompt(prompt_type=prompt_scene, current_question=user_question)
# 步骤3:若无需提示且有提问,生成基础答案+推送资源
final_answer = ""
resource_text = ""
if prompt_scene == "none" and user_question:
# 3.1 格式化引用片段(原有逻辑)
if retrieval_result["status"] == "success":
formatted_refs = ref_retriever.format_references(retrieval_result["data"]["references"])
else:
formatted_refs = "无相关外部知识引用。"
# 3.2 生成基础答案(原有逻辑)
history = context_manager.get_history(session_id=session_id)
prompt = f"基于外部知识和历史对话回答:\n{formatted_refs}\n历史对话:{history}\n问题:{user_question}"
llm_result = llm_caller.generate(prompt=prompt)
if llm_result["status"] == "success":
final_answer = llm_result["data"]["output_text"]
else:
final_answer = f"答案生成失败:{llm_result['error']}"
# 3.3 推送资源(新增逻辑)
resource_text = resource_pusher.generate_resource_text(
user_question=user_question,
session_id=session_id
)
# 步骤4:整合最终输出(提示+答案+资源)
output = {
"status": "success",
"data": {
"prompt": prompt_data, # 提示信息(含是否显示、文本、可交互建议)
"answer": final_answer + resource_text, # 答案+资源
"session_id": session_id
},
"error": None
}
# 步骤5:更新上下文(原有逻辑)
if user_question and final_answer:
context_manager.update_history(
session_id=session_id,
user_msg=user_question,
ai_msg=final_answer
)
return output
# 测试:用户首次打开(无提问)→ 触发引导提示
print(handle_user_question_enhanced(session_id="user_001"))
# 测试:用户提问“请假流程”(模糊)→ 触发纠错提示
print(handle_user_question_enhanced(session_id="user_001", user_question="请假流程"))
# 测试:用户提问“年假申请流程”(清晰)→ 生成答案+推送资源
print(handle_user_question_enhanced(session_id="user_001", user_question="年假申请流程"))
2. 用户界面展示逻辑(以 Web 客户端为例)
在 Vue3 Web 客户端中,根据prompt_data动态展示提示,资源文本随答案一同显示,核心代码片段:
vue
<template>
<!-- 提示展示区域(动态显示) -->
<div v-if="promptData.show_prompt" class="mb-3 p-3 rounded" :class="getPromptClass(promptData.prompt_type)">
<p class="text-sm">{{ promptData.prompt_text }}</p>
<!-- 可交互提示:显示建议输入按钮 -->
<div v-if="promptData.operable" class="mt-2 flex gap-2 flex-wrap">
<button
v-for="(input, idx) in promptData.suggested_inputs"
:key="idx"
class="bg-blue-100 text-blue-700 px-2 py-1 rounded text-xs hover:bg-blue-200"
@click="fillQuestion(input)"
>
{{ input }}
</button>
</div>
</div>
<!-- 答案+资源展示区域 -->
<div class="bg-white p-3 rounded shadow-sm">
<p class="text-sm whitespace-pre-wrap">{{ answer }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
const promptData = ref({ show_prompt: false, prompt_text: "", prompt_type: "none", operable: false, suggested_inputs: [] });
const answer = ref("");
// 根据提示类型设置样式(引导:浅蓝,纠错:浅橙,示例:浅绿)
const getPromptClass = (type) => {
const classes = {
"guide": "bg-blue-50 text-blue-700",
"error": "bg-orange-50 text-orange-700",
"example": "bg-green-50 text-green-700"
};
return classes[type] || "bg-gray-50 text-gray-700";
};
// 填充建议输入到提问框
const fillQuestion = (input) => {
// 调用父组件方法填充提问框
emit("fill-question", input);
};
</script>
五、联调与优化:确保提示精准、资源有用
1. 高频问题与解决方案
| 问题类型 | 具体表现 | 解决方案 |
|---|---|---|
| 提示误触发 | 用户清晰提问(如 “年假申请需要几天审批”)却触发纠错提示 | 优化_is_vague_question方法:增加 “具体主题关键词” 判断(如含 “年假” 则不判定为模糊) |
| 资源推送冗余 | 所有提问都推送相同资源(如 “社保查询” 和 “年假申请” 都推 “员工手册”) | 细化scene_keywords:为 “员工手册” 添加更精准的关键词(如 “薪酬政策”“考勤制度”),避免泛化匹配 |
| 提示干扰用户 | 用户正在输入时弹出引导提示,打断操作 | 调整提示触发时机:用户输入过程中(输入框有内容时)不触发引导提示,仅在输入框为空且超时后触发 |
| 资源链接失效 | 推送的下载链接 / 系统入口无法访问 | 在ResourceManagerComponent中添加 “资源有效性校验”:定期检查链接状态,失效资源标记为 “不可用” 并不推送 |
2. 优化方向(提升用户体验)
- 提示个性化:根据用户历史提问记录调整提示(如频繁咨询社保的用户,引导提示优先展示社保相关方向);
- 资源权限精细化:区分 “普通员工”“管理者” 权限(如管理者可获取 “部门请假统计” 资源,普通员工不可);
- 提示可关闭:用户点击 “不再显示” 后,同一场景的提示不再触发(通过
session_id记录用户关闭偏好); - 资源互动反馈:用户点击资源后,记录 “资源点击量”,后续优先推送高点击量资源。
六、总结与后续扩展
1. 本集核心收获
- 明确提示与资源功能的价值定位:提示解决 “用户不会用”,资源解决 “答案不够全”,二者共同提升 Chatbot 的易用性与实用价值;
- 掌握组件化实现方法:提示功能通过
PromptGuideComponent实现场景化判断与生成,资源功能通过 “管理 + 推送” 双组件实现存储与推送,均遵循 MCP “低耦合” 原则; - 学会整合逻辑:将新增组件融入现有 MCP 分层,不破坏原有流程,同时通过用户行为记录、场景匹配提升功能精准度。
2. 后续扩展方向
- 多模态提示:支持语音提示(如移动端 Chatbot 用语音引导 “您可咨询年假政策”)、图文提示(如用流程图展示 “请假流程” 示例);
- 资源动态更新:对接企业内部文档系统(如 Confluence),当文档更新时自动同步到
ResourceManagerComponent,无需手动维护; - 智能资源推荐:结合用户角色、部门、历史行为,实现 “千人千面” 的资源推送(如研发部门用户优先推送 “研发项目报销流程” 资源);
- 提示效果分析:添加 “提示转化率” 统计(如用户点击示例提示后提交提问的比例),持续优化提示内容与触发时机。
更多推荐
所有评论(0)