# 码道:让大模型做你的游戏主持人——AI 对话式交互文字冒险「无尽回廊」开发全记录
码道:让大模型做你的游戏主持人——AI 对话式交互文字冒险「无尽回廊」开发全记录
用 HTML5 + CSS3 + JavaScript 从零搭建一个由 DeepSeek 驱动的无限叙事文字冒险游戏,不依赖任何框架与构建工具,纯前端拥抱大模型。本文完整记录了项目从灵感到落地、从 Python 参考实现到 JavaScript 流式重写的全过程。
一、前言:一次"即兴叙事"的冲动
你有没有过这样的时刻:读完一本小说,恨不得自己就是主角;玩完一款游戏,却对每个选项的走向烂熟于心;看完一部电影,惋惜分支剧情只能存在于导演的剪辑室。传统媒介里的故事总是"写完即定稿",玩家能做的不过是在有限的选项里挑一个,游戏的终点早已被设计者埋好。
但大模型的出现改变了一切。当语言模型拥有数以百亿计的参数、足够强的上下文理解能力与丰富的世界知识时,"生成式叙事"不再是科幻。AI 可以即时理解你的一句话行动指令,并根据设定好的世界观与角色逻辑,即时编织出下一段剧情——你向左转,它为你描绘左侧走廊里的烛台与蛛网;你选择驻足倾听,它让黑暗中传来低沉的呼吸声。
正是这种"无限可能性",让我决定亲手做一个项目。它既不是传统的视觉小说脚本,也不是套壳 Chatbot,而是一个真正意义上由 AI 主持、完全开放、可持续数小时也不会重复的交互式文字冒险游戏——我把它命名为「无尽回廊」。
这个项目的技术选型出人意料地保守:HTML5、CSS3、JavaScript,零第三方依赖、零构建工具、零后端服务。而支撑它运行的核心,是 DeepSeek-V4-Flash 模型的一次次流式推理调用。
本文将从设计动机、技术选型、核心实现、落地过程与踩坑经验几个维度,完整复盘这个项目的开发旅程。文章会比较长,因为我想把每一个值得分享的细节都记录下来,也希望给同样想用"大模型做产品"的开发者一些可复用的经验。

二、项目缘起:为什么做一款 AI 文字冒险
2.1 传统文字冒险的痛点
文字冒险游戏(Text Adventure / Interactive Fiction)历史悠久,从早期的 Zork 到如今的各类视觉小说,其核心矛盾始终存在:
- 内容成本极高:一条剧情线需要策划、文案、测试反复打磨,制作一个十小时体量的作品往往需要团队数月投入。
- 分支呈指数爆炸:两个选项就分裂出两条线,三个选项就分裂出三条线,想覆盖所有可能的行动组合几乎不可能。绝大多数游戏只能"假分支"——选项长得不一样,结局通向同一处。
- 玩家创造力受限:玩家输入"把蜡烛放到窗台上",系统若没有预设这个交互,就只能回复"你无法这样做"。这种挫败感是传统引擎的硬伤。
2.2 大模型给出的解法
大模型恰好同时解决了上述三个问题:
- 零边际内容成本:剧情由模型动态生成,世界无限大,不存在"内容用完"的概念。
- 分支天然收敛:无论玩家输入什么,模型都能依据当前状态输出合理的续写,既包容了想象,又不至于让开发维护爆炸。
- 自由输入自然语言:抛弃预设选项的枷锁,玩家可以直接键入任何行动,“让蜡烛发光”“回头看看脚印”“对着黑暗大喊”——模型都能理解语义并给出合理回应。
这正是"对话式交互"与"文字冒险"结合的意义所在。大模型不只是一个会聊天的机器人,它是一个可以承载世界观、维护状态、推进叙事的游戏主持人(Game Master)。
2.3 为什么采用对话式界面
我特意选择了"对话/聊天"式的交互形态,而非传统游戏的按钮式 UI。理由有三:
- 亲切感:聊天界面是当下用户最熟悉的交互范式,学习成本几乎为零。
- 叙事连续:聊天记录天然形成"事件流",玩家回看上一条行动与对应反馈,故事脉络一目了然。
- 契合创作:写作本身就是一个对话过程——策划与作者、作者与角色、角色与读者。将聊天界面用作叙事舞台,语义上严丝合缝。
于是「无尽回廊」的形态就此确定:左侧是玩家角色状态面板,中间是剧情舞台,底部是自由输入框。你打字,AI 编织命运。
三、技术选型:纯前端的三重考量
确定了产品形态,接下来是技术栈。很多人可能会下意识选择 React/Vue + Node 后端 + 数据库,但我最终选定了纯静态三件套。这并非保守,而是一种刻意的取舍。
3.1 零依赖,零门槛
- 无需 Node 环境:整个项目只有四个文件,任何一个装有现代浏览器的设备都能直接运行。
- 无需构建流程:没有 webpack、vite、npm install,改完代码刷新即可看到效果,对初学者极度友好。
- 部署即复制:把文件扔到任何静态文件服务器(Nginx、GitHub Pages、对象存储)就能上线,不需要运维任何后端进程。
3.2 浏览器原生能力已足够
过去"纯前端调大模型"最大的障碍是跨域(CORS)问题。好消息是,很多大模型服务商(包括本项目使用的 GitCode 开放 API)已经开放了浏览器直连许可。现代浏览器原生提供的 fetch + ReadableStream 足以实现完整的流式通信,连 EventSource 的 SSE 协议都无需依赖(因为需要 POST 请求,且要携带鉴权头)。
3.3 聚焦产品本身
去掉框架,反而让我把注意力放在了两件真正重要的事上,那就是提示词设计与渲染体验。项目的价值不在于某个炫酷的组件库,而在于那一纸"系统提示词"——它定义了 AI 的行为边界与输出契约,是整个产品心智的核心。
当然,纯前端方案也有代价:API 密钥暴露在浏览器端,无法做到真正的服务端鉴权。这一点的应对策略我会在安全章节详细说明。
四、从 Python 参考实现到 JavaScript:一次流式改写之旅
项目的 API 调用部分最初拿到的是 Python 参考代码。利用 Python 生态中的 requests 库,流式接收大模型响应几乎是开箱即用的体验。但我们的目标是纯前端,因此必须将其完整翻译为浏览器端的 JavaScript。这趟"翻译"看似机械,实际上躲着几个不深不浅的坑。
4.1 Python 参考实现长什么样
参考代码的核心逻辑大致如下:
def query(payload):
response = requests.post(API_URL, headers=headers, json=payload, stream=True)
for line in response.iter_lines():
if not line.startswith(b"data:"):
continue
if line.strip() in (b"data:[DONE]", b"data: [DONE]"):
return
yield json.loads(line.decode("utf-8").lstrip("data:").rstrip("/n"))
几个值得注意的细节:
stream=True:开启 HTTP 流式传输,服务端分批返回,客户端逐行消费。iter_lines():按行迭代字节流。- 前缀过滤:只处理以
data:开头的事件行(SSE 协议格式)。 - 结束哨兵:遇到
data: [DONE]终止迭代。 - 生成器(yield):逐块产出解析后的 JSON,调用方可以实时消费。
4.2 浏览器端对应的写法
JavaScript 没有 iter_lines(),但浏览器提供了一套等价的机制——Response.body.getReader() 配合 TextDecoder:
const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop(); // 保留可能被截断的残行
for (const rawLine of lines) {
const line = rawLine.trim();
if (!line.startsWith("data:")) continue;
if (line === "data:[DONE]" || line === "data: [DONE]") continue;
const json = JSON.parse(line.slice(5).trim());
const delta = json.choices?.[0]?.delta?.content;
if (delta) fullText += delta;
}
}
4.3 翻译过程中的三个关键坑
坑一:半行问题(频段边界)。网络块(chunk)的边界与 SSE 行的边界不一致,一行可能被切到两个 chunk 中。解决方案是维护一个 buffer,每次先把残行拼接完整再逐行处理。这正是 Python iter_lines() 内部帮我们做掉的事情,浏览器端需要自己实现一次。
坑二:多字节字符的分裂。中文 UTF-8 编码占 3 字节,一个汉字可能被一个 chunk 截成两半。TextDecoder(..., { stream: true }) 专门解决了这个问题——它会保存上一个块未完成的字节,等下一块到来时拼成完整的字符。千万不能省略 stream: true,否则会出现乱码。
**坑三:python 与 javascript 的行尾差异**。参考代码中的 rstrip(“/n”)(反斜杠 n 字符串)其实是原文笔误,Python 的 strip() 已经足够。在 JavaScript 侧,line.slice(5).trim()才是更稳妥的做法,它同时兼容data:` 后是否带空格两种情况。
4.4 请求体的参数对齐
请求体与参考实现保持一致,并在独立配置文件 config.js 中统一管理:
const CONFIG = {
API_URL: "https://api-ai.gitcode.com/v1/chat/completions",
MODEL: "deepseek-ai/DeepSeek-V4-Flash",
MAX_TOKENS: 2048,
TEMPERATURE: 0.6, // 温度:略低,保证叙事稳定
TOP_P: 0.95, // 核采样:保留一定的多样性
FREQUENCY_PENALTY: 0, // 不做重复惩罚,让语气自然
THINKING_BUDGET: 2048
};
把这些参数单独抽到配置文件而不是散落在代码里的好处是:非技术人员也可以直接改配置文件来调整游戏风格,而不需要碰业务代码。
五、系统提示词:让大模型化身"游戏主持人"
这是整个项目含金量最高的部分。同样的 API,写给聊天机器人看的系统提示词和写给游戏主持人看的提示词,效果天差地别。
5.1 角色设定:Game Master
系统提示词的开头必须一句话锁定角色:
你是「无尽回廊」文字冒险游戏的叙事引擎与游戏主持人(Game Master)。玩家正身处于一个充满神秘与危机的奇幻世界中,一切将由你实时生成。
“游戏主持人"这个角色定义极其重要,它同时约束了三点:叙事口吻(第二人称"你”)、行为边界(只输出剧情相关内容)、职责范围(负责世界运行与状态管理)。一旦角色确立,模型就会自动"入戏",极少再跳脱出框架输出无关内容。
5.2 结构契约:让 HTML 更好显示的 JSON
大多数 AI 应用失败在"返回值自由发挥"。为了让前端 HTML 稳定渲染,我在系统提示词中硬性规定了输出格式——一个固定的 JSON 结构,包含 8 个字段:
{
"scene_title": "场景小标题,例如「尘封的回廊」",
"location": "当前所处地点名称,例如「旧图书馆 · 一层」",
"narration": "对该场景的沉浸式描写,3~6 句话,第二人称“你”……",
"event_summary": "玩家上一回合行动产生的直接后果……",
"hp": 100,
"stamina": 100,
"inventory": ["物品A", "物品B"],
"options": [
{"text": "简短动作选项", "hint": "给玩家的私密提示"}
]
}
在提示词中,我不只是列出结构,还针对每个字段写了类型要求、取值范围、取值语义和示例。比如:
hp / stamina必须为 0~100 的整数,依剧情合理增减;options固定 3~4 个,必须是"具体的行动"而非抽象描述;inventory每回合完整给出(增删物品都要在列表里体现);- 结局时
options置空数组。
为什么这么详细?因为语言模型遵循的"规则"就是提示词中出现的每一个约束。约束写得越具体、越可验证,模型输出的越稳定。实践下来,模型几乎可以 100% 输出结构正确的 JSON。
5.3 状态一致性协议
游戏的主持人必须"记住"玩家状态,但 LLM 是无状态的——每次调用都得把历史上下文完整喂回去。我的协议是:
- 每一次玩家行动后,模型返回上述 JSON;
- 前端把模型的原始 JSON 文本原样记录为 assistant 消息,追加进消息历史;
- 下次请求时携带完整历史;模型从历史中读取当前 hp、背包、场景,继续演进。
采用"JSON 即上下文"的设计,避免了前端自行维护状态的结构漂移:模型读取的、与前端渲染的,是同一份数据,两边永远不会对不上。
5.4 上下文长度治理
游戏玩久了,历史消息会越来越长,最终击穿模型的上下文窗口。我在前端做了滑动窗口策略:保留最近 16 条消息(system 提示词单独拼装),更早的历史自然截断。对于强调沉浸式连续性的文字冒险来说,16 条通常足够覆盖"最近发生的事",既能维持连贯叙事,又能稳定控制 token 成本。
六、结构化数据契约:前端渲染的基石
传统聊天应用的返回是纯文本,前端只能整段展示。而在文字冒险里,我们需要的是一套结构化状态:场景标题、地点、血量、精力、背包、选项。这些数据只有被精确解析,UI 才能做到"健康条增减、背包增删、选项按钮化"。
6.1 JSON 解析的容错武器
即使提示词约束得再严格,也不能完全信任模型的输出。现实中可能遇到这些情况:
- 模型输出了 markdown 代码围栏(```json);
- 模型在 JSON 前后加了"好的,这是你的场景:"之类的杂质文本;
- 流式拼接时个别字符损坏导致整段 JSON 无法直接解析。
因此我实现了一个多重兜底的解析函数 extractJson():
- 先剥离 ```json 围栏与首尾空白;
- 尝试直接
JSON.parse; - 失败则截取第一个
{到最后一个}之间的子串再解析; - 仍失败则返回
null,触发上层重试逻辑。
这个"截最大花括号区间"的手法朴实但极其有效,实测能救回绝大部分杂质输出。
6.2 字段规范化:脏数据的最后防线
即使 JSON 结构正确,字段值也可能"越界"。例如模型返回 hp: 150、stamina: -20 或 inventory: "金币"(字符串而非数组)。normalizeScene() 负责把所有字段收编为安全值:
- 数值字段做 0~100 钳制;
- 数组字段校验并映射为字符串数组;
- 选项过滤掉空文本,避免渲染出空按钮;
- 缺失字段回退到当前游戏状态的默认值。
经过这两层处理,前端渲染逻辑就可以"信任数据",不需要到处写防御性分支。
6.3 数据契约带来的 UI 收益
正因为有了结构化数据,渲染层才能轻松实现:
- 健康条动画:hp 变化时宽度过渡动画,直观呈现战斗/休息反馈;
- 背包列表:新增物品自动出现在面板,丢失物品自动消失;
- 选项按钮化:点击选项即发送该行动,一步直达;
- 提示气泡:
hint字段作为 title tooltip,玩家悬停可窥探"直觉",但不直白剧透。
这些体验,是纯文本聊天界面完全做不到的。
七、前端渲染引擎与交互设计
7.1 页面布局:三区结构
围绕"游戏化"目标,页面采用三区布局:
- 左侧状态面板:生命值、精力条、地点、背包。信息密度高、常驻可见,让玩家时刻掌握角色处境。
- 中间剧情舞台:聊天式滚动区,承载事件反馈、场景标题、叙述文本与行动选项。
- 底部输入区:自由输入框 + 发送按钮,Enter 快捷发送。
7.2 打字机效果:叙事节奏的艺术
文字冒险的沉浸感,很大程度上来自文本的"呼吸感"。瞬时显示一大段文本会让玩家失去节奏,我因此为叙述文本实现了打字机逐字效果:
- 每帧输出 2 个字符(观感更流畅且不过分缓慢);
- 显示一个闪烁的光标作为"AI 正在书写"的可视锚点;
- 长文本自动加快速度,避免等待焦躁;
- 自动滚动到屏幕底部,保证最新内容始终可见。
打字机效果不只是"炫技",它对叙事体验有实质增益:玩家被动地跟随 AI 的叙述节奏,悬念被拉开、情绪被酝酿,这恰恰是文字冒险最需要的"临场感"。
7.3 事件反馈与历史留存设计
每一轮交互,界面会依次呈现:
- 玩家行动气泡(如果是自由输入);
- 上回合后果反馈(event_summary,金色高亮);
- 场景标题;
- 叙述正文(打字机);
- 本轮选项按钮。
关键设计决策是:每一轮都创建全新的 DOM 节点追加到历史区,而不是复用固定元素。这个细节避免了一个隐蔽 bug——如果复用同一个事件框节点,后一轮的内容会覆盖前一轮,玩家回看历史时只能看到最后一回合的只言片语。独立节点让整个剧情在 DOM 中形成一条永不消逝的时间线,任何时候向上滚动都能复盘之前的奇遇。
7.4 视觉风格:暗黑奇幻的构成要素
用 CSS 变量统一管理设计令牌:
:root {
--bg-deep: #0b0f1a; /* 深邃底色 */
--gold: #d4af37; /* 主题金色 */
--hp: #e0605f; /* 生命条 */
--sta: #57b8ff; /* 精力条 */
}
氛围营造采用了几个关键手法:
- 径向渐变模拟暗夜中的微光(顶部偏蓝、角落透金);
- 毛玻璃(backdrop-filter)面板呈现"魔法书页"质感;
- 金色作为唯一强调色,点缀标题、装饰符、选项图标;
- 柔和 glitch 感不易实现,改用"辉光"(box-shadow)营造神秘层次;
- 开场动画的浮动城堡图标,暗示"门扉之后的世界"。
响应式布局保证了移动端也能完整体验:窄屏下状态面板自动转为横向并排。

八、游戏主流程与状态管理
8.1 一回合请求的完整生命周期
以玩家点击选项为例,一次完整交互的生命周期为:
点击选项按钮
↓
组装 user 消息并 push 进历史
↓
构造 payload = [system, ...历史消息]
↓
流式请求(loading 遮罩显示"命运之书正在书写...(N字)")
↓
收到完整文本 → extractJson → normalizeScene
↓
失败则重试(最多 MAX_RETRY 次)
↓
成功:把模型原始 JSON 作为 assistant 消息入历史
↓
渲染:事件反馈 / 标题 / 打字机叙述 / 选项
↓
更新状态面板 → 等待玩家下一次输入
8.2 并发与输入防护
游戏进行中必须禁止玩家重复发送请求,否则消息历史会被并发请求搅乱。我引入 game.busy 标志位:请求期间禁用发送按钮、禁用输入框、隐藏选项区;渲染完本轮才恢复。这个"单飞"模型(同一时刻最多一个在途请求)虽然简单,却彻底杜绝了乱序响应的可能性。
8.3 加载文案的巧思
加载遮罩的提示文案是"命运之书正在书写…",并且我在流式解析时实时更新 (已收到 N 字)。这不仅是装饰——当用户在窄带宽下等待大段生成时,这在视觉和心理上给了用户"有东西正在产生"的正反馈,极大地降低了等待焦虑。
九、里程碑:从第一行代码到完整游玩的收获
9.1 关于"严格模式"与健壮性
我在 script.js 顶部声明了 "use strict"。严格模式不是可选项——它能提前暴露许多潜在的编码错误(比如误用未声明变量),对单人、小团队维护的成长型项目尤其重要。
9.2 关于错误的重试观
AI 返回质量不佳(解析失败)时的自动重试,我做了带指数的重试策略:最多 MAX_RETRY(默认 2)次,每次间隔 600ms,失败提示 (重试 N 次)。值得一提的细节是:重试时不需要清空或修改历史消息——因为模型是概率性的,同样的输入再次生成,结果往往就正常了。这与传统系统的"重试幂等"思维不同,是 LLM 应用特有的工程经验。
9.3 关于可读性:注释与文档
整个项目文件虽少,但都有清晰的区块注释:配置、DOM 引用、游戏状态、提示词、解析、渲染、主流程。因为这类项目天然适合被初学者复制学习,代码即文档是对读者最大的尊重。配套的 README 更是包含了完整的部署说明、Python↔JavaScript 对照表、数据契约说明与 FAQ。
十、安全实践:密钥不入库
纯前端项目最大的安全短板是 API 密钥的暴露问题。任何用户打开浏览器开发者工具都能看到请求头里的 Authorization: Bearer xxx。因此安全策略必须"以会泄露为前提"来设计:
10.1 三个层次的风险控制
- 开发期:密钥写在
config.js,但默认为空占位。克隆者必须自行申请并填入密钥,任何人都无法直接偷用别人的配额。 - 发布期:如果必须公开展示,配置密钥交给服务端代理(如 Cloudflare Workers、云函数)转发,浏览器只与同源代理通信。
- 运营期:密钥设置用量上限,定期轮换;日志脱敏,严禁将完整密钥写入日志或错误上报。
10.2 Git 提交的止血法
我特别避免将真实密钥提交进 git 历史——git 历史中的密钥视为永久泄露,即使后来删除,攻击者仍可从历史记录中提取。因此代码提交时,密钥位置始终是占位符,并借 README 醒目警告。这是我认为所有开源 AI 应用都应坚守的底线。
十一、本地验证与真实 Agent 的端到端测试
项目并非"写完就提交",我在交付前执行了四层验证,确保交付物可靠:
11.1 语法与静态检查
node --check script.js 校验 JS 语法零错误;逐一核对 HTML 中所有 id 与 JS 中 document.getElementById 的引用完全对应,杜绝"元素找不到"的空指针。
11.2 纯函数单元测试
针对 extractJson() 写了四组用例:纯净 JSON、含 markdown 围栏、前后夹杂质文本、纯垃圾文本。前三组应正确提取,第四组应返回 null。全部通过。
11.3 真实 API 流式端到端测试
用真实的 DeepSeek-V4-Flash 接口发起流式请求,验证:
- SSE 帧按行正确切分;
data:[DONE]哨兵正确终止;- 47 个增量 chunk 正确拼接为完整 JSON;
- 完整游戏提示词下,模型对 8 个契约字段全部正确填充。
实测返回的 scene_title 为"尘封的回廊",叙述文本自然、选项 4 个、状态数值合法,说明提示词契约质量过硬。
11.4 本地 HTTP 服务资源巡检
启动静态文件服务器,轮询五个交付文件(HTML/CSS/JS/Config/README)全部返回 200,字节数与预期一致,确认部署无缺漏。
十二、如何运行这个项目
如果你也想体验一把由 AI 主持的冒险,步骤非常简单:
# 1. 克隆仓库
git clone https://atomgit.com/2601_94918285/AI_Adventur1.git
cd AI_Adventur1
# 2. 配置密钥:编辑 config.js,填入你的 API Key
# API_KEY: "your_api_key_here"
# 3. 用任意本地静态服务启动
python -m http.server 8080
# 或 npx serve .
# 4. 浏览器打开
# http://localhost:8080
点击"进入冒险",AI 立刻为你生成第一个场景。之后你可以:
- 点击选项按钮推进剧情;
- 在底部输入框自由输入任何行动;
- 随时点击"⟲ 新游戏"开启全新剧情线。
十三、你还可以这样做:二次开发的方向
这个项目刻意保持了极简,留出了大量可扩展空间:
13.1 玩法维度
- 多角色共存:给每个 NPC 独立的 system 角色,实现"同伴系统";
- 时间与天气系统:在 JSON 契约中增加
day、weather字段,让世界随时间推移而演化; - 任务与倒计时:加入
quests、timer字段,AI 可在限定回合内制造紧迫感; - 多语言:修改 system 提示词即可让 AI 用英文、日文等语言主持冒险。
13.2 技术维度
- 服务端代理层:接一层轻量后端(Node/Go/云函数),把密钥迁移到服务端,开放限流与统计;
- 存档系统:把消息历史 + 游戏状态序列化为 JSON,存入 localStorage 或导出文件,实现"读档重玩";
- 音效与图片:根据
mood字段接 TTS 朗读叙述、生成场景插画,升级为"多模态叙事"; - 记忆持久化:引入向量数据库存储"玩家已探索的世界",让游戏世界跨会话延续。
13.3 模式启发
这个"系统提示词定义数据结构 → 前端结构化解构渲染"的架构,其实可以泛化到很多应用:
- AI 表格填写助手:让模型返回结构化行数据,前端渲染成表格;
- AI 表单生成器:模型返回字段 schema,前端动态生成表单;
- AI 数据看板:让模型直接返回图表所需的
data与config,前端交给图表库渲染。
把"模型输出"从自由文本进化为"结构化契约",是 LLM 应用走向工程化的关键一步,远比反复调 prompt 更有杠杆。
十四、结语:让代码替你讲故事
回望整个项目,最令我感慨的并不是代码量——它只有区区一千多行——而是架构的轻盈与体验的厚重之间的反差。四个静态文件,撑起了一个理论上可以无限延续的世界。没有数据库,却有会流血、会疲惫、会捡起背包里每一件战利品的角色;没有服务端,却有实时流式生成的叙事;没有策划团队,却有每次运行都不重样的剧情。
这正是大模型时代最迷人的一面:当模型足够聪明,产品的最小可行形态可以小到极致,而体验的上限却由想象力决定。
「无尽回廊」是这扇门的一个入口。如果你也想亲手推开它,仓库就在这里:
仓库地址:https://atomgit.com/2601_94918285/AI_Adventur1
技术栈:HTML5 + CSS3 + JavaScript + DeepSeek-V4-Flash(OpenAI 兼容 Chat Completions 流式接口)
愿你的每一段冒险,都由大模型温柔相待。
*本文为「码道」系列技术分享文章,欢迎转载,注明出处即可。*在这里插入图片描述
更多推荐


所有评论(0)