ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零构建SpaceXAI:Grok 4.6大模型应用开发与FastAPI流式问答实践

从零构建SpaceXAI:Grok 4.6大模型应用开发与FastAPI流式问答实践 在实际的 AI 应用开发里调通一次大模型 API 只是起点真正花时间的往往是如何把模型能力稳定地嵌进一个具体场景。SpaceXAI 这个名字听起来像是一个航天主题的 AI 项目它真正想解决的问题是围绕 Grok 4.6 这类大模型能力搭建一个面向航天知识问答、科普内容生成和文档导出的完整小应用。Grok 4.6 在这里作为模型版本示例出现实际的接入方式、提示词设计、流式输出、缓存和排错链路都可以迁移到其他兼容 OpenAI 接口的模型上。这篇文章会从零开始把一个名为 SpaceXAI 的项目拆开先讲清楚它为什么这样设计再给出环境准备、接口封装、FastAPI 服务、Word 导出、前端联调最后落到常见坑和生产环境建议。先说清楚读者能获得什么。如果你正在学习如何把大模型 API 接入自己的项目或者需要做一个面向垂直领域比如航天、天文、工程科普的问答机器人又或者已经接通过接口但不太会处理流式响应、缓存、异常和文档导出这篇内容会比较适合。整篇文章会贯穿一条主线设计一个最小可运行的 SpaceXAI 服务用 Grok 4.6 生成航天知识回答用流式输出改善体验用 Markdown 到 Word 的转换让结果变成可交付文档同时把开发中容易踩的坑逐一列出来。1. 先理解 SpaceXAI 为什么需要一个模型服务层1.1 场景拆解航天知识助手不只是“调接口”航天知识领域的问答有一个特点用户经常会问“猎鹰 9 号一级回收流程是什么”“星舰的隔热材料有什么要求”“ISS 轨道高度怎么保持”这类复合问题。它们既需要模型具备基础航天常识也需要回答有结构、有步骤、可引用最好还能直接导出成 Word 报告。单纯在网页里塞一个聊天框并不够。SpaceXAI 的核心场景可以拆成三个层次问答层用户输入自然语言问题模型返回中文回答。结构化层回答不只输出纯文本还要能输出 Markdown 标题、列表、表格方便后续排版。交付层用户把生成结果导出为 Word 文档离线阅读或继续编辑。这三个层次决定了项目不能只写一个 Python 脚本就结束而是要有清晰的模块边界。把模型调用单独抽成服务层业务接口和模型实现解耦后续即使更换模型或调整提示词也不会影响路由和页面。1.2 为什么选择 Grok 系列模型作为示例底座Grok 是 xAI 推出的对话模型系列Grok 4.6 在这里是示例配置名。把一个模型作为应用底座时主要看四件事是否兼容 OpenAI 的 chat completions 协议、是否支持流式输出、是否支持 system prompt、是否可以通过参数控制输出长度和随机性。Grok 4.6 在当前示例中按这些能力假设设计实际接入时要以你使用的 API 平台返回为准。选择 Grok 系列作为示例还因为它具备不错的代码生成和结构化输出能力适合演示“把对话转成可运行小应用”的扩展方向。后面第 5 节的 Word 导出功能本质上就是在利用模型的 Markdown 生成能力再用代码把它转成 docx 文件。这样就把模型能力从“聊天”扩展到了“生产内容工具”这也是 SpaceXAI 这个名字里 AI 部分的意义所在。注意本文所有代码中的模型名、API 地址和参数都只是示例。不同平台的接口地址、模型名、限流策略可能不同落地前必须用真实 API Key 和模型清单确认。1.3 本文完成的目标和技术边界这篇文章会完成一个可以本地运行的最小项目包含以下结果一个封装了 Grok 4.6 客户端调用的模型服务模块。一个基于 FastAPI 的问答接口支持普通 JSON 返回和流式返回。一个航天领域专用的 System Prompt要求模型输出结构化的 Markdown。一个 Markdown 转 Word 的工具函数可以生成 docx 文档。一个简单的 HTML 页面用户输入问题后可以看到流式文字输出并点击按钮导出 Word。一段完整的排查路径和上线前检查清单。需要提前说明的技术边界这个项目不包含用户体系、多轮会话持久化、大模型向量检索RAG、内容审核平台、分布式缓存。这些属于生产环境增强项会在第 7 节展开讲。学习阶段先跑通最小闭环比一上来就堆组件更有效。2. 技术架构与项目目录设计2.1 请求流转路径SpaceXAI 的服务端请求路径可以这样理解用户在页面输入问题前端通过 fetch 把问题发送到 FastAPI 服务。FastAPI 的/api/chat/stream接口接收请求拼装 system prompt 和用户消息。模型服务层调用 Grok 4.6 的 chat completions 接口。模型返回的流式内容通过 HTTP 流逐段转发给前端。页面逐字渲染内容用户点击导出时前端把完整 Markdown 文本发给/api/export/word接口。后端把 Markdown 转成 docx返回文件下载。这个路径里前端不直接接触 API Key所有模型调用都发生在后端。这个设计不只是为了“好看”更是为了安全API Key 一旦暴露在浏览器里就意味着任何访问页面的人都能消耗你的模型额度。2.2 项目目录结构spacexai/ ├── app.py # FastAPI 入口和路由 ├── grok_client.py # Grok 4.6 客户端封装 ├── prompts.py # System Prompt 和提示词模板 ├── cache.py # 简单 TTL 缓存 ├── docx_exporter.py # Markdown 转 Word 工具 ├── requirements.txt ├── .env.example # 环境变量示例 ├── static/ │ └── index.html # 前端页面 └── output/ # 导出的 Word 文件目录在学习环境里这个目录足够。生产环境建议再拆分出routers/、services/、schemas/、config/以便多个接口和多个模型实例复用。2.3 环境要求推荐使用 Python 3.11 或 3.12。这个项目不依赖特殊系统库Windows、macOS、Linux 都能运行。依赖作用版本示例fastapiWeb 框架提供路由和接口文档0.115.xuvicornASGI 服务器负责运行 FastAPI0.32.xopenai官方 Python SDK兼容 OpenAI 协议的大模型接口1.57.xpython-dotenv读取 .env 文件中的环境变量1.0.xpython-docx生成 Word 文档1.1.xmarkdown把 Markdown 文本转为 HTML可选用于预览3.7.x安装命令python -m venv .venv source .venv/bin/activate # Windows 使用 .venv\Scripts\activate pip install -r requirements.txt在学习环境中全部用最新稳定版本问题不大。在团队项目中建议把依赖版本锁定避免半年后某个库升级导致接口行为变化。3. 从配置 API Key 到完成第一次模型调用3.1 配置环境变量避免把密钥写进代码新建.env文件内容参考.env.exampleGROK_API_KEYyour_api_key_here GROK_BASE_URLhttps://api.example.com/v1 GROK_MODELgrok-4.6GROK_BASE_URL用来指向兼容 OpenAI 接口的服务地址。这里只写示例实际要以你开通模型服务的平台提供地址为准。把 base_url 设计成可配置而不是硬编码在代码里是为了后续切换模型服务商时不需要改代码。.env文件必须加入.gitignore避免密钥被提交到仓库。如果项目使用 Git检查一下提交历史里有没有出现过.env。3.2 安装依赖并验证 Python 环境python --version pip install -r requirements.txt检查关键库是否可用python -c import fastapi, openai, docx; print(deps ok)这条命令能排除“依赖没装成功”这一层问题后面排查接口报错时就不用再怀疑基础环境了。3.3 封装 Grok 客户端模块创建grok_client.py。这里用 openai 库的OpenAI类作为客户端因为 Grok 4.6 在当前示例中按兼容接口处理。封装后其他模块不应该直接创建OpenAI实例统一通过GrokClient调用。from openai import OpenAI from typing import Optional class GrokClient: def __init__(self, api_key: str, base_url: str, model: str): self.model model self.client OpenAI(api_keyapi_key, base_urlbase_url) def chat( self, messages: list, temperature: float 0.5, max_tokens: int 1024, stream: bool False, ): return self.client.chat.completions.create( modelself.model, messagesmessages, temperaturetemperature, max_tokensmax_tokens, streamstream, )为什么要单独封装一层原因有三个。第一统一管理模型名、base_url 和调用参数。第二后续如果要记录 token 消耗、做熔断、增加重试只需要改这一个文件。第三前端和路由层不关心模型 SDK 的细节它们只需要拿到最终文本或流式内容。3.4 用最小脚本验证连通性创建test_grok.pyimport os from dotenv import load_dotenv from grok_client import GrokClient load_dotenv() client GrokClient( api_keyos.getenv(GROK_API_KEY), base_urlos.getenv(GROK_BASE_URL), modelos.getenv(GROK_MODEL), ) response client.chat( messages[ {role: system, content: 你是一个航天知识助手请用简体中文回答。}, {role: user, content: 猎鹰9号的一级火箭回收分几个阶段}, ], temperature0.5, max_tokens1024, ) print(response.choices[0].message.content)运行python test_grok.py如果返回了内容说明 API 连通性、Key 权限、模型名都正确。如果报 401检查 Key 是否有效如果报 404多半是模型名填错如果报超时先看网络能否访问对应的 API 地址再看是否需要配置企业内网出口。3.5 关键参数速查参数作用示例值调大/调小影响错误配置表现temperature控制随机性0.2 ~ 0.7调大更发散调小更稳定回答可能过多重复或跑题max_tokens控制最大输出长度512 ~ 2048调大可以生成更长内容但成本更高回答被硬截断没有结束符号stream是否流式返回true / false流式提升首字速度非流式解析代码读取时异常model模型标识grok-4.6必须与平台模型清单一致404 或 model not foundbase_url接口地址平台提供的 /v1 地址缺/v1可能路径拼接错误404 或 route not found在航天这类需要准确性的场景里temperature 不宜太大建议先使用 0.3 到 0.5 之间。需要发散创意时再调高。4. 实现 FastAPI 问答服务从普通响应到流式响应4.1 定义请求体结构创建app.py先定义 pydantic 模型保证接口输入可校验。from pydantic import BaseModel class ChatRequest(BaseModel): question: str temperature: float 0.4 max_tokens: int 1024 class ChatResponse(BaseModel): answer: str model: strquestion是必填字段temperature和max_tokens给默认值。这样前端可以只传问题后端有一套稳妥的默认参数。4.2 设计航天领域 System PromptSystem Prompt 是整个应用效果好坏的杠杆。同样的模型提示词不同输出质量可能差很多。prompts.py内容如下SYSTEM_PROMPT 你是一个严谨的航天领域知识助手名字叫 SpaceXAI。 回答要求 1. 优先使用简体中文术语可以保留英文原名并在括号内注明。 2. 回答必须结构清晰使用 Markdown 语法组织内容。 3. 涉及步骤、流程、参数对比时优先使用有序列表或表格。 4. 对于不确定的数据不要编造明确说明“该数据需要进一步查证”。 5. 不要讨论与航天无关的话题不要提供危险操作建议。 这里把“不要编造数据”写进系统提示词是因为大模型在专业领域容易一本正经地出错。虽然提示词不能完全消除幻觉但可以降低风险至少让模型在不确定时用防御性表述。继续在prompts.py里加一个拼接函数def build_messages(question: str) - list: return [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: question}, ]后续新增历史对话时只需要在build_messages里把旧消息插入 system 和 user 之间即可。4.3 实现普通 JSON 接口在app.py里加入非流式问答接口import os from fastapi import FastAPI from dotenv import load_dotenv from grok_client import GrokClient from prompts import build_messages load_dotenv() app FastAPI(titleSpaceXAI) client GrokClient( api_keyos.getenv(GROK_API_KEY), base_urlos.getenv(GROK_BASE_URL), modelos.getenv(GROK_MODEL), ) app.post(/api/chat, response_modelChatResponse) def chat(req: ChatRequest): messages build_messages(req.question) response client.chat( messagesmessages, temperaturereq.temperature, max_tokensreq.max_tokens, streamFalse, ) answer response.choices[0].message.content return ChatResponse(answeranswer, modelclient.model)普通接口适合前端展示“完整回答”但用户等待时间较长模型生成多久用户就盯着空白页面多久。所以还需要流式接口。4.4 实现流式接口提升交互体验流式接口使用StreamingResponse通过text/event-stream或纯文本流把内容分段返回给浏览器。from fastapi.responses import StreamingResponse app.post(/api/chat/stream) def chat_stream(req: ChatRequest): messages build_messages(req.question) def generate(): stream client.chat( messagesmessages, temperaturereq.temperature, max_tokensreq.max_tokens, streamTrue, ) for chunk in stream: if not chunk.choices: continue delta chunk.choices[0].delta content delta.content if delta and delta.content else if content: yield content return StreamingResponse(generate(), media_typetext/plain; charsetutf-8)这段代码有几个关键点generate()是生成器函数模型每返回一段内容就立刻yield出去。chunk.choices[0].delta对应流式片段的内容不同 SDK 的结构可能略有不同但要先判断是否为空。media_type使用text/plain而不是text/event-stream这样前端可以用response.text()配合ReadableStream解析也可以直接用 fetch 的流式读取。前端处理纯文本流时需要不断读取reader.read()并解码。这种方式比text/event-stream更容易上手适合当前项目。4.5 增加 TTL 缓存避免重复消耗模型额度航天科普问题的重复率不低。同一个问题用户可能从不同入口提交多次。如果每次都调模型既增加延迟也增加成本。cache.py实现一个简单的 TTL 缓存。import hashlib import time class TTLCache: def __init__(self, ttl: int 600): self.ttl ttl self.store {} def _key(self, question: str, temperature: float, max_tokens: int) - str: raw f{question}|{temperature}|{max_tokens} return hashlib.sha256(raw.encode(utf-8)).hexdigest() def get(self, question: str, temperature: float, max_tokens: int): key self._key(question, temperature, max_tokens) item self.store.get(key) if item is None: return None if time.time() - item[ts] self.ttl: del self.store[key] return None return item[value] def set(self, question: str, temperature: float, max_tokens: int, value: str): key self._key(question, temperature, max_tokens) self.store[key] {ts: time.time(), value: value}使用时先在缓存查询如果命中就直接返回未命中再调模型并写入缓存。TTL 建议普通问答用 10 分钟技术文档生成类内容可以用 1 小时。缓存只适合确定性较高的参数组合temperature 太高时命中的回答可能不稳定实际项目可以根据自己的场景决定是否缓存。4.6 挂载静态页面为了让项目可以直接演示把前端放在static/index.html并在应用里挂载静态目录from fastapi.staticfiles import StaticFiles app.mount(/static, StaticFiles(directorystatic), namestatic)访问http://127.0.0.1:8000/static/index.html即可打开页面。注意app.mount必须在路由定义之后否则会抢占路由匹配规则。5. 用 Grok 4.6 生成结构化内容并导出 Word5.1 通过提示词让模型输出 Markdown问答接口已经能满足“看”但航天知识问答的场景里用户往往还想把内容保存下来放进文档或汇报材料。让模型直接输出纯文本转 Word 时只能是一堆段落没有标题层级没有列表排版效果很差。解决方法是在提示词里明确要求 Markdown 格式。比如用户问“星舰的发射流程”模型可能会返回# 星舰发射流程 ## 1. 发射前检查 - 推进剂加注 - 发动机静态点火测试 - 航区安全评估 ## 2. 倒计时 - T-10 分钟加注完成 - T-3 秒发动机点火这种结构化的输出可以直接被python-docx解析成 Word 中的标题、正文和项目符号列表。5.2 实现 Markdown 转 Word 工具创建docx_exporter.pyimport re from docx import Document def markdown_to_docx(markdown_text: str, output_path: str): doc Document() for line in markdown_text.splitlines(): line line.strip() if not line: continue if line.startswith(### ): doc.add_heading(line[4:], level3) elif line.startswith(## ): doc.add_heading(line[3:], level2) elif line.startswith(# ): doc.add_heading(line[2:], level1) elif re.match(r^[-*] , line): doc.add_paragraph(line[2:], styleList Bullet) elif re.match(r^\d\. , line): doc.add_paragraph(line, styleList Number) elif line.startswith(|): # 表格行处理从简这里默认作为段落输出 doc.add_paragraph(line) else: doc.add_paragraph(line) doc.save(output_path) return output_path做导出接口时需要接收前端传来的完整 Markdown 文本。注意不能让前端传文件路径否则会有路径穿越风险。接口只接收内容后端自己决定输出目录和文件名。5.3 导出接口实现import uuid from fastapi import HTTPException from fastapi.responses import FileResponse from docx_exporter import markdown_to_docx class ExportRequest(BaseModel): markdown_content: str filename: str spacexai_report app.post(/api/export/word) def export_word(req: ExportRequest): if len(req.markdown_content) 100_000: raise HTTPException(status_code400, detail内容过长) safe_name re.sub(r[^\w\u4e00-\u9fa5-], _, req.filename) output_path foutput/{safe_name}_{uuid.uuid4().hex[:8]}.docx markdown_to_docx(req.markdown_content, output_path) return FileResponse( output_path, filenamef{safe_name}.docx, media_typeapplication/vnd.openxmlformats-officedocument.wordprocessingml.document, )这个接口做了两层限制内容长度限制防止超大文本导致内存压力文件名清洗防止用户传入特殊字符。5.4 演示流程生成猎鹰 9 号发射流程报告用 curl 直接测试curl -X POST http://127.0.0.1:8000/api/chat \ -H Content-Type: application/json \ -d {question: 猎鹰9号的一次完整发射流程包含哪些阶段请给出Markdown格式的步骤说明}把返回的answer字段内容保存到文件再调用导出接口curl -X POST http://127.0.0.1:8000/api/export/word \ -H Content-Type: application/json \ -d {markdown_content: # 猎鹰9号发射流程\n\n## 1. 发射前准备\n- 载荷集成\n- 静态点火测试\n, filename: falcon9}打开生成的 docx可以看到标题和列表都被 Word 正确识别。6. 前端联调与运行验证6.1 启动 FastAPI 服务uvicorn app:app --host 0.0.0.0 --port 8000 --reload参数说明--reload开发模式下热加载代码改完代码自动重启。--host 0.0.0.0允许局域网访问方便手机或同事电脑联调。生产环境建议关闭--reload用多个 worker 启动。启动成功后访问http://127.0.0.1:8000/docs可以看到 FastAPI 自动生成的接口文档也可以直接在页面里测试/api/chat。6.2 前端页面核心代码static/index.html需要实现三个能力发送问题、读取流式响应、导出 Word。这里给出关键逻辑。!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleSpaceXAI/title /head body h1SpaceXAI 航天知识助手/h1 textarea idquestion rows3 placeholder请输入航天问题/textarea button idsendBtn发送/button button idexportBtn导出 Word/button pre idoutput/pre script const questionInput document.getElementById(question); const output document.getElementById(output); let fullMarkdown ; async function sendStream() { const question questionInput.value.trim(); if (!question) return; output.textContent ; fullMarkdown ; const resp await fetch(/api/chat/stream, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ question }) }); if (!resp.ok) { output.textContent 请求失败: resp.status; return; } const reader resp.body.getReader(); const decoder new TextDecoder(utf-8); while (true) { const { done, value } await reader.read(); if (done) break; const text decoder.decode(value, { stream: true }); fullMarkdown text; output.textContent fullMarkdown; } } async function exportWord() { if (!fullMarkdown) { alert(请先生成内容); return; } const resp await fetch(/api/export/word, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ markdown_content: fullMarkdown, filename: spacexai_report }) }); const blob await resp.blob(); const url URL.createObjectURL(blob); const a document.createElement(a); a.href url; a.download spacexai_report.docx; a.click(); URL.revokeObjectURL(url); } document.getElementById(sendBtn).addEventListener(click, sendStream); document.getElementById(exportBtn).addEventListener(click, exportWord); /script /body /html这段代码不复杂但有两个容易忽略的点decoder.decode(value, { stream: true })很重要。如果不传{ stream: true }多字节中文在流式传输时可能被切断导致页面出现乱码。fullMarkdown变量记录了流式累加后的完整内容。导出时发送的是完整文本不是最后一次输出的片段。6.3 用 curl 验证流式接口curl -N -X POST http://127.0.0.1:8000/api/chat/stream \ -H Content-Type: application/json \ -d {question: 什么是卡门线}-N参数可以关闭 curl 的缓冲让返回内容一有多字节就直接打印。正常会看到内容分段出现而不是等待全部结束才显示。6.4 验证结果判断标准验证项预期结果检查位置依赖导入输出 deps ok命令行非流式接口返回 JSON包含 answer 和 model/docs 或 curl流式接口内容分段输出浏览器页面、curl -N缓存命中第二次同一问题响应更快日志无模型调用服务端日志Word 导出下载文件可打开标题列表正常output 目录中文显示无乱码页面、docx7. 常见坑与排查路径7.1 高频错误与解决方案问题现象常见原因检查方式处理建议401 UnauthorizedAPI Key 错误或未生效检查 .env 中 GROK_API_KEY重新生成 Key确认环境变量加载成功404 model not found模型名与平台不一致查看模型清单把 GROK_MODEL 改为平台提供的准确名称请求超时网络问题或模型负载高用 curl 直接测试 base_url增加超时和重试逻辑确认网络出口流式返回乱码解码未使用 stream: true检查 fetch 解码逻辑TextDecoder设置{ stream: true }生成内容被截断max_tokens 过小查看回答是否以句子中断增大 max_tokens或让模型先给摘要再展开Word 表格丢失解析器没有处理 Markdown 表格检查 docx_exporter.py需要引入更完整的 Markdown 解析库如 markdown_it7.2 排查链路从现象倒推根因当用户反馈“页面没有内容”时按这个顺序排查打开浏览器开发者工具看/api/chat/stream请求是否返回 200。如果 200 但无内容看服务端日志中是否有异常堆栈。如果服务端有模型调用异常先直接跑test_grok.py排除前端因素。如果test_grok.py也失败重点检查 API Key、base_url、模型名。如果test_grok.py成功但页面失败检查前端是否把 response body 当作 JSON 解析。流式接口返回的是纯文本流不是 JSON。如果内容出现但乱码检查 TextDecoder。如果是 Node 或 Python 脚本确认没有错误地设置编码。遵循“输入 - 路径 - 依赖 - 权限 - 日志”的顺序大部分问题都能在几分钟内定位。7.3 学习环境与生产环境的差异本地跑通只是第一步。进入生产环境至少还要补这些能力维度学习环境生产环境要求配置本地 .env配置中心或环境变量管理密钥加密日志控制台打印结构化日志记录 request_id、token 消耗、耗时限流无每个用户/每个 IP 限制请求频率缓存进程内 TTLRedis 或分布式缓存内容安全无增加敏感内容过滤和模型输出审核监控无接口成功率、平均延迟、错误码分布告警回滚直接改代码模型参数和提示词配置化支持热更新7.4 上线前检查清单[ ] API Key 不在代码仓库中.env已加入.gitignore。[ ] 模型名、base_url 与开通环境一致未硬编码。[ ] 所有接口都做了输入长度和类型校验。[ ] 导出接口限制了文件名和内容长度。[ ] 流式接口设置了超时和异常处理避免生成器中断导致连接挂起。[ ] 日志中不打印完整 API Key只打印脱敏后的后四位。[ ] 做了至少一轮中文输入输出测试确认无乱码。[ ] 确认模型输出的 Markdown 能被导出工具正确解析。8. 常见坑与最佳实践8.1 三个与本文强相关的高频坑第一个坑把 System Prompt 写在业务代码里导致调试困难。直接在路由函数里硬编码提示词初期最快但一旦要调整语气或规范就必须改代码重启。推荐把提示词集中在prompts.py并且预留版本字段方便对比不同版本的效果差异。第二个坑流式接口没有处理异常。模型接口偶尔会中断如果生成器函数不捕获异常FastAPI 要么返回 500要么连接直接断开。推荐在生成器里用 try/except 包裹调用逻辑异常时输出一条明确的错误消息。def generate(): try: stream client.chat(messagesmessages, streamTrue) for chunk in stream: ... except Exception as e: yield f\n\n[生成失败: {type(e).__name__}]第三个坑把 Markdown 转 Word 想得太简单。python-docx本身不解析 Markdown如果内容包含复杂表格、代码块、引用块简单逐行处理会丢失格式。当前项目只处理了标题、列表、正文。如果要完整支持建议先使用markdown_it解析成 AST再遍历节点生成 Word 元素。8.2 提示词设计的最佳实践在 System Prompt 中明确“不要编造数据”但对不确定的数据要给出防御性表达。要求模型输出中文时显式声明“使用简体中文”不要靠默认行为。要求结构化输出时给出具体格式示例模型会更稳定地按格式返回。在单轮问答中system prompt 不要过长。航天领域规则虽然多但要控制在一屏以内避免模型忽略尾部约束。每次调整提示词后用固定测试集跑一遍确认新的提示词没有降低既有问题回答质量。8.3 成本控制实践大模型应用最容易失控的就是 token 消耗。几个落地方案对重复问题做缓存这是最直接的降本手段。在接口层限制单次请求的max_tokens防止用户利用长文本生成功能消耗过多额度。记录每个请求的 token 用量定时分析高消耗问题看是否提示词过长或回答重复。对导出 Word 的长文档生成建议拆分成多个段落生成而不是让模型一次性输出万字长文这样即使中断也便于重试。8.4 扩展方向SpaceXAI 当前是“单轮问答 静态内容”的最小闭环。后续值得扩展的方向有三个。一是接入 RAG。航天领域资料非常多把公开的发射手册、航天器参数、技术报告做向量化检索后拼进 prompt可以让模型回答更依赖资料而非记忆。这能显著减少幻觉但需要额外维护向量库和处理文档解析。二是加入工具调用能力也就是“Grok Build”这类思路用户提出需求后模型不只是给出文字而是生成一段可运行的代码、一个页面组件或一份数据文件。比如用户说“画一张猎鹰9号回收流程图”模型调用绘图工具或直接生成 SVG 代码返回给前端渲染。这比单纯聊天更进一步也更接近真实生产力工具。三是增加多轮对话和会话持久化。当前项目每个请求都是独立的没有上下文。要支持追问“那它和星舰有什么不同”就需要把历史消息存起来。生产上可以存在 Redis也可以用轻量级的 SQLite 保存会话记录。9. 收尾这个项目最值得带走的技术判断SpaceXAI 这个项目看起来是一个“用 Grok 4.6 做航天问答”的玩具级应用但它实际上覆盖了大模型应用接入的完整链路环境变量管理、模型客户端封装、提示词设计、普通接口与流式接口、缓存、文档导出、前端联调、排错和生产化建议。把这套骨架跑通之后换一个垂直领域、换一个模型名称只改 System Prompt 和业务接口就能复用。对新手来说最有价值的练习不是把代码复制一遍就结束而是按下面的路径自己重写一遍先只做普通接口验证连通后再加流式输出流式通了再考虑缓存和 Word 导出最后自行设计一个限流和日志方案。每一步都能看到明确结果逐步从“调模型”走向“做产品”。如果把这个项目继续往前推最重要的一条建议是不要把模型能力直接暴露给用户而是通过 system prompt、参数控制、内容长度限制和缓存策略把模型行为约束在业务边界内。大模型的返回结果可以是起点但最终交付给用户的一定要是经过结构化、校验和包装后的内容。
返回列表