记录利用Cursor快速实现拖拽式问卷题型创建

帮我实现一个可拖拽式的调查问卷demo,左侧是可拖拽生成的题型类别(比如:单选题、多选题、填空题),中间是可拖拽生成题型的区域,区域内的题型可以自行上下拖拽,右侧是点击中间区域对应的题型,可以对其进行编辑修改,设置禁用项,输入长度限制等等。总结来说类似于"调问"和"问卷星"。

简简单单,你就跟产品或者项目经理似的给 Cursor 提任务需求就可以了,他就能够快速自动帮你实现,话不多说,先看下成果~

Cursor 在整个实现过程前前后后可能也就不到 10分钟 就完事了,想当初为了实现此功能,先是搜索了大量的Git项目案例,找到合适的项目demo后,又是开始熟悉了解使用方法。

一开始没有找项目案例,纯找实现方法,发现实现起来还是有点费劲

《Vue2 _ 实现拖拽功能》https://blog.csdn.net/weixin_58099903/article/details/122186582?fromshare=blogdetail&sharetype=blogdetail&sharerId=122186582&sharerefer=PC&sharesource=weixin_58099903&sharefrom=from_link

后来找的项目demo,里面使用了 Vue 的一款 拖拽插件 vue.draggable

推荐学习文章:《记录Vue.Draggable拖拽组件的使用历程》

《记录Vue.Draggable拖拽组件的使用历程》https://blog.csdn.net/weixin_58099903/article/details/125655355?fromshare=blogdetail&sharetype=blogdetail&sharerId=125655355&sharerefer=PC&sharesource=weixin_58099903&sharefrom=from_link前前后后包括搜索项目案例和学习使用方法就花费了 一周 的时间,可见其成本和效率,

可以毫不夸张的说,使用 Cursor 开发,效率提升至少 10 倍!


接下来咱们细看一下 Cursor 是如何一步一步实现的吧~

1、先查看项目结构与依赖。

2、自动 安装 vue-draggable-plus 并注册 Pinia。

3、创建类型、工厂函数、Pinia store 与问卷搭建页面。

1、src\types\survey.ts --- 题型与数据结构

TypeScript 复制代码
export type QuestionKind = 'single' | 'multiple' | 'fill'

export interface OptionItem {
  id: string
  label: string
  disabled?: boolean
}

export interface SurveyQuestionBase {
  id: string
  type: QuestionKind
  title: string
  required: boolean
}

export interface SingleQuestion extends SurveyQuestionBase {
  type: 'single'
  options: OptionItem[]
}

export interface MultipleQuestion extends SurveyQuestionBase {
  type: 'multiple'
  options: OptionItem[]
  minSelect?: number
  maxSelect?: number
}

export interface FillQuestion extends SurveyQuestionBase {
  type: 'fill'
  placeholder?: string
  minLength?: number
  maxLength?: number
}

export type SurveyQuestion = SingleQuestion | MultipleQuestion | FillQuestion

export interface PaletteItem {
  id: string
  kind: QuestionKind
  label: string
  description: string
}

2、src\utils\surveyFactory.ts --- createQuestionPALETTE_ITEMS

TypeScript 复制代码
import type {
  FillQuestion,
  MultipleQuestion,
  OptionItem,
  QuestionKind,
  SingleQuestion,
  SurveyQuestion,
} from '@/types/survey'

function uid(): string {
  return crypto.randomUUID()
}

function defaultOptions(): OptionItem[] {
  return ['选项 A', '选项 B', '选项 C', '选项 D'].map((label) => ({
    id: uid(),
    label,
    disabled: false,
  }))
}

export function createQuestion(kind: QuestionKind): SurveyQuestion {
  const base = { id: uid(), title: '未命名题目', required: false }
  if (kind === 'single') {
    const q: SingleQuestion = {
      ...base,
      type: 'single',
      options: defaultOptions(),
    }
    return q
  }
  if (kind === 'multiple') {
    const q: MultipleQuestion = {
      ...base,
      type: 'multiple',
      options: defaultOptions(),
      minSelect: 1,
      maxSelect: undefined,
    }
    return q
  }
  const q: FillQuestion = {
    ...base,
    type: 'fill',
    placeholder: '请输入内容',
    minLength: undefined,
    maxLength: 200,
  }
  return q
}

export const PALETTE_ITEMS = [
  {
    id: 'palette-single',
    kind: 'single' as const,
    label: '单选题',
    description: '从多个选项中选一项',
  },
  {
    id: 'palette-multiple',
    kind: 'multiple' as const,
    label: '多选题',
    description: '从多个选项中选多项',
  },
  {
    id: 'palette-fill',
    kind: 'fill' as const,
    label: '填空题',
    description: '短文本输入',
  },
]

3、src\stores\surveyBuilder.ts --- Pinia:题目列表、选中项、patchQuestionupdateOption

TypeScript 复制代码
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import type { OptionItem, SurveyQuestion } from '@/types/survey'
export const useSurveyBuilderStore = defineStore('surveyBuilder', () => {
  const questions = ref<SurveyQuestion[]>([])
  const selectedId = ref<string | null>(null)

  const selectedQuestion = computed(() => {
    if (!selectedId.value) return null
    return questions.value.find((q) => q.id === selectedId.value) ?? null
  })

  function selectQuestion(id: string | null) {
    selectedId.value = id
  }

  function removeQuestion(id: string) {
    questions.value = questions.value.filter((q) => q.id !== id)
    if (selectedId.value === id) selectedId.value = null
  }

  function patchQuestion(id: string, patch: Partial<SurveyQuestion>) {
    const i = questions.value.findIndex((q) => q.id === id)
    if (i === -1) return
    const cur = questions.value[i]
    if (!cur) return
    questions.value[i] = { ...cur, ...patch } as SurveyQuestion
  }

  function updateOption(
    questionId: string,
    optionId: string,
    patch: Partial<OptionItem>,
  ) {
    const q = questions.value.find((x) => x.id === questionId)
    if (!q || (q.type !== 'single' && q.type !== 'multiple')) return
    const opts = q.options.map((o) =>
      o.id === optionId ? { ...o, ...patch } : o,
    )
    patchQuestion(questionId, { options: opts } as Partial<SurveyQuestion>)
  }

  function addOption(questionId: string) {
    const q = questions.value.find((x) => x.id === questionId)
    if (!q || (q.type !== 'single' && q.type !== 'multiple')) return
    const next: OptionItem = {
      id: crypto.randomUUID(),
      label: `选项 ${q.options.length + 1}`,
      disabled: false,
    }
    patchQuestion(questionId, {
      options: [...q.options, next],
    } as Partial<SurveyQuestion>)
  }

  function removeOption(questionId: string, optionId: string) {
    const q = questions.value.find((x) => x.id === questionId)
    if (!q || (q.type !== 'single' && q.type !== 'multiple')) return
    if (q.options.length <= 1) return
    patchQuestion(questionId, {
      options: q.options.filter((o) => o.id !== optionId),
    } as Partial<SurveyQuestion>)
  }

  return {
    questions,
    selectedId,
    selectedQuestion,
    selectQuestion,
    removeQuestion,
    patchQuestion,
    updateOption,
    addOption,
    removeOption,
  }
})

4、src\components\survey-builder\QuestionInspector.vue --- 右侧表单(Element Plus)

TypeScript 复制代码
<template>
  <div class="inspector">
    <h3 class="inspector-title">题目设置</h3>
    <div v-if="!q" class="inspector-empty">
      请在中间区域点击一道题目,即可在此编辑标题、选项与校验规则。
    </div>
    <el-form v-else label-position="top" class="inspector-form">
      <el-form-item label="题目标题">
        <el-input
          :model-value="q.title"
          maxlength="200"
          show-word-limit
          placeholder="请输入标题"
          @update:model-value="store.patchQuestion(q.id, { title: $event })"
        />
      </el-form-item>
      <el-form-item label="必答">
        <el-switch
          :model-value="q.required"
          @update:model-value="store.patchQuestion(q.id, { required: $event })"
        />
      </el-form-item>

      <template v-if="q.type === 'single' || q.type === 'multiple'">
        <el-divider content-position="left">选项</el-divider>
        <p class="hint">可关闭某选项前的「启用」以在答题时隐藏该选项(禁用项)。</p>
        <div
          v-for="(opt, idx) in q.options"
          :key="opt.id"
          class="option-row"
        >
          <span class="opt-index">{{ idx + 1 }}.</span>
          <el-input
            class="opt-input"
            :model-value="opt.label"
            placeholder="选项文案"
            @update:model-value="
              store.updateOption(q.id, opt.id, { label: $event })
            "
          />
          <el-switch
            :model-value="!opt.disabled"
            inline-prompt
            active-text="启用"
            inactive-text="禁用"
            style="flex-shrink: 0"
            @update:model-value="
              store.updateOption(q.id, opt.id, { disabled: !$event })
            "
          />
          <el-button
            type="danger"
            link
            :disabled="q.options.length <= 1"
            @click="store.removeOption(q.id, opt.id)"
          >
            删除
          </el-button>
        </div>
        <el-button class="add-opt" @click="store.addOption(q.id)">
          + 添加选项
        </el-button>
      </template>

      <template v-if="q.type === 'multiple'">
        <el-divider content-position="left">多选限制</el-divider>
        <el-form-item label="最少选几项">
          <el-input-number
            :model-value="q.minSelect ?? 0"
            :min="0"
            :max="q.options.length"
            controls-position="right"
            @update:model-value="patchMultipleMin($event)"
          />
        </el-form-item>
        <el-form-item label="最多选几项(空为不限制)">
          <el-input-number
            :model-value="q.maxSelect ?? undefined"
            :min="1"
            :max="q.options.length"
            controls-position="right"
            :value-on-clear="undefined"
            @update:model-value="patchMultipleMax($event)"
          />
        </el-form-item>
      </template>

      <template v-if="q.type === 'fill'">
        <el-divider content-position="left">填空设置</el-divider>
        <el-form-item label="占位提示">
          <el-input
            :model-value="q.placeholder ?? ''"
            placeholder="输入框占位文字"
            @update:model-value="patchFillPlaceholder($event)"
          />
        </el-form-item>
        <el-form-item label="最少字数">
          <el-input-number
            :model-value="q.minLength ?? undefined"
            :min="0"
            :max="99999"
            controls-position="right"
            :value-on-clear="undefined"
            placeholder="不限制"
            @update:model-value="patchFillMinLen($event)"
          />
        </el-form-item>
        <el-form-item label="最多字数">
          <el-input-number
            :model-value="q.maxLength ?? undefined"
            :min="1"
            :max="99999"
            controls-position="right"
            :value-on-clear="undefined"
            placeholder="不限制"
            @update:model-value="patchFillMaxLen($event)"
          />
        </el-form-item>
      </template>
    </el-form>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { useSurveyBuilderStore } from '@/stores/surveyBuilder'

const store = useSurveyBuilderStore()
const q = computed(() => store.selectedQuestion)

function patchMultipleMin(val: number | undefined) {
  const cur = q.value
  if (!cur || cur.type !== 'multiple') return
  store.patchQuestion(cur.id, { minSelect: val ?? undefined })
}

function patchMultipleMax(val: number | undefined) {
  const cur = q.value
  if (!cur || cur.type !== 'multiple') return
  store.patchQuestion(cur.id, { maxSelect: val ?? undefined })
}

function patchFillPlaceholder(val: string) {
  const cur = q.value
  if (!cur || cur.type !== 'fill') return
  store.patchQuestion(cur.id, { placeholder: val || undefined })
}

function patchFillMinLen(val: number | undefined) {
  const cur = q.value
  if (!cur || cur.type !== 'fill') return
  store.patchQuestion(cur.id, { minLength: val ?? undefined })
}

function patchFillMaxLen(val: number | undefined) {
  const cur = q.value
  if (!cur || cur.type !== 'fill') return
  store.patchQuestion(cur.id, { maxLength: val ?? undefined })
}
</script>

<style scoped>
.inspector {
  height: 100%;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.inspector-title {
  margin: 0 0 12px;
  font-size: 15px;
  font-weight: 600;
  color: #303133;
}

.inspector-empty {
  font-size: 13px;
  line-height: 1.6;
  color: #909399;
  padding: 8px 0;
}

.inspector-form {
  flex: 1;
  overflow: auto;
  padding-right: 4px;
}

.hint {
  margin: 0 0 12px;
  font-size: 12px;
  color: #909399;
  line-height: 1.5;
}

.option-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.opt-index {
  width: 22px;
  flex-shrink: 0;
  font-size: 13px;
  color: #606266;
}

.opt-input {
  flex: 1;
  min-width: 0;
}

.add-opt {
  width: 100%;
  margin-top: 4px;
}
</style>

值得一提的是,Cursor 会自己检测代码并修正优化。

5、src\views\SurveyBuilderDemo.vue --- 三栏布局 + 双 VueDraggable

TypeScript 复制代码
<template>
  <div class="survey-builder-wrap">
    <header class="survey-header">
      <h1 class="survey-title">问卷搭建器 Demo</h1>
      <p class="survey-sub">
        从左侧拖入题型到中间;中间可拖拽排序;点击题目在右侧编辑。
      </p>
      <router-link class="survey-link" to="/marquee">返回滚动演示</router-link>
    </header>

    <div class="survey-grid">
      <aside class="panel panel-left">
        <h2 class="panel-heading">题型库</h2>
        <p class="panel-tip">按住拖入中间画布</p>
        <VueDraggable
          v-model="paletteItems"
          :group="{ name: 'survey', pull: 'clone', put: false }"
          :clone="clonePaletteItem"
          :sort="false"
          :animation="200"
          class="palette-draggable"
        >
          <div
            v-for="p in paletteItems"
            :key="p.id"
            class="palette-card"
          >
            <span class="palette-icon" aria-hidden="true">≡</span>
            <div class="palette-body">
              <div class="palette-label">{{ p.label }}</div>
              <div class="palette-desc">{{ p.description }}</div>
            </div>
          </div>
        </VueDraggable>
      </aside>

      <main class="panel panel-center">
        <h2 class="panel-heading">问卷内容</h2>
        <VueDraggable
          v-model="questions"
          :group="{ name: 'survey', pull: true, put: true }"
          :animation="200"
          handle=".q-drag-handle"
          ghost-class="ghost-card"
          class="canvas-draggable"
        >
          <div
            v-for="(q, index) in questions"
            :key="q.id"
            class="question-card"
            :class="{ 'is-active': selectedId === q.id }"
            @click="store.selectQuestion(q.id)"
          >
            <div class="q-drag-handle" title="拖动排序" @click.stop>
              ⋮⋮
            </div>
            <div class="q-main">
              <div class="q-head">
                <span class="q-no">Q{{ index + 1 }}</span>
                <el-tag size="small" type="info">{{ typeLabel(q.type) }}</el-tag>
                <span v-if="q.required" class="q-req">必答</span>
                <el-button
                  type="danger"
                  link
                  class="q-del"
                  @click.stop="store.removeQuestion(q.id)"
                >
                  删除
                </el-button>
              </div>
              <div class="q-title">{{ q.title }}</div>
              <div class="q-preview">
                <template v-if="q.type === 'single'">
                  <el-radio-group class="preview-group" :model-value="''">
                    <el-radio
                      v-for="opt in q.options"
                      :key="opt.id"
                      :label="opt.id"
                      :disabled="opt.disabled"
                    >
                      {{ opt.label }}
                    </el-radio>
                  </el-radio-group>
                </template>
                <template v-else-if="q.type === 'multiple'">
                  <el-checkbox-group class="preview-group" :model-value="[]">
                    <el-checkbox
                      v-for="opt in q.options"
                      :key="opt.id"
                      :label="opt.id"
                      :disabled="opt.disabled"
                    >
                      {{ opt.label }}
                    </el-checkbox>
                  </el-checkbox-group>
                </template>
                <template v-else>
                  <el-input
                    :model-value="''"
                    :placeholder="q.placeholder || '答题者输入'"
                    disabled
                  />
                </template>
              </div>
            </div>
          </div>
        </VueDraggable>
        <div v-if="questions.length === 0" class="canvas-empty">
          将左侧「单选题 / 多选题 / 填空题」拖放到此处开始组卷
        </div>
      </main>

      <aside class="panel panel-right">
        <QuestionInspector />
      </aside>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { storeToRefs } from 'pinia'
import { VueDraggable } from 'vue-draggable-plus'
import { useSurveyBuilderStore } from '@/stores/surveyBuilder'
import { PALETTE_ITEMS, createQuestion } from '@/utils/surveyFactory'
import type { PaletteItem, SurveyQuestion } from '@/types/survey'
import QuestionInspector from '@/components/survey-builder/QuestionInspector.vue'

const store = useSurveyBuilderStore()
const { questions, selectedId } = storeToRefs(store)

const paletteItems = ref<PaletteItem[]>([...PALETTE_ITEMS])

function clonePaletteItem(item: PaletteItem): SurveyQuestion {
  return createQuestion(item.kind)
}

function typeLabel(type: SurveyQuestion['type']) {
  const map = { single: '单选题', multiple: '多选题', fill: '填空题' }
  return map[type]
}
</script>

<style scoped>
.survey-builder-wrap {
  position: relative;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  width: 100vw;
  min-height: calc(100vh - 32px);
  box-sizing: border-box;
  padding: 16px 20px 24px;
  background: linear-gradient(180deg, #f5f7fa 0%, #eef1f6 100%);
}

.survey-header {
  max-width: 1200px;
  margin: 0 auto 16px;
}

.survey-title {
  margin: 0 0 6px;
  font-size: 22px;
  font-weight: 700;
  color: #303133;
}

.survey-sub {
  margin: 0 0 8px;
  font-size: 14px;
  color: #606266;
}

.survey-link {
  font-size: 13px;
  color: #409eff;
}

.survey-grid {
  display: grid;
  grid-template-columns: 240px minmax(360px, 1fr) 300px;
  gap: 16px;
  max-width: 1200px;
  margin: 0 auto;
  align-items: stretch;
  min-height: 520px;
}

.panel {
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
  padding: 14px 12px;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.panel-heading {
  margin: 0 0 4px;
  font-size: 15px;
  font-weight: 600;
  color: #303133;
}

.panel-tip {
  margin: 0 0 12px;
  font-size: 12px;
  color: #909399;
}

.palette-draggable {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.palette-card {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 10px;
  border: 1px dashed #c0c4cc;
  border-radius: 8px;
  cursor: grab;
  background: #fafafa;
  transition: border-color 0.2s, background 0.2s;
}

.palette-card:hover {
  border-color: #409eff;
  background: #ecf5ff;
}

.palette-icon {
  color: #909399;
  font-size: 18px;
  line-height: 1.2;
  user-select: none;
}

.palette-label {
  font-size: 14px;
  font-weight: 600;
  color: #303133;
}

.palette-desc {
  margin-top: 4px;
  font-size: 12px;
  color: #909399;
  line-height: 1.4;
}

.panel-center {
  position: relative;
}

.canvas-draggable {
  flex: 1;
  min-height: 200px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-bottom: 8px;
}

.canvas-empty {
  pointer-events: none;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -30%);
  max-width: 280px;
  text-align: center;
  font-size: 14px;
  color: #c0c4cc;
  line-height: 1.6;
}

.question-card {
  display: flex;
  gap: 8px;
  padding: 12px;
  border: 2px solid transparent;
  border-radius: 8px;
  background: #fafafa;
  cursor: pointer;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.question-card:hover {
  background: #f0f9ff;
}

.question-card.is-active {
  border-color: #409eff;
  background: #ecf5ff;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
}

.q-drag-handle {
  flex-shrink: 0;
  width: 28px;
  text-align: center;
  color: #c0c4cc;
  cursor: grab;
  user-select: none;
  font-size: 14px;
  line-height: 1.8;
}

.q-drag-handle:active {
  cursor: grabbing;
}

.q-main {
  flex: 1;
  min-width: 0;
}

.q-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}

.q-no {
  font-weight: 600;
  color: #606266;
  font-size: 13px;
}

.q-req {
  font-size: 12px;
  color: #f56c6c;
}

.q-del {
  margin-left: auto;
}

.q-title {
  font-size: 15px;
  font-weight: 500;
  color: #303133;
  margin-bottom: 10px;
}

.q-preview {
  font-size: 13px;
}

.preview-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}

.panel-right {
  overflow: hidden;
}

:deep(.ghost-card) {
  opacity: 0.55;
  background: #e1f0ff !important;
}
</style>

6、src\main.ts --- 已注册 Pinia、Element Plus(中文语言包)

TypeScript 复制代码
import './assets/main.css'

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'

createApp(App)
  .use(createPinia())
  .use(ElementPlus, { locale: zhCn })
  .use(router)
  .mount('#app')

7、src\router\index.ts --- 路由 /survey-builder/ 默认重定向到 /survey-builder

TypeScript 复制代码
import { createRouter, createWebHistory } from 'vue-router'
import ScrollMarqueeDemo from '@/views/ScrollMarqueeDemo.vue'
import SurveyBuilderDemo from '@/views/SurveyBuilderDemo.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      redirect: '/survey-builder',
    },
    {
      path: '/marquee',
      name: 'marquee',
      component: ScrollMarqueeDemo,
    },
    {
      path: '/survey-builder',
      name: 'survey-builder',
      component: SurveyBuilderDemo,
    },
  ],
})

export default router

大功告成:

已实现一个可拖拽的问卷搭建 Demo,说明如下。

功能概览

区域 作用
左侧「题型库」 单选题 / 多选题 / 填空题三种卡片,拖到中间即可生成题目(vue-draggable-plusgroup + pull: 'clone')。
中间「问卷内容」 展示已添加题目,左侧 ⋮⋮ 为拖动手柄,仅在手柄上拖动可上下排序;点击卡片选中并在右侧编辑;「删除」仅移除该题。
右侧「题目设置」 对当前选中题编辑:标题、必答;单选/多选:选项文案、启用/禁用选项、增删选项;多选额外:最少/最多选几项;填空:占位符、最少/最多字数。

涉及文件

  • src/types/survey.ts --- 题型与数据结构
  • src/utils/surveyFactory.ts --- createQuestionPALETTE_ITEMS
  • src/stores/surveyBuilder.ts --- Pinia:题目列表、选中项、patchQuestionupdateOption
  • src/views/SurveyBuilderDemo.vue --- 三栏布局 + 双 VueDraggable
  • src/components/survey-builder/QuestionInspector.vue --- 右侧表单(Element Plus)
  • src/main.ts --- 已注册 Pinia、Element Plus(中文语言包)
  • src/router/index.ts --- 路由 /survey-builder/ 默认重定向到 /survey-builder

本地执行 npm run dev,打开 http://localhost:5173/survey-builder(或根路径 /)即可。


最终看一眼效果图:

相关推荐
江畔柳前堤3 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore4 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考5 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX6 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面7 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号7 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽7 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI7 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者9 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者9 小时前
【征程6】校准量化中HistogramObserver解析
算法