Files
test-repo/docs/.vitepress/theme/components/appendix/context-engineering/LostInMiddleDemo.vue
T
sanbuphy d35211071a style: update border-radius and padding values across components
- standardize border-radius from 8px to 6px for consistent styling
- adjust padding values from 1rem to 0.75rem for better visual hierarchy
- remove redundant overflow-y properties for cleaner code
2026-02-14 20:23:34 +08:00

284 lines
6.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="lost-in-middle-demo">
<div class="control-panel">
<div class="control-group">
<label>关键信息大概在整段话的哪个位置{{ needlePosition }}%</label>
<input
type="range"
v-model.number="needlePosition"
min="0"
max="100"
step="1"
class="slider-input"
>
</div>
</div>
<div class="visualization-area">
<!-- Context Window Bar -->
<div class="context-bar">
<div class="context-label start">Start (System)</div>
<div class="context-label end">End (Query)</div>
<!-- Attention Heatmap Background -->
<div class="attention-heatmap"></div>
<!-- Needle Marker -->
<div
class="needle-marker"
:style="{ left: `${needlePosition}%` }"
>
<div class="needle-icon">📍</div>
<div class="needle-tooltip">关键事实</div>
</div>
</div>
<!-- Probability Curve Chart -->
<div class="chart-container">
<svg viewBox="0 0 100 60" preserveAspectRatio="none" class="chart-svg">
<!-- U-Curve Path -->
<path
d="M 0 5 Q 50 55 100 5"
fill="none"
stroke="var(--vp-c-divider)"
stroke-width="2"
stroke-dasharray="4"
/>
<!-- Active Dot -->
<circle
:cx="needlePosition"
:cy="60 - (retrievalProb * 0.5 + 5)"
r="3"
fill="var(--vp-c-brand)"
/>
</svg>
<div class="chart-label y-axis">被记住的概率</div>
<div class="chart-label x-axis">在上下文里的位置</div>
</div>
</div>
<div class="metrics-panel">
<div class="metric-card">
<div class="metric-value" :class="getScoreClass(retrievalProb)">
{{ retrievalProb.toFixed(1) }}%
</div>
<div class="metric-label">检索成功率</div>
</div>
<div class="metric-card">
<div class="metric-value">{{ positionLabel }}</div>
<div class="metric-label">位置描述</div>
</div>
</div>
<div class="info-box">
<p>
<span class="icon">🔍</span>
<strong>实验观察</strong>当关键信息藏在整段话的<strong>中间位置</strong>模型最容易漏看掉Lost in the Middle
<br>
最靠谱的做法把重要指令放在<strong>最前面的 System Prompt</strong>或者<strong>最后的用户问题里</strong>
</p>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const needlePosition = ref(50) // 0 to 100
// Parabolic curve calculation: Vertex at (50, 40), passing through (0, 95) and (100, 95)
// y = a(x-h)^2 + k
// a = 0.022
const retrievalProb = computed(() => {
const x = needlePosition.value
const prob = 0.022 * Math.pow(x - 50, 2) + 40
return Math.min(99.9, Math.max(0, prob))
})
const positionLabel = computed(() => {
const p = needlePosition.value
if (p < 20) return '偏开头'
if (p > 80) return '偏结尾'
return '中间区域(最危险)'
})
const getScoreClass = (score) => {
if (score > 85) return 'text-success'
if (score > 60) return 'text-warning'
return 'text-danger'
}
</script>
<style scoped>
.lost-in-middle-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
background-color: var(--vp-c-bg-soft);
padding: 0.75rem;
margin: 0.5rem 0;
font-family: var(--vp-font-family-mono);
}
.control-panel {
margin-bottom: 1rem;
background: var(--vp-c-bg);
padding: 0.75rem;
border-radius: 6px;
border: 1px solid var(--vp-c-divider);
}
.control-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.control-group label {
font-weight: bold;
font-size: 0.85rem;
}
.slider-input {
width: 100%;
accent-color: var(--vp-c-brand);
}
.visualization-area {
margin-bottom: 1rem;
position: relative;
}
.context-bar {
height: 40px;
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
position: relative;
margin-bottom: 0.75rem;
background: var(--vp-c-bg);
overflow: visible; /* Allow needle to stick out */
}
.attention-heatmap {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 6px;
background: linear-gradient(
90deg,
rgba(16, 185, 129, 0.2) 0%,
rgba(239, 68, 68, 0.1) 50%,
rgba(16, 185, 129, 0.2) 100%
);
opacity: 0.6;
}
.context-label {
position: absolute;
top: -18px;
font-size: 0.7rem;
color: var(--vp-c-text-2);
}
.context-label.start { left: 0; }
.context-label.end { right: 0; }
.needle-marker {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
z-index: 10;
cursor: grab;
transition: left 0.1s ease;
}
.needle-icon {
font-size: 1.25rem;
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
}
.needle-tooltip {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: var(--vp-c-text-1);
color: var(--vp-c-bg);
padding: 2px 6px;
border-radius: 4px;
font-size: 0.7rem;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
}
.needle-marker:hover .needle-tooltip {
opacity: 1;
}
.chart-container {
height: 60px;
position: relative;
border-bottom: 1px solid var(--vp-c-divider);
margin-top: 0.75rem;
}
.chart-svg {
width: 100%;
height: 100%;
overflow: visible;
}
.chart-label {
position: absolute;
font-size: 0.7rem;
color: var(--vp-c-text-3);
}
.chart-label.y-axis { top: 0; left: 0; }
.chart-label.x-axis { bottom: -1rem; width: 100%; text-align: center; }
.metrics-panel {
display: flex;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.metric-card {
flex: 1;
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
text-align: center;
}
.metric-value {
font-size: 1.25rem;
font-weight: bold;
}
.metric-label {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-top: 0.2rem;
}
.text-success { color: var(--vp-c-success-1); }
.text-warning { color: var(--vp-c-warning-1); }
.text-danger { color: var(--vp-c-danger-1); }
.info-box {
background-color: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
}
.info-box .icon {
margin-right: 0.5rem;
}
</style>