chore: rebuild CentOS7 release package
This commit is contained in:
660
public/app.js
660
public/app.js
@@ -2,11 +2,12 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const ASSET_VERSION = '20260625-branch-bubble';
|
||||
const ASSET_VERSION = '20260626-ccweb-prompt-compact-ui';
|
||||
const WS_URL = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/ws`;
|
||||
const RENDER_DEBOUNCE = 100;
|
||||
const COMPOSER_SUGGESTION_DEBOUNCE = 120;
|
||||
const DIVIDER_TIME_STORAGE_KEY = 'cc-web-show-divider-time';
|
||||
const CCWEB_PROMPT_VIEW_MODE_STORAGE_KEY = 'cc-web-ccweb-prompt-view-mode';
|
||||
const PROJECT_COLLAPSE_STORAGE_KEY = 'cc-web-collapsed-projects';
|
||||
const CROSS_CONVERSATION_REPLY_COLLAPSE_STORAGE_KEY = 'cc-web-collapsed-cross-replies';
|
||||
const CROSS_CONVERSATION_REPLY_COLLAPSE_LIMIT = 500;
|
||||
@@ -210,6 +211,7 @@
|
||||
let queuedMessageSeq = 0;
|
||||
let queuedMessageDrainTimer = null;
|
||||
let isReloadingMcp = false;
|
||||
const mcpStartupToastKeys = new Map();
|
||||
let sessionSearchQuery = '';
|
||||
const collapsedProjectKeys = (() => {
|
||||
try {
|
||||
@@ -263,6 +265,8 @@
|
||||
const chatCwd = $('#chat-cwd');
|
||||
const userOutlineBtn = $('#user-outline-btn');
|
||||
const userOutlinePanel = $('#user-outline-panel');
|
||||
const ccwebPromptOutlineBtn = $('#ccweb-prompt-outline-btn');
|
||||
const ccwebPromptOutlinePanel = $('#ccweb-prompt-outline-panel');
|
||||
const reloadMcpBtn = $('#reload-mcp-btn');
|
||||
const costDisplay = $('#cost-display');
|
||||
const attachmentTray = $('#attachment-tray');
|
||||
@@ -525,6 +529,7 @@
|
||||
pendingNotesTray.innerHTML = '';
|
||||
const notes = getCurrentNotes(false);
|
||||
const queuedMessages = getCurrentQueue(false);
|
||||
renderPendingCcwebPrompts({ scroll: false, updateScrollbar: false });
|
||||
if ((!notes || notes.length === 0) && (!queuedMessages || queuedMessages.length === 0)) {
|
||||
pendingNotesTray.hidden = true;
|
||||
if (options.updateScrollbar !== false) updateScrollbar();
|
||||
@@ -544,6 +549,140 @@
|
||||
if (options.updateScrollbar !== false) updateScrollbar();
|
||||
}
|
||||
|
||||
function collectCurrentPendingCcwebPrompts() {
|
||||
if (!currentSessionId) return [];
|
||||
const prompts = [];
|
||||
const seen = new Set();
|
||||
const entry = sessionCache.get(currentSessionId);
|
||||
const messages = Array.isArray(entry?.snapshot?.messages) ? entry.snapshot.messages : [];
|
||||
messages.forEach((message) => {
|
||||
const prompt = message?.ccwebPrompt;
|
||||
if (!prompt?.id || seen.has(prompt.id) || (prompt.status || 'pending') !== 'pending') return;
|
||||
seen.add(prompt.id);
|
||||
prompts.push(prompt);
|
||||
});
|
||||
messagesDiv?.querySelectorAll?.('.ccweb-prompt-card[data-status="pending"]').forEach((card) => {
|
||||
const promptId = card.dataset.promptId || '';
|
||||
if (!promptId || seen.has(promptId)) return;
|
||||
seen.add(promptId);
|
||||
prompts.push({
|
||||
id: promptId,
|
||||
title: card.querySelector('.ccweb-prompt-title')?.textContent || '需要用户确认',
|
||||
questions: Array.from(card.querySelectorAll('.ccweb-prompt-question')).map((questionEl) => ({
|
||||
id: questionEl.dataset.questionId || '',
|
||||
})),
|
||||
});
|
||||
});
|
||||
return prompts;
|
||||
}
|
||||
|
||||
function scrollToCcwebPrompt(promptId) {
|
||||
if (!promptId || !messagesDiv) return false;
|
||||
const card = messagesDiv.querySelector(`.ccweb-prompt-card[data-prompt-id="${cssEscape(promptId)}"]`);
|
||||
if (!card) {
|
||||
showToast('未找到待提交表单', '可能在未加载的历史消息中');
|
||||
return false;
|
||||
}
|
||||
const target = card.closest('.msg') || card;
|
||||
const containerRect = messagesDiv.getBoundingClientRect();
|
||||
const targetRect = target.getBoundingClientRect();
|
||||
const targetTop = messagesDiv.scrollTop + targetRect.top - containerRect.top - 72;
|
||||
messagesDiv.scrollTo({ top: Math.max(0, targetTop), behavior: 'smooth' });
|
||||
card.classList.remove('ccweb-prompt-focus');
|
||||
requestAnimationFrame(() => {
|
||||
card.classList.add('ccweb-prompt-focus');
|
||||
window.setTimeout(() => card.classList.remove('ccweb-prompt-focus'), 1400);
|
||||
});
|
||||
updateScrollbar();
|
||||
return true;
|
||||
}
|
||||
|
||||
function dismissCcwebPrompt(promptId) {
|
||||
if (!promptId || !currentSessionId) return;
|
||||
send({
|
||||
type: 'ccweb_prompt_user_dismiss',
|
||||
sessionId: currentSessionId,
|
||||
promptId,
|
||||
});
|
||||
}
|
||||
|
||||
function createPendingCcwebPromptElement(prompt) {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'pending-ccweb-prompt';
|
||||
item.dataset.promptId = prompt.id || '';
|
||||
|
||||
const badge = document.createElement('span');
|
||||
badge.className = 'pending-ccweb-prompt-badge';
|
||||
badge.setAttribute('aria-label', '未提交');
|
||||
|
||||
const title = document.createElement('div');
|
||||
title.className = 'pending-ccweb-prompt-title';
|
||||
const questionCount = Array.isArray(prompt.questions) ? prompt.questions.length : 0;
|
||||
title.textContent = `${prompt.title || '需要用户确认'} · ${questionCount || 1} 题`;
|
||||
|
||||
const action = document.createElement('button');
|
||||
action.type = 'button';
|
||||
action.className = 'pending-ccweb-prompt-action';
|
||||
action.textContent = '定位';
|
||||
action.addEventListener('click', () => {
|
||||
closeCcwebPromptOutlinePanel();
|
||||
scrollToCcwebPrompt(prompt.id);
|
||||
});
|
||||
|
||||
const dismiss = document.createElement('button');
|
||||
dismiss.type = 'button';
|
||||
dismiss.className = 'pending-ccweb-prompt-dismiss';
|
||||
dismiss.textContent = '忽略';
|
||||
dismiss.title = '忽略并删除这个未提交表单';
|
||||
dismiss.addEventListener('click', () => {
|
||||
dismiss.disabled = true;
|
||||
dismiss.textContent = '删除中';
|
||||
dismissCcwebPrompt(prompt.id);
|
||||
});
|
||||
|
||||
item.append(badge, title, action, dismiss);
|
||||
return item;
|
||||
}
|
||||
|
||||
function renderPendingCcwebPrompts(options = {}) {
|
||||
if (!ccwebPromptOutlineBtn || !ccwebPromptOutlinePanel) return;
|
||||
const prompts = collectCurrentPendingCcwebPrompts();
|
||||
const anchor = ccwebPromptOutlineBtn.closest('.ccweb-prompt-outline-anchor');
|
||||
if (prompts.length === 0) {
|
||||
if (anchor) anchor.hidden = true;
|
||||
closeCcwebPromptOutlinePanel();
|
||||
delete ccwebPromptOutlineBtn.dataset.count;
|
||||
ccwebPromptOutlinePanel.innerHTML = '';
|
||||
if (options.updateScrollbar !== false) updateScrollbar();
|
||||
return;
|
||||
}
|
||||
if (anchor) anchor.hidden = false;
|
||||
ccwebPromptOutlineBtn.disabled = false;
|
||||
ccwebPromptOutlineBtn.dataset.count = String(prompts.length);
|
||||
ccwebPromptOutlinePanel.replaceChildren(...prompts.map((prompt) => createPendingCcwebPromptElement(prompt)));
|
||||
if (options.updateScrollbar !== false) updateScrollbar();
|
||||
}
|
||||
|
||||
function closeCcwebPromptOutlinePanel() {
|
||||
if (!ccwebPromptOutlinePanel || !ccwebPromptOutlineBtn) return;
|
||||
ccwebPromptOutlinePanel.hidden = true;
|
||||
ccwebPromptOutlineBtn.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
|
||||
function toggleCcwebPromptOutlinePanel() {
|
||||
if (!ccwebPromptOutlinePanel || !ccwebPromptOutlineBtn) return;
|
||||
if (ccwebPromptOutlinePanel.hidden) {
|
||||
renderPendingCcwebPrompts({ scroll: false, updateScrollbar: false });
|
||||
const anchor = ccwebPromptOutlineBtn.closest('.ccweb-prompt-outline-anchor');
|
||||
if (anchor?.hidden || !ccwebPromptOutlinePanel.children.length) return;
|
||||
closeUserOutlinePanel();
|
||||
ccwebPromptOutlinePanel.hidden = false;
|
||||
ccwebPromptOutlineBtn.setAttribute('aria-expanded', 'true');
|
||||
} else {
|
||||
closeCcwebPromptOutlinePanel();
|
||||
}
|
||||
}
|
||||
|
||||
function findPendingNote(noteId) {
|
||||
const key = getCurrentNoteKey();
|
||||
const notes = getNotesForKey(key, false);
|
||||
@@ -1246,6 +1385,7 @@
|
||||
if (!userOutlinePanel || !userOutlineBtn) return;
|
||||
if (userOutlinePanel.hidden) {
|
||||
updateUserOutlinePanel();
|
||||
closeCcwebPromptOutlinePanel();
|
||||
userOutlinePanel.hidden = false;
|
||||
userOutlineBtn.setAttribute('aria-expanded', 'true');
|
||||
} else {
|
||||
@@ -1843,15 +1983,65 @@
|
||||
reloadMcpBtn.setAttribute('aria-busy', isReloadingMcp ? 'true' : 'false');
|
||||
}
|
||||
|
||||
function normalizeMcpStartupStatusPayload(payload) {
|
||||
if (!payload || typeof payload !== 'object') return null;
|
||||
if (payload.mcpStatus && typeof payload.mcpStatus === 'object') return payload.mcpStatus;
|
||||
if (payload.status && typeof payload.status === 'object') return payload.status;
|
||||
return payload;
|
||||
}
|
||||
|
||||
function mcpStartupStatusToastText(status) {
|
||||
const summary = normalizeMcpStartupStatusPayload(status);
|
||||
if (!summary) return '已请求重载,等待状态';
|
||||
const server = String(summary.server || summary.name || 'ccweb').trim() || 'ccweb';
|
||||
const state = String(summary.status || 'unknown').trim().toLowerCase();
|
||||
const message = String(summary.message || '').trim();
|
||||
if (state === 'ready') return `${server} MCP 已启动`;
|
||||
if (state === 'failed') return `${server} MCP 启动失败${message ? `:${message}` : ''}`;
|
||||
if (state === 'cancelled' || state === 'canceled') return `${server} MCP 启动已取消${message ? `:${message}` : ''}`;
|
||||
if (state === 'starting') return `${server} MCP 正在启动`;
|
||||
if (state === 'pending' || state === 'unknown') return '已请求重载,等待状态';
|
||||
return `${server} MCP 状态:${state}`;
|
||||
}
|
||||
|
||||
function rememberMcpStartupStatus(sessionId, status) {
|
||||
const summary = normalizeMcpStartupStatusPayload(status);
|
||||
if (!sessionId || !summary) return;
|
||||
updateCachedSession(sessionId, (snapshot) => {
|
||||
snapshot.codexAppMcpStartupStatus = deepClone(summary);
|
||||
});
|
||||
}
|
||||
|
||||
function showMcpStartupStatusToast(status, sessionId = currentSessionId, options = {}) {
|
||||
const summary = normalizeMcpStartupStatusPayload(status);
|
||||
const text = mcpStartupStatusToastText(summary);
|
||||
const server = String(summary?.server || summary?.name || 'ccweb').trim() || 'ccweb';
|
||||
const state = String(summary?.status || 'pending').trim().toLowerCase() || 'pending';
|
||||
if (state === 'ready' && !options.notifyReady) return;
|
||||
if ((state === 'starting' || state === 'pending' || state === 'unknown') && !options.notifyPending) return;
|
||||
const stamp = state === 'failed' || state === 'cancelled' || state === 'canceled'
|
||||
? String(summary?.message || text || '')
|
||||
: '';
|
||||
const cacheKey = sessionId || currentSessionId || 'global';
|
||||
const nextKey = `${server}|${state}|${stamp}`;
|
||||
if (mcpStartupToastKeys.get(cacheKey) === nextKey) return;
|
||||
mcpStartupToastKeys.set(cacheKey, nextKey);
|
||||
showToast(text, sessionId);
|
||||
}
|
||||
|
||||
async function reloadCurrentMcpServers() {
|
||||
if (!currentSessionId || !isCodexAppAgent(currentAgent) || isReloadingMcp) return;
|
||||
isReloadingMcp = true;
|
||||
updateReloadMcpButtonUI();
|
||||
try {
|
||||
await fetchAuthJson(`/api/sessions/${encodeURIComponent(currentSessionId)}/reload-mcp`, {
|
||||
const data = await fetchAuthJson(`/api/sessions/${encodeURIComponent(currentSessionId)}/reload-mcp`, {
|
||||
method: 'POST',
|
||||
});
|
||||
showToast('已请求重载 MCP');
|
||||
rememberMcpStartupStatus(currentSessionId, data.mcpStatus);
|
||||
showMcpStartupStatusToast(data.mcpStatus || { status: 'pending' }, currentSessionId, {
|
||||
notifyReady: true,
|
||||
notifyPending: true,
|
||||
});
|
||||
} catch (err) {
|
||||
showToast(err?.message || '重载 MCP 失败');
|
||||
} finally {
|
||||
@@ -2102,6 +2292,432 @@
|
||||
panel.querySelector('input, button')?.focus();
|
||||
}
|
||||
|
||||
function ccwebPromptStatusLabel(status) {
|
||||
if (status === 'submitted') return '已提交';
|
||||
if (status === 'cancelled') return '已取消';
|
||||
return '待回答';
|
||||
}
|
||||
|
||||
function ccwebPromptRecommendedOption(question) {
|
||||
const options = Array.isArray(question?.options) ? question.options : [];
|
||||
return options.find((option) => option?.recommended) || options[0] || null;
|
||||
}
|
||||
|
||||
function getCcwebPromptViewMode() {
|
||||
return localStorage.getItem(CCWEB_PROMPT_VIEW_MODE_STORAGE_KEY) === 'tabs' ? 'tabs' : 'cards';
|
||||
}
|
||||
|
||||
function setCcwebPromptActiveQuestion(card, index) {
|
||||
if (!card) return;
|
||||
const questions = Array.from(card.querySelectorAll('.ccweb-prompt-question'));
|
||||
if (questions.length === 0) return;
|
||||
const activeIndex = Math.min(Math.max(Number(index) || 0, 0), questions.length - 1);
|
||||
card.dataset.activeQuestionIndex = String(activeIndex);
|
||||
questions.forEach((questionEl, questionIndex) => {
|
||||
const isActive = questionIndex === activeIndex;
|
||||
questionEl.classList.toggle('is-active', isActive);
|
||||
questionEl.setAttribute('aria-hidden', isActive ? 'false' : 'true');
|
||||
});
|
||||
card.querySelectorAll('.ccweb-prompt-tab').forEach((tab, tabIndex) => {
|
||||
const isActive = tabIndex === activeIndex;
|
||||
tab.classList.toggle('is-active', isActive);
|
||||
tab.setAttribute('aria-selected', isActive ? 'true' : 'false');
|
||||
tab.tabIndex = isActive ? 0 : -1;
|
||||
});
|
||||
const counter = card.querySelector('.ccweb-prompt-tab-counter');
|
||||
if (counter) counter.textContent = `问题 ${activeIndex + 1} / ${questions.length}`;
|
||||
const prev = card.querySelector('[data-ccweb-prompt-prev]');
|
||||
const next = card.querySelector('[data-ccweb-prompt-next]');
|
||||
if (prev) prev.disabled = activeIndex <= 0;
|
||||
if (next) next.disabled = activeIndex >= questions.length - 1;
|
||||
}
|
||||
|
||||
function setCcwebPromptViewMode(card, mode) {
|
||||
if (!card) return;
|
||||
const normalized = mode === 'tabs' ? 'tabs' : 'cards';
|
||||
card.dataset.viewMode = normalized;
|
||||
card.querySelectorAll('.ccweb-prompt-view-btn').forEach((button) => {
|
||||
const isActive = button.dataset.viewMode === normalized;
|
||||
button.classList.toggle('is-active', isActive);
|
||||
button.setAttribute('aria-pressed', isActive ? 'true' : 'false');
|
||||
});
|
||||
if (normalized === 'tabs') {
|
||||
setCcwebPromptActiveQuestion(card, Number(card.dataset.activeQuestionIndex || 0));
|
||||
} else {
|
||||
card.querySelectorAll('.ccweb-prompt-question').forEach((questionEl) => {
|
||||
questionEl.setAttribute('aria-hidden', 'false');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createCcwebPromptViewControls(card, questions) {
|
||||
const switcher = document.createElement('div');
|
||||
switcher.className = 'ccweb-prompt-view-switcher';
|
||||
switcher.setAttribute('aria-label', '表单显示方式');
|
||||
[
|
||||
{ mode: 'cards', label: '▦', title: '卡片视图' },
|
||||
{ mode: 'tabs', label: '▤', title: '页签视图' },
|
||||
].forEach((item) => {
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.className = 'ccweb-prompt-view-btn';
|
||||
button.dataset.viewMode = item.mode;
|
||||
button.textContent = item.label;
|
||||
button.title = item.title;
|
||||
button.setAttribute('aria-label', item.title);
|
||||
button.addEventListener('click', () => {
|
||||
localStorage.setItem(CCWEB_PROMPT_VIEW_MODE_STORAGE_KEY, item.mode);
|
||||
setCcwebPromptViewMode(card, item.mode);
|
||||
});
|
||||
switcher.appendChild(button);
|
||||
});
|
||||
return switcher;
|
||||
}
|
||||
|
||||
function createCcwebPromptTabs(card, questions) {
|
||||
const controls = document.createElement('div');
|
||||
controls.className = 'ccweb-prompt-view-controls';
|
||||
|
||||
const tabs = document.createElement('div');
|
||||
tabs.className = 'ccweb-prompt-tabs';
|
||||
tabs.setAttribute('role', 'tablist');
|
||||
questions.forEach((question, index) => {
|
||||
const tab = document.createElement('button');
|
||||
tab.type = 'button';
|
||||
tab.className = 'ccweb-prompt-tab';
|
||||
tab.setAttribute('role', 'tab');
|
||||
tab.textContent = question.title || `问题 ${index + 1}`;
|
||||
tab.addEventListener('click', () => setCcwebPromptActiveQuestion(card, index));
|
||||
tabs.appendChild(tab);
|
||||
});
|
||||
|
||||
controls.append(tabs);
|
||||
return controls;
|
||||
}
|
||||
|
||||
function createCcwebPromptTabNav(card, questions) {
|
||||
const nav = document.createElement('div');
|
||||
nav.className = 'ccweb-prompt-tab-nav';
|
||||
if (!Array.isArray(questions) || questions.length <= 1) return nav;
|
||||
const prev = document.createElement('button');
|
||||
prev.type = 'button';
|
||||
prev.className = 'ccweb-prompt-tab-nav-btn';
|
||||
prev.dataset.ccwebPromptPrev = '1';
|
||||
prev.textContent = '上一个';
|
||||
prev.addEventListener('click', () => setCcwebPromptActiveQuestion(card, Number(card.dataset.activeQuestionIndex || 0) - 1));
|
||||
const counter = document.createElement('span');
|
||||
counter.className = 'ccweb-prompt-tab-counter';
|
||||
const next = document.createElement('button');
|
||||
next.type = 'button';
|
||||
next.className = 'ccweb-prompt-tab-nav-btn';
|
||||
next.dataset.ccwebPromptNext = '1';
|
||||
next.textContent = '下一个';
|
||||
next.addEventListener('click', () => setCcwebPromptActiveQuestion(card, Number(card.dataset.activeQuestionIndex || 0) + 1));
|
||||
nav.append(prev, counter, next);
|
||||
return nav;
|
||||
}
|
||||
|
||||
function setCcwebPromptError(card, message) {
|
||||
const error = card.querySelector('.ccweb-prompt-error');
|
||||
if (!error) return;
|
||||
error.textContent = message || '';
|
||||
error.hidden = !message;
|
||||
}
|
||||
|
||||
function updateCcwebPromptAnswerFromSelection(questionEl, question) {
|
||||
const textarea = questionEl.querySelector('.ccweb-prompt-answer');
|
||||
if (!textarea) return;
|
||||
const selectedIds = Array.from(questionEl.querySelectorAll('.ccweb-prompt-option.is-selected'))
|
||||
.map((button) => button.dataset.optionId || '')
|
||||
.filter(Boolean);
|
||||
const selectedOptions = (question.options || []).filter((option) => selectedIds.includes(option.id));
|
||||
const answerText = selectedOptions.map((option) => option.answerText || option.label || '').filter(Boolean).join('\n');
|
||||
if (answerText) textarea.value = answerText;
|
||||
}
|
||||
|
||||
function selectCcwebPromptOption(questionEl, question, optionId) {
|
||||
const buttons = Array.from(questionEl.querySelectorAll('.ccweb-prompt-option'));
|
||||
if (question.selectionMode === 'multi') {
|
||||
buttons.forEach((button) => {
|
||||
if (button.dataset.optionId === optionId) button.classList.toggle('is-selected');
|
||||
});
|
||||
} else {
|
||||
buttons.forEach((button) => {
|
||||
button.classList.toggle('is-selected', button.dataset.optionId === optionId);
|
||||
});
|
||||
}
|
||||
updateCcwebPromptAnswerFromSelection(questionEl, question);
|
||||
}
|
||||
|
||||
function createCcwebPromptQuestionElement(question, index, prompt) {
|
||||
const questionEl = document.createElement('section');
|
||||
questionEl.className = 'ccweb-prompt-question';
|
||||
questionEl.dataset.questionId = question.id || `question_${index + 1}`;
|
||||
|
||||
const head = document.createElement('div');
|
||||
head.className = 'ccweb-prompt-question-head';
|
||||
const title = document.createElement('div');
|
||||
title.className = 'ccweb-prompt-question-title';
|
||||
title.textContent = question.title || `问题 ${index + 1}`;
|
||||
head.appendChild(title);
|
||||
if (question.required !== false && prompt.status !== 'submitted') {
|
||||
const required = document.createElement('span');
|
||||
required.className = 'ccweb-prompt-required';
|
||||
required.textContent = '必答';
|
||||
head.appendChild(required);
|
||||
}
|
||||
questionEl.appendChild(head);
|
||||
|
||||
if (question.question) {
|
||||
const body = document.createElement('div');
|
||||
body.className = 'ccweb-prompt-question-body';
|
||||
body.textContent = question.question;
|
||||
questionEl.appendChild(body);
|
||||
}
|
||||
|
||||
if (prompt.status === 'submitted') {
|
||||
const answer = prompt.answers?.[question.id] || {};
|
||||
if (Array.isArray(answer.selectedOptionLabels) && answer.selectedOptionLabels.length > 0) {
|
||||
const selected = document.createElement('div');
|
||||
selected.className = 'ccweb-prompt-selected-readonly';
|
||||
selected.textContent = `选择:${answer.selectedOptionLabels.join(',')}`;
|
||||
questionEl.appendChild(selected);
|
||||
}
|
||||
const answerText = document.createElement('div');
|
||||
answerText.className = 'ccweb-prompt-answer-readonly';
|
||||
answerText.textContent = answer.answerText || '(未填写答案)';
|
||||
questionEl.appendChild(answerText);
|
||||
return questionEl;
|
||||
}
|
||||
|
||||
const options = Array.isArray(question.options) ? question.options : [];
|
||||
if (options.length > 0 && question.selectionMode !== 'none') {
|
||||
const optionList = document.createElement('div');
|
||||
optionList.className = 'ccweb-prompt-options';
|
||||
options.forEach((option) => {
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.className = 'ccweb-prompt-option';
|
||||
button.dataset.optionId = option.id || '';
|
||||
const label = document.createElement('span');
|
||||
label.className = 'ccweb-prompt-option-label';
|
||||
label.textContent = option.label || option.id || '选项';
|
||||
button.appendChild(label);
|
||||
if (option.recommended) {
|
||||
const badge = document.createElement('span');
|
||||
badge.className = 'ccweb-prompt-option-badge';
|
||||
badge.textContent = '推荐';
|
||||
button.appendChild(badge);
|
||||
}
|
||||
if (option.description) {
|
||||
const desc = document.createElement('span');
|
||||
desc.className = 'ccweb-prompt-option-desc';
|
||||
desc.textContent = option.description;
|
||||
button.appendChild(desc);
|
||||
}
|
||||
button.addEventListener('click', () => selectCcwebPromptOption(questionEl, question, option.id));
|
||||
optionList.appendChild(button);
|
||||
});
|
||||
questionEl.appendChild(optionList);
|
||||
}
|
||||
|
||||
const answer = document.createElement('textarea');
|
||||
answer.className = 'ccweb-prompt-answer';
|
||||
answer.rows = 4;
|
||||
answer.placeholder = question.answerPlaceholder || '填写你的答案...';
|
||||
answer.value = question.defaultAnswer || '';
|
||||
questionEl.appendChild(answer);
|
||||
|
||||
const recommended = ccwebPromptRecommendedOption(question);
|
||||
if (recommended?.recommended) {
|
||||
selectCcwebPromptOption(questionEl, question, recommended.id);
|
||||
}
|
||||
|
||||
return questionEl;
|
||||
}
|
||||
|
||||
function collectCcwebPromptAnswers(card, prompt) {
|
||||
const answers = {};
|
||||
for (const question of prompt.questions || []) {
|
||||
const escapedId = cssEscape(question.id || '');
|
||||
const questionEl = card.querySelector(`.ccweb-prompt-question[data-question-id="${escapedId}"]`);
|
||||
if (!questionEl) continue;
|
||||
const selectedOptionIds = Array.from(questionEl.querySelectorAll('.ccweb-prompt-option.is-selected'))
|
||||
.map((button) => button.dataset.optionId || '')
|
||||
.filter(Boolean);
|
||||
const answerText = String(questionEl.querySelector('.ccweb-prompt-answer')?.value || '').trim();
|
||||
if (question.required !== false && !answerText) {
|
||||
return { ok: false, message: `请填写「${question.title || question.id}」的答案。` };
|
||||
}
|
||||
answers[question.id] = { selectedOptionIds, answerText };
|
||||
}
|
||||
return { ok: true, answers };
|
||||
}
|
||||
|
||||
function createCcwebPromptElement(prompt, meta = {}) {
|
||||
const card = document.createElement('section');
|
||||
const promptStatus = prompt?.status || 'pending';
|
||||
const questions = Array.isArray(prompt?.questions) ? prompt.questions : [];
|
||||
card.className = 'ccweb-prompt-card';
|
||||
card.dataset.promptId = prompt?.id || '';
|
||||
card.dataset.status = promptStatus;
|
||||
card.dataset.viewMode = 'cards';
|
||||
|
||||
const header = document.createElement('div');
|
||||
header.className = 'ccweb-prompt-header';
|
||||
const titleWrap = document.createElement('div');
|
||||
titleWrap.className = 'ccweb-prompt-title-wrap';
|
||||
const title = document.createElement('div');
|
||||
title.className = 'ccweb-prompt-title';
|
||||
title.textContent = prompt?.title || '需要用户确认';
|
||||
titleWrap.appendChild(title);
|
||||
header.appendChild(titleWrap);
|
||||
const headerActions = document.createElement('div');
|
||||
headerActions.className = 'ccweb-prompt-header-actions';
|
||||
const status = document.createElement('span');
|
||||
status.className = 'ccweb-prompt-status';
|
||||
status.textContent = promptStatus === 'pending' ? '●' : ccwebPromptStatusLabel(prompt?.status || 'pending');
|
||||
status.title = ccwebPromptStatusLabel(prompt?.status || 'pending');
|
||||
status.setAttribute('aria-label', ccwebPromptStatusLabel(prompt?.status || 'pending'));
|
||||
headerActions.appendChild(status);
|
||||
if (promptStatus === 'pending' && questions.length > 1) {
|
||||
headerActions.appendChild(createCcwebPromptViewControls(card, questions));
|
||||
}
|
||||
header.appendChild(headerActions);
|
||||
card.appendChild(header);
|
||||
|
||||
if (prompt?.description) {
|
||||
const desc = document.createElement('div');
|
||||
desc.className = 'ccweb-prompt-desc';
|
||||
desc.textContent = prompt.description;
|
||||
card.appendChild(desc);
|
||||
}
|
||||
|
||||
if (promptStatus === 'pending' && questions.length > 1) {
|
||||
card.appendChild(createCcwebPromptTabs(card, questions));
|
||||
}
|
||||
|
||||
const questionsWrap = document.createElement('div');
|
||||
questionsWrap.className = 'ccweb-prompt-questions';
|
||||
questions.forEach((question, index) => {
|
||||
questionsWrap.appendChild(createCcwebPromptQuestionElement(question, index, prompt));
|
||||
});
|
||||
card.appendChild(questionsWrap);
|
||||
|
||||
const error = document.createElement('div');
|
||||
error.className = 'ccweb-prompt-error';
|
||||
error.hidden = true;
|
||||
card.appendChild(error);
|
||||
|
||||
if ((prompt?.status || 'pending') === 'pending') {
|
||||
const footer = document.createElement('div');
|
||||
footer.className = 'ccweb-prompt-footer';
|
||||
if (questions.length > 1) {
|
||||
footer.appendChild(createCcwebPromptTabNav(card, questions));
|
||||
}
|
||||
const footerActions = document.createElement('div');
|
||||
footerActions.className = 'ccweb-prompt-footer-actions';
|
||||
const fillRecommended = document.createElement('button');
|
||||
fillRecommended.type = 'button';
|
||||
fillRecommended.className = 'ccweb-prompt-secondary';
|
||||
fillRecommended.textContent = '填入推荐';
|
||||
fillRecommended.addEventListener('click', () => {
|
||||
questions.forEach((question) => {
|
||||
const option = ccwebPromptRecommendedOption(question);
|
||||
if (!option) return;
|
||||
const questionEl = card.querySelector(`.ccweb-prompt-question[data-question-id="${cssEscape(question.id || '')}"]`);
|
||||
if (questionEl) selectCcwebPromptOption(questionEl, question, option.id);
|
||||
});
|
||||
});
|
||||
footerActions.appendChild(fillRecommended);
|
||||
|
||||
const submit = document.createElement('button');
|
||||
submit.type = 'button';
|
||||
submit.className = 'ccweb-prompt-submit';
|
||||
submit.textContent = '提交全部';
|
||||
submit.addEventListener('click', () => {
|
||||
const collected = collectCcwebPromptAnswers(card, prompt);
|
||||
if (!collected.ok) {
|
||||
setCcwebPromptError(card, collected.message);
|
||||
return;
|
||||
}
|
||||
setCcwebPromptError(card, '');
|
||||
submit.disabled = true;
|
||||
submit.textContent = '提交中';
|
||||
send({
|
||||
type: 'ccweb_prompt_user_response',
|
||||
sessionId: meta.sessionId || currentSessionId,
|
||||
promptId: prompt.id,
|
||||
answers: collected.answers,
|
||||
});
|
||||
});
|
||||
footerActions.appendChild(submit);
|
||||
footer.appendChild(footerActions);
|
||||
card.appendChild(footer);
|
||||
}
|
||||
|
||||
if (promptStatus === 'pending' && questions.length > 1) {
|
||||
setCcwebPromptActiveQuestion(card, 0);
|
||||
setCcwebPromptViewMode(card, getCcwebPromptViewMode());
|
||||
}
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
function updateCcwebPromptMessageInSnapshot(snapshot, prompt) {
|
||||
if (!snapshot || !Array.isArray(snapshot.messages) || !prompt?.id) return;
|
||||
for (const message of snapshot.messages) {
|
||||
if (message?.ccwebPrompt?.id === prompt.id) {
|
||||
message.ccwebPrompt = deepClone(prompt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function removeCcwebPromptMessageFromSnapshot(snapshot, promptId) {
|
||||
if (!snapshot || !Array.isArray(snapshot.messages) || !promptId) return;
|
||||
snapshot.messages = snapshot.messages.filter((message) => message?.ccwebPrompt?.id !== promptId);
|
||||
}
|
||||
|
||||
function removeCcwebPromptMessageFromDom(promptId) {
|
||||
if (!promptId) return 0;
|
||||
let removed = 0;
|
||||
document.querySelectorAll(`.ccweb-prompt-card[data-prompt-id="${cssEscape(promptId)}"]`).forEach((card) => {
|
||||
const messageEl = card.closest('.msg');
|
||||
if (messageEl?.parentNode) {
|
||||
messageEl.remove();
|
||||
} else {
|
||||
card.remove();
|
||||
}
|
||||
removed += 1;
|
||||
});
|
||||
if (removed > 0) {
|
||||
updateUserOutlinePanel();
|
||||
updateScrollbar();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
function applyCcwebPromptUserUpdate(msg) {
|
||||
if (msg.sessionId && msg.prompt) {
|
||||
updateCachedSession(msg.sessionId, (snapshot) => updateCcwebPromptMessageInSnapshot(snapshot, msg.prompt));
|
||||
}
|
||||
if (msg.sessionId !== currentSessionId || !msg.prompt?.id) return;
|
||||
document.querySelectorAll(`.ccweb-prompt-card[data-prompt-id="${cssEscape(msg.prompt.id)}"]`).forEach((card) => {
|
||||
card.replaceWith(createCcwebPromptElement(msg.prompt, { sessionId: msg.sessionId }));
|
||||
});
|
||||
renderPendingCcwebPrompts({ scroll: false });
|
||||
}
|
||||
|
||||
function applyCcwebPromptUserRemove(msg) {
|
||||
const promptId = msg.promptId || msg.prompt?.id || '';
|
||||
if (msg.sessionId && promptId) {
|
||||
updateCachedSession(msg.sessionId, (snapshot) => removeCcwebPromptMessageFromSnapshot(snapshot, promptId));
|
||||
}
|
||||
if (msg.sessionId !== currentSessionId || !promptId) return;
|
||||
removeCcwebPromptMessageFromDom(promptId);
|
||||
renderPendingCcwebPrompts({ scroll: false });
|
||||
}
|
||||
|
||||
function closeDirectoryPicker() {
|
||||
if (!directoryPickerState) return;
|
||||
const { overlay, escapeHandler } = directoryPickerState;
|
||||
@@ -3399,6 +4015,7 @@
|
||||
function resetChatView(agent) {
|
||||
setCurrentAgent(agent);
|
||||
closeUserOutlinePanel();
|
||||
closeCcwebPromptOutlinePanel();
|
||||
closeFileBrowser();
|
||||
currentSessionId = null;
|
||||
loadedHistorySessionId = null;
|
||||
@@ -3460,6 +4077,7 @@
|
||||
setCurrentSessionRunningState(snapshot.isRunning);
|
||||
setStatsDisplay(snapshot);
|
||||
closeUserOutlinePanel();
|
||||
closeCcwebPromptOutlinePanel();
|
||||
currentCwd = snapshot.cwd || null;
|
||||
updateCwdBadge();
|
||||
if (snapshot.mode && MODE_LABELS[snapshot.mode]) {
|
||||
@@ -3492,6 +4110,7 @@
|
||||
const { preserveCurrent = true, loadLast = true } = options;
|
||||
setCurrentAgent(targetAgent);
|
||||
closeUserOutlinePanel();
|
||||
closeCcwebPromptOutlinePanel();
|
||||
renderSessionList();
|
||||
|
||||
const currentMeta = currentSessionId ? getSessionMeta(currentSessionId) : null;
|
||||
@@ -3651,6 +4270,7 @@
|
||||
send({ type: 'detach_view' });
|
||||
}
|
||||
closeUserOutlinePanel();
|
||||
closeCcwebPromptOutlinePanel();
|
||||
clearSessionLoading();
|
||||
touchSessionCache(sessionId);
|
||||
applySessionSnapshot(snapshot, { immediate: true, suppressUnreadToast: true });
|
||||
@@ -3660,6 +4280,7 @@
|
||||
function openSession(sessionId, options = {}) {
|
||||
if (!sessionId) return;
|
||||
closeUserOutlinePanel();
|
||||
closeCcwebPromptOutlinePanel();
|
||||
if (options.forceSync) {
|
||||
beginSessionSwitch(sessionId, { blocking: options.blocking !== false, force: true, label: options.label });
|
||||
return;
|
||||
@@ -4355,6 +4976,7 @@
|
||||
messagesDiv.appendChild(buildMsgElement(msg.message, messageIndex));
|
||||
followOutputIfNeeded(shouldFollow);
|
||||
setCurrentSessionRunningState(!!getSessionMeta(currentSessionId)?.isRunning);
|
||||
renderPendingCcwebPrompts({ scroll: false });
|
||||
}
|
||||
renderSessionList();
|
||||
break;
|
||||
@@ -4499,6 +5121,19 @@
|
||||
applyCcwebMcpChildAgentUpdate(msg);
|
||||
break;
|
||||
|
||||
case 'ccweb_prompt_user_update':
|
||||
applyCcwebPromptUserUpdate(msg);
|
||||
break;
|
||||
|
||||
case 'ccweb_prompt_user_remove':
|
||||
applyCcwebPromptUserRemove(msg);
|
||||
break;
|
||||
|
||||
case 'mcp_startup_status':
|
||||
rememberMcpStartupStatus(msg.sessionId, msg.mcpStatus || msg.status);
|
||||
showMcpStartupStatusToast(msg.mcpStatus || msg.status, msg.sessionId);
|
||||
break;
|
||||
|
||||
case 'mode_changed':
|
||||
if (msg.mode && MODE_LABELS[msg.mode]) {
|
||||
currentMode = msg.mode;
|
||||
@@ -5870,6 +6505,10 @@
|
||||
|
||||
function buildMsgElement(m, messageIndex = null) {
|
||||
const el = createMsgElement(m.role, m.content, m.attachments || [], m);
|
||||
if (m.ccwebPrompt) {
|
||||
const bubble = el.querySelector('.msg-bubble');
|
||||
if (bubble) bubble.appendChild(createCcwebPromptElement(m.ccwebPrompt, { sessionId: currentSessionId }));
|
||||
}
|
||||
if (m.role === 'assistant' && m.toolCalls && m.toolCalls.length > 0) {
|
||||
const bubble = el.querySelector('.msg-bubble');
|
||||
const toolMount = bubble.querySelector(':scope > .cross-conversation-reply-body') || bubble;
|
||||
@@ -7489,6 +8128,16 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (ccwebPromptOutlineBtn && ccwebPromptOutlinePanel) {
|
||||
ccwebPromptOutlineBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
toggleCcwebPromptOutlinePanel();
|
||||
});
|
||||
ccwebPromptOutlinePanel.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
if (reloadMcpBtn) {
|
||||
reloadMcpBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
@@ -7551,6 +8200,11 @@
|
||||
e.target !== userOutlineBtn) {
|
||||
closeUserOutlinePanel();
|
||||
}
|
||||
if (ccwebPromptOutlinePanel && !ccwebPromptOutlinePanel.hidden &&
|
||||
!ccwebPromptOutlinePanel.contains(e.target) &&
|
||||
e.target !== ccwebPromptOutlineBtn) {
|
||||
closeCcwebPromptOutlinePanel();
|
||||
}
|
||||
});
|
||||
sendBtn.addEventListener('click', sendMessage);
|
||||
if (queueSendBtn) {
|
||||
|
||||
@@ -112,6 +112,10 @@
|
||||
<button id="user-outline-btn" class="user-outline-btn" type="button" aria-expanded="false" aria-controls="user-outline-panel" title="定位用户消息">定位</button>
|
||||
<div id="user-outline-panel" class="user-outline-panel" hidden></div>
|
||||
</div>
|
||||
<div class="ccweb-prompt-outline-anchor" hidden>
|
||||
<button id="ccweb-prompt-outline-btn" class="user-outline-btn ccweb-prompt-outline-btn" type="button" aria-expanded="false" aria-controls="ccweb-prompt-outline-panel" title="定位待处理表单">表单</button>
|
||||
<div id="ccweb-prompt-outline-panel" class="user-outline-panel ccweb-prompt-outline-panel" hidden></div>
|
||||
</div>
|
||||
<button id="reload-mcp-btn" class="reload-mcp-btn" type="button" title="重载 Codex App MCP 配置" hidden>重载 MCP</button>
|
||||
<span id="cost-display" class="cost-display" hidden></span>
|
||||
</div>
|
||||
|
||||
@@ -6,398 +6,476 @@
|
||||
<title>RAG 入门:原理、流程与使用</title>
|
||||
<style>
|
||||
:root{
|
||||
--bg:#f6f8fb;
|
||||
--paper:#ffffff;
|
||||
--ink:#0a2540;
|
||||
--muted:#486176;
|
||||
--soft:#eef3f8;
|
||||
--line:#d9e2ec;
|
||||
--blue:#1d4ed8;
|
||||
--mint:#0f9f8f;
|
||||
--orange:#d97706;
|
||||
--rose:#e11d48;
|
||||
--shadow:0 14px 34px rgba(10,37,64,.10),0 2px 7px rgba(10,37,64,.05);
|
||||
--blue:#0b63f6;
|
||||
--blue2:#0f8bff;
|
||||
--cyan:#15c8c2;
|
||||
--green:#12a57d;
|
||||
--navy:#061b4e;
|
||||
--ink:#102047;
|
||||
--muted:#51627f;
|
||||
--line:#c8dcff;
|
||||
--soft:#f3f8ff;
|
||||
--glass:rgba(255,255,255,.86);
|
||||
--shadow:0 20px 46px rgba(16,45,100,.16),0 2px 10px rgba(16,45,100,.08);
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
html,body{margin:0;width:100%;height:100%;overflow:hidden;background:var(--bg);color:var(--ink);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans SC","Microsoft YaHei",Arial,sans-serif}
|
||||
.deck{position:relative;width:100vw;height:100vh;overflow:hidden;background:linear-gradient(135deg,#f8fafc,#eef3f8)}
|
||||
.slide{position:absolute;inset:0;display:none;padding:72px 88px;background:radial-gradient(circle at 85% 12%,rgba(29,78,216,.08),transparent 28%),var(--paper);align-items:center;justify-content:center}
|
||||
.slide.active{display:flex}
|
||||
.slide-inner{width:100%;max-height:calc(100vh - 150px)}
|
||||
.slide::before{content:"";position:absolute;left:0;top:0;bottom:0;width:8px;background:linear-gradient(180deg,var(--blue),var(--mint))}
|
||||
.topline{position:absolute;left:88px;right:88px;top:28px;display:flex;justify-content:space-between;align-items:center;font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:#8aa0b5}
|
||||
.footer{position:absolute;left:88px;right:88px;bottom:24px;display:flex;justify-content:space-between;color:#8aa0b5;font-size:12px}
|
||||
.progress{position:fixed;left:0;right:0;bottom:0;height:4px;background:#dbe4ee;z-index:20}
|
||||
.progress span{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--blue),var(--mint));transition:width .2s ease}
|
||||
.nav-controls{position:fixed;right:28px;bottom:26px;z-index:30;display:flex;align-items:center;gap:8px;padding:8px;border:1px solid rgba(10,37,64,.12);border-radius:999px;background:rgba(255,255,255,.92);box-shadow:0 8px 26px rgba(10,37,64,.14);backdrop-filter:blur(10px)}
|
||||
.nav-btn{width:38px;height:38px;border:0;border-radius:50%;background:#0a2540;color:#fff;font-size:22px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer}
|
||||
.nav-btn:disabled{opacity:.32;cursor:not-allowed}
|
||||
.nav-index{min-width:58px;text-align:center;font-size:13px;font-weight:800;color:var(--muted)}
|
||||
.kicker{margin:0 0 12px;color:var(--blue);font-size:15px;font-weight:700;letter-spacing:.1em;text-transform:uppercase}
|
||||
html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#eef3fb;color:var(--ink);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans SC","Microsoft YaHei",Arial,sans-serif}
|
||||
body{display:grid;place-items:center}
|
||||
h1,h2,h3,h4,p{margin:0}
|
||||
h1{font-size:68px;line-height:1.05;letter-spacing:0;font-weight:800;max-width:980px}
|
||||
h2{font-size:44px;line-height:1.15;letter-spacing:0;font-weight:760;max-width:1040px}
|
||||
h3{font-size:24px;line-height:1.25;font-weight:740}
|
||||
h4{font-size:18px;line-height:1.3;font-weight:730}
|
||||
.lead{font-size:23px;line-height:1.55;color:var(--muted);max-width:900px;margin-top:22px}
|
||||
.muted{color:var(--muted)}
|
||||
.accent{background:linear-gradient(135deg,var(--blue),var(--mint));-webkit-background-clip:text;background-clip:text;color:transparent}
|
||||
.row{display:flex;gap:16px;align-items:stretch}
|
||||
.grid2{display:grid;grid-template-columns:repeat(2,1fr);gap:18px}
|
||||
.grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
|
||||
.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
|
||||
.mt{margin-top:30px}.mt-sm{margin-top:16px}.mt-lg{margin-top:42px}
|
||||
.card{background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:22px}
|
||||
.card.soft{background:var(--soft);box-shadow:none}
|
||||
.tag{display:inline-flex;align-items:center;justify-content:center;border-radius:999px;padding:5px 12px;background:#edf4ff;color:var(--blue);font-size:12px;font-weight:800}
|
||||
.tag.mint{background:#e8faf7;color:var(--mint)}
|
||||
.tag.orange{background:#fff4df;color:var(--orange)}
|
||||
.tag.rose{background:#fff0f4;color:var(--rose)}
|
||||
.num{width:40px;height:40px;border-radius:9px;background:var(--blue);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;margin-bottom:14px}
|
||||
.num.mint{background:var(--mint)}.num.orange{background:var(--orange)}.num.rose{background:var(--rose)}
|
||||
.pillbar{display:flex;flex-wrap:wrap;gap:10px;margin-top:32px}
|
||||
.pill{border:1px solid var(--line);background:#fff;border-radius:999px;padding:8px 14px;font-size:14px;color:var(--muted);font-weight:650}
|
||||
.stage{display:grid;grid-template-columns:1fr 52px 1fr 52px 1fr;gap:10px;align-items:center;margin-top:38px}
|
||||
.stage .box{text-align:center;padding:28px 18px;border:1px solid var(--line);border-radius:12px;background:#fff;box-shadow:var(--shadow)}
|
||||
.stage .box.main{background:var(--blue);color:#fff}
|
||||
.stage .box.main p{color:#dbeafe}
|
||||
.arrow{font-size:34px;color:#93a4b5;text-align:center;font-weight:900}
|
||||
.compare{display:grid;grid-template-columns:1fr 88px 1fr;gap:22px;align-items:center;margin-top:34px}
|
||||
.compare .mid{text-align:center;font-size:42px;color:#9aacbd;font-weight:900}
|
||||
ul{margin:14px 0 0;padding-left:22px;color:var(--muted);line-height:1.85;font-size:18px}
|
||||
.small{font-size:14px;line-height:1.55;color:var(--muted)}
|
||||
.flow{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-top:30px}
|
||||
.flow .step{position:relative;background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:18px;min-height:150px}
|
||||
.flow .step h4{margin:8px 0 6px}.flow .step p{font-size:13px;line-height:1.5;color:var(--muted)}
|
||||
.flow .step.hot{border-color:rgba(29,78,216,.45);box-shadow:0 0 0 3px rgba(29,78,216,.10),var(--shadow)}
|
||||
.chunks{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:24px}
|
||||
.chunk{border:1px dashed #9fb0c2;background:#fff;border-radius:9px;padding:17px;min-height:122px}
|
||||
.chunk b{color:var(--blue);font-size:14px}.chunk p{font-size:13px;line-height:1.6;color:var(--muted);margin-top:8px}
|
||||
.vector{display:grid;grid-template-columns:repeat(10,1fr);gap:6px;margin-top:14px}
|
||||
.bar{height:44px;border-radius:5px;background:var(--blue);opacity:.28}.bar:nth-child(2n){opacity:.55}.bar:nth-child(3n){opacity:.82}.bar:nth-child(5n){opacity:.42}
|
||||
.search{display:grid;grid-template-columns:1.02fr .98fr;gap:20px;margin-top:26px}
|
||||
.result{display:flex;gap:12px;border:1px solid var(--line);border-radius:9px;background:#fff;padding:14px;margin-top:10px}
|
||||
.rank{width:34px;height:34px;border-radius:8px;background:#edf4ff;color:var(--blue);display:flex;align-items:center;justify-content:center;font-weight:900;flex-shrink:0}
|
||||
.prompt{background:#09213a;color:#e8f1ff;border-radius:12px;box-shadow:var(--shadow);padding:22px 24px;font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;font-size:15px;line-height:1.85}
|
||||
.prompt .dim{color:#8fb1d6}.prompt .mark{color:#fde68a}
|
||||
.agent-map{display:grid;grid-template-columns:1fr 46px 1fr 46px 1fr;gap:10px;align-items:center;margin-top:28px}
|
||||
.agent{background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:20px;text-align:center;min-height:170px}
|
||||
.agent p{font-size:13px;line-height:1.55;color:var(--muted);margin-top:8px}
|
||||
.summary{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:34px}
|
||||
.summary .card{min-height:150px}
|
||||
.learning-map{display:grid;grid-template-columns:1fr 38px 1fr 38px 1fr 38px 1fr 38px 1fr;gap:10px;align-items:stretch;margin-top:34px}
|
||||
.map-card{background:#fff;border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow);padding:20px 16px;min-height:270px}
|
||||
.map-card .num{margin-bottom:16px}
|
||||
.map-card h3{font-size:21px}
|
||||
.map-list{margin:14px 0 0;padding-left:18px;color:var(--muted);font-size:14px;line-height:1.75}
|
||||
.map-arrow{display:flex;align-items:center;justify-content:center;font-size:28px;color:#9aacbd;font-weight:900}
|
||||
.mini-flow{display:grid;grid-template-columns:1fr 44px 1fr 44px 1fr;gap:10px;align-items:center;margin-top:32px}
|
||||
.mini-flow .node{background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:18px;text-align:center;min-height:126px}
|
||||
.mini-flow .node.main{background:var(--blue);color:#fff}
|
||||
.mini-flow .node.main p{color:#dbeafe}
|
||||
.mini-flow p{font-size:13px;line-height:1.5;color:var(--muted);margin-top:6px}
|
||||
.mcp-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;margin-top:30px}
|
||||
.mcp-card{background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:22px;min-height:205px}
|
||||
.tool-list{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-top:24px}
|
||||
.tool-list span{display:flex;align-items:center;justify-content:center;min-height:58px;border-radius:10px;background:var(--soft);border:1px solid var(--line);font-size:14px;font-weight:800;color:var(--muted)}
|
||||
.deck{position:relative;width:100vw;height:100vh;display:grid;place-items:center;background:radial-gradient(circle at 8% 15%,rgba(11,99,246,.13),transparent 24%),radial-gradient(circle at 90% 80%,rgba(21,200,194,.16),transparent 28%),#edf3fb}
|
||||
.slide{position:relative;display:none;width:min(100vw,calc(100vh * 16 / 9));aspect-ratio:16/9;max-height:100vh;background:#fff;overflow:hidden;box-shadow:var(--shadow);padding:46px 56px 42px}
|
||||
.slide.active{display:block}
|
||||
.slide::before{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(12,97,246,.05) 1px,transparent 1px),linear-gradient(rgba(12,97,246,.05) 1px,transparent 1px);background-size:36px 36px;mask-image:radial-gradient(ellipse at 45% 40%,black 18%,transparent 82%);pointer-events:none}
|
||||
.slide::after{content:"";position:absolute;left:-120px;bottom:-70px;width:580px;height:180px;background:repeating-linear-gradient(155deg,rgba(11,99,246,.11) 0 2px,transparent 2px 12px);transform:skewX(-18deg);opacity:.55;pointer-events:none}
|
||||
.slide > *{position:relative;z-index:1}
|
||||
.slide-inner{height:100%;display:flex;flex-direction:column;gap:18px}
|
||||
.top{height:66px;display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:22px;border-bottom:2px solid #dbe8ff;padding-bottom:14px}
|
||||
.chapter{height:56px;min-width:122px;display:flex;align-items:center;justify-content:center;color:#fff;font-size:30px;font-weight:900;letter-spacing:.03em;background:linear-gradient(135deg,#0054e6,#0d82ff);clip-path:polygon(0 0,82% 0,100% 50%,82% 100%,0 100%);box-shadow:0 10px 22px rgba(11,99,246,.24)}
|
||||
.head h2{font-size:34px;line-height:1.05;font-weight:900;letter-spacing:0;color:#061b4e}
|
||||
.head p{font-size:15px;color:var(--muted);margin-top:6px}
|
||||
.brand{display:flex;align-items:center;gap:10px;color:var(--blue);font-weight:900}
|
||||
.brand-mark{width:44px;height:44px;border:2px solid var(--blue);border-radius:12px;display:grid;place-items:center;background:#fff;font-weight:900}
|
||||
.content{flex:1;min-height:0;display:flex;flex-direction:column;justify-content:center}
|
||||
.footer{height:42px;display:flex;align-items:flex-end;justify-content:space-between;color:#7d91b5;font-size:11px;letter-spacing:.14em;text-transform:uppercase;border-top:1px solid #dbe8ff;padding-top:12px}
|
||||
.page-corner{position:absolute;right:0;bottom:0;width:86px;height:52px;background:linear-gradient(135deg,#0b63f6,#0050ca);clip-path:polygon(38% 0,100% 0,100% 100%,0 100%);color:#fff;font-size:18px;font-weight:900;display:flex;align-items:flex-end;justify-content:flex-end;padding:0 18px 12px;z-index:3}
|
||||
.kicker{font-size:13px;font-weight:900;letter-spacing:.18em;color:var(--blue);text-transform:uppercase;margin-bottom:8px}
|
||||
.big-title{font-size:58px;line-height:1.08;font-weight:950;color:#061b4e;letter-spacing:0}
|
||||
.sub{font-size:20px;line-height:1.55;color:var(--muted);max-width:760px;margin-top:14px}
|
||||
.accent{background:linear-gradient(135deg,var(--blue),var(--cyan));-webkit-background-clip:text;background-clip:text;color:transparent}
|
||||
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:18px}
|
||||
.grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
|
||||
.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
|
||||
.card{background:var(--glass);border:1.5px solid var(--line);border-radius:14px;box-shadow:0 12px 26px rgba(38,91,160,.09);padding:18px}
|
||||
.card h3{font-size:20px;color:#08205d;font-weight:900}
|
||||
.card h4{font-size:17px;color:#08205d;font-weight:900}
|
||||
.card p,.card li{font-size:13px;line-height:1.55;color:var(--muted)}
|
||||
.tag{display:inline-flex;align-items:center;justify-content:center;height:28px;padding:0 12px;border-radius:999px;background:#eaf3ff;color:var(--blue);font-size:12px;font-weight:900}
|
||||
.tag.green{background:#e7fbf5;color:var(--green)}
|
||||
.tag.cyan{background:#e7fbff;color:#0796a5}
|
||||
.tag.warn{background:#fff4de;color:#d27a00}
|
||||
.tag.red{background:#fff0f4;color:#d81948}
|
||||
.icon{width:56px;height:56px;border-radius:50%;display:grid;place-items:center;background:#fff;border:1px solid #c8dcff;box-shadow:0 8px 18px rgba(11,99,246,.12);color:var(--blue);font-size:23px;font-weight:950;margin-bottom:10px}
|
||||
.ribbon-row{display:grid;grid-template-columns:175px 1fr;gap:18px;align-items:center;margin:14px 0}
|
||||
.ribbon{height:78px;display:flex;align-items:center;gap:14px;color:#fff;background:linear-gradient(135deg,var(--blue),#0050d8);clip-path:polygon(0 0,88% 0,100% 50%,88% 100%,0 100%);border-radius:10px 0 0 10px;padding:0 22px;font-size:22px;font-weight:950}
|
||||
.ribbon.green{background:linear-gradient(135deg,#08a88f,#06c1b8)}
|
||||
.ribbon.navy{background:linear-gradient(135deg,#12327a,#0b63f6)}
|
||||
.ribbon-line{min-height:78px;border:1.5px solid var(--line);border-radius:12px;background:rgba(255,255,255,.78);display:grid;grid-template-columns:90px 1fr;align-items:center;padding:14px 22px}
|
||||
.dot-list{display:grid;gap:7px}
|
||||
.dot-list span{position:relative;padding-left:16px;color:#1b2b58;font-size:14px;line-height:1.4}
|
||||
.dot-list span::before{content:"";position:absolute;left:0;top:.62em;width:6px;height:6px;border-radius:50%;background:var(--blue)}
|
||||
.diagram-title{height:34px;display:inline-flex;align-items:center;padding:0 18px;border-radius:10px;background:linear-gradient(135deg,var(--blue),#0053df);color:#fff;font-weight:950;box-shadow:0 10px 18px rgba(11,99,246,.22)}
|
||||
.stack{display:grid;gap:12px}
|
||||
.stack-layer{position:relative;border:1.5px solid #a7c8ff;border-radius:20px;background:linear-gradient(180deg,#fff,rgba(237,247,255,.92));box-shadow:0 14px 26px rgba(11,99,246,.12);padding:18px 20px}
|
||||
.stack-layer::after{content:"";position:absolute;left:42px;right:42px;bottom:-11px;height:18px;border-radius:0 0 22px 22px;background:linear-gradient(90deg,rgba(11,99,246,.18),rgba(21,200,194,.18));z-index:-1}
|
||||
.stack-items{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:12px}
|
||||
.mini{background:#fff;border:1px solid #d7e6ff;border-radius:12px;padding:13px;text-align:center;min-height:92px}
|
||||
.mini strong{display:block;font-size:16px;color:#08205d;margin-bottom:4px}
|
||||
.mini span{font-size:12px;line-height:1.35;color:var(--muted)}
|
||||
.side-notes{display:grid;gap:20px}
|
||||
.side-note{display:grid;grid-template-columns:56px 1fr;gap:12px;align-items:center}
|
||||
.side-note .round{width:52px;height:52px;border-radius:50%;border:2px solid #d7e6ff;background:#fff;display:grid;place-items:center;color:var(--blue);font-weight:950;font-size:20px}
|
||||
.side-note strong{display:block;color:var(--blue);font-size:16px}
|
||||
.side-note span{font-size:12px;color:var(--muted)}
|
||||
.value-strip{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-top:18px;border:1px solid #d8e6ff;border-radius:14px;background:rgba(255,255,255,.76);padding:12px 14px}
|
||||
.value{display:grid;grid-template-columns:42px 1fr;gap:10px;align-items:center;border-right:1px solid #d8e6ff}
|
||||
.value:last-child{border-right:0}
|
||||
.value .vicon{width:38px;height:38px;border-radius:10px;background:#eaf3ff;color:var(--blue);display:grid;place-items:center;font-weight:950}
|
||||
.value strong{display:block;font-size:15px;color:var(--blue)}
|
||||
.value span{font-size:11px;color:var(--muted)}
|
||||
.flow{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;align-items:stretch}
|
||||
.step{position:relative;min-height:142px;padding:16px;border:1.5px solid #bdd7ff;border-radius:14px;background:#fff;box-shadow:0 10px 22px rgba(11,99,246,.08)}
|
||||
.step::after{content:"";position:absolute;right:-13px;top:50%;width:14px;height:2px;background:#8db9ff}
|
||||
.step:last-child::after{display:none}
|
||||
.step .num{width:34px;height:34px;border-radius:9px;background:linear-gradient(135deg,var(--blue),var(--cyan));color:#fff;display:grid;place-items:center;font-weight:950;margin-bottom:10px}
|
||||
.step h3{font-size:18px;color:#08205d;font-weight:950}
|
||||
.step p{font-size:12px;line-height:1.45;color:var(--muted);margin-top:6px}
|
||||
.step.hot{border-color:var(--cyan);box-shadow:0 0 0 4px rgba(21,200,194,.12),0 10px 22px rgba(11,99,246,.08)}
|
||||
.arrow{font-size:24px;color:#75a7ff;font-weight:950;text-align:center}
|
||||
.compare{display:grid;grid-template-columns:1fr 82px 1fr;gap:16px;align-items:center}
|
||||
.compare .mid{height:82px;border-radius:50%;display:grid;place-items:center;background:linear-gradient(135deg,var(--blue),var(--cyan));color:#fff;font-size:26px;font-weight:950;box-shadow:0 12px 24px rgba(11,99,246,.24)}
|
||||
.center-badge{width:150px;height:150px;border-radius:36px;background:linear-gradient(135deg,#0b63f6,#12c8c2);color:#fff;display:grid;place-items:center;text-align:center;font-size:28px;font-weight:950;box-shadow:0 20px 38px rgba(11,99,246,.28);margin:auto}
|
||||
.limit-grid{display:grid;grid-template-columns:1fr 170px 1fr;gap:18px;align-items:center}
|
||||
.limit-col{display:grid;gap:14px}
|
||||
.limit{display:grid;grid-template-columns:50px 1fr;gap:12px;align-items:center;border:1.5px solid #cfe0ff;border-radius:14px;background:#fff;padding:14px}
|
||||
.limit .n{width:46px;height:46px;border-radius:12px;background:#eaf3ff;color:var(--blue);display:grid;place-items:center;font-weight:950}
|
||||
.pipeline{display:grid;grid-template-columns:1.1fr 1.2fr 1.1fr;gap:18px;align-items:center}
|
||||
.pipe-card{border:1.5px solid #cfe0ff;border-radius:18px;background:#fff;padding:18px;min-height:260px}
|
||||
.bad-list{display:grid;gap:10px;margin-top:14px}
|
||||
.bad-list span{border:1px dashed #ffb4c4;border-radius:10px;background:#fff7fa;color:#a6193c;padding:10px;font-size:13px}
|
||||
.filter{display:grid;place-items:center;min-height:280px}
|
||||
.filter .funnel{width:190px;height:230px;background:linear-gradient(180deg,#e9f3ff,#fff);clip-path:polygon(8% 0,92% 0,62% 48%,62% 100%,38% 100%,38% 48%);border:2px solid #9fc3ff;filter:drop-shadow(0 12px 20px rgba(11,99,246,.16));display:grid;place-items:center;color:var(--blue);font-size:28px;font-weight:950}
|
||||
.chunks{display:grid;grid-template-columns:1.1fr .9fr;gap:18px;align-items:center}
|
||||
.doc{border:1.5px solid #cfe0ff;border-radius:18px;background:#fff;padding:18px}
|
||||
.slice{border-left:5px solid var(--blue);border-radius:10px;background:#f6faff;padding:12px;margin-top:10px}
|
||||
.vector-bars{display:grid;grid-template-columns:repeat(12,1fr);gap:6px;margin-top:16px}
|
||||
.bar{height:56px;border-radius:7px;background:var(--blue);opacity:.25}
|
||||
.bar:nth-child(2n){opacity:.45}.bar:nth-child(3n){opacity:.75}.bar:nth-child(5n){opacity:.9}
|
||||
.rank-list{display:grid;gap:10px}
|
||||
.rank{display:grid;grid-template-columns:42px 1fr auto;gap:12px;align-items:center;border:1.5px solid #cfe0ff;border-radius:12px;background:#fff;padding:12px}
|
||||
.rank .rnum{width:38px;height:38px;border-radius:10px;background:#eaf3ff;color:var(--blue);display:grid;place-items:center;font-weight:950}
|
||||
.score{font-size:20px;font-weight:950;color:var(--green)}
|
||||
.prompt-box{background:#071d48;color:#e7f0ff;border-radius:18px;padding:18px 20px;font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;font-size:13px;line-height:1.65;box-shadow:0 18px 34px rgba(7,29,72,.24)}
|
||||
.prompt-box b{color:#7dd3fc}.prompt-box mark{background:rgba(250,204,21,.18);color:#fde68a;padding:1px 4px;border-radius:4px}
|
||||
.agent-map{display:grid;grid-template-columns:1fr 70px 1fr 70px 1fr;gap:10px;align-items:center}
|
||||
.agent-card{border:1.5px solid #cfe0ff;border-radius:18px;background:#fff;padding:18px;text-align:center;min-height:190px}
|
||||
.agent-card .icon{margin:0 auto 12px}
|
||||
.tool-bus{display:grid;grid-template-columns:1fr 1.3fr 1fr;gap:18px;align-items:center}
|
||||
.bus{height:96px;border-radius:22px;background:linear-gradient(135deg,var(--blue),var(--cyan));color:#fff;display:grid;place-items:center;text-align:center;font-size:26px;font-weight:950;box-shadow:0 16px 30px rgba(11,99,246,.24)}
|
||||
.tools{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}
|
||||
.tool{border:1.5px solid #cfe0ff;background:#fff;border-radius:14px;padding:15px;text-align:center;font-weight:900;color:#08205d}
|
||||
.tool span{display:block;font-size:12px;color:var(--muted);font-weight:500;margin-top:4px}
|
||||
.cover{padding:58px 70px 52px}
|
||||
.cover .slide-inner{justify-content:center}
|
||||
.cover-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:34px;align-items:center}
|
||||
.cover-panel{border:1.5px solid #cfe0ff;background:rgba(255,255,255,.82);border-radius:24px;padding:26px;box-shadow:0 14px 30px rgba(11,99,246,.12)}
|
||||
.cover-visual{position:relative;height:440px}
|
||||
.orb{position:absolute;border-radius:50%;background:linear-gradient(135deg,var(--blue),var(--cyan));box-shadow:0 24px 44px rgba(11,99,246,.24)}
|
||||
.orb.one{width:205px;height:205px;left:160px;top:64px;display:grid;place-items:center;color:#fff;font-size:54px;font-weight:950}
|
||||
.ring{position:absolute;border:2px dashed #9ac1ff;border-radius:50%;inset:22px;animation:spin 18s linear infinite}
|
||||
@keyframes spin{to{transform:rotate(360deg)}}
|
||||
.orbit-card{position:absolute;width:150px;border:1px solid #cfe0ff;border-radius:16px;background:#fff;padding:14px;text-align:center;box-shadow:0 12px 22px rgba(11,99,246,.13)}
|
||||
.orbit-card.a{left:16px;top:36px}.orbit-card.b{right:18px;top:56px}.orbit-card.c{left:40px;bottom:52px}.orbit-card.d{right:42px;bottom:28px}
|
||||
.orbit-card strong{display:block;color:var(--blue);font-size:18px}.orbit-card span{font-size:12px;color:var(--muted)}
|
||||
.nav-controls{position:fixed;left:50%;bottom:10px;transform:translateX(-50%);z-index:30;display:flex;align-items:center;gap:6px;padding:6px;border:1px solid rgba(16,32,71,.12);border-radius:999px;background:rgba(255,255,255,.74);box-shadow:0 8px 24px rgba(16,32,71,.12);backdrop-filter:blur(10px);opacity:.72;transition:opacity .18s ease,background .18s ease}
|
||||
.nav-controls:hover,.nav-controls:focus-within{opacity:1;background:rgba(255,255,255,.94)}
|
||||
.nav-btn{width:32px;height:32px;border:0;border-radius:50%;background:#061b4e;color:#fff;font-size:19px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer}
|
||||
.nav-btn:disabled{opacity:.32;cursor:not-allowed}
|
||||
.nav-index{min-width:58px;text-align:center;font-size:13px;font-weight:900;color:var(--muted)}
|
||||
.progress{position:fixed;left:0;right:0;bottom:0;height:4px;background:#dbe6f6;z-index:25}
|
||||
.progress span{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--blue),var(--cyan));transition:width .2s ease}
|
||||
.notes{display:none}
|
||||
@media (max-aspect-ratio:16/9){
|
||||
.slide{width:calc(100vh * 16 / 9);height:100vh}
|
||||
}
|
||||
@media (max-width:900px){
|
||||
.slide{padding:62px 28px 54px;overflow:auto;align-items:flex-start}
|
||||
.slide-inner{max-height:none}
|
||||
.topline,.footer{left:28px;right:28px}
|
||||
h1{font-size:42px}h2{font-size:32px}.lead{font-size:18px}
|
||||
.grid2,.grid3,.grid4,.flow,.chunks,.search,.summary,.learning-map,.mcp-grid,.tool-list{grid-template-columns:1fr}
|
||||
.stage,.compare,.agent-map,.mini-flow{grid-template-columns:1fr}
|
||||
.arrow,.map-arrow,.compare .mid{display:none}
|
||||
body{overflow:auto;display:block}
|
||||
html,body{height:auto;min-height:100%;overflow:auto}
|
||||
.deck{display:block;height:auto;min-height:100vh;padding:0;background:#fff}
|
||||
.slide{width:100%;height:auto;aspect-ratio:auto;min-height:100vh;box-shadow:none;padding:28px 22px 34px}
|
||||
.slide.active{display:block}
|
||||
.top{height:auto;grid-template-columns:1fr;gap:10px}
|
||||
.chapter{width:112px}
|
||||
.head h2{font-size:28px}
|
||||
.brand{display:none}
|
||||
.big-title{font-size:40px}
|
||||
.content{justify-content:flex-start;padding-top:24px}
|
||||
.cover-grid,.grid2,.grid3,.grid4,.pipeline,.chunks,.tool-bus,.limit-grid,.agent-map{grid-template-columns:1fr}
|
||||
.flow{grid-template-columns:1fr}
|
||||
.step::after,.arrow{display:none}
|
||||
.ribbon-row{grid-template-columns:1fr}
|
||||
.ribbon{clip-path:none;border-radius:12px}
|
||||
.ribbon-line{grid-template-columns:1fr}
|
||||
.value-strip{grid-template-columns:1fr}
|
||||
.value{border-right:0;border-bottom:1px solid #d8e6ff;padding-bottom:8px}
|
||||
.page-corner{display:none}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="deck" id="deck">
|
||||
|
||||
<section class="slide active" data-title="封面">
|
||||
<section class="slide cover active" data-title="封面">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>RAG Primer</span><span>原理和使用</span></div>
|
||||
<p class="kicker">RAG · LLM · Retrieval · Prompt · Agent · MCP</p>
|
||||
<h1>RAG 入门:让 AI <span class="accent">先查资料</span>再回答</h1>
|
||||
<p class="lead">从 LLM 的对话限制出发,理解 RAG 的建库、检索、排序、提示词和 Agent 扩展。</p>
|
||||
<div class="pillbar">
|
||||
<span class="pill">RAG解释</span><span class="pill">LLM解释</span><span class="pill">上下文限制</span><span class="pill">幻觉</span><span class="pill">注意力顺序</span><span class="pill">切片</span><span class="pill">向量化</span><span class="pill">排序</span><span class="pill">语义检索</span><span class="pill">提示词工程</span><span class="pill">AGENTS</span><span class="pill">MCP</span>
|
||||
</div>
|
||||
<div class="footer"><span>RAG 原理和使用</span><span class="page"></span></div>
|
||||
<div class="notes">开场不用讲算法,先讲主线:大模型会说话,但它不是企业知识库。因为它有上下文、幻觉、注意力和顺序方面的限制,所以需要 RAG 这套“先查资料,再组织答案”的机制。</div>
|
||||
|
||||
<div class="cover-grid">
|
||||
<div>
|
||||
<div class="kicker">RAG · LLM · Prompt · Agent · MCP</div>
|
||||
<h1 class="big-title">RAG 入门:让 AI <span class="accent">先查资料</span> 再回答</h1>
|
||||
<p class="sub">从 LLM 的限制讲起,串起知识库建设、语义检索、排序、提示词工程、Agent 和 MCP。</p>
|
||||
<div class="value-strip" style="grid-template-columns:repeat(3,1fr);margin-top:28px">
|
||||
<div class="value"><div class="vicon">01</div><div><strong>先懂限制</strong><span>上下文、幻觉、注意力</span></div></div>
|
||||
<div class="value"><div class="vicon">02</div><div><strong>再懂流程</strong><span>建库、检索、生成</span></div></div>
|
||||
<div class="value"><div class="vicon">03</div><div><strong>最后扩展</strong><span>Agent、MCP、工具</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cover-panel">
|
||||
<div class="cover-visual">
|
||||
<div class="orb one"><div class="ring"></div>RAG</div>
|
||||
<div class="orbit-card a"><strong>LLM</strong><span>理解和生成</span></div>
|
||||
<div class="orbit-card b"><strong>知识库</strong><span>资料与来源</span></div>
|
||||
<div class="orbit-card c"><strong>检索</strong><span>找相关片段</span></div>
|
||||
<div class="orbit-card d"><strong>提示词</strong><span>约束回答</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>RAG Primer</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="目录">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Roadmap</span><span>学习路径</span></div>
|
||||
<p class="kicker">由浅入深</p>
|
||||
<h2>从“会生成”到“会查资料、会调用工具”</h2>
|
||||
<div class="learning-map">
|
||||
<div class="map-card"><div class="num">1</div><h3>基础概念</h3><ul class="map-list"><li>RAG 是什么</li><li>LLM 是什么</li></ul></div>
|
||||
<div class="map-arrow">→</div>
|
||||
<div class="map-card"><div class="num orange">2</div><h3>LLM 限制</h3><ul class="map-list"><li>上下文</li><li>幻觉</li><li>注意力与顺序</li></ul></div>
|
||||
<div class="map-arrow">→</div>
|
||||
<div class="map-card"><div class="num mint">3</div><h3>离线建库</h3><ul class="map-list"><li>资料清洗</li><li>切片</li><li>向量化入库</li></ul></div>
|
||||
<div class="map-arrow">→</div>
|
||||
<div class="map-card"><div class="num">4</div><h3>在线问答</h3><ul class="map-list"><li>语义检索</li><li>排序 / 重排</li><li>提示词工程</li></ul></div>
|
||||
<div class="map-arrow">→</div>
|
||||
<div class="map-card"><div class="num rose">5</div><h3>能力扩展</h3><ul class="map-list"><li>Agents 分工</li><li>MCP 连接工具</li></ul></div>
|
||||
</div>
|
||||
<div class="footer"><span>目录</span><span class="page"></span></div>
|
||||
<div class="notes">这页把路线说清楚。后面每一页都围绕 LLM 限制到 RAG 方案,再到提示词工程和 Agent 的路径推进。</div>
|
||||
|
||||
<div class="top"><div class="chapter">01</div><div class="head"><h2>学习路径</h2><p>由浅入深:先理解问题,再理解方案,最后理解扩展能力。</p></div><div class="brand"><div class="brand-mark">AI</div><span>RAG 入门</span></div></div>
|
||||
<div class="content">
|
||||
<div class="flow">
|
||||
<div class="step hot"><div class="num">1</div><h3>基础概念</h3><p>RAG 是什么;LLM 是什么;两者分别负责什么。</p></div>
|
||||
<div class="step"><div class="num">2</div><h3>LLM 限制</h3><p>上下文有限、会幻觉、长内容专注度下降、顺序不稳定。</p></div>
|
||||
<div class="step"><div class="num">3</div><h3>离线建库</h3><p>资料准备、清洗、切片、元数据、向量化入库。</p></div>
|
||||
<div class="step"><div class="num">4</div><h3>在线问答</h3><p>用户提问、语义检索、候选排序、拼上下文、生成答案。</p></div>
|
||||
<div class="step"><div class="num">5</div><h3>能力扩展</h3><p>提示词工程、多个 LLM 分工、Agent 编排、MCP 连接工具。</p></div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">懂</div><div><strong>概念</strong><span>知道每个词在干什么</span></div></div>
|
||||
<div class="value"><div class="vicon">看</div><div><strong>流程</strong><span>知道一次问答怎么跑</span></div></div>
|
||||
<div class="value"><div class="vicon">抓</div><div><strong>关键</strong><span>切片、排序、提示词</span></div></div>
|
||||
<div class="value"><div class="vicon">扩</div><div><strong>边界</strong><span>Agent 和工具调用</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Roadmap</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="RAG解释">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>RAG</span><span>检索增强生成</span></div>
|
||||
<p class="kicker">RAG 解释</p>
|
||||
<h2>RAG = 先检索资料,再增强上下文,最后生成答案</h2>
|
||||
<div class="mini-flow">
|
||||
<div class="node"><span class="tag">Retrieval</span><h3 class="mt-sm">检索</h3><p>从知识库找到相关资料。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="node main"><span class="tag" style="background:rgba(255,255,255,.18);color:#fff">Augmented</span><h3 class="mt-sm">增强</h3><p>把资料放进上下文。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="node"><span class="tag mint">Generation</span><h3 class="mt-sm">生成</h3><p>LLM 基于资料回答。</p></div>
|
||||
</div>
|
||||
<div class="grid2 mt">
|
||||
<div class="card"><h3>不是训练模型</h3><p class="lead" style="font-size:19px;margin-top:8px">知识不写进模型参数,而是每次回答前动态查资料。</p></div>
|
||||
<div class="card soft"><h3>不是全量塞资料</h3><p class="lead" style="font-size:19px;margin-top:8px">只取与问题相关的片段,降低上下文压力和噪声。</p></div>
|
||||
</div>
|
||||
<div class="footer"><span>RAG = Retrieval-Augmented Generation</span><span class="page"></span></div>
|
||||
<div class="notes">这页讲 RAG 的基本定义。先给出完整定义,再强调 RAG 不是训练模型,也不是把全部资料塞给模型。</div>
|
||||
|
||||
<div class="top"><div class="chapter">02</div><div class="head"><h2>RAG 是什么</h2><p>RAG = Retrieval-Augmented Generation,检索增强生成。</p></div><div class="brand"><div class="brand-mark">R</div><span>先查再答</span></div></div>
|
||||
<div class="content">
|
||||
<div class="pipeline">
|
||||
<div class="pipe-card"><span class="tag">Retrieval</span><div class="icon">查</div><h3>检索</h3><p>先从知识库中找到和问题相关的资料片段。</p></div>
|
||||
<div class="filter"><div class="funnel">RAG<br><span style="font-size:14px">筛选相关资料</span></div></div>
|
||||
<div class="pipe-card"><span class="tag green">Generation</span><div class="icon">答</div><h3>生成</h3><p>LLM 只基于筛出来的资料组织自然语言答案。</p></div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">≠</div><div><strong>不是训练模型</strong><span>知识不写进模型参数</span></div></div>
|
||||
<div class="value"><div class="vicon">≠</div><div><strong>不是全量塞资料</strong><span>只取相关片段</span></div></div>
|
||||
<div class="value"><div class="vicon">=</div><div><strong>动态查资料</strong><span>每次提问实时检索</span></div></div>
|
||||
<div class="value"><div class="vicon">✓</div><div><strong>降低幻觉</strong><span>让答案有依据</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>RAG = Retrieval + Augmented + Generation</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="LLM 是什么">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>LLM</span><span>大语言模型</span></div>
|
||||
<p class="kicker">定义</p>
|
||||
<h2>LLM:理解上下文,生成自然语言</h2>
|
||||
<div class="compare">
|
||||
<div class="card">
|
||||
<span class="tag">能力</span>
|
||||
<h3 class="mt-sm">理解上下文,生成答案</h3>
|
||||
<ul>
|
||||
<li>读懂用户问题的大意</li>
|
||||
<li>把零散信息组织成自然语言</li>
|
||||
<li>按要求改写、总结、解释、翻译</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mid">≠</div>
|
||||
<div class="card">
|
||||
<span class="tag rose">边界</span>
|
||||
<h3 class="mt-sm">企业资料库或事实系统</h3>
|
||||
<ul>
|
||||
<li>不会天然知道最新制度</li>
|
||||
<li>不知道内部文档和私有数据</li>
|
||||
<li>不能保证每句话都有来源</li>
|
||||
</ul>
|
||||
<div class="top"><div class="chapter">03</div><div class="head"><h2>LLM 是什么</h2><p>大语言模型擅长理解上下文和生成表达,但不是企业事实库。</p></div><div class="brand"><div class="brand-mark">LLM</div><span>语言引擎</span></div></div>
|
||||
<div class="content">
|
||||
<div class="compare">
|
||||
<div class="card" style="min-height:300px"><span class="tag">能力</span><div class="icon">AI</div><h3>理解与表达</h3><div class="dot-list" style="margin-top:14px"><span>读懂问题意图</span><span>总结、改写、解释、翻译</span><span>把零散资料组织成答案</span></div></div>
|
||||
<div class="mid">≠</div>
|
||||
<div class="card" style="min-height:300px"><span class="tag red">边界</span><div class="icon">DB</div><h3>企业事实系统</h3><div class="dot-list" style="margin-top:14px"><span>不会天然知道内部文档</span><span>不知道最新政策和数据</span><span>不能保证每句话都有来源</span></div></div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">读</div><div><strong>读懂上下文</strong><span>理解语义,不是简单关键词</span></div></div>
|
||||
<div class="value"><div class="vicon">写</div><div><strong>生成答案</strong><span>组织语言和结构</span></div></div>
|
||||
<div class="value"><div class="vicon">缺</div><div><strong>缺事实来源</strong><span>私有知识需要外部供给</span></div></div>
|
||||
<div class="value"><div class="vicon">接</div><div><strong>接 RAG</strong><span>把资料交给 LLM 使用</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>LLM handles language, not source-of-truth</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="card soft mt"><h3>定位</h3><p class="lead" style="font-size:20px;margin-top:8px">LLM 负责读懂和表达,事实依据来自外部资料。</p></div>
|
||||
<div class="footer"><span>LLM 不是知识库</span><span class="page"></span></div>
|
||||
<div class="notes">这里不要把 LLM 讲成搜索引擎。LLM 最强的是语言理解和生成,事实来源要靠外部知识、数据库或工具补充。</div>
|
||||
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="LLM 的限制">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Limits</span><span>对话限制</span></div>
|
||||
<p class="kicker">对话限制</p>
|
||||
<h2>LLM 的 4 个对话限制</h2>
|
||||
<div class="grid4 mt">
|
||||
<div class="card"><div class="num">1</div><h3>上下文有限</h3><p class="small mt-sm">输入窗口有限;资料过多会变慢、变贵、变乱。</p></div>
|
||||
<div class="card"><div class="num orange">2</div><h3>会有幻觉</h3><p class="small mt-sm">资料不足或指令不清时,会生成看似合理的错误内容。</p></div>
|
||||
<div class="card"><div class="num mint">3</div><h3>专注度下降</h3><p class="small mt-sm">长资料和噪声会稀释重点,关键信息可能被忽略。</p></div>
|
||||
<div class="card"><div class="num rose">4</div><h3>顺序不稳定</h3><p class="small mt-sm">位置、相似内容、前后冲突都会影响答案。</p></div>
|
||||
</div>
|
||||
<div class="card soft mt"><p class="lead" style="font-size:20px;margin-top:0">处理策略:每次只给最相关、最可信的少量资料。</p></div>
|
||||
<div class="footer"><span>上下文 · 幻觉 · 注意力 · 顺序</span><span class="page"></span></div>
|
||||
<div class="notes">这一页要明确回应用户大纲:上下文限制、幻觉、专注度、不会稳定关注内容顺序。它们共同解释了为什么不能简单粗暴地把所有文档塞进去。</div>
|
||||
|
||||
<div class="top"><div class="chapter">04</div><div class="head"><h2>LLM 的对话限制</h2><p>正因为有这些限制,不能把所有知识一次性丢给 LLM。</p></div><div class="brand"><div class="brand-mark">!</div><span>为什么需要 RAG</span></div></div>
|
||||
<div class="content">
|
||||
<div class="limit-grid">
|
||||
<div class="limit-col">
|
||||
<div class="limit"><div class="n">01</div><div><h4>上下文有限</h4><p>输入窗口有限;资料过多会变慢、变贵、变乱。</p></div></div>
|
||||
<div class="limit"><div class="n">02</div><div><h4>会有幻觉</h4><p>资料不足或指令不清时,会编出看似合理的内容。</p></div></div>
|
||||
</div>
|
||||
<div class="center-badge">不能<br>全量塞<br>资料</div>
|
||||
<div class="limit-col">
|
||||
<div class="limit"><div class="n">03</div><div><h4>专注度下降</h4><p>长资料和噪声会稀释重点,关键信息被忽略。</p></div></div>
|
||||
<div class="limit"><div class="n">04</div><div><h4>顺序不稳定</h4><p>内容位置、相似片段、前后冲突都会影响答案。</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">少</div><div><strong>少量</strong><span>只给必要资料</span></div></div>
|
||||
<div class="value"><div class="vicon">准</div><div><strong>准确</strong><span>优先高相关来源</span></div></div>
|
||||
<div class="value"><div class="vicon">新</div><div><strong>新鲜</strong><span>版本和时间可控</span></div></div>
|
||||
<div class="value"><div class="vicon">规</div><div><strong>规则</strong><span>提示词约束回答边界</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Context · Hallucination · Attention · Order</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="为什么需要 RAG">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Why RAG</span><span>限制带来方案</span></div>
|
||||
<p class="kicker">从限制到方案</p>
|
||||
<h2>RAG 的核心:不是让模型记住全部知识,而是让它按需查资料</h2>
|
||||
<div class="stage">
|
||||
<div class="box"><span class="tag rose">全量输入</span><h3 class="mt-sm">全部塞给 LLM</h3><p class="small mt-sm">长、乱、贵,容易混入过期和无权限资料。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="box main"><span class="tag" style="background:rgba(255,255,255,.18);color:#fff">RAG</span><h3 class="mt-sm">先查,再答</h3><p class="small mt-sm">每次只取跟问题最相关的资料片段。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="box"><span class="tag mint">生成</span><h3 class="mt-sm">基于资料回答</h3><p class="small mt-sm">LLM 根据资料生成,必要时引用来源。</p></div>
|
||||
</div>
|
||||
<div class="card soft mt"><h3>RAG = 检索增强生成</h3><p class="lead" style="font-size:20px;margin-top:8px">检索相关资料 → 放入上下文 → LLM 生成答案。</p></div>
|
||||
<div class="footer"><span>先查资料,再生成</span><span class="page"></span></div>
|
||||
<div class="notes">这页把 RAG 的必要性讲出来:不是因为向量数据库酷,而是因为 LLM 的上下文和注意力有限,必须把资料筛小、筛准,再交给模型。</div>
|
||||
|
||||
<div class="top"><div class="chapter">05</div><div class="head"><h2>从限制到方案</h2><p>RAG 的核心不是让模型记住全部知识,而是让模型按需查资料。</p></div><div class="brand"><div class="brand-mark">→</div><span>方案转化</span></div></div>
|
||||
<div class="content">
|
||||
<div class="pipeline">
|
||||
<div class="pipe-card"><span class="tag red">错误做法</span><h3 style="margin-top:16px">全部塞给 LLM</h3><div class="bad-list"><span>长文档堆叠,重点被稀释</span><span>过期资料混入,结果不可信</span><span>无权限内容可能泄露</span><span>成本高,速度慢</span></div></div>
|
||||
<div class="filter"><div class="funnel">检索<br>过滤<br>排序</div></div>
|
||||
<div class="pipe-card"><span class="tag green">RAG 做法</span><h3 style="margin-top:16px">只给相关资料</h3><div class="bad-list"><span style="border-color:#8fe0cf;background:#f1fffb;color:#0b8066">按问题查资料</span><span style="border-color:#8fe0cf;background:#f1fffb;color:#0b8066">按相关性排序</span><span style="border-color:#8fe0cf;background:#f1fffb;color:#0b8066">拼成小上下文</span><span style="border-color:#8fe0cf;background:#f1fffb;color:#0b8066">让 LLM 基于依据回答</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>RAG turns big documents into precise context</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="后台建库">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Offline Pipeline</span><span>后台整理资料</span></div>
|
||||
<p class="kicker">离线流程</p>
|
||||
<h2>资料整理成可检索的知识库</h2>
|
||||
<div class="flow">
|
||||
<div class="step"><span class="tag">01</span><h4>收集资料</h4><p>产品手册、FAQ、制度、接口文档、案例、流程说明。</p></div>
|
||||
<div class="step"><span class="tag orange">02</span><h4>清洗资料</h4><p>去掉重复、过期、广告、目录噪声和格式错误。</p></div>
|
||||
<div class="step hot"><span class="tag mint">03</span><h4>切片</h4><p>把长文档拆成能独立表达意思的小片段。</p></div>
|
||||
<div class="step"><span class="tag">04</span><h4>加元数据</h4><p>来源、版本、时间、部门、权限、适用范围。</p></div>
|
||||
<div class="step"><span class="tag">05</span><h4>向量化入库</h4><p>把每个片段变成语义向量,写入向量库。</p></div>
|
||||
</div>
|
||||
<div class="card soft mt"><p class="lead" style="font-size:20px;margin-top:0">资料质量决定检索质量。</p></div>
|
||||
<div class="footer"><span>资料准备 → 切片 → 向量库</span><span class="page"></span></div>
|
||||
<div class="notes">这里是“前期准备”。强调 RAG 不只是问答界面,后台知识库准备很关键。元数据也很重要,因为后面排序和权限过滤会用到。</div>
|
||||
|
||||
<div class="top"><div class="chapter">06</div><div class="head"><h2>后台建库:把资料整理成可检索系统</h2><p>RAG 不是只有一个问答框,前期知识库整理决定最终效果。</p></div><div class="brand"><div class="brand-mark">KB</div><span>离线流程</span></div></div>
|
||||
<div class="content">
|
||||
<div class="ribbon-row">
|
||||
<div class="ribbon">资料层</div>
|
||||
<div class="ribbon-line"><div class="icon">文</div><div class="dot-list"><span>产品手册、FAQ、制度、接口文档、案例、流程说明</span><span>确认来源、版本、时间、权限和适用范围</span></div></div>
|
||||
</div>
|
||||
<div class="ribbon-row">
|
||||
<div class="ribbon green">处理层</div>
|
||||
<div class="ribbon-line"><div class="icon">洗</div><div class="dot-list"><span>清洗重复、过期、广告、目录噪声和格式错误</span><span>长文档拆成能独立表达意思的小片段</span></div></div>
|
||||
</div>
|
||||
<div class="ribbon-row">
|
||||
<div class="ribbon navy">索引层</div>
|
||||
<div class="ribbon-line"><div class="icon">库</div><div class="dot-list"><span>每个切片转成语义向量,写入向量库</span><span>同时保留元数据,用于过滤、排序和引用来源</span></div></div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">质</div><div><strong>资料质量</strong><span>决定检索上限</span></div></div>
|
||||
<div class="value"><div class="vicon">粒</div><div><strong>切片粒度</strong><span>决定召回精度</span></div></div>
|
||||
<div class="value"><div class="vicon">源</div><div><strong>元数据</strong><span>决定过滤和引用</span></div></div>
|
||||
<div class="value"><div class="vicon">库</div><div><strong>向量库</strong><span>支持语义检索</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Prepare · Clean · Chunk · Embed · Index</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="切片和向量库">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Chunk & Embedding</span><span>切片和向量化</span></div>
|
||||
<p class="kicker">索引构建</p>
|
||||
<h2>切片 + 向量化:支持语义检索</h2>
|
||||
<div class="chunks">
|
||||
<div class="chunk"><b>切片 A:退费条件</b><p>购买后 7 天内,且未使用核心服务,可以申请全额退款。</p></div>
|
||||
<div class="chunk"><b>切片 B:不可退场景</b><p>已开具发票、已交付定制服务、超过合同期限,不支持自动退款。</p></div>
|
||||
<div class="chunk"><b>切片 C:审批路径</b><p>超过 5 万元的退款申请,需要客户成功经理和财务双审批。</p></div>
|
||||
</div>
|
||||
<div class="grid2 mt">
|
||||
<div class="card"><span class="tag">切片</span><h3 class="mt-sm">粒度适中</h3><p class="small mt-sm">过大噪声多,过小语义断;每片覆盖一个局部问题。</p></div>
|
||||
<div class="card"><span class="tag mint">向量库</span><h3 class="mt-sm">语义坐标</h3><p class="small mt-sm">文字转换成数字向量;语义相近,距离更近。</p><div class="vector"><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i></div></div>
|
||||
</div>
|
||||
<div class="footer"><span>Chunking + Embedding</span><span class="page"></span></div>
|
||||
<div class="notes">用卡片和地图类比:切片是把书拆成卡片,向量化是给卡片标语义坐标。用户问法不一样,也能找到意思接近的片段。</div>
|
||||
|
||||
<div class="top"><div class="chapter">07</div><div class="head"><h2>切片 + 向量化</h2><p>把长文档拆成小卡片,再给每张卡片标上“语义坐标”。</p></div><div class="brand"><div class="brand-mark">V</div><span>语义检索</span></div></div>
|
||||
<div class="content">
|
||||
<div class="chunks">
|
||||
<div class="doc">
|
||||
<span class="tag">原始资料:退款政策</span>
|
||||
<div class="slice"><h4>切片 A:退费条件</h4><p>购买后 7 天内,且未使用核心服务,可以申请全额退款。</p></div>
|
||||
<div class="slice"><h4>切片 B:不可退场景</h4><p>已开具发票、已交付定制服务、超过合同期限,不支持自动退款。</p></div>
|
||||
<div class="slice"><h4>切片 C:审批路径</h4><p>超过 5 万元的退款申请,需要客户成功经理和财务双审批。</p></div>
|
||||
</div>
|
||||
<div class="doc">
|
||||
<span class="tag green">向量化结果</span>
|
||||
<h3 style="margin-top:14px">语义相近,距离更近</h3>
|
||||
<p style="font-size:13px;line-height:1.65;color:var(--muted);margin-top:10px">用户问“买了 3 天没用能退吗”,即使没有出现“退费条件”这几个字,也能找到切片 A。</p>
|
||||
<div class="vector-bars"><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Chunking + Embedding</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="用户提问时怎么查">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Online Retrieval</span><span>检索和排序</span></div>
|
||||
<p class="kicker">在线流程</p>
|
||||
<h2>用户提问后:检索候选,排序后交给 LLM</h2>
|
||||
<div class="flow">
|
||||
<div class="step"><span class="tag">01</span><h4>问题改写</h4><p>把口语问题改成更适合检索的查询。</p></div>
|
||||
<div class="step"><span class="tag">02</span><h4>问题向量化</h4><p>把用户问题也转成语义向量。</p></div>
|
||||
<div class="step"><span class="tag mint">03</span><h4>召回候选</h4><p>从向量库里找语义距离近的片段。</p></div>
|
||||
<div class="step hot"><span class="tag orange">04</span><h4>排序 / 重排</h4><p>按相关性、时效、权限、来源可信度重新排序。</p></div>
|
||||
<div class="step"><span class="tag">05</span><h4>拼上下文</h4><p>只把最有用的几段资料交给 LLM。</p></div>
|
||||
</div>
|
||||
<div class="search">
|
||||
<div class="card"><h3>排序后的候选资料</h3><div class="result"><div class="rank">1</div><div><h4>退款政策 v2026Q2</h4><p class="small">最相关,且版本最新。</p></div></div><div class="result"><div class="rank">2</div><div><h4>大客户审批流程</h4><p class="small">相关,但只在金额超过 5 万时使用。</p></div></div></div>
|
||||
<div class="card soft"><h3>排序作用</h3><ul><li>过期资料降权</li><li>无权限资料过滤</li><li>可信来源优先</li><li>减少噪声,保留重点</li></ul></div>
|
||||
</div>
|
||||
<div class="footer"><span>Retrieve + Rerank</span><span class="page"></span></div>
|
||||
<div class="notes">这里必须引出“排序”概念。召回只是先捞一批候选,排序/重排才决定哪些片段真正进入上下文。排序质量直接影响最终答案。</div>
|
||||
|
||||
<div class="top"><div class="chapter">08</div><div class="head"><h2>用户提问时怎么查</h2><p>召回只是先捞候选,排序 / 重排决定哪些资料真正进入上下文。</p></div><div class="brand"><div class="brand-mark">S</div><span>在线检索</span></div></div>
|
||||
<div class="content">
|
||||
<div class="flow">
|
||||
<div class="step"><div class="num">1</div><h3>问题改写</h3><p>把口语问题改成适合检索的查询。</p></div>
|
||||
<div class="step"><div class="num">2</div><h3>问题向量化</h3><p>用户问题也转成语义向量。</p></div>
|
||||
<div class="step"><div class="num">3</div><h3>召回候选</h3><p>从向量库找语义距离近的片段。</p></div>
|
||||
<div class="step hot"><div class="num">4</div><h3>排序 / 重排</h3><p>按相关性、时效、权限、来源可信度重新排序。</p></div>
|
||||
<div class="step"><div class="num">5</div><h3>拼上下文</h3><p>只把最有用的几段交给 LLM。</p></div>
|
||||
</div>
|
||||
<div class="grid2" style="margin-top:18px">
|
||||
<div class="card"><h3>排序后的候选资料</h3><div class="rank-list" style="margin-top:12px"><div class="rank"><div class="rnum">1</div><div><h4>退款政策 v2026Q2</h4><p>最相关,版本最新</p></div><div class="score">96</div></div><div class="rank"><div class="rnum">2</div><div><h4>大客户审批流程</h4><p>金额超过 5 万时使用</p></div><div class="score">78</div></div></div></div>
|
||||
<div class="card"><h3>排序看什么</h3><div class="dot-list" style="margin-top:12px"><span>相关性:是否真的回答这个问题</span><span>时效性:新版本优先,过期资料降权</span><span>权限:用户不能看的资料先过滤</span><span>可信度:制度、合同、权威来源优先</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Retrieve · Rerank · Context Assembly</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="提示词工程">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Prompt Engineering</span><span>系统提示词</span></div>
|
||||
<p class="kicker">生成约束</p>
|
||||
<h2>系统提示词规定 LLM 的资料使用规则</h2>
|
||||
<div class="search">
|
||||
<div class="prompt">
|
||||
<div class="dim">SYSTEM:</div>
|
||||
<div>你是客服助手。只能基于 CONTEXT 回答;资料不足时说“不确定”,不要编造。</div>
|
||||
<br>
|
||||
<div class="dim">CONTEXT:</div>
|
||||
<div class="mark">[退款政策 v2026Q2] 购买后 7 天内且未使用核心服务,可全额退款。</div>
|
||||
<br>
|
||||
<div class="dim">USER:</div>
|
||||
<div>客户买了 3 天,还没使用,可以退吗?</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<span class="tag">提示词工程</span>
|
||||
<h3 class="mt-sm">规则</h3>
|
||||
<ul>
|
||||
<li>角色:你是谁</li>
|
||||
<li>边界:只能基于资料回答</li>
|
||||
<li>格式:分点、引用来源、给结论</li>
|
||||
<li>兜底:不知道就说不知道</li>
|
||||
<li>安全:不要泄露无权限信息</li>
|
||||
</ul>
|
||||
<div class="top"><div class="chapter">09</div><div class="head"><h2>提示词工程:规定资料怎么用</h2><p>RAG 找资料,系统提示词规定 LLM 的角色、边界、格式和兜底方式。</p></div><div class="brand"><div class="brand-mark">P</div><span>生成约束</span></div></div>
|
||||
<div class="content">
|
||||
<div class="grid2">
|
||||
<div class="prompt-box">
|
||||
<b>SYSTEM</b><br>
|
||||
你是客服助手。只能基于 CONTEXT 回答;资料不足时说“不确定”,不要编造。<br><br>
|
||||
<b>CONTEXT</b><br>
|
||||
<mark>[退款政策 v2026Q2]</mark> 购买后 7 天内且未使用核心服务,可全额退款。<br><br>
|
||||
<b>USER</b><br>
|
||||
客户买了 3 天,还没使用,可以退吗?
|
||||
</div>
|
||||
<div class="stack">
|
||||
<div class="stack-layer"><div class="diagram-title">提示词工程</div><div class="stack-items"><div class="mini"><strong>角色</strong><span>你是谁</span></div><div class="mini"><strong>边界</strong><span>只能基于资料</span></div><div class="mini"><strong>格式</strong><span>结论、理由、来源</span></div></div></div>
|
||||
<div class="stack-layer"><div class="diagram-title" style="background:linear-gradient(135deg,#0aa58f,#14c8bf)">安全兜底</div><div class="stack-items"><div class="mini"><strong>不知道</strong><span>就说不确定</span></div><div class="mini"><strong>冲突</strong><span>说明版本差异</span></div><div class="mini"><strong>权限</strong><span>不泄露资料</span></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>System Prompt + Context + User Question</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="card soft mt"><p class="lead" style="font-size:20px;margin-top:0">RAG 找资料;提示词规定资料的使用方式。</p></div>
|
||||
<div class="footer"><span>System Prompt + Context + User Question</span><span class="page"></span></div>
|
||||
<div class="notes">这一页承接用户大纲:给到 LLM 的时候需要系统提示词,由此引出提示词工程。提示词工程重点不是花哨话术,而是角色、边界、格式、引用和兜底。</div>
|
||||
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="Agent">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Agent</span><span>复杂任务的分工协作</span></div>
|
||||
<p class="kicker">复杂任务</p>
|
||||
<h2>复杂任务:多步骤、多角色、多 LLM 协作</h2>
|
||||
<div class="agent-map">
|
||||
<div class="agent"><span class="tag">规划者</span><h3 class="mt-sm">拆任务</h3><p>规划检索、工具调用和结果组织。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="agent"><span class="tag mint">检索者</span><h3 class="mt-sm">查资料</h3><p>使用 RAG 从知识库里找依据,必要时多轮检索。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="agent"><span class="tag orange">执行者</span><h3 class="mt-sm">调用工具</h3><p>查订单、建工单、读数据库、调用业务系统接口。</p></div>
|
||||
</div>
|
||||
<div class="grid2 mt">
|
||||
<div class="card"><h3>Agent</h3><p class="lead" style="font-size:19px;margin-top:8px">目标驱动流程:规划步骤、选择工具、读取结果、继续推进。</p></div>
|
||||
<div class="card soft"><h3>和 RAG 的关系</h3><p class="lead" style="font-size:19px;margin-top:8px">RAG 提供知识入口;Agent 负责任务编排。</p></div>
|
||||
</div>
|
||||
<div class="footer"><span>RAG 是知识入口,Agent 是任务编排</span><span class="page"></span></div>
|
||||
<div class="notes">不要把 Agent 讲玄。它就是更复杂任务里的规划和编排:可能一个 LLM 规划,一个 LLM 检索,一个 LLM 写答案,也可能调用外部工具。</div>
|
||||
|
||||
<div class="top"><div class="chapter">10</div><div class="head"><h2>复杂任务需要 Agent</h2><p>当任务不只是“答一句话”,就需要规划、检索、执行、校验等分工。</p></div><div class="brand"><div class="brand-mark">A</div><span>任务编排</span></div></div>
|
||||
<div class="content">
|
||||
<div class="agent-map">
|
||||
<div class="agent-card"><div class="icon">规</div><h3>规划者</h3><p>拆步骤,决定先查什么、再调用什么工具。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="agent-card"><div class="icon">查</div><h3>检索者</h3><p>使用 RAG 找依据,必要时多轮检索。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="agent-card"><div class="icon">执</div><h3>执行者</h3><p>查订单、建工单、读数据库、调用接口。</p></div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">R</div><div><strong>RAG</strong><span>提供知识入口</span></div></div>
|
||||
<div class="value"><div class="vicon">P</div><div><strong>Prompt</strong><span>规定回答规则</span></div></div>
|
||||
<div class="value"><div class="vicon">A</div><div><strong>Agent</strong><span>负责任务编排</span></div></div>
|
||||
<div class="value"><div class="vicon">T</div><div><strong>Tools</strong><span>执行外部动作</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Agent = Plan + Retrieve + Act + Check</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="MCP">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>MCP</span><span>工具连接</span></div>
|
||||
<p class="kicker">MCP</p>
|
||||
<h2>MCP:让 Agent 稳定连接外部工具和业务系统</h2>
|
||||
<div class="mcp-grid">
|
||||
<div class="mcp-card"><span class="tag">统一接口</span><h3 class="mt-sm">工具接入规范</h3><p class="small mt-sm">把不同系统的能力包装成模型可调用的工具。</p></div>
|
||||
<div class="mcp-card"><span class="tag mint">上下文供给</span><h3 class="mt-sm">读取外部信息</h3><p class="small mt-sm">查数据库、读文件、取工单、访问知识系统。</p></div>
|
||||
<div class="mcp-card"><span class="tag orange">动作执行</span><h3 class="mt-sm">调用业务能力</h3><p class="small mt-sm">创建工单、查询订单、发送通知、写入结果。</p></div>
|
||||
</div>
|
||||
<div class="tool-list">
|
||||
<span>CRM</span><span>工单</span><span>数据库</span><span>搜索</span><span>文件</span>
|
||||
</div>
|
||||
<div class="card soft mt"><p class="lead" style="font-size:20px;margin-top:0">RAG 负责查知识;Agent 负责编排任务;MCP 负责连接工具。</p></div>
|
||||
<div class="footer"><span>RAG · Agent · MCP</span><span class="page"></span></div>
|
||||
<div class="notes">这页讲 MCP。它不需要展开协议细节,只要说明 MCP 是让模型/Agent 稳定连接外部工具和系统的接口层。</div>
|
||||
|
||||
<div class="top"><div class="chapter">11</div><div class="head"><h2>MCP:让 Agent 连接工具</h2><p>MCP 可以理解为模型/Agent 调用外部系统的一套统一连接方式。</p></div><div class="brand"><div class="brand-mark">M</div><span>工具连接</span></div></div>
|
||||
<div class="content">
|
||||
<div class="tool-bus">
|
||||
<div class="card"><span class="tag">Agent</span><h3 style="margin-top:14px">会规划任务</h3><p style="margin-top:10px">但真正查数据、改状态、发通知,需要连接业务系统。</p></div>
|
||||
<div class="bus">MCP<br><span style="font-size:14px;font-weight:700">统一工具接口 / 上下文供给 / 动作执行</span></div>
|
||||
<div class="tools">
|
||||
<div class="tool">CRM<span>客户资料</span></div>
|
||||
<div class="tool">工单<span>创建 / 查询</span></div>
|
||||
<div class="tool">数据库<span>读数据</span></div>
|
||||
<div class="tool">文件<span>读文档</span></div>
|
||||
<div class="tool">搜索<span>查外部信息</span></div>
|
||||
<div class="tool">消息<span>发送通知</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">知</div><div><strong>RAG</strong><span>查知识</span></div></div>
|
||||
<div class="value"><div class="vicon">编</div><div><strong>Agent</strong><span>编排任务</span></div></div>
|
||||
<div class="value"><div class="vicon">接</div><div><strong>MCP</strong><span>连接工具</span></div></div>
|
||||
<div class="value"><div class="vicon">做</div><div><strong>业务系统</strong><span>完成动作</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Model Context Protocol</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="总结">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Takeaway</span><span>关键链路</span></div>
|
||||
<p class="kicker">核心链路</p>
|
||||
<h2>RAG → LLM 限制 → 切片 → 向量化 → 语义检索 → 排序 → 提示词 → Agent → MCP</h2>
|
||||
<div class="summary">
|
||||
<div class="card"><span class="tag rose">限制</span><h3 class="mt-sm">LLM 不能吃下全部知识</h3><p class="small mt-sm">上下文有限、会幻觉、专注度和顺序都不稳定。</p></div>
|
||||
<div class="card"><span class="tag mint">建库</span><h3 class="mt-sm">资料要先整理成片段</h3><p class="small mt-sm">清洗、切片、向量化、加元数据,再放入向量库。</p></div>
|
||||
<div class="card"><span class="tag orange">检索</span><h3 class="mt-sm">提问时先找资料</h3><p class="small mt-sm">召回候选,再排序过滤,把最相关内容放进上下文。</p></div>
|
||||
<div class="card"><span class="tag">扩展</span><h3 class="mt-sm">Agent + MCP</h3><p class="small mt-sm">Agent 编排多步骤任务;MCP 连接外部工具和系统。</p></div>
|
||||
</div>
|
||||
<div class="card soft mt"><p class="lead" style="font-size:21px;margin-top:0">RAG 不是替代 LLM,而是给 LLM 配一套“会查资料的工作台”。</p></div>
|
||||
<div class="footer"><span>End</span><span class="page"></span></div>
|
||||
<div class="notes">收尾不要再加新概念。重复主线:LLM 有限制,所以需要 RAG;RAG 后台建库,前台检索排序,再通过提示词交给 LLM;复杂任务用 Agent。</div>
|
||||
|
||||
<div class="top"><div class="chapter">12</div><div class="head"><h2>入门之后,要抓住这条主线</h2><p>LLM 有限制,所以需要 RAG;RAG 把资料找准,再交给 LLM 生成。</p></div><div class="brand"><div class="brand-mark">✓</div><span>核心链路</span></div></div>
|
||||
<div class="content">
|
||||
<div class="flow">
|
||||
<div class="step"><div class="num">1</div><h3>LLM</h3><p>负责理解和表达,但不是企业知识库。</p></div>
|
||||
<div class="step"><div class="num">2</div><h3>限制</h3><p>上下文、幻觉、专注度、顺序带来风险。</p></div>
|
||||
<div class="step"><div class="num">3</div><h3>RAG</h3><p>后台建库;前台检索;排序后拼上下文。</p></div>
|
||||
<div class="step"><div class="num">4</div><h3>Prompt</h3><p>规定角色、边界、格式、兜底和安全。</p></div>
|
||||
<div class="step"><div class="num">5</div><h3>Agent + MCP</h3><p>复杂任务用 Agent 编排,用 MCP 连接工具。</p></div>
|
||||
</div>
|
||||
<div class="stack-layer" style="margin-top:24px;text-align:center">
|
||||
<div class="diagram-title">一句话总结</div>
|
||||
<h3 style="font-size:30px;margin-top:18px;color:#061b4e">RAG 不是替代 LLM,而是给 LLM 配一套“会查资料的工作台”。</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>End</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
@@ -418,6 +496,7 @@ ul{margin:14px 0 0;padding-left:22px;color:var(--muted);line-height:1.85;font-si
|
||||
function render(){
|
||||
slides.forEach((s,i)=>s.classList.toggle('active',i===idx));
|
||||
document.querySelectorAll('.page').forEach(el=>{el.textContent=(idx+1)+' / '+slides.length});
|
||||
document.querySelectorAll('.page-corner').forEach(el=>{el.textContent=String(idx+1).padStart(2,'0')});
|
||||
navIndex.textContent = (idx+1)+' / '+slides.length;
|
||||
prevBtn.disabled = idx === 0;
|
||||
nextBtn.disabled = idx === slides.length - 1;
|
||||
|
||||
@@ -6,398 +6,476 @@
|
||||
<title>RAG 入门:原理、流程与使用</title>
|
||||
<style>
|
||||
:root{
|
||||
--bg:#f6f8fb;
|
||||
--paper:#ffffff;
|
||||
--ink:#0a2540;
|
||||
--muted:#486176;
|
||||
--soft:#eef3f8;
|
||||
--line:#d9e2ec;
|
||||
--blue:#1d4ed8;
|
||||
--mint:#0f9f8f;
|
||||
--orange:#d97706;
|
||||
--rose:#e11d48;
|
||||
--shadow:0 14px 34px rgba(10,37,64,.10),0 2px 7px rgba(10,37,64,.05);
|
||||
--blue:#0b63f6;
|
||||
--blue2:#0f8bff;
|
||||
--cyan:#15c8c2;
|
||||
--green:#12a57d;
|
||||
--navy:#061b4e;
|
||||
--ink:#102047;
|
||||
--muted:#51627f;
|
||||
--line:#c8dcff;
|
||||
--soft:#f3f8ff;
|
||||
--glass:rgba(255,255,255,.86);
|
||||
--shadow:0 20px 46px rgba(16,45,100,.16),0 2px 10px rgba(16,45,100,.08);
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
html,body{margin:0;width:100%;height:100%;overflow:hidden;background:var(--bg);color:var(--ink);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans SC","Microsoft YaHei",Arial,sans-serif}
|
||||
.deck{position:relative;width:100vw;height:100vh;overflow:hidden;background:linear-gradient(135deg,#f8fafc,#eef3f8)}
|
||||
.slide{position:absolute;inset:0;display:none;padding:72px 88px;background:radial-gradient(circle at 85% 12%,rgba(29,78,216,.08),transparent 28%),var(--paper);align-items:center;justify-content:center}
|
||||
.slide.active{display:flex}
|
||||
.slide-inner{width:100%;max-height:calc(100vh - 150px)}
|
||||
.slide::before{content:"";position:absolute;left:0;top:0;bottom:0;width:8px;background:linear-gradient(180deg,var(--blue),var(--mint))}
|
||||
.topline{position:absolute;left:88px;right:88px;top:28px;display:flex;justify-content:space-between;align-items:center;font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:#8aa0b5}
|
||||
.footer{position:absolute;left:88px;right:88px;bottom:24px;display:flex;justify-content:space-between;color:#8aa0b5;font-size:12px}
|
||||
.progress{position:fixed;left:0;right:0;bottom:0;height:4px;background:#dbe4ee;z-index:20}
|
||||
.progress span{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--blue),var(--mint));transition:width .2s ease}
|
||||
.nav-controls{position:fixed;right:28px;bottom:26px;z-index:30;display:flex;align-items:center;gap:8px;padding:8px;border:1px solid rgba(10,37,64,.12);border-radius:999px;background:rgba(255,255,255,.92);box-shadow:0 8px 26px rgba(10,37,64,.14);backdrop-filter:blur(10px)}
|
||||
.nav-btn{width:38px;height:38px;border:0;border-radius:50%;background:#0a2540;color:#fff;font-size:22px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer}
|
||||
.nav-btn:disabled{opacity:.32;cursor:not-allowed}
|
||||
.nav-index{min-width:58px;text-align:center;font-size:13px;font-weight:800;color:var(--muted)}
|
||||
.kicker{margin:0 0 12px;color:var(--blue);font-size:15px;font-weight:700;letter-spacing:.1em;text-transform:uppercase}
|
||||
html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#eef3fb;color:var(--ink);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans SC","Microsoft YaHei",Arial,sans-serif}
|
||||
body{display:grid;place-items:center}
|
||||
h1,h2,h3,h4,p{margin:0}
|
||||
h1{font-size:68px;line-height:1.05;letter-spacing:0;font-weight:800;max-width:980px}
|
||||
h2{font-size:44px;line-height:1.15;letter-spacing:0;font-weight:760;max-width:1040px}
|
||||
h3{font-size:24px;line-height:1.25;font-weight:740}
|
||||
h4{font-size:18px;line-height:1.3;font-weight:730}
|
||||
.lead{font-size:23px;line-height:1.55;color:var(--muted);max-width:900px;margin-top:22px}
|
||||
.muted{color:var(--muted)}
|
||||
.accent{background:linear-gradient(135deg,var(--blue),var(--mint));-webkit-background-clip:text;background-clip:text;color:transparent}
|
||||
.row{display:flex;gap:16px;align-items:stretch}
|
||||
.grid2{display:grid;grid-template-columns:repeat(2,1fr);gap:18px}
|
||||
.grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
|
||||
.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
|
||||
.mt{margin-top:30px}.mt-sm{margin-top:16px}.mt-lg{margin-top:42px}
|
||||
.card{background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:22px}
|
||||
.card.soft{background:var(--soft);box-shadow:none}
|
||||
.tag{display:inline-flex;align-items:center;justify-content:center;border-radius:999px;padding:5px 12px;background:#edf4ff;color:var(--blue);font-size:12px;font-weight:800}
|
||||
.tag.mint{background:#e8faf7;color:var(--mint)}
|
||||
.tag.orange{background:#fff4df;color:var(--orange)}
|
||||
.tag.rose{background:#fff0f4;color:var(--rose)}
|
||||
.num{width:40px;height:40px;border-radius:9px;background:var(--blue);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;margin-bottom:14px}
|
||||
.num.mint{background:var(--mint)}.num.orange{background:var(--orange)}.num.rose{background:var(--rose)}
|
||||
.pillbar{display:flex;flex-wrap:wrap;gap:10px;margin-top:32px}
|
||||
.pill{border:1px solid var(--line);background:#fff;border-radius:999px;padding:8px 14px;font-size:14px;color:var(--muted);font-weight:650}
|
||||
.stage{display:grid;grid-template-columns:1fr 52px 1fr 52px 1fr;gap:10px;align-items:center;margin-top:38px}
|
||||
.stage .box{text-align:center;padding:28px 18px;border:1px solid var(--line);border-radius:12px;background:#fff;box-shadow:var(--shadow)}
|
||||
.stage .box.main{background:var(--blue);color:#fff}
|
||||
.stage .box.main p{color:#dbeafe}
|
||||
.arrow{font-size:34px;color:#93a4b5;text-align:center;font-weight:900}
|
||||
.compare{display:grid;grid-template-columns:1fr 88px 1fr;gap:22px;align-items:center;margin-top:34px}
|
||||
.compare .mid{text-align:center;font-size:42px;color:#9aacbd;font-weight:900}
|
||||
ul{margin:14px 0 0;padding-left:22px;color:var(--muted);line-height:1.85;font-size:18px}
|
||||
.small{font-size:14px;line-height:1.55;color:var(--muted)}
|
||||
.flow{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-top:30px}
|
||||
.flow .step{position:relative;background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:18px;min-height:150px}
|
||||
.flow .step h4{margin:8px 0 6px}.flow .step p{font-size:13px;line-height:1.5;color:var(--muted)}
|
||||
.flow .step.hot{border-color:rgba(29,78,216,.45);box-shadow:0 0 0 3px rgba(29,78,216,.10),var(--shadow)}
|
||||
.chunks{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:24px}
|
||||
.chunk{border:1px dashed #9fb0c2;background:#fff;border-radius:9px;padding:17px;min-height:122px}
|
||||
.chunk b{color:var(--blue);font-size:14px}.chunk p{font-size:13px;line-height:1.6;color:var(--muted);margin-top:8px}
|
||||
.vector{display:grid;grid-template-columns:repeat(10,1fr);gap:6px;margin-top:14px}
|
||||
.bar{height:44px;border-radius:5px;background:var(--blue);opacity:.28}.bar:nth-child(2n){opacity:.55}.bar:nth-child(3n){opacity:.82}.bar:nth-child(5n){opacity:.42}
|
||||
.search{display:grid;grid-template-columns:1.02fr .98fr;gap:20px;margin-top:26px}
|
||||
.result{display:flex;gap:12px;border:1px solid var(--line);border-radius:9px;background:#fff;padding:14px;margin-top:10px}
|
||||
.rank{width:34px;height:34px;border-radius:8px;background:#edf4ff;color:var(--blue);display:flex;align-items:center;justify-content:center;font-weight:900;flex-shrink:0}
|
||||
.prompt{background:#09213a;color:#e8f1ff;border-radius:12px;box-shadow:var(--shadow);padding:22px 24px;font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;font-size:15px;line-height:1.85}
|
||||
.prompt .dim{color:#8fb1d6}.prompt .mark{color:#fde68a}
|
||||
.agent-map{display:grid;grid-template-columns:1fr 46px 1fr 46px 1fr;gap:10px;align-items:center;margin-top:28px}
|
||||
.agent{background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:20px;text-align:center;min-height:170px}
|
||||
.agent p{font-size:13px;line-height:1.55;color:var(--muted);margin-top:8px}
|
||||
.summary{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:34px}
|
||||
.summary .card{min-height:150px}
|
||||
.learning-map{display:grid;grid-template-columns:1fr 38px 1fr 38px 1fr 38px 1fr 38px 1fr;gap:10px;align-items:stretch;margin-top:34px}
|
||||
.map-card{background:#fff;border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow);padding:20px 16px;min-height:270px}
|
||||
.map-card .num{margin-bottom:16px}
|
||||
.map-card h3{font-size:21px}
|
||||
.map-list{margin:14px 0 0;padding-left:18px;color:var(--muted);font-size:14px;line-height:1.75}
|
||||
.map-arrow{display:flex;align-items:center;justify-content:center;font-size:28px;color:#9aacbd;font-weight:900}
|
||||
.mini-flow{display:grid;grid-template-columns:1fr 44px 1fr 44px 1fr;gap:10px;align-items:center;margin-top:32px}
|
||||
.mini-flow .node{background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:18px;text-align:center;min-height:126px}
|
||||
.mini-flow .node.main{background:var(--blue);color:#fff}
|
||||
.mini-flow .node.main p{color:#dbeafe}
|
||||
.mini-flow p{font-size:13px;line-height:1.5;color:var(--muted);margin-top:6px}
|
||||
.mcp-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;margin-top:30px}
|
||||
.mcp-card{background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:22px;min-height:205px}
|
||||
.tool-list{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-top:24px}
|
||||
.tool-list span{display:flex;align-items:center;justify-content:center;min-height:58px;border-radius:10px;background:var(--soft);border:1px solid var(--line);font-size:14px;font-weight:800;color:var(--muted)}
|
||||
.deck{position:relative;width:100vw;height:100vh;display:grid;place-items:center;background:radial-gradient(circle at 8% 15%,rgba(11,99,246,.13),transparent 24%),radial-gradient(circle at 90% 80%,rgba(21,200,194,.16),transparent 28%),#edf3fb}
|
||||
.slide{position:relative;display:none;width:min(100vw,calc(100vh * 16 / 9));aspect-ratio:16/9;max-height:100vh;background:#fff;overflow:hidden;box-shadow:var(--shadow);padding:46px 56px 42px}
|
||||
.slide.active{display:block}
|
||||
.slide::before{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(12,97,246,.05) 1px,transparent 1px),linear-gradient(rgba(12,97,246,.05) 1px,transparent 1px);background-size:36px 36px;mask-image:radial-gradient(ellipse at 45% 40%,black 18%,transparent 82%);pointer-events:none}
|
||||
.slide::after{content:"";position:absolute;left:-120px;bottom:-70px;width:580px;height:180px;background:repeating-linear-gradient(155deg,rgba(11,99,246,.11) 0 2px,transparent 2px 12px);transform:skewX(-18deg);opacity:.55;pointer-events:none}
|
||||
.slide > *{position:relative;z-index:1}
|
||||
.slide-inner{height:100%;display:flex;flex-direction:column;gap:18px}
|
||||
.top{height:66px;display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:22px;border-bottom:2px solid #dbe8ff;padding-bottom:14px}
|
||||
.chapter{height:56px;min-width:122px;display:flex;align-items:center;justify-content:center;color:#fff;font-size:30px;font-weight:900;letter-spacing:.03em;background:linear-gradient(135deg,#0054e6,#0d82ff);clip-path:polygon(0 0,82% 0,100% 50%,82% 100%,0 100%);box-shadow:0 10px 22px rgba(11,99,246,.24)}
|
||||
.head h2{font-size:34px;line-height:1.05;font-weight:900;letter-spacing:0;color:#061b4e}
|
||||
.head p{font-size:15px;color:var(--muted);margin-top:6px}
|
||||
.brand{display:flex;align-items:center;gap:10px;color:var(--blue);font-weight:900}
|
||||
.brand-mark{width:44px;height:44px;border:2px solid var(--blue);border-radius:12px;display:grid;place-items:center;background:#fff;font-weight:900}
|
||||
.content{flex:1;min-height:0;display:flex;flex-direction:column;justify-content:center}
|
||||
.footer{height:42px;display:flex;align-items:flex-end;justify-content:space-between;color:#7d91b5;font-size:11px;letter-spacing:.14em;text-transform:uppercase;border-top:1px solid #dbe8ff;padding-top:12px}
|
||||
.page-corner{position:absolute;right:0;bottom:0;width:86px;height:52px;background:linear-gradient(135deg,#0b63f6,#0050ca);clip-path:polygon(38% 0,100% 0,100% 100%,0 100%);color:#fff;font-size:18px;font-weight:900;display:flex;align-items:flex-end;justify-content:flex-end;padding:0 18px 12px;z-index:3}
|
||||
.kicker{font-size:13px;font-weight:900;letter-spacing:.18em;color:var(--blue);text-transform:uppercase;margin-bottom:8px}
|
||||
.big-title{font-size:58px;line-height:1.08;font-weight:950;color:#061b4e;letter-spacing:0}
|
||||
.sub{font-size:20px;line-height:1.55;color:var(--muted);max-width:760px;margin-top:14px}
|
||||
.accent{background:linear-gradient(135deg,var(--blue),var(--cyan));-webkit-background-clip:text;background-clip:text;color:transparent}
|
||||
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:18px}
|
||||
.grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
|
||||
.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
|
||||
.card{background:var(--glass);border:1.5px solid var(--line);border-radius:14px;box-shadow:0 12px 26px rgba(38,91,160,.09);padding:18px}
|
||||
.card h3{font-size:20px;color:#08205d;font-weight:900}
|
||||
.card h4{font-size:17px;color:#08205d;font-weight:900}
|
||||
.card p,.card li{font-size:13px;line-height:1.55;color:var(--muted)}
|
||||
.tag{display:inline-flex;align-items:center;justify-content:center;height:28px;padding:0 12px;border-radius:999px;background:#eaf3ff;color:var(--blue);font-size:12px;font-weight:900}
|
||||
.tag.green{background:#e7fbf5;color:var(--green)}
|
||||
.tag.cyan{background:#e7fbff;color:#0796a5}
|
||||
.tag.warn{background:#fff4de;color:#d27a00}
|
||||
.tag.red{background:#fff0f4;color:#d81948}
|
||||
.icon{width:56px;height:56px;border-radius:50%;display:grid;place-items:center;background:#fff;border:1px solid #c8dcff;box-shadow:0 8px 18px rgba(11,99,246,.12);color:var(--blue);font-size:23px;font-weight:950;margin-bottom:10px}
|
||||
.ribbon-row{display:grid;grid-template-columns:175px 1fr;gap:18px;align-items:center;margin:14px 0}
|
||||
.ribbon{height:78px;display:flex;align-items:center;gap:14px;color:#fff;background:linear-gradient(135deg,var(--blue),#0050d8);clip-path:polygon(0 0,88% 0,100% 50%,88% 100%,0 100%);border-radius:10px 0 0 10px;padding:0 22px;font-size:22px;font-weight:950}
|
||||
.ribbon.green{background:linear-gradient(135deg,#08a88f,#06c1b8)}
|
||||
.ribbon.navy{background:linear-gradient(135deg,#12327a,#0b63f6)}
|
||||
.ribbon-line{min-height:78px;border:1.5px solid var(--line);border-radius:12px;background:rgba(255,255,255,.78);display:grid;grid-template-columns:90px 1fr;align-items:center;padding:14px 22px}
|
||||
.dot-list{display:grid;gap:7px}
|
||||
.dot-list span{position:relative;padding-left:16px;color:#1b2b58;font-size:14px;line-height:1.4}
|
||||
.dot-list span::before{content:"";position:absolute;left:0;top:.62em;width:6px;height:6px;border-radius:50%;background:var(--blue)}
|
||||
.diagram-title{height:34px;display:inline-flex;align-items:center;padding:0 18px;border-radius:10px;background:linear-gradient(135deg,var(--blue),#0053df);color:#fff;font-weight:950;box-shadow:0 10px 18px rgba(11,99,246,.22)}
|
||||
.stack{display:grid;gap:12px}
|
||||
.stack-layer{position:relative;border:1.5px solid #a7c8ff;border-radius:20px;background:linear-gradient(180deg,#fff,rgba(237,247,255,.92));box-shadow:0 14px 26px rgba(11,99,246,.12);padding:18px 20px}
|
||||
.stack-layer::after{content:"";position:absolute;left:42px;right:42px;bottom:-11px;height:18px;border-radius:0 0 22px 22px;background:linear-gradient(90deg,rgba(11,99,246,.18),rgba(21,200,194,.18));z-index:-1}
|
||||
.stack-items{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:12px}
|
||||
.mini{background:#fff;border:1px solid #d7e6ff;border-radius:12px;padding:13px;text-align:center;min-height:92px}
|
||||
.mini strong{display:block;font-size:16px;color:#08205d;margin-bottom:4px}
|
||||
.mini span{font-size:12px;line-height:1.35;color:var(--muted)}
|
||||
.side-notes{display:grid;gap:20px}
|
||||
.side-note{display:grid;grid-template-columns:56px 1fr;gap:12px;align-items:center}
|
||||
.side-note .round{width:52px;height:52px;border-radius:50%;border:2px solid #d7e6ff;background:#fff;display:grid;place-items:center;color:var(--blue);font-weight:950;font-size:20px}
|
||||
.side-note strong{display:block;color:var(--blue);font-size:16px}
|
||||
.side-note span{font-size:12px;color:var(--muted)}
|
||||
.value-strip{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-top:18px;border:1px solid #d8e6ff;border-radius:14px;background:rgba(255,255,255,.76);padding:12px 14px}
|
||||
.value{display:grid;grid-template-columns:42px 1fr;gap:10px;align-items:center;border-right:1px solid #d8e6ff}
|
||||
.value:last-child{border-right:0}
|
||||
.value .vicon{width:38px;height:38px;border-radius:10px;background:#eaf3ff;color:var(--blue);display:grid;place-items:center;font-weight:950}
|
||||
.value strong{display:block;font-size:15px;color:var(--blue)}
|
||||
.value span{font-size:11px;color:var(--muted)}
|
||||
.flow{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;align-items:stretch}
|
||||
.step{position:relative;min-height:142px;padding:16px;border:1.5px solid #bdd7ff;border-radius:14px;background:#fff;box-shadow:0 10px 22px rgba(11,99,246,.08)}
|
||||
.step::after{content:"";position:absolute;right:-13px;top:50%;width:14px;height:2px;background:#8db9ff}
|
||||
.step:last-child::after{display:none}
|
||||
.step .num{width:34px;height:34px;border-radius:9px;background:linear-gradient(135deg,var(--blue),var(--cyan));color:#fff;display:grid;place-items:center;font-weight:950;margin-bottom:10px}
|
||||
.step h3{font-size:18px;color:#08205d;font-weight:950}
|
||||
.step p{font-size:12px;line-height:1.45;color:var(--muted);margin-top:6px}
|
||||
.step.hot{border-color:var(--cyan);box-shadow:0 0 0 4px rgba(21,200,194,.12),0 10px 22px rgba(11,99,246,.08)}
|
||||
.arrow{font-size:24px;color:#75a7ff;font-weight:950;text-align:center}
|
||||
.compare{display:grid;grid-template-columns:1fr 82px 1fr;gap:16px;align-items:center}
|
||||
.compare .mid{height:82px;border-radius:50%;display:grid;place-items:center;background:linear-gradient(135deg,var(--blue),var(--cyan));color:#fff;font-size:26px;font-weight:950;box-shadow:0 12px 24px rgba(11,99,246,.24)}
|
||||
.center-badge{width:150px;height:150px;border-radius:36px;background:linear-gradient(135deg,#0b63f6,#12c8c2);color:#fff;display:grid;place-items:center;text-align:center;font-size:28px;font-weight:950;box-shadow:0 20px 38px rgba(11,99,246,.28);margin:auto}
|
||||
.limit-grid{display:grid;grid-template-columns:1fr 170px 1fr;gap:18px;align-items:center}
|
||||
.limit-col{display:grid;gap:14px}
|
||||
.limit{display:grid;grid-template-columns:50px 1fr;gap:12px;align-items:center;border:1.5px solid #cfe0ff;border-radius:14px;background:#fff;padding:14px}
|
||||
.limit .n{width:46px;height:46px;border-radius:12px;background:#eaf3ff;color:var(--blue);display:grid;place-items:center;font-weight:950}
|
||||
.pipeline{display:grid;grid-template-columns:1.1fr 1.2fr 1.1fr;gap:18px;align-items:center}
|
||||
.pipe-card{border:1.5px solid #cfe0ff;border-radius:18px;background:#fff;padding:18px;min-height:260px}
|
||||
.bad-list{display:grid;gap:10px;margin-top:14px}
|
||||
.bad-list span{border:1px dashed #ffb4c4;border-radius:10px;background:#fff7fa;color:#a6193c;padding:10px;font-size:13px}
|
||||
.filter{display:grid;place-items:center;min-height:280px}
|
||||
.filter .funnel{width:190px;height:230px;background:linear-gradient(180deg,#e9f3ff,#fff);clip-path:polygon(8% 0,92% 0,62% 48%,62% 100%,38% 100%,38% 48%);border:2px solid #9fc3ff;filter:drop-shadow(0 12px 20px rgba(11,99,246,.16));display:grid;place-items:center;color:var(--blue);font-size:28px;font-weight:950}
|
||||
.chunks{display:grid;grid-template-columns:1.1fr .9fr;gap:18px;align-items:center}
|
||||
.doc{border:1.5px solid #cfe0ff;border-radius:18px;background:#fff;padding:18px}
|
||||
.slice{border-left:5px solid var(--blue);border-radius:10px;background:#f6faff;padding:12px;margin-top:10px}
|
||||
.vector-bars{display:grid;grid-template-columns:repeat(12,1fr);gap:6px;margin-top:16px}
|
||||
.bar{height:56px;border-radius:7px;background:var(--blue);opacity:.25}
|
||||
.bar:nth-child(2n){opacity:.45}.bar:nth-child(3n){opacity:.75}.bar:nth-child(5n){opacity:.9}
|
||||
.rank-list{display:grid;gap:10px}
|
||||
.rank{display:grid;grid-template-columns:42px 1fr auto;gap:12px;align-items:center;border:1.5px solid #cfe0ff;border-radius:12px;background:#fff;padding:12px}
|
||||
.rank .rnum{width:38px;height:38px;border-radius:10px;background:#eaf3ff;color:var(--blue);display:grid;place-items:center;font-weight:950}
|
||||
.score{font-size:20px;font-weight:950;color:var(--green)}
|
||||
.prompt-box{background:#071d48;color:#e7f0ff;border-radius:18px;padding:18px 20px;font-family:"SFMono-Regular",Consolas,"Liberation Mono",monospace;font-size:13px;line-height:1.65;box-shadow:0 18px 34px rgba(7,29,72,.24)}
|
||||
.prompt-box b{color:#7dd3fc}.prompt-box mark{background:rgba(250,204,21,.18);color:#fde68a;padding:1px 4px;border-radius:4px}
|
||||
.agent-map{display:grid;grid-template-columns:1fr 70px 1fr 70px 1fr;gap:10px;align-items:center}
|
||||
.agent-card{border:1.5px solid #cfe0ff;border-radius:18px;background:#fff;padding:18px;text-align:center;min-height:190px}
|
||||
.agent-card .icon{margin:0 auto 12px}
|
||||
.tool-bus{display:grid;grid-template-columns:1fr 1.3fr 1fr;gap:18px;align-items:center}
|
||||
.bus{height:96px;border-radius:22px;background:linear-gradient(135deg,var(--blue),var(--cyan));color:#fff;display:grid;place-items:center;text-align:center;font-size:26px;font-weight:950;box-shadow:0 16px 30px rgba(11,99,246,.24)}
|
||||
.tools{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}
|
||||
.tool{border:1.5px solid #cfe0ff;background:#fff;border-radius:14px;padding:15px;text-align:center;font-weight:900;color:#08205d}
|
||||
.tool span{display:block;font-size:12px;color:var(--muted);font-weight:500;margin-top:4px}
|
||||
.cover{padding:58px 70px 52px}
|
||||
.cover .slide-inner{justify-content:center}
|
||||
.cover-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:34px;align-items:center}
|
||||
.cover-panel{border:1.5px solid #cfe0ff;background:rgba(255,255,255,.82);border-radius:24px;padding:26px;box-shadow:0 14px 30px rgba(11,99,246,.12)}
|
||||
.cover-visual{position:relative;height:440px}
|
||||
.orb{position:absolute;border-radius:50%;background:linear-gradient(135deg,var(--blue),var(--cyan));box-shadow:0 24px 44px rgba(11,99,246,.24)}
|
||||
.orb.one{width:205px;height:205px;left:160px;top:64px;display:grid;place-items:center;color:#fff;font-size:54px;font-weight:950}
|
||||
.ring{position:absolute;border:2px dashed #9ac1ff;border-radius:50%;inset:22px;animation:spin 18s linear infinite}
|
||||
@keyframes spin{to{transform:rotate(360deg)}}
|
||||
.orbit-card{position:absolute;width:150px;border:1px solid #cfe0ff;border-radius:16px;background:#fff;padding:14px;text-align:center;box-shadow:0 12px 22px rgba(11,99,246,.13)}
|
||||
.orbit-card.a{left:16px;top:36px}.orbit-card.b{right:18px;top:56px}.orbit-card.c{left:40px;bottom:52px}.orbit-card.d{right:42px;bottom:28px}
|
||||
.orbit-card strong{display:block;color:var(--blue);font-size:18px}.orbit-card span{font-size:12px;color:var(--muted)}
|
||||
.nav-controls{position:fixed;left:50%;bottom:10px;transform:translateX(-50%);z-index:30;display:flex;align-items:center;gap:6px;padding:6px;border:1px solid rgba(16,32,71,.12);border-radius:999px;background:rgba(255,255,255,.74);box-shadow:0 8px 24px rgba(16,32,71,.12);backdrop-filter:blur(10px);opacity:.72;transition:opacity .18s ease,background .18s ease}
|
||||
.nav-controls:hover,.nav-controls:focus-within{opacity:1;background:rgba(255,255,255,.94)}
|
||||
.nav-btn{width:32px;height:32px;border:0;border-radius:50%;background:#061b4e;color:#fff;font-size:19px;line-height:1;display:flex;align-items:center;justify-content:center;cursor:pointer}
|
||||
.nav-btn:disabled{opacity:.32;cursor:not-allowed}
|
||||
.nav-index{min-width:58px;text-align:center;font-size:13px;font-weight:900;color:var(--muted)}
|
||||
.progress{position:fixed;left:0;right:0;bottom:0;height:4px;background:#dbe6f6;z-index:25}
|
||||
.progress span{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--blue),var(--cyan));transition:width .2s ease}
|
||||
.notes{display:none}
|
||||
@media (max-aspect-ratio:16/9){
|
||||
.slide{width:calc(100vh * 16 / 9);height:100vh}
|
||||
}
|
||||
@media (max-width:900px){
|
||||
.slide{padding:62px 28px 54px;overflow:auto;align-items:flex-start}
|
||||
.slide-inner{max-height:none}
|
||||
.topline,.footer{left:28px;right:28px}
|
||||
h1{font-size:42px}h2{font-size:32px}.lead{font-size:18px}
|
||||
.grid2,.grid3,.grid4,.flow,.chunks,.search,.summary,.learning-map,.mcp-grid,.tool-list{grid-template-columns:1fr}
|
||||
.stage,.compare,.agent-map,.mini-flow{grid-template-columns:1fr}
|
||||
.arrow,.map-arrow,.compare .mid{display:none}
|
||||
body{overflow:auto;display:block}
|
||||
html,body{height:auto;min-height:100%;overflow:auto}
|
||||
.deck{display:block;height:auto;min-height:100vh;padding:0;background:#fff}
|
||||
.slide{width:100%;height:auto;aspect-ratio:auto;min-height:100vh;box-shadow:none;padding:28px 22px 34px}
|
||||
.slide.active{display:block}
|
||||
.top{height:auto;grid-template-columns:1fr;gap:10px}
|
||||
.chapter{width:112px}
|
||||
.head h2{font-size:28px}
|
||||
.brand{display:none}
|
||||
.big-title{font-size:40px}
|
||||
.content{justify-content:flex-start;padding-top:24px}
|
||||
.cover-grid,.grid2,.grid3,.grid4,.pipeline,.chunks,.tool-bus,.limit-grid,.agent-map{grid-template-columns:1fr}
|
||||
.flow{grid-template-columns:1fr}
|
||||
.step::after,.arrow{display:none}
|
||||
.ribbon-row{grid-template-columns:1fr}
|
||||
.ribbon{clip-path:none;border-radius:12px}
|
||||
.ribbon-line{grid-template-columns:1fr}
|
||||
.value-strip{grid-template-columns:1fr}
|
||||
.value{border-right:0;border-bottom:1px solid #d8e6ff;padding-bottom:8px}
|
||||
.page-corner{display:none}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="deck" id="deck">
|
||||
|
||||
<section class="slide active" data-title="封面">
|
||||
<section class="slide cover active" data-title="封面">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>RAG Primer</span><span>原理和使用</span></div>
|
||||
<p class="kicker">RAG · LLM · Retrieval · Prompt · Agent · MCP</p>
|
||||
<h1>RAG 入门:让 AI <span class="accent">先查资料</span>再回答</h1>
|
||||
<p class="lead">从 LLM 的对话限制出发,理解 RAG 的建库、检索、排序、提示词和 Agent 扩展。</p>
|
||||
<div class="pillbar">
|
||||
<span class="pill">RAG解释</span><span class="pill">LLM解释</span><span class="pill">上下文限制</span><span class="pill">幻觉</span><span class="pill">注意力顺序</span><span class="pill">切片</span><span class="pill">向量化</span><span class="pill">排序</span><span class="pill">语义检索</span><span class="pill">提示词工程</span><span class="pill">AGENTS</span><span class="pill">MCP</span>
|
||||
</div>
|
||||
<div class="footer"><span>RAG 原理和使用</span><span class="page"></span></div>
|
||||
<div class="notes">开场不用讲算法,先讲主线:大模型会说话,但它不是企业知识库。因为它有上下文、幻觉、注意力和顺序方面的限制,所以需要 RAG 这套“先查资料,再组织答案”的机制。</div>
|
||||
|
||||
<div class="cover-grid">
|
||||
<div>
|
||||
<div class="kicker">RAG · LLM · Prompt · Agent · MCP</div>
|
||||
<h1 class="big-title">RAG 入门:让 AI <span class="accent">先查资料</span> 再回答</h1>
|
||||
<p class="sub">从 LLM 的限制讲起,串起知识库建设、语义检索、排序、提示词工程、Agent 和 MCP。</p>
|
||||
<div class="value-strip" style="grid-template-columns:repeat(3,1fr);margin-top:28px">
|
||||
<div class="value"><div class="vicon">01</div><div><strong>先懂限制</strong><span>上下文、幻觉、注意力</span></div></div>
|
||||
<div class="value"><div class="vicon">02</div><div><strong>再懂流程</strong><span>建库、检索、生成</span></div></div>
|
||||
<div class="value"><div class="vicon">03</div><div><strong>最后扩展</strong><span>Agent、MCP、工具</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cover-panel">
|
||||
<div class="cover-visual">
|
||||
<div class="orb one"><div class="ring"></div>RAG</div>
|
||||
<div class="orbit-card a"><strong>LLM</strong><span>理解和生成</span></div>
|
||||
<div class="orbit-card b"><strong>知识库</strong><span>资料与来源</span></div>
|
||||
<div class="orbit-card c"><strong>检索</strong><span>找相关片段</span></div>
|
||||
<div class="orbit-card d"><strong>提示词</strong><span>约束回答</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>RAG Primer</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="目录">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Roadmap</span><span>学习路径</span></div>
|
||||
<p class="kicker">由浅入深</p>
|
||||
<h2>从“会生成”到“会查资料、会调用工具”</h2>
|
||||
<div class="learning-map">
|
||||
<div class="map-card"><div class="num">1</div><h3>基础概念</h3><ul class="map-list"><li>RAG 是什么</li><li>LLM 是什么</li></ul></div>
|
||||
<div class="map-arrow">→</div>
|
||||
<div class="map-card"><div class="num orange">2</div><h3>LLM 限制</h3><ul class="map-list"><li>上下文</li><li>幻觉</li><li>注意力与顺序</li></ul></div>
|
||||
<div class="map-arrow">→</div>
|
||||
<div class="map-card"><div class="num mint">3</div><h3>离线建库</h3><ul class="map-list"><li>资料清洗</li><li>切片</li><li>向量化入库</li></ul></div>
|
||||
<div class="map-arrow">→</div>
|
||||
<div class="map-card"><div class="num">4</div><h3>在线问答</h3><ul class="map-list"><li>语义检索</li><li>排序 / 重排</li><li>提示词工程</li></ul></div>
|
||||
<div class="map-arrow">→</div>
|
||||
<div class="map-card"><div class="num rose">5</div><h3>能力扩展</h3><ul class="map-list"><li>Agents 分工</li><li>MCP 连接工具</li></ul></div>
|
||||
</div>
|
||||
<div class="footer"><span>目录</span><span class="page"></span></div>
|
||||
<div class="notes">这页把路线说清楚。后面每一页都围绕 LLM 限制到 RAG 方案,再到提示词工程和 Agent 的路径推进。</div>
|
||||
|
||||
<div class="top"><div class="chapter">01</div><div class="head"><h2>学习路径</h2><p>由浅入深:先理解问题,再理解方案,最后理解扩展能力。</p></div><div class="brand"><div class="brand-mark">AI</div><span>RAG 入门</span></div></div>
|
||||
<div class="content">
|
||||
<div class="flow">
|
||||
<div class="step hot"><div class="num">1</div><h3>基础概念</h3><p>RAG 是什么;LLM 是什么;两者分别负责什么。</p></div>
|
||||
<div class="step"><div class="num">2</div><h3>LLM 限制</h3><p>上下文有限、会幻觉、长内容专注度下降、顺序不稳定。</p></div>
|
||||
<div class="step"><div class="num">3</div><h3>离线建库</h3><p>资料准备、清洗、切片、元数据、向量化入库。</p></div>
|
||||
<div class="step"><div class="num">4</div><h3>在线问答</h3><p>用户提问、语义检索、候选排序、拼上下文、生成答案。</p></div>
|
||||
<div class="step"><div class="num">5</div><h3>能力扩展</h3><p>提示词工程、多个 LLM 分工、Agent 编排、MCP 连接工具。</p></div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">懂</div><div><strong>概念</strong><span>知道每个词在干什么</span></div></div>
|
||||
<div class="value"><div class="vicon">看</div><div><strong>流程</strong><span>知道一次问答怎么跑</span></div></div>
|
||||
<div class="value"><div class="vicon">抓</div><div><strong>关键</strong><span>切片、排序、提示词</span></div></div>
|
||||
<div class="value"><div class="vicon">扩</div><div><strong>边界</strong><span>Agent 和工具调用</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Roadmap</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="RAG解释">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>RAG</span><span>检索增强生成</span></div>
|
||||
<p class="kicker">RAG 解释</p>
|
||||
<h2>RAG = 先检索资料,再增强上下文,最后生成答案</h2>
|
||||
<div class="mini-flow">
|
||||
<div class="node"><span class="tag">Retrieval</span><h3 class="mt-sm">检索</h3><p>从知识库找到相关资料。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="node main"><span class="tag" style="background:rgba(255,255,255,.18);color:#fff">Augmented</span><h3 class="mt-sm">增强</h3><p>把资料放进上下文。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="node"><span class="tag mint">Generation</span><h3 class="mt-sm">生成</h3><p>LLM 基于资料回答。</p></div>
|
||||
</div>
|
||||
<div class="grid2 mt">
|
||||
<div class="card"><h3>不是训练模型</h3><p class="lead" style="font-size:19px;margin-top:8px">知识不写进模型参数,而是每次回答前动态查资料。</p></div>
|
||||
<div class="card soft"><h3>不是全量塞资料</h3><p class="lead" style="font-size:19px;margin-top:8px">只取与问题相关的片段,降低上下文压力和噪声。</p></div>
|
||||
</div>
|
||||
<div class="footer"><span>RAG = Retrieval-Augmented Generation</span><span class="page"></span></div>
|
||||
<div class="notes">这页讲 RAG 的基本定义。先给出完整定义,再强调 RAG 不是训练模型,也不是把全部资料塞给模型。</div>
|
||||
|
||||
<div class="top"><div class="chapter">02</div><div class="head"><h2>RAG 是什么</h2><p>RAG = Retrieval-Augmented Generation,检索增强生成。</p></div><div class="brand"><div class="brand-mark">R</div><span>先查再答</span></div></div>
|
||||
<div class="content">
|
||||
<div class="pipeline">
|
||||
<div class="pipe-card"><span class="tag">Retrieval</span><div class="icon">查</div><h3>检索</h3><p>先从知识库中找到和问题相关的资料片段。</p></div>
|
||||
<div class="filter"><div class="funnel">RAG<br><span style="font-size:14px">筛选相关资料</span></div></div>
|
||||
<div class="pipe-card"><span class="tag green">Generation</span><div class="icon">答</div><h3>生成</h3><p>LLM 只基于筛出来的资料组织自然语言答案。</p></div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">≠</div><div><strong>不是训练模型</strong><span>知识不写进模型参数</span></div></div>
|
||||
<div class="value"><div class="vicon">≠</div><div><strong>不是全量塞资料</strong><span>只取相关片段</span></div></div>
|
||||
<div class="value"><div class="vicon">=</div><div><strong>动态查资料</strong><span>每次提问实时检索</span></div></div>
|
||||
<div class="value"><div class="vicon">✓</div><div><strong>降低幻觉</strong><span>让答案有依据</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>RAG = Retrieval + Augmented + Generation</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="LLM 是什么">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>LLM</span><span>大语言模型</span></div>
|
||||
<p class="kicker">定义</p>
|
||||
<h2>LLM:理解上下文,生成自然语言</h2>
|
||||
<div class="compare">
|
||||
<div class="card">
|
||||
<span class="tag">能力</span>
|
||||
<h3 class="mt-sm">理解上下文,生成答案</h3>
|
||||
<ul>
|
||||
<li>读懂用户问题的大意</li>
|
||||
<li>把零散信息组织成自然语言</li>
|
||||
<li>按要求改写、总结、解释、翻译</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mid">≠</div>
|
||||
<div class="card">
|
||||
<span class="tag rose">边界</span>
|
||||
<h3 class="mt-sm">企业资料库或事实系统</h3>
|
||||
<ul>
|
||||
<li>不会天然知道最新制度</li>
|
||||
<li>不知道内部文档和私有数据</li>
|
||||
<li>不能保证每句话都有来源</li>
|
||||
</ul>
|
||||
<div class="top"><div class="chapter">03</div><div class="head"><h2>LLM 是什么</h2><p>大语言模型擅长理解上下文和生成表达,但不是企业事实库。</p></div><div class="brand"><div class="brand-mark">LLM</div><span>语言引擎</span></div></div>
|
||||
<div class="content">
|
||||
<div class="compare">
|
||||
<div class="card" style="min-height:300px"><span class="tag">能力</span><div class="icon">AI</div><h3>理解与表达</h3><div class="dot-list" style="margin-top:14px"><span>读懂问题意图</span><span>总结、改写、解释、翻译</span><span>把零散资料组织成答案</span></div></div>
|
||||
<div class="mid">≠</div>
|
||||
<div class="card" style="min-height:300px"><span class="tag red">边界</span><div class="icon">DB</div><h3>企业事实系统</h3><div class="dot-list" style="margin-top:14px"><span>不会天然知道内部文档</span><span>不知道最新政策和数据</span><span>不能保证每句话都有来源</span></div></div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">读</div><div><strong>读懂上下文</strong><span>理解语义,不是简单关键词</span></div></div>
|
||||
<div class="value"><div class="vicon">写</div><div><strong>生成答案</strong><span>组织语言和结构</span></div></div>
|
||||
<div class="value"><div class="vicon">缺</div><div><strong>缺事实来源</strong><span>私有知识需要外部供给</span></div></div>
|
||||
<div class="value"><div class="vicon">接</div><div><strong>接 RAG</strong><span>把资料交给 LLM 使用</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>LLM handles language, not source-of-truth</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="card soft mt"><h3>定位</h3><p class="lead" style="font-size:20px;margin-top:8px">LLM 负责读懂和表达,事实依据来自外部资料。</p></div>
|
||||
<div class="footer"><span>LLM 不是知识库</span><span class="page"></span></div>
|
||||
<div class="notes">这里不要把 LLM 讲成搜索引擎。LLM 最强的是语言理解和生成,事实来源要靠外部知识、数据库或工具补充。</div>
|
||||
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="LLM 的限制">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Limits</span><span>对话限制</span></div>
|
||||
<p class="kicker">对话限制</p>
|
||||
<h2>LLM 的 4 个对话限制</h2>
|
||||
<div class="grid4 mt">
|
||||
<div class="card"><div class="num">1</div><h3>上下文有限</h3><p class="small mt-sm">输入窗口有限;资料过多会变慢、变贵、变乱。</p></div>
|
||||
<div class="card"><div class="num orange">2</div><h3>会有幻觉</h3><p class="small mt-sm">资料不足或指令不清时,会生成看似合理的错误内容。</p></div>
|
||||
<div class="card"><div class="num mint">3</div><h3>专注度下降</h3><p class="small mt-sm">长资料和噪声会稀释重点,关键信息可能被忽略。</p></div>
|
||||
<div class="card"><div class="num rose">4</div><h3>顺序不稳定</h3><p class="small mt-sm">位置、相似内容、前后冲突都会影响答案。</p></div>
|
||||
</div>
|
||||
<div class="card soft mt"><p class="lead" style="font-size:20px;margin-top:0">处理策略:每次只给最相关、最可信的少量资料。</p></div>
|
||||
<div class="footer"><span>上下文 · 幻觉 · 注意力 · 顺序</span><span class="page"></span></div>
|
||||
<div class="notes">这一页要明确回应用户大纲:上下文限制、幻觉、专注度、不会稳定关注内容顺序。它们共同解释了为什么不能简单粗暴地把所有文档塞进去。</div>
|
||||
|
||||
<div class="top"><div class="chapter">04</div><div class="head"><h2>LLM 的对话限制</h2><p>正因为有这些限制,不能把所有知识一次性丢给 LLM。</p></div><div class="brand"><div class="brand-mark">!</div><span>为什么需要 RAG</span></div></div>
|
||||
<div class="content">
|
||||
<div class="limit-grid">
|
||||
<div class="limit-col">
|
||||
<div class="limit"><div class="n">01</div><div><h4>上下文有限</h4><p>输入窗口有限;资料过多会变慢、变贵、变乱。</p></div></div>
|
||||
<div class="limit"><div class="n">02</div><div><h4>会有幻觉</h4><p>资料不足或指令不清时,会编出看似合理的内容。</p></div></div>
|
||||
</div>
|
||||
<div class="center-badge">不能<br>全量塞<br>资料</div>
|
||||
<div class="limit-col">
|
||||
<div class="limit"><div class="n">03</div><div><h4>专注度下降</h4><p>长资料和噪声会稀释重点,关键信息被忽略。</p></div></div>
|
||||
<div class="limit"><div class="n">04</div><div><h4>顺序不稳定</h4><p>内容位置、相似片段、前后冲突都会影响答案。</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">少</div><div><strong>少量</strong><span>只给必要资料</span></div></div>
|
||||
<div class="value"><div class="vicon">准</div><div><strong>准确</strong><span>优先高相关来源</span></div></div>
|
||||
<div class="value"><div class="vicon">新</div><div><strong>新鲜</strong><span>版本和时间可控</span></div></div>
|
||||
<div class="value"><div class="vicon">规</div><div><strong>规则</strong><span>提示词约束回答边界</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Context · Hallucination · Attention · Order</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="为什么需要 RAG">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Why RAG</span><span>限制带来方案</span></div>
|
||||
<p class="kicker">从限制到方案</p>
|
||||
<h2>RAG 的核心:不是让模型记住全部知识,而是让它按需查资料</h2>
|
||||
<div class="stage">
|
||||
<div class="box"><span class="tag rose">全量输入</span><h3 class="mt-sm">全部塞给 LLM</h3><p class="small mt-sm">长、乱、贵,容易混入过期和无权限资料。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="box main"><span class="tag" style="background:rgba(255,255,255,.18);color:#fff">RAG</span><h3 class="mt-sm">先查,再答</h3><p class="small mt-sm">每次只取跟问题最相关的资料片段。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="box"><span class="tag mint">生成</span><h3 class="mt-sm">基于资料回答</h3><p class="small mt-sm">LLM 根据资料生成,必要时引用来源。</p></div>
|
||||
</div>
|
||||
<div class="card soft mt"><h3>RAG = 检索增强生成</h3><p class="lead" style="font-size:20px;margin-top:8px">检索相关资料 → 放入上下文 → LLM 生成答案。</p></div>
|
||||
<div class="footer"><span>先查资料,再生成</span><span class="page"></span></div>
|
||||
<div class="notes">这页把 RAG 的必要性讲出来:不是因为向量数据库酷,而是因为 LLM 的上下文和注意力有限,必须把资料筛小、筛准,再交给模型。</div>
|
||||
|
||||
<div class="top"><div class="chapter">05</div><div class="head"><h2>从限制到方案</h2><p>RAG 的核心不是让模型记住全部知识,而是让模型按需查资料。</p></div><div class="brand"><div class="brand-mark">→</div><span>方案转化</span></div></div>
|
||||
<div class="content">
|
||||
<div class="pipeline">
|
||||
<div class="pipe-card"><span class="tag red">错误做法</span><h3 style="margin-top:16px">全部塞给 LLM</h3><div class="bad-list"><span>长文档堆叠,重点被稀释</span><span>过期资料混入,结果不可信</span><span>无权限内容可能泄露</span><span>成本高,速度慢</span></div></div>
|
||||
<div class="filter"><div class="funnel">检索<br>过滤<br>排序</div></div>
|
||||
<div class="pipe-card"><span class="tag green">RAG 做法</span><h3 style="margin-top:16px">只给相关资料</h3><div class="bad-list"><span style="border-color:#8fe0cf;background:#f1fffb;color:#0b8066">按问题查资料</span><span style="border-color:#8fe0cf;background:#f1fffb;color:#0b8066">按相关性排序</span><span style="border-color:#8fe0cf;background:#f1fffb;color:#0b8066">拼成小上下文</span><span style="border-color:#8fe0cf;background:#f1fffb;color:#0b8066">让 LLM 基于依据回答</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>RAG turns big documents into precise context</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="后台建库">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Offline Pipeline</span><span>后台整理资料</span></div>
|
||||
<p class="kicker">离线流程</p>
|
||||
<h2>资料整理成可检索的知识库</h2>
|
||||
<div class="flow">
|
||||
<div class="step"><span class="tag">01</span><h4>收集资料</h4><p>产品手册、FAQ、制度、接口文档、案例、流程说明。</p></div>
|
||||
<div class="step"><span class="tag orange">02</span><h4>清洗资料</h4><p>去掉重复、过期、广告、目录噪声和格式错误。</p></div>
|
||||
<div class="step hot"><span class="tag mint">03</span><h4>切片</h4><p>把长文档拆成能独立表达意思的小片段。</p></div>
|
||||
<div class="step"><span class="tag">04</span><h4>加元数据</h4><p>来源、版本、时间、部门、权限、适用范围。</p></div>
|
||||
<div class="step"><span class="tag">05</span><h4>向量化入库</h4><p>把每个片段变成语义向量,写入向量库。</p></div>
|
||||
</div>
|
||||
<div class="card soft mt"><p class="lead" style="font-size:20px;margin-top:0">资料质量决定检索质量。</p></div>
|
||||
<div class="footer"><span>资料准备 → 切片 → 向量库</span><span class="page"></span></div>
|
||||
<div class="notes">这里是“前期准备”。强调 RAG 不只是问答界面,后台知识库准备很关键。元数据也很重要,因为后面排序和权限过滤会用到。</div>
|
||||
|
||||
<div class="top"><div class="chapter">06</div><div class="head"><h2>后台建库:把资料整理成可检索系统</h2><p>RAG 不是只有一个问答框,前期知识库整理决定最终效果。</p></div><div class="brand"><div class="brand-mark">KB</div><span>离线流程</span></div></div>
|
||||
<div class="content">
|
||||
<div class="ribbon-row">
|
||||
<div class="ribbon">资料层</div>
|
||||
<div class="ribbon-line"><div class="icon">文</div><div class="dot-list"><span>产品手册、FAQ、制度、接口文档、案例、流程说明</span><span>确认来源、版本、时间、权限和适用范围</span></div></div>
|
||||
</div>
|
||||
<div class="ribbon-row">
|
||||
<div class="ribbon green">处理层</div>
|
||||
<div class="ribbon-line"><div class="icon">洗</div><div class="dot-list"><span>清洗重复、过期、广告、目录噪声和格式错误</span><span>长文档拆成能独立表达意思的小片段</span></div></div>
|
||||
</div>
|
||||
<div class="ribbon-row">
|
||||
<div class="ribbon navy">索引层</div>
|
||||
<div class="ribbon-line"><div class="icon">库</div><div class="dot-list"><span>每个切片转成语义向量,写入向量库</span><span>同时保留元数据,用于过滤、排序和引用来源</span></div></div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">质</div><div><strong>资料质量</strong><span>决定检索上限</span></div></div>
|
||||
<div class="value"><div class="vicon">粒</div><div><strong>切片粒度</strong><span>决定召回精度</span></div></div>
|
||||
<div class="value"><div class="vicon">源</div><div><strong>元数据</strong><span>决定过滤和引用</span></div></div>
|
||||
<div class="value"><div class="vicon">库</div><div><strong>向量库</strong><span>支持语义检索</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Prepare · Clean · Chunk · Embed · Index</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="切片和向量库">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Chunk & Embedding</span><span>切片和向量化</span></div>
|
||||
<p class="kicker">索引构建</p>
|
||||
<h2>切片 + 向量化:支持语义检索</h2>
|
||||
<div class="chunks">
|
||||
<div class="chunk"><b>切片 A:退费条件</b><p>购买后 7 天内,且未使用核心服务,可以申请全额退款。</p></div>
|
||||
<div class="chunk"><b>切片 B:不可退场景</b><p>已开具发票、已交付定制服务、超过合同期限,不支持自动退款。</p></div>
|
||||
<div class="chunk"><b>切片 C:审批路径</b><p>超过 5 万元的退款申请,需要客户成功经理和财务双审批。</p></div>
|
||||
</div>
|
||||
<div class="grid2 mt">
|
||||
<div class="card"><span class="tag">切片</span><h3 class="mt-sm">粒度适中</h3><p class="small mt-sm">过大噪声多,过小语义断;每片覆盖一个局部问题。</p></div>
|
||||
<div class="card"><span class="tag mint">向量库</span><h3 class="mt-sm">语义坐标</h3><p class="small mt-sm">文字转换成数字向量;语义相近,距离更近。</p><div class="vector"><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i></div></div>
|
||||
</div>
|
||||
<div class="footer"><span>Chunking + Embedding</span><span class="page"></span></div>
|
||||
<div class="notes">用卡片和地图类比:切片是把书拆成卡片,向量化是给卡片标语义坐标。用户问法不一样,也能找到意思接近的片段。</div>
|
||||
|
||||
<div class="top"><div class="chapter">07</div><div class="head"><h2>切片 + 向量化</h2><p>把长文档拆成小卡片,再给每张卡片标上“语义坐标”。</p></div><div class="brand"><div class="brand-mark">V</div><span>语义检索</span></div></div>
|
||||
<div class="content">
|
||||
<div class="chunks">
|
||||
<div class="doc">
|
||||
<span class="tag">原始资料:退款政策</span>
|
||||
<div class="slice"><h4>切片 A:退费条件</h4><p>购买后 7 天内,且未使用核心服务,可以申请全额退款。</p></div>
|
||||
<div class="slice"><h4>切片 B:不可退场景</h4><p>已开具发票、已交付定制服务、超过合同期限,不支持自动退款。</p></div>
|
||||
<div class="slice"><h4>切片 C:审批路径</h4><p>超过 5 万元的退款申请,需要客户成功经理和财务双审批。</p></div>
|
||||
</div>
|
||||
<div class="doc">
|
||||
<span class="tag green">向量化结果</span>
|
||||
<h3 style="margin-top:14px">语义相近,距离更近</h3>
|
||||
<p style="font-size:13px;line-height:1.65;color:var(--muted);margin-top:10px">用户问“买了 3 天没用能退吗”,即使没有出现“退费条件”这几个字,也能找到切片 A。</p>
|
||||
<div class="vector-bars"><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i><i class="bar"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Chunking + Embedding</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="用户提问时怎么查">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Online Retrieval</span><span>检索和排序</span></div>
|
||||
<p class="kicker">在线流程</p>
|
||||
<h2>用户提问后:检索候选,排序后交给 LLM</h2>
|
||||
<div class="flow">
|
||||
<div class="step"><span class="tag">01</span><h4>问题改写</h4><p>把口语问题改成更适合检索的查询。</p></div>
|
||||
<div class="step"><span class="tag">02</span><h4>问题向量化</h4><p>把用户问题也转成语义向量。</p></div>
|
||||
<div class="step"><span class="tag mint">03</span><h4>召回候选</h4><p>从向量库里找语义距离近的片段。</p></div>
|
||||
<div class="step hot"><span class="tag orange">04</span><h4>排序 / 重排</h4><p>按相关性、时效、权限、来源可信度重新排序。</p></div>
|
||||
<div class="step"><span class="tag">05</span><h4>拼上下文</h4><p>只把最有用的几段资料交给 LLM。</p></div>
|
||||
</div>
|
||||
<div class="search">
|
||||
<div class="card"><h3>排序后的候选资料</h3><div class="result"><div class="rank">1</div><div><h4>退款政策 v2026Q2</h4><p class="small">最相关,且版本最新。</p></div></div><div class="result"><div class="rank">2</div><div><h4>大客户审批流程</h4><p class="small">相关,但只在金额超过 5 万时使用。</p></div></div></div>
|
||||
<div class="card soft"><h3>排序作用</h3><ul><li>过期资料降权</li><li>无权限资料过滤</li><li>可信来源优先</li><li>减少噪声,保留重点</li></ul></div>
|
||||
</div>
|
||||
<div class="footer"><span>Retrieve + Rerank</span><span class="page"></span></div>
|
||||
<div class="notes">这里必须引出“排序”概念。召回只是先捞一批候选,排序/重排才决定哪些片段真正进入上下文。排序质量直接影响最终答案。</div>
|
||||
|
||||
<div class="top"><div class="chapter">08</div><div class="head"><h2>用户提问时怎么查</h2><p>召回只是先捞候选,排序 / 重排决定哪些资料真正进入上下文。</p></div><div class="brand"><div class="brand-mark">S</div><span>在线检索</span></div></div>
|
||||
<div class="content">
|
||||
<div class="flow">
|
||||
<div class="step"><div class="num">1</div><h3>问题改写</h3><p>把口语问题改成适合检索的查询。</p></div>
|
||||
<div class="step"><div class="num">2</div><h3>问题向量化</h3><p>用户问题也转成语义向量。</p></div>
|
||||
<div class="step"><div class="num">3</div><h3>召回候选</h3><p>从向量库找语义距离近的片段。</p></div>
|
||||
<div class="step hot"><div class="num">4</div><h3>排序 / 重排</h3><p>按相关性、时效、权限、来源可信度重新排序。</p></div>
|
||||
<div class="step"><div class="num">5</div><h3>拼上下文</h3><p>只把最有用的几段交给 LLM。</p></div>
|
||||
</div>
|
||||
<div class="grid2" style="margin-top:18px">
|
||||
<div class="card"><h3>排序后的候选资料</h3><div class="rank-list" style="margin-top:12px"><div class="rank"><div class="rnum">1</div><div><h4>退款政策 v2026Q2</h4><p>最相关,版本最新</p></div><div class="score">96</div></div><div class="rank"><div class="rnum">2</div><div><h4>大客户审批流程</h4><p>金额超过 5 万时使用</p></div><div class="score">78</div></div></div></div>
|
||||
<div class="card"><h3>排序看什么</h3><div class="dot-list" style="margin-top:12px"><span>相关性:是否真的回答这个问题</span><span>时效性:新版本优先,过期资料降权</span><span>权限:用户不能看的资料先过滤</span><span>可信度:制度、合同、权威来源优先</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Retrieve · Rerank · Context Assembly</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="提示词工程">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Prompt Engineering</span><span>系统提示词</span></div>
|
||||
<p class="kicker">生成约束</p>
|
||||
<h2>系统提示词规定 LLM 的资料使用规则</h2>
|
||||
<div class="search">
|
||||
<div class="prompt">
|
||||
<div class="dim">SYSTEM:</div>
|
||||
<div>你是客服助手。只能基于 CONTEXT 回答;资料不足时说“不确定”,不要编造。</div>
|
||||
<br>
|
||||
<div class="dim">CONTEXT:</div>
|
||||
<div class="mark">[退款政策 v2026Q2] 购买后 7 天内且未使用核心服务,可全额退款。</div>
|
||||
<br>
|
||||
<div class="dim">USER:</div>
|
||||
<div>客户买了 3 天,还没使用,可以退吗?</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<span class="tag">提示词工程</span>
|
||||
<h3 class="mt-sm">规则</h3>
|
||||
<ul>
|
||||
<li>角色:你是谁</li>
|
||||
<li>边界:只能基于资料回答</li>
|
||||
<li>格式:分点、引用来源、给结论</li>
|
||||
<li>兜底:不知道就说不知道</li>
|
||||
<li>安全:不要泄露无权限信息</li>
|
||||
</ul>
|
||||
<div class="top"><div class="chapter">09</div><div class="head"><h2>提示词工程:规定资料怎么用</h2><p>RAG 找资料,系统提示词规定 LLM 的角色、边界、格式和兜底方式。</p></div><div class="brand"><div class="brand-mark">P</div><span>生成约束</span></div></div>
|
||||
<div class="content">
|
||||
<div class="grid2">
|
||||
<div class="prompt-box">
|
||||
<b>SYSTEM</b><br>
|
||||
你是客服助手。只能基于 CONTEXT 回答;资料不足时说“不确定”,不要编造。<br><br>
|
||||
<b>CONTEXT</b><br>
|
||||
<mark>[退款政策 v2026Q2]</mark> 购买后 7 天内且未使用核心服务,可全额退款。<br><br>
|
||||
<b>USER</b><br>
|
||||
客户买了 3 天,还没使用,可以退吗?
|
||||
</div>
|
||||
<div class="stack">
|
||||
<div class="stack-layer"><div class="diagram-title">提示词工程</div><div class="stack-items"><div class="mini"><strong>角色</strong><span>你是谁</span></div><div class="mini"><strong>边界</strong><span>只能基于资料</span></div><div class="mini"><strong>格式</strong><span>结论、理由、来源</span></div></div></div>
|
||||
<div class="stack-layer"><div class="diagram-title" style="background:linear-gradient(135deg,#0aa58f,#14c8bf)">安全兜底</div><div class="stack-items"><div class="mini"><strong>不知道</strong><span>就说不确定</span></div><div class="mini"><strong>冲突</strong><span>说明版本差异</span></div><div class="mini"><strong>权限</strong><span>不泄露资料</span></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>System Prompt + Context + User Question</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="card soft mt"><p class="lead" style="font-size:20px;margin-top:0">RAG 找资料;提示词规定资料的使用方式。</p></div>
|
||||
<div class="footer"><span>System Prompt + Context + User Question</span><span class="page"></span></div>
|
||||
<div class="notes">这一页承接用户大纲:给到 LLM 的时候需要系统提示词,由此引出提示词工程。提示词工程重点不是花哨话术,而是角色、边界、格式、引用和兜底。</div>
|
||||
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="Agent">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Agent</span><span>复杂任务的分工协作</span></div>
|
||||
<p class="kicker">复杂任务</p>
|
||||
<h2>复杂任务:多步骤、多角色、多 LLM 协作</h2>
|
||||
<div class="agent-map">
|
||||
<div class="agent"><span class="tag">规划者</span><h3 class="mt-sm">拆任务</h3><p>规划检索、工具调用和结果组织。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="agent"><span class="tag mint">检索者</span><h3 class="mt-sm">查资料</h3><p>使用 RAG 从知识库里找依据,必要时多轮检索。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="agent"><span class="tag orange">执行者</span><h3 class="mt-sm">调用工具</h3><p>查订单、建工单、读数据库、调用业务系统接口。</p></div>
|
||||
</div>
|
||||
<div class="grid2 mt">
|
||||
<div class="card"><h3>Agent</h3><p class="lead" style="font-size:19px;margin-top:8px">目标驱动流程:规划步骤、选择工具、读取结果、继续推进。</p></div>
|
||||
<div class="card soft"><h3>和 RAG 的关系</h3><p class="lead" style="font-size:19px;margin-top:8px">RAG 提供知识入口;Agent 负责任务编排。</p></div>
|
||||
</div>
|
||||
<div class="footer"><span>RAG 是知识入口,Agent 是任务编排</span><span class="page"></span></div>
|
||||
<div class="notes">不要把 Agent 讲玄。它就是更复杂任务里的规划和编排:可能一个 LLM 规划,一个 LLM 检索,一个 LLM 写答案,也可能调用外部工具。</div>
|
||||
|
||||
<div class="top"><div class="chapter">10</div><div class="head"><h2>复杂任务需要 Agent</h2><p>当任务不只是“答一句话”,就需要规划、检索、执行、校验等分工。</p></div><div class="brand"><div class="brand-mark">A</div><span>任务编排</span></div></div>
|
||||
<div class="content">
|
||||
<div class="agent-map">
|
||||
<div class="agent-card"><div class="icon">规</div><h3>规划者</h3><p>拆步骤,决定先查什么、再调用什么工具。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="agent-card"><div class="icon">查</div><h3>检索者</h3><p>使用 RAG 找依据,必要时多轮检索。</p></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="agent-card"><div class="icon">执</div><h3>执行者</h3><p>查订单、建工单、读数据库、调用接口。</p></div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">R</div><div><strong>RAG</strong><span>提供知识入口</span></div></div>
|
||||
<div class="value"><div class="vicon">P</div><div><strong>Prompt</strong><span>规定回答规则</span></div></div>
|
||||
<div class="value"><div class="vicon">A</div><div><strong>Agent</strong><span>负责任务编排</span></div></div>
|
||||
<div class="value"><div class="vicon">T</div><div><strong>Tools</strong><span>执行外部动作</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Agent = Plan + Retrieve + Act + Check</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="MCP">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>MCP</span><span>工具连接</span></div>
|
||||
<p class="kicker">MCP</p>
|
||||
<h2>MCP:让 Agent 稳定连接外部工具和业务系统</h2>
|
||||
<div class="mcp-grid">
|
||||
<div class="mcp-card"><span class="tag">统一接口</span><h3 class="mt-sm">工具接入规范</h3><p class="small mt-sm">把不同系统的能力包装成模型可调用的工具。</p></div>
|
||||
<div class="mcp-card"><span class="tag mint">上下文供给</span><h3 class="mt-sm">读取外部信息</h3><p class="small mt-sm">查数据库、读文件、取工单、访问知识系统。</p></div>
|
||||
<div class="mcp-card"><span class="tag orange">动作执行</span><h3 class="mt-sm">调用业务能力</h3><p class="small mt-sm">创建工单、查询订单、发送通知、写入结果。</p></div>
|
||||
</div>
|
||||
<div class="tool-list">
|
||||
<span>CRM</span><span>工单</span><span>数据库</span><span>搜索</span><span>文件</span>
|
||||
</div>
|
||||
<div class="card soft mt"><p class="lead" style="font-size:20px;margin-top:0">RAG 负责查知识;Agent 负责编排任务;MCP 负责连接工具。</p></div>
|
||||
<div class="footer"><span>RAG · Agent · MCP</span><span class="page"></span></div>
|
||||
<div class="notes">这页讲 MCP。它不需要展开协议细节,只要说明 MCP 是让模型/Agent 稳定连接外部工具和系统的接口层。</div>
|
||||
|
||||
<div class="top"><div class="chapter">11</div><div class="head"><h2>MCP:让 Agent 连接工具</h2><p>MCP 可以理解为模型/Agent 调用外部系统的一套统一连接方式。</p></div><div class="brand"><div class="brand-mark">M</div><span>工具连接</span></div></div>
|
||||
<div class="content">
|
||||
<div class="tool-bus">
|
||||
<div class="card"><span class="tag">Agent</span><h3 style="margin-top:14px">会规划任务</h3><p style="margin-top:10px">但真正查数据、改状态、发通知,需要连接业务系统。</p></div>
|
||||
<div class="bus">MCP<br><span style="font-size:14px;font-weight:700">统一工具接口 / 上下文供给 / 动作执行</span></div>
|
||||
<div class="tools">
|
||||
<div class="tool">CRM<span>客户资料</span></div>
|
||||
<div class="tool">工单<span>创建 / 查询</span></div>
|
||||
<div class="tool">数据库<span>读数据</span></div>
|
||||
<div class="tool">文件<span>读文档</span></div>
|
||||
<div class="tool">搜索<span>查外部信息</span></div>
|
||||
<div class="tool">消息<span>发送通知</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="value-strip">
|
||||
<div class="value"><div class="vicon">知</div><div><strong>RAG</strong><span>查知识</span></div></div>
|
||||
<div class="value"><div class="vicon">编</div><div><strong>Agent</strong><span>编排任务</span></div></div>
|
||||
<div class="value"><div class="vicon">接</div><div><strong>MCP</strong><span>连接工具</span></div></div>
|
||||
<div class="value"><div class="vicon">做</div><div><strong>业务系统</strong><span>完成动作</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>Model Context Protocol</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
<section class="slide" data-title="总结">
|
||||
<div class="slide-inner">
|
||||
<div class="topline"><span>Takeaway</span><span>关键链路</span></div>
|
||||
<p class="kicker">核心链路</p>
|
||||
<h2>RAG → LLM 限制 → 切片 → 向量化 → 语义检索 → 排序 → 提示词 → Agent → MCP</h2>
|
||||
<div class="summary">
|
||||
<div class="card"><span class="tag rose">限制</span><h3 class="mt-sm">LLM 不能吃下全部知识</h3><p class="small mt-sm">上下文有限、会幻觉、专注度和顺序都不稳定。</p></div>
|
||||
<div class="card"><span class="tag mint">建库</span><h3 class="mt-sm">资料要先整理成片段</h3><p class="small mt-sm">清洗、切片、向量化、加元数据,再放入向量库。</p></div>
|
||||
<div class="card"><span class="tag orange">检索</span><h3 class="mt-sm">提问时先找资料</h3><p class="small mt-sm">召回候选,再排序过滤,把最相关内容放进上下文。</p></div>
|
||||
<div class="card"><span class="tag">扩展</span><h3 class="mt-sm">Agent + MCP</h3><p class="small mt-sm">Agent 编排多步骤任务;MCP 连接外部工具和系统。</p></div>
|
||||
</div>
|
||||
<div class="card soft mt"><p class="lead" style="font-size:21px;margin-top:0">RAG 不是替代 LLM,而是给 LLM 配一套“会查资料的工作台”。</p></div>
|
||||
<div class="footer"><span>End</span><span class="page"></span></div>
|
||||
<div class="notes">收尾不要再加新概念。重复主线:LLM 有限制,所以需要 RAG;RAG 后台建库,前台检索排序,再通过提示词交给 LLM;复杂任务用 Agent。</div>
|
||||
|
||||
<div class="top"><div class="chapter">12</div><div class="head"><h2>入门之后,要抓住这条主线</h2><p>LLM 有限制,所以需要 RAG;RAG 把资料找准,再交给 LLM 生成。</p></div><div class="brand"><div class="brand-mark">✓</div><span>核心链路</span></div></div>
|
||||
<div class="content">
|
||||
<div class="flow">
|
||||
<div class="step"><div class="num">1</div><h3>LLM</h3><p>负责理解和表达,但不是企业知识库。</p></div>
|
||||
<div class="step"><div class="num">2</div><h3>限制</h3><p>上下文、幻觉、专注度、顺序带来风险。</p></div>
|
||||
<div class="step"><div class="num">3</div><h3>RAG</h3><p>后台建库;前台检索;排序后拼上下文。</p></div>
|
||||
<div class="step"><div class="num">4</div><h3>Prompt</h3><p>规定角色、边界、格式、兜底和安全。</p></div>
|
||||
<div class="step"><div class="num">5</div><h3>Agent + MCP</h3><p>复杂任务用 Agent 编排,用 MCP 连接工具。</p></div>
|
||||
</div>
|
||||
<div class="stack-layer" style="margin-top:24px;text-align:center">
|
||||
<div class="diagram-title">一句话总结</div>
|
||||
<h3 style="font-size:30px;margin-top:18px;color:#061b4e">RAG 不是替代 LLM,而是给 LLM 配一套“会查资料的工作台”。</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer"><span>End</span><span class="page"></span></div>
|
||||
</div>
|
||||
<div class="page-corner"></div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
@@ -418,6 +496,7 @@ ul{margin:14px 0 0;padding-left:22px;color:var(--muted);line-height:1.85;font-si
|
||||
function render(){
|
||||
slides.forEach((s,i)=>s.classList.toggle('active',i===idx));
|
||||
document.querySelectorAll('.page').forEach(el=>{el.textContent=(idx+1)+' / '+slides.length});
|
||||
document.querySelectorAll('.page-corner').forEach(el=>{el.textContent=String(idx+1).padStart(2,'0')});
|
||||
navIndex.textContent = (idx+1)+' / '+slides.length;
|
||||
prevBtn.disabled = idx === 0;
|
||||
nextBtn.disabled = idx === slides.length - 1;
|
||||
|
||||
573
public/style.css
573
public/style.css
@@ -1736,6 +1736,31 @@ body.session-loading-active {
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ccweb-prompt-outline-anchor {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ccweb-prompt-outline-btn {
|
||||
position: relative;
|
||||
}
|
||||
.ccweb-prompt-outline-btn[data-count]::after {
|
||||
content: attr(data-count);
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -7px;
|
||||
min-width: 16px;
|
||||
height: 16px;
|
||||
padding: 0 4px;
|
||||
border-radius: 999px;
|
||||
background: var(--accent);
|
||||
color: var(--accent-ink);
|
||||
font-size: 10px;
|
||||
font-weight: 900;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
box-shadow: 0 0 0 2px var(--bg-primary);
|
||||
}
|
||||
.user-outline-btn:hover,
|
||||
.reload-mcp-btn:hover:not(:disabled) {
|
||||
background: rgba(91, 126, 161, 0.16);
|
||||
@@ -3387,6 +3412,76 @@ html[data-divider-time='hide'] .msg-bubble .agent-message-divider span {
|
||||
background: var(--note-border);
|
||||
border-radius: 999px;
|
||||
}
|
||||
.pending-ccweb-prompt {
|
||||
display: grid;
|
||||
grid-template-columns: 10px minmax(0, 1fr) auto auto;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-height: 36px;
|
||||
padding: 6px 8px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
background: transparent;
|
||||
animation: fadeIn 0.2s ease;
|
||||
}
|
||||
.pending-ccweb-prompt:hover {
|
||||
background: var(--accent-light);
|
||||
}
|
||||
.pending-ccweb-prompt-badge {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
box-shadow: 0 0 0 3px rgba(192, 85, 58, 0.12);
|
||||
}
|
||||
.pending-ccweb-prompt-title {
|
||||
color: var(--text-primary);
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
line-height: 1.35;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pending-ccweb-prompt-action {
|
||||
min-height: 26px;
|
||||
padding: 3px 9px;
|
||||
border: 1px solid rgba(192, 85, 58, 0.24);
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 249, 242, 0.9);
|
||||
color: var(--accent);
|
||||
font: inherit;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.16s ease, background 0.16s ease, transform 0.16s ease;
|
||||
}
|
||||
.pending-ccweb-prompt-action:hover {
|
||||
border-color: var(--accent);
|
||||
background: var(--bg-primary);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.pending-ccweb-prompt-dismiss {
|
||||
min-height: 26px;
|
||||
padding: 3px 8px;
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
background: transparent;
|
||||
color: var(--text-muted);
|
||||
font: inherit;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
}
|
||||
.pending-ccweb-prompt-dismiss:hover {
|
||||
background: rgba(139, 100, 32, 0.1);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.pending-ccweb-prompt-dismiss:disabled {
|
||||
opacity: 0.55;
|
||||
cursor: wait;
|
||||
}
|
||||
.pending-note {
|
||||
display: grid;
|
||||
grid-template-columns: 28px minmax(0, 1fr);
|
||||
@@ -3704,6 +3799,7 @@ html[data-divider-time='hide'] .msg-bubble .agent-message-divider span {
|
||||
font-size: 11px;
|
||||
}
|
||||
.user-outline-btn,
|
||||
.ccweb-prompt-outline-btn,
|
||||
.reload-mcp-btn {
|
||||
padding: 4px 8px;
|
||||
font-size: 10px;
|
||||
@@ -3747,9 +3843,13 @@ html[data-divider-time='hide'] .msg-bubble .agent-message-divider span {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
align-items: stretch;
|
||||
}
|
||||
.ccweb-prompt-outline-anchor {
|
||||
width: 100%;
|
||||
}
|
||||
.chat-cwd,
|
||||
.mode-select,
|
||||
.user-outline-btn,
|
||||
.ccweb-prompt-outline-btn,
|
||||
.reload-mcp-btn,
|
||||
.chat-runtime-state {
|
||||
width: 100%;
|
||||
@@ -4719,6 +4819,474 @@ html[data-theme='coolvibe'] .settings-back:hover {
|
||||
.codex-user-input-text:focus {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.ccweb-prompt-card {
|
||||
width: min(100%, 720px);
|
||||
margin-top: 14px;
|
||||
padding: 0;
|
||||
border: 1px solid rgba(192, 85, 58, 0.18);
|
||||
border-left: 4px solid var(--accent);
|
||||
border-radius: 8px;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 249, 242, 0.98), rgba(250, 246, 240, 0.94));
|
||||
color: var(--text-primary);
|
||||
box-shadow: 0 14px 34px rgba(45, 31, 20, 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
.ccweb-prompt-card.ccweb-prompt-focus {
|
||||
animation: ccwebPromptFocus 1.4s ease;
|
||||
}
|
||||
@keyframes ccwebPromptFocus {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(192, 85, 58, 0.34), 0 14px 34px rgba(45, 31, 20, 0.08);
|
||||
}
|
||||
45% {
|
||||
box-shadow: 0 0 0 5px rgba(192, 85, 58, 0.18), 0 18px 38px rgba(45, 31, 20, 0.12);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(192, 85, 58, 0), 0 14px 34px rgba(45, 31, 20, 0.08);
|
||||
}
|
||||
}
|
||||
.ccweb-prompt-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
min-height: 46px;
|
||||
padding: 9px 12px;
|
||||
border-bottom: 1px solid rgba(221, 208, 192, 0.72);
|
||||
}
|
||||
.ccweb-prompt-title-wrap {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
.ccweb-prompt-kicker {
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.ccweb-prompt-title {
|
||||
color: var(--text-primary);
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
line-height: 1.3;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ccweb-prompt-header-actions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.ccweb-prompt-status {
|
||||
flex: 0 0 auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
padding: 0;
|
||||
border: 1px solid rgba(192, 85, 58, 0.18);
|
||||
border-radius: 999px;
|
||||
background: rgba(245, 221, 212, 0.6);
|
||||
color: var(--accent);
|
||||
font-size: 10px;
|
||||
font-weight: 800;
|
||||
}
|
||||
.ccweb-prompt-card[data-status='submitted'] .ccweb-prompt-status {
|
||||
width: auto;
|
||||
padding: 0 7px;
|
||||
border-color: rgba(93, 138, 84, 0.28);
|
||||
background: rgba(93, 138, 84, 0.12);
|
||||
color: var(--success);
|
||||
font-size: 11px;
|
||||
}
|
||||
.ccweb-prompt-desc {
|
||||
margin: 0;
|
||||
padding: 10px 12px 0;
|
||||
color: var(--text-secondary);
|
||||
font-size: 13px;
|
||||
line-height: 1.55;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.ccweb-prompt-view-controls {
|
||||
padding: 8px 12px 0;
|
||||
}
|
||||
.ccweb-prompt-view-switcher {
|
||||
display: inline-flex;
|
||||
width: max-content;
|
||||
max-width: 100%;
|
||||
padding: 1px;
|
||||
border: 1px solid rgba(221, 208, 192, 0.94);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.48);
|
||||
}
|
||||
.ccweb-prompt-view-btn {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
min-height: 26px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: var(--text-muted);
|
||||
font: inherit;
|
||||
font-size: 14px;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ccweb-prompt-view-btn.is-active {
|
||||
background: var(--accent);
|
||||
color: var(--accent-ink);
|
||||
}
|
||||
.ccweb-prompt-tabs {
|
||||
display: none;
|
||||
min-width: 0;
|
||||
gap: 6px;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
.ccweb-prompt-tab {
|
||||
flex: 0 0 auto;
|
||||
max-width: 168px;
|
||||
min-height: 30px;
|
||||
padding: 5px 10px;
|
||||
border: 1px solid rgba(221, 208, 192, 0.94);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 249, 242, 0.72);
|
||||
color: var(--text-secondary);
|
||||
font: inherit;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ccweb-prompt-tab.is-active {
|
||||
border-color: var(--accent);
|
||||
background: rgba(245, 221, 212, 0.72);
|
||||
color: var(--accent);
|
||||
}
|
||||
.ccweb-prompt-tab-nav {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
.ccweb-prompt-tab-nav-btn {
|
||||
min-height: 30px;
|
||||
padding: 5px 9px;
|
||||
border: 1px solid rgba(221, 208, 192, 0.98);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 249, 242, 0.75);
|
||||
color: var(--text-primary);
|
||||
font: inherit;
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ccweb-prompt-tab-nav-btn:disabled {
|
||||
opacity: 0.45;
|
||||
cursor: default;
|
||||
}
|
||||
.ccweb-prompt-tab-counter {
|
||||
min-width: 64px;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
text-align: center;
|
||||
}
|
||||
.ccweb-prompt-card[data-view-mode='tabs'] .ccweb-prompt-tabs {
|
||||
display: flex;
|
||||
}
|
||||
.ccweb-prompt-card[data-view-mode='cards'] .ccweb-prompt-view-controls {
|
||||
display: none;
|
||||
}
|
||||
.ccweb-prompt-card[data-view-mode='tabs'] .ccweb-prompt-tab-nav {
|
||||
display: flex;
|
||||
}
|
||||
.ccweb-prompt-card[data-view-mode='tabs'] .ccweb-prompt-question:not(.is-active) {
|
||||
display: none;
|
||||
}
|
||||
.ccweb-prompt-questions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-top: 0;
|
||||
padding: 10px 12px 4px;
|
||||
}
|
||||
.ccweb-prompt-question {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 13px 14px;
|
||||
border: 1px solid rgba(221, 208, 192, 0.92);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.46);
|
||||
}
|
||||
.ccweb-prompt-question-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
.ccweb-prompt-question-title {
|
||||
color: var(--text-primary);
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
line-height: 1.35;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.ccweb-prompt-required {
|
||||
flex: 0 0 auto;
|
||||
padding: 2px 6px;
|
||||
border-radius: 999px;
|
||||
background: rgba(192, 85, 58, 0.1);
|
||||
color: var(--danger);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
.ccweb-prompt-question-body {
|
||||
color: var(--text-secondary);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.ccweb-prompt-options {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 7px;
|
||||
}
|
||||
.ccweb-prompt-option {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
column-gap: 9px;
|
||||
row-gap: 4px;
|
||||
min-width: 0;
|
||||
align-items: start;
|
||||
width: 100%;
|
||||
padding: 9px 11px;
|
||||
border: 1px solid rgba(221, 208, 192, 0.96);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 249, 242, 0.82);
|
||||
color: var(--text-primary);
|
||||
font: inherit;
|
||||
font-size: 13px;
|
||||
line-height: 1.35;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.16s ease, background 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
|
||||
}
|
||||
.ccweb-prompt-option::before {
|
||||
content: '';
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
margin-top: 1px;
|
||||
border: 1.5px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
background: rgba(255, 255, 255, 0.75);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ccweb-prompt-option:hover {
|
||||
border-color: var(--accent);
|
||||
background: rgba(255, 249, 242, 0.98);
|
||||
box-shadow: 0 8px 18px rgba(45, 31, 20, 0.06);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.ccweb-prompt-option.is-selected {
|
||||
border-color: var(--accent);
|
||||
background: rgba(245, 221, 212, 0.72);
|
||||
color: var(--text-primary);
|
||||
box-shadow: inset 0 0 0 1px rgba(192, 85, 58, 0.16);
|
||||
}
|
||||
.ccweb-prompt-option.is-selected::before {
|
||||
content: '✓';
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-color: var(--accent);
|
||||
background: var(--accent);
|
||||
color: var(--accent-ink);
|
||||
font-size: 10px;
|
||||
font-weight: 900;
|
||||
}
|
||||
.ccweb-prompt-option-label {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
font-weight: 800;
|
||||
}
|
||||
.ccweb-prompt-option-badge {
|
||||
flex: 0 0 auto;
|
||||
align-self: start;
|
||||
padding: 2px 6px;
|
||||
border-radius: 999px;
|
||||
background: rgba(192, 85, 58, 0.12);
|
||||
color: var(--accent);
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
}
|
||||
.ccweb-prompt-option-desc {
|
||||
grid-column: 2 / -1;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
line-height: 1.45;
|
||||
text-align: left;
|
||||
}
|
||||
.ccweb-prompt-answer {
|
||||
width: 100%;
|
||||
min-height: 84px;
|
||||
resize: vertical;
|
||||
padding: 10px 11px;
|
||||
border: 1px solid rgba(221, 208, 192, 0.98);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.62);
|
||||
color: var(--text-primary);
|
||||
font: inherit;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
outline: none;
|
||||
transition: border-color 0.16s ease, background 0.16s ease, box-shadow 0.16s ease;
|
||||
}
|
||||
.ccweb-prompt-answer:focus {
|
||||
border-color: var(--accent);
|
||||
background: var(--bg-primary);
|
||||
box-shadow: 0 0 0 3px rgba(192, 85, 58, 0.1);
|
||||
}
|
||||
.ccweb-prompt-selected-readonly,
|
||||
.ccweb-prompt-answer-readonly {
|
||||
padding: 10px 11px;
|
||||
border: 1px solid rgba(221, 208, 192, 0.92);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.56);
|
||||
color: var(--text-primary);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.ccweb-prompt-selected-readonly {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.ccweb-prompt-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
margin-top: 0;
|
||||
padding: 9px 12px 11px;
|
||||
border-top: 1px solid rgba(221, 208, 192, 0.72);
|
||||
background: rgba(242, 235, 226, 0.38);
|
||||
}
|
||||
.ccweb-prompt-footer-actions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-left: auto;
|
||||
}
|
||||
.ccweb-prompt-submit,
|
||||
.ccweb-prompt-secondary {
|
||||
min-height: 32px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 8px;
|
||||
font: inherit;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.16s ease, background 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
|
||||
}
|
||||
.ccweb-prompt-submit {
|
||||
border: 1px solid var(--accent);
|
||||
background: var(--accent);
|
||||
color: var(--accent-ink);
|
||||
}
|
||||
.ccweb-prompt-submit:hover:not(:disabled) {
|
||||
background: var(--accent-hover);
|
||||
border-color: var(--accent-hover);
|
||||
box-shadow: 0 8px 18px rgba(192, 85, 58, 0.18);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.ccweb-prompt-submit:disabled {
|
||||
opacity: 0.65;
|
||||
cursor: wait;
|
||||
}
|
||||
.ccweb-prompt-secondary {
|
||||
border: 1px solid rgba(221, 208, 192, 0.98);
|
||||
background: rgba(255, 249, 242, 0.75);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.ccweb-prompt-secondary:hover {
|
||||
border-color: var(--accent);
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
.ccweb-prompt-error {
|
||||
margin: 2px 18px 0;
|
||||
color: var(--danger);
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
.pending-ccweb-prompt {
|
||||
grid-template-columns: 10px minmax(72px, 1fr) auto auto;
|
||||
}
|
||||
.pending-ccweb-prompt-title {
|
||||
max-width: none;
|
||||
}
|
||||
.ccweb-prompt-card {
|
||||
width: 100%;
|
||||
}
|
||||
.ccweb-prompt-header {
|
||||
padding: 9px 10px;
|
||||
}
|
||||
.ccweb-prompt-header-actions {
|
||||
gap: 5px;
|
||||
}
|
||||
.ccweb-prompt-desc {
|
||||
padding: 9px 10px 0;
|
||||
}
|
||||
.ccweb-prompt-view-controls {
|
||||
padding: 8px 10px 0;
|
||||
}
|
||||
.ccweb-prompt-view-switcher {
|
||||
width: auto;
|
||||
}
|
||||
.ccweb-prompt-question-head {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.ccweb-prompt-tab-nav {
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
.ccweb-prompt-tab-nav-btn {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.ccweb-prompt-questions {
|
||||
padding: 10px 10px 4px;
|
||||
}
|
||||
.ccweb-prompt-footer {
|
||||
flex-wrap: wrap;
|
||||
padding: 9px 10px 10px;
|
||||
}
|
||||
.ccweb-prompt-footer-actions {
|
||||
flex: 1 1 auto;
|
||||
margin-left: 0;
|
||||
}
|
||||
.ccweb-prompt-error {
|
||||
margin-right: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.ccweb-prompt-submit,
|
||||
.ccweb-prompt-secondary {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
.codex-approval-panel {
|
||||
max-width: 560px;
|
||||
}
|
||||
@@ -5460,8 +6028,10 @@ html[data-theme='coolvibe'] .settings-back:hover {
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .mode-select,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .chat-cwd,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .user-outline-btn,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .ccweb-prompt-outline-btn,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .reload-mcp-btn,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .user-outline-item,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .pending-ccweb-prompt,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .settings-back,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .settings-nav-card,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .settings-toggle-row,
|
||||
@@ -5551,7 +6121,8 @@ html[data-theme='coolvibe'] .settings-back:hover {
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .cmd-item:hover,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .cmd-item.active,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .file-browser-item:hover,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .user-outline-item:hover {
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .user-outline-item:hover,
|
||||
:is(html[data-theme='carbon'], html[data-theme='nocturne'], html[data-theme='cinder']) .pending-ccweb-prompt:hover {
|
||||
background: var(--accent-light);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user