手把手教你搭一个高校招生数字人:从通义千问到星云SDK全流程
每年六月到八月,高校招生办的电话就没停过。家长问专业、问分数线、问宿舍、问就业率,翻来覆去就那些问题,但每一个都得耐心回答。
去年暑假,某高校的朋友跟我吐槽:招生办三个人,接了两个月的电话,嗓子全哑了。
我当时正好在研究具身交互智能的方向,就提议:要不做一个数字人招生顾问?把常见问题灌进去,让AI先回答第一层,复杂问题再转人工。
这篇文章把整个搭建过程拆开来讲,代码和配置都给出来,感兴趣的朋友可以跟着做。
第一步:准备大模型和知识库
招生场景的知识库比较结构化:学校概况、院系专业、历年分数线、招生计划、校园生活、就业数据。我把这些信息整理成了Markdown文档,作为RAG的知识源。
大模型选了通义千问。原因很简单:中文理解能力强,招生咨询里经常有口语化的表达("你们学校那个什么专业好不好"),通义千问处理这类输入比较稳。
Agent层用了LangChain,搭了一个标准的RAG流程:
用户提问 → 意图识别 → 知识库检索 → 大模型生成回答 → 输出
这里有个细节:招生咨询的意图比较集中,我做了一个意图分类的前置层,把问题分成"专业介绍""分数线查询""校园生活""招生政策"四个类别,分别路由到对应的知识库子集。这样检索准确率会高很多。
第二步:接入星云SDK
大模型和Agent解决的是"AI知道什么"的问题,星云SDK解决的是"AI怎么跟你说话"的问题。
星云SDK是魔珐科技做的具身交互智能平台,它的作用是把大模型的文字输出变成一个3D数字人的实时播报——包括语音、口型、表情和肢体动作。
接入过程不复杂。先引入SDK:
<script src="https://media.xingyun3d.com/xingyun3d/general/litesdk/xmovAvatar@latest.js"></script>
然后初始化:
// 招生数字人 - 星云SDK初始化 const sdk = new XmovAvatar({ containerId: "#admission-assistant", appId: "YOUR_APP_ID", appSecret: "YOUR_APP_SECRET", gatewayServer: "https://nebula-agent.xingyun3d.com/user/v1/ttsa/session", onMessage: (msg) => { console.log("SDK Event:", msg); if (msg.type === "voice_state_change") { const state = msg.state || msg; if (state === "idle") { console.log("播报完毕,可以接受新提问"); } } }, proxyWidget: { "subtitle_on": (data) => { document.getElementById("subtitle").innerText = data.text; document.getElementById("subtitle").style.display = "block"; return false; // 屏蔽默认字幕,用自定义样式 }, "subtitle_off": () => { document.getElementById("subtitle").style.display = "none"; return false; } } }); // 初始化,处理下载进度 await sdk.init({ onDownloadProgress: (p) => { if (p < 100) { document.getElementById("progress").innerText = `加载中 ${p}%`; } } });第三步:实现对话流程
把大模型和SDK串起来的核心逻辑:
async function handleStudentQuestion(question) { // 1. 大模型生成回答 const answer = await getAgentResponse(question); // 2. 按句拆分 const sentences = splitSentences(answer); // 3. 流式播报给数字人 for (let i = 0; i < sentences.length; i++) { const isFirst = i === 0; const isLast = i === sentences.length - 1; sdk.speak(sentences[i], isFirst, isLast); // 如果不是最后一句,等当前句播完再播下一句 if (!isLast) { await waitForVoiceEnd(); } } }家长随时可能打断,比如数字人在介绍专业设置,家长突然想问分数线:
// 家长打断处理 function onParentInterrupt(newQuestion) { // 先打断当前播报 sdk.interactiveidle(); // 等状态恢复后播报新内容 const originalHandler = sdk.config.onMessage; sdk.config.onMessage = (msg) => { originalHandler(msg); const state = msg.state || msg; if (state === "idle") { handleStudentQuestion(newQuestion); sdk.config.onMessage = originalHandler; // 恢复 } }; }第四步:终端部署
招生场景的终端主要是两种:招生咨询大厅的大屏和线上招生网站的嵌入。
大屏部署比较简单,把HTML页面全屏展示就行。星云SDK的端侧渲染方案对硬件要求很低,普通的大屏一体机就能流畅运行。
// 全屏适配招生大厅大屏 function setupFullScreen() { document.documentElement.style.margin = "0"; document.documentElement.style.overflow = "hidden"; const container = document.getElementById("admission-assistant"); container.style.width = "100vw"; container.style.height = "100vh"; }线上嵌入的话,把整个页面作为一个iframe嵌入招生网站就行,SDK会自动适配容器大小。
第五步:横竖屏切换
有些宣传场景需要竖屏展示(比如门口的立式广告机),星云SDK支持直接通过CSS切换容器比例:
function switchToPortrait() { const container = document.getElementById("admission-assistant"); container.style.width = "1080px"; container.style.height = "1920px"; } function switchToLandscape() { const container = document.getElementById("admission-assistant"); container.style.width = "1920px"; container.style.height = "1080px"; }实际效果
这个招生数字人在某高校招生办跑了整个暑假。几个数据:
日均处理咨询约200次,覆盖了大约70%的常见提问。招生办的电话量下降了约40%。
家长反馈比较好的点:不用排队等人工接待,到了就能问;数字人回答比较耐心,同一个问题问三遍也不会不耐烦(这点人工真做不到)。
需要改进的点:一些非常具体的问题(比如"某省某年某专业录取的最低分是多少"),知识库覆盖不够细,需要持续补充。
写在最后
整个项目从开发到上线大约两周。技术栈不复杂:通义千问做大模型,LangChain做Agent,星云SDK做交互层,部署在普通大屏上。
核心体验的提升来自具身交互智能——不再是让家长在一个文本框里打字,而是面对面和一个"招生老师"对话。这个交互方式的改变,对不擅长打字的家长群体来说,体验提升是质的飞跃。
想自己动手试试的朋友,可以去星云官网下载SDK,基础开发文档写得很清楚,先跑个Demo出来再接自己的大模型。招生季马上又到了,时间还来得及。
官网地址:https://xingyun3d.com/?utm_campaign=daily&utm_source=juzhen