本文将深入讲解如何在 FastAPI AI 聊天应用中接入 DeepkSeek 等有深度思考功能的模型时,如何让 AI 能够展示其推理过程, 提升用户对 AI 回答的理解和信任度。通过本教程,你将学会如何处理 AI 模型的 reasoning_content (思考内容)输出, 并在前端优雅地展示思考过程。
📖 项目地址:github.com/wayn111/fas...
温馨提示:本文全文约七千字,看完约需 10 分钟。
本章概述
深度思考功能的核心在于正确处理两种不同类型的数据流。本项目将使用 openai python sdk 提供的通用方式来检测 reasoning_content
(思考内容)和 content
(普通内容)字段来区分不同类型的内容,前端则根据 type
字段进行差异化渲染。
核心功能
- 思考过程可视化:实时展示 AI 的推理步骤和思考逻辑
- 双重内容流:后端代码如何区分思考内容(reasoning_content)和最终回答(content)
- 差异化展示:前端展示时,思考内容和最终回答采用不同的视觉样式
技术栈
- 后端框架:FastAPI(高性能异步 Web 框架)
- AI 集成:OpenAI SDK(支持 reasoning_content 的模型,比如 DeepSeek)
- 流式协议:Server-Sent Events(SSE)
- 前端渲染:Marked.js + Highlight.js(Markdown 和代码高亮)
- 样式设计:HTML5 + CSS3(差异化视觉效果)
支持深度思考的模型
- OpenAI:o4-mini
- DeepSeek:deepseek-reasoner
- Qwen:qwen-plus
核心设计
设计理念
深度思考功能的实现基于三个核心设计原则:
1. 内容分离原则思考内容(reasoning_content)和最终回答(content)是两个独立的数据流,需要分别处理和展示。这样可以让用户清楚地区分 AI 的思考过程和最终结论。
2. 实时展示原则思考过程应该实时展示,让用户能够跟随 AI 的思维轨迹。这不仅提升了用户体验,还增加了 AI 回答的透明度和可信度。
3. 视觉区分原则思考内容和最终回答需要采用不同的视觉样式,让用户能够一眼区分两种不同类型的内容。
代码分层
深度思考功能的架构分为三个清晰的层次:
1. 通用处理层(OpenAICompatibleProvider(BaseAIProvider))
这一层负责处理 AI 模型的原始输出,识别和分离 reasoning_content 和 content:
python
# class OpenAICompatibleProvider(BaseAIProvider):
asyncdef generate_streaming_response(
self,
messages: List[AIMessage],
**kwargs
) -> AsyncGenerator[str, None]:
"""
生成流式AI响应,支持深度思考内容
Args:
messages: 对话历史消息列表
**kwargs: 其他参数
Yields:
str: 流式响应内容片段,包含类型标识
"""
try:
# 格式化消息并构建请求参数
system_prompt = kwargs.get('system_prompt')
formatted_messages = self.format_messages(messages, system_prompt)
request_params = self._build_request_params(formatted_messages, stream=True, **kwargs)
logger.info(f"调用{self.get_provider_display_name()}流式API - 模型: {request_params['model']}")
# 调用流式API
response = self.client.chat.completions.create(**request_params)
chunk_count = 0
import json
for chunk in response:
# 处理深度思考内容
if hasattr(chunk.choices[0].delta, 'reasoning_content') and chunk.choices[0].delta.reasoning_content:
content = chunk.choices[0].delta.reasoning_content
chunk_count += 1
# 返回带类型标识的思考内容
yieldf"data: {json.dumps({'type': 'reasoning', 'content': content})}\n\n"
# 处理普通回答内容
elif hasattr(chunk.choices[0].delta, 'content') and chunk.choices[0].delta.content:
content = chunk.choices[0].delta.content
chunk_count += 1
# 返回带类型标识的回答内容
yieldf"data: {json.dumps({'type': 'content', 'content': content})}\n\n"
logger.info(f"{self.get_provider_display_name()}流式响应完成 - 块数: {chunk_count}")
except Exception as e:
logger.error(f"{self.get_provider_display_name()}流式响应失败: {e}")
yieldf"抱歉,{self.get_provider_display_name()}流式服务暂时不可用:{str(e)}"
核心特点:
- 双重检测:在返回的 response 中同时检测 reasoning_content 和 content 字段
- 类型标识:为每个数据块添加 type 字段,便于前端区分处理 reasoning_content 和 content
- JSON 格式:使用结构化的 JSON 格式传输数据
- 错误处理:完善的异常处理机制
2. 接口传输层(FastAPI)
在 main.py
的流式响应处理中,系统会解析每个数据块并只保存 type: 'content'
的内容到 Redis, 在大模型的多轮对话记忆中,无需添加 reasoning_content 字段。
ini
full_response = ""
content_only_response = ""# 只保存 type: 'content' 的内容
chunk_count = 0
asyncfor chunk in ai_manager.generate_streaming_response(
messages=ai_messages,
provider=provider,
model=model,
system_prompt=system_prompt
):
if chunk:
full_response += chunk
chunk_count += 1
# 解析chunk数据,只保留 type: 'content' 的内容到Redis
try:
if chunk.startswith("data: "):
json_str = chunk[6:].strip() # 移除 "data: " 前缀
if json_str:
chunk_data = json.loads(json_str)
# 只累积 type 为 'content' 的内容用于保存到Redis
if chunk_data.get('type') == 'content'and'content'in chunk_data:
content_only_response += chunk_data['content']
except (json.JSONDecodeError, KeyError) as e:
# 如果解析失败,按原来的方式处理(向后兼容)
logger.debug(f"解析chunk数据失败,使用原始内容: {e}")
yield chunk
logger.info(f"流式响应完成 - 用户: {user_id}, 会话: {session_id[:8]}..., 块数: {chunk_count}, 总长度: {len(full_response)}, 内容长度: {len(content_only_response)}")
# 保存AI响应(只保存 type: 'content' 的内容)
ai_msg = ChatMessage(
role="assistant",
content=content_only_response, # 使用过滤后的内容
timestamp=time.time()
)
await save_message_to_redis(user_id, session_id, ai_msg)
3. 前端展示层(JavaScript)
这一层负责接收数据并进行差异化展示:
ini
// 项目中的实际前端处理逻辑
if (data.type === 'chunk' || data.type === 'content' || data.type === 'reasoning') {
if (data.type === 'reasoning') {
// 深度思考内容
if (!reasoningElement) {
reasoningElement = document.createElement('div');
reasoningElement.className = 'message-content reasoning-content';
// 创建reasoning-body容器
const reasoningBody = document.createElement('div');
reasoningBody.className = 'reasoning-body';
reasoningElement.appendChild(reasoningBody);
// 将reasoning元素添加到消息容器的content wrapper中
const contentWrapper = messageContainer.querySelector('.message-content-wrapper');
contentWrapper.appendChild(reasoningElement);
}
reasoningMessage += data.content;
...
scrollToBottom();
} else {
// 普通内容
if (!contentElement) {
contentElement = document.createElement('div');
contentElement.className = 'message-content';
// 将content元素添加到消息容器的content wrapper中
const contentWrapper = messageContainer.querySelector('.message-content-wrapper');
contentWrapper.appendChild(contentElement);
}
contentMessage += data.content;
...
scrollToBottom();
}
scrollToBottom();
}
前端在接受 SSE 响应上,要区分 data 返回的 type 类型是 reason 还是 content,以此作不同展示。
启动一下
python start_server.py
打开浏览器访问:http://localhost:8000
测试一下深度思考功能~
选择 deepseek-reasoner,进行模型问答,

- 数学问题求解
用户:证明勾股定理

2. 编程问题分析
用户:设计一个高效的排序算法

FastAPI开发AI应用系列文章
📚 总结
本文详细介绍了在 FastAPI AI 聊天应用中集成深度思考功能的完整实现方案。通过分层设计(通用处理层、接口传输层、前端展示层),成功实现了 AI 推理过程的可视化展示。
最后觉得本文写的不错的话,可以关注我,我会继续更新 FastAPI 框架开发 AI 聊天应用代码。