You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Ruby on Rails中使用ruby-openai API Gem实现流式对话与会话历史

解决ruby-openai的流式对话与会话历史问题

1. 手动维护会话历史

ruby-openai本身不追踪会话上下文,需自行按OpenAI API要求的格式维护对话消息数组,每次请求时将该数组传入messages参数,实现上下文延续。

实现思路

  • 用会话存储(session)或数据库模型持久化对话历史,每条消息需包含role(取值为system/user/assistant)和content字段。
  • 用户发送新消息时,将其追加到历史数组;收到AI回复后,同样把回复存入数组,确保后续请求能携带完整对话上下文。

Rails控制器示例代码

# 初始化会话历史(首次请求时设置系统提示词)
session[:chat_history] ||= [{ role: "system", content: "你是一名专业的Ruby on Rails技术顾问" }]

# 追加用户新提问到历史
user_message = params[:user_input].strip
session[:chat_history] << { role: "user", content: user_message }

# 调用ruby-openai API,传入完整会话历史
client = OpenAI::Client.new(api_key: ENV["OPENAI_API_KEY"])
response = client.chat(
  parameters: {
    model: "gpt-3.5-turbo",
    messages: session[:chat_history],
    temperature: 0.7
  }
)

# 提取AI回复并追加到会话历史
assistant_response = response.dig("choices", 0, "message", "content")
session[:chat_history] << { role: "assistant", content: assistant_response }

# 返回回复给前端
render json: { reply: assistant_response }

持久化扩展(跨会话保存)

若需要永久保存对话记录,可创建数据库模型:

# 生成模型:rails generate model Conversation user:references
# rails generate model ConversationMessage conversation:references role:string content:text

# 保存对话消息的示例
conversation = current_user.conversations.find_or_create_by(title: "技术咨询")
ConversationMessage.create!(conversation: conversation, role: "user", content: user_message)

# 查询历史消息组成数组
chat_history = conversation.conversation_messages.order(created_at: :asc).map do |msg|
  { role: msg.role, content: msg.content }
end

2. 实现流式对话

ruby-openai原生不支持流式响应,需手动调用OpenAI的HTTP API处理分块传输的响应,配合前端实现实时内容渲染。

实现思路

  • 使用Ruby标准库Net::HTTP发送带stream: true参数的请求,逐块读取响应内容。
  • 解析Server-Sent Events(SSE)格式的响应块,提取AI的增量回复内容,可搭配Rails Action Cable实现前端实时接收。

流式请求示例代码

require 'net/http'
require 'json'

uri = URI("https://api.openai.com/v1/chat/completions")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer #{ENV['OPENAI_API_KEY']}"

# 传入会话历史并开启流式
request.body = JSON.dump({
  model: "gpt-3.5-turbo",
  messages: session[:chat_history],
  stream: true
})

# 逐块处理流式响应
full_response = ""
http.request(request) do |response|
  response.read_body do |chunk|
    chunk.split("\n").each do |line|
      next unless line.start_with?("data: ")
      data = line.gsub("data: ", "")
      next if data == "[DONE]"

      json_chunk = JSON.parse(data)
      delta_content = json_chunk.dig("choices", 0, "delta", "content")
      next unless delta_content

      full_response += delta_content
      # 若用Action Cable,此处可推送内容给前端:
      # ChatChannel.broadcast_to(current_user, { content: delta_content })
    end
  end
end

# 最后将完整回复追加到会话历史
session[:chat_history] << { role: "assistant", content: full_response }

内容的提问来源于stack exchange,提问作者Olivier Girardot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 01:22:35