Skip to content

ComparisonMessage 对比组件 ​

A/B 偏好对比组件:左右双列并排展示两个候选回复,每列底部各一个「我更喜欢这个回复」按钮,用于收集用户偏好(如 RLHF 偏好数据)。窄屏(< 640px)自动堆叠为上下排列。

代码演示 ​

点击选择 ​

点击任一列骑在底边上的按钮即可选中并高亮该列,prefer 事件回传 { chosen, left, right }:

回复 A
回复 B

当前偏好:(尚未选择)

受控选中 ​

chosen 非 null 时高亮由父组件控制(如回放历史偏好数据);外部按钮可随时切换或清除:

chosen = null
回复 A
回复 B

列内容经 MessageContent 走 markdown-it 渲染,支持代码高亮、公式等;按钮在消息卡下边界正中、主题色圆角,文案可经 buttonLabel 配置(默认「喜欢这个」)。

消息类型驱动渲染 ​

服务端响应可直接在 Message 上携带 comparison 载荷(ComparisonPayload),宿主按消息类型决定渲染 ComparisonMessage 还是普通消息;用户选中后把选中内容固化回 content、清空 comparison,状态随消息持久(切换会话再回来依然保留):

vue
<template>
  <Message v-for="msg in chat.messages" :key="msg.id" :from="msg.role">
    <ComparisonMessage
      v-if="msg.comparison"
      :left="msg.comparison.left"
      :right="msg.comparison.right"
      :left-label="msg.comparison.leftLabel"
      :right-label="msg.comparison.rightLabel"
      @prefer="(p) => onPrefer(msg, p)"
    />
    <MessageContent v-else :content="msg.content" />
  </Message>
</template>

<script setup lang="ts">
function onPrefer(
  msg: Message,
  p: { chosen: 'A' | 'B'; left: string; right: string },
) {
  msg.content = p.chosen === 'A' ? p.left : p.right
  msg.comparison = undefined
}
</script>

API ​

Props ​

属性名类型默认值说明
leftstring—候选 A 内容(markdown,必填)
rightstring—候选 B 内容(markdown,必填)
leftLabelstring'回复 A'左列标题
rightLabelstring'回复 B'右列标题
chosen'A' | 'B' | nullnull受控选中;非 null 时高亮由父控制
buttonLabelstring'喜欢这个'底部按钮文案
stackOnMobilebooleantrue窄屏(< 640px)堆叠为上下
disabledbooleanfalse禁用选择

Events ​

事件名载荷说明
prefer{ chosen: 'A' | 'B'; left: string; right: string }点击任一列按钮时触发

Slots ​

插槽名作用域说明
left{ label: string }自定义左列内容(覆盖 left)
right{ label: string }自定义右列内容(覆盖 right)
action-left—自定义左列底部按钮
action-right—自定义右列底部按钮

列内容默认经 MessageContent 渲染为 markdown(支持代码高亮、公式等,与消息流一致)。Message.comparison 为可选字段(渐进增强),不携带时组件库行为不变,后端无关。