Closed5
Structured Output + ストリーミングで常にvalidなレスポンスを返す
Structured Outputをストリーミングでやる場合、例えば以下のような出力フォーマットの場合
from typing import List
from pydantic import BaseModel
class EntitiesModel(BaseModel):
colors: List[str]
animals: List[str]
messages=[
{
"role": "system",
"content": "入力テキストからエンティティを抽出して。"},
{
"role": "user",
"content": "茶色いキツネは青い瞳の怠け者の犬を飛び越える。",
},
]
ストリーミング中のレスポンスも"valid"であってほしい。こんな感じで。
出力
{}
{'colors': []}
{'colors': ['茶色']}
{'colors': ['茶色', '青']}
{'colors': ['茶色', '青'], 'animals': []}
{'colors': ['茶色', '青'], 'animals': ['キツネ']}
{'colors': ['茶色', '青'], 'animals': ['キツネ', '犬']}
こうであってほしくない。これだとストリーミングの完了を待たないとパースできないので、ストリーミングである必要がない。
出力
{
'
colors
'
:
[
'
茶
色
'
,
(snip)
でOpenAIの場合はこれが可能。
再掲。以下記事でやった例。
from typing import List
from pydantic import BaseModel
from openai import OpenAI
from enum import Enum
class Sentiment(str, Enum):
happy = "happy"
angry = "angry"
sad = "sad"
fun = "fun"
class ResponseWithSentiment(BaseModel):
message: List[str]
sentiment: Sentiment
client = OpenAI()
with client.beta.chat.completions.stream(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": "あなたは親切な日本語のアシスタントです。"},
{
"role": "user",
"content": "おはよう。。。昨日は競馬ボロ負けしちゃったよ。。。。",
},
],
response_format=ResponseWithSentiment,
) as stream:
for event in stream:
if event.type == "content.delta":
if event.parsed is not None:
# パースされたデータをJSONで出力
print("パースされた差分コンテンツ:", event.parsed)
elif event.type == "content.done":
print("コンテンツ終了")
elif event.type == "error":
print("ストリームでエラーが発生しました:", event.error)
final_completion = stream.get_final_completion()
print("最終結果:")
pprint(final_completion.choices[0].message.parsed.model_dump())
出力
パースされた差分コンテンツ: {}
パースされた差分コンテンツ: {}
パースされた差分コンテンツ: {'message': []}
パースされた差分コンテンツ: {'message': []}
パースされた差分コンテンツ: {'message': []}
パースされた差分コンテンツ: {'message': []}
パースされた差分コンテンツ: {'message': []}
パースされた差分コンテンツ: {'message': []}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!']}
パースされた差分コンテンツ: {'message': ['おはようございます!', '競馬で負けてしまったのは残念ですね。']}
パースされた差分コンテンツ: {'message': ['おはようございます!', '競馬で負けてしまったのは残念ですね。']}
パースされた差分コンテンツ: {'message': ['おはようございます!', '競馬で負けてしまったのは残念ですね。']}
パースされた差分コンテンツ: {'message': ['おはようございます!', '競馬で負けてしまったのは残念ですね。']}
パースされた差分コンテンツ: {'message': ['おはようございます!', '競馬で負けてしまったのは残念ですね。']}
パースされた差分コンテンツ: {'message': ['おはようございます!', '競馬で負けてしまったのは残念ですね。']}
パースされた差分コンテンツ: {'message': ['おはようございます!', '競馬で負けてしまったのは残念ですね。'], 'sentiment': 'sad'}
コンテンツ終了
最終結果:
{'message': ['おはようございます!', '競馬で負けてしまったのは残念ですね。'],
'sentiment': <Sentiment.sad: 'sad'>}
さすがに値の中身までストリーミングしてくれるわけではない(なのでListを使っている)が、このあたりはOpenAI SDKがよしなにやってくれる。
なお、Function Callingもレスポンスのストリーミングに対応している。
のだが、こちらは値の中身がストリーミングされるので、結合してやる必要があるみたい。ドキュメントのサンプルコードを元に書いてみた。
from openai import OpenAI
client = OpenAI()
tools = [{
"type": "function",
"function": {
"name": "get_reply_with_sentiment",
"description": "ユーザのクエリに対し、回答を返すと共に、ユーザのクエリから読み取れる感情を付与する。",
"parameters": {
"type": "object",
"properties": {
"reply": {
"type": "string",
"description": "あなたの返答",
},
"sentiment": {
"type": "string",
"enum": ["happy", "angry", "sad", "fun", "neutral"],
"description": "ユーザのクエリから読み取れる感情",
},
},
"required": ["reply", "sentiment"],
"additionalProperties": False
},
"strict": True
}
}]
stream = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": "先週末の競馬、馬券を買い間違えて、当ててたはずの万馬券を逃しちゃったよ・・・・"
}
],
tools=tools,
stream=True
)
final_tool_calls = {}
for chunk in stream:
for tool_call in chunk.choices[0].delta.tool_calls or []:
index = tool_call.index
if index not in final_tool_calls:
final_tool_calls[index] = tool_call
final_tool_calls[index].function.arguments += tool_call.function.arguments
print(final_tool_calls[0].function.arguments)
結果
出力
{"
{"reply
{"reply":"
{"reply":"それ
{"reply":"それは
{"reply":"それは残
{"reply":"それは残念
{"reply":"それは残念でした
{"reply":"それは残念でしたね
{"reply":"それは残念でしたね。
{"reply":"それは残念でしたね。き
{"reply":"それは残念でしたね。きっと
{"reply":"それは残念でしたね。きっと悔
{"reply":"それは残念でしたね。きっと悔しい
{"reply":"それは残念でしたね。きっと悔しい思
{"reply":"それは残念でしたね。きっと悔しい思い
{"reply":"それは残念でしたね。きっと悔しい思いを
{"reply":"それは残念でしたね。きっと悔しい思いをされた
{"reply":"それは残念でしたね。きっと悔しい思いをされたので
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回は
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はき
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出る
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ること
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!また
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャ
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレン
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジ
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジして
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみ
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみて
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみてください
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみてくださいね
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみてくださいね。
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみてくださいね。","
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみてくださいね。","sent
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみてくださいね。","sentiment
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみてくださいね。","sentiment":"
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみてくださいね。","sentiment":"sad
{"reply":"それは残念でしたね。きっと悔しい思いをされたのでしょう。でも、次回はきっと良い結果が出ることを願っています!またチャレンジしてみてくださいね。","sentiment":"sad"}
だめじゃん。
ということで、ネイティブSDKしかでき無いといろいろ辛いし、これは他のモデルプロバイダでも同じ。
ちょっと代替案を探してみる。
Instructorを使う。ちなみに。EnumやLiteralを使う場合はPartialLiteralMixinを使うのがポイント。
import openai
import instructor
from typing import List, Literal, Optional
from pydantic import BaseModel, Field
from enum import Enum
from instructor.dsl.partial import PartialLiteralMixin
import time
class Sentiment(Enum):
happy = "happy"
angry = "angry"
sad = "sad"
fun = "fun"
neutral = "neutral"
class ResponseWithSentiment(BaseModel, PartialLiteralMixin):
reply: List[str] = Field(description="あなたの返答。できるだけ長く。")
sentiment: Sentiment= Field(description="ユーザのクエリから読み取れる感情")
text = "先週末の競馬、馬券を買い間違えて、当ててたはずの万馬券を逃しちゃったよ・・・・"
client = instructor.from_openai(openai.OpenAI())
PartialResponseWithSentiment = instructor.Partial[ResponseWithSentiment]
stream = client.chat.completions.create_partial(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": text},
],
response_model=PartialResponseWithSentiment,
)
for event in stream:
print(event.model_dump_json())
出力
{"reply":null,"sentiment":null}
{"reply":null,"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":[],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!","もう一度、競馬を楽しんで、是非リベンジしてみてください。応援しています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!","もう一度、競馬を楽しんで、是非リベンジしてみてください。応援しています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!","もう一度、競馬を楽しんで、是非リベンジしてみてください。応援しています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!","もう一度、競馬を楽しんで、是非リベンジしてみてください。応援しています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!","もう一度、競馬を楽しんで、是非リベンジしてみてください。応援しています!"],"sentiment":null}
{"reply":["それは本当に残念でしたね。競馬は運やタイミングが影響しますから、間違えてしまうこともありますよね。","次回はぜひ、買い間違えないように気を付けてください。万馬券を逃したのは悔しいですが、次のチャンスが待っています!","もう一度、競馬を楽しんで、是非リベンジしてみてください。応援しています!"],"sentiment":"sad"}
json-repairを使う
さっきのFunction Callingのストリーミングのサンプルをjson-repairを使ってみる。
from openai import OpenAI
import json_repair
client = OpenAI()
tools = [{
"type": "function",
"function": {
"name": "get_reply_with_sentiment",
"description": "ユーザのクエリに対し、回答を返すと共に、ユーザのクエリから読み取れる感情を付与する。",
"parameters": {
"type": "object",
"properties": {
"reply": {
"type": "string",
"description": "あなたの返答",
},
"sentiment": {
"type": "string",
"enum": ["happy", "angry", "sad", "fun", "neutral"],
"description": "ユーザのクエリから読み取れる感情",
},
},
"required": ["reply", "sentiment"],
"additionalProperties": False
},
"strict": True
}
}]
stream = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": "先週末の競馬、馬券を買い間違えて、当ててたはずの万馬券を逃しちゃったよ・・・・"
}
],
tools=tools,
stream=True
)
final_tool_calls = {}
for chunk in stream:
for tool_call in chunk.choices[0].delta.tool_calls or []:
index = tool_call.index
if index not in final_tool_calls:
final_tool_calls[index] = tool_call
final_tool_calls[index].function.arguments += tool_call.function.arguments
print(json_repair.repair_json(final_tool_calls[index].function.arguments, return_objects=True))
結果
出力
{}
{}
{'reply': ''}
{'reply': 'それ'}
{'reply': 'それは'}
{'reply': 'それは本'}
{'reply': 'それは本当に'}
{'reply': 'それは本当に悔'}
{'reply': 'それは本当に悔しい'}
{'reply': 'それは本当に悔しいですよ'}
{'reply': 'それは本当に悔しいですよね'}
{'reply': 'それは本当に悔しいですよね。'}
{'reply': 'それは本当に悔しいですよね。慌'}
{'reply': 'それは本当に悔しいですよね。慌ただ'}
{'reply': 'それは本当に悔しいですよね。慌ただしい'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中で'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中での'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミ'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミス'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避け'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けら'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられ'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられない'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこと'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないことも'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともあります'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、や'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱ'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ち'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになります'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよ'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回は'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はし'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっ'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっか'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかり'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴ら'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せ'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せる'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せると'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せるといい'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せるといいですね'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せるといいですね。'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せるといいですね。'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せるといいですね。'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せるといいですね。'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せるといいですね。', 'sentiment': ''}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せるといいですね。', 'sentiment': 'sad'}
{'reply': 'それは本当に悔しいですよね。慌ただしい中でのミスは避けられないこともありますが、やっぱり残念な気持ちになりますよね。次回はしっかりと確認して、素晴らしい結果を出せるといいですね。', 'sentiment': 'sad'}
Pydanticで Partial JSON Parsing
from openai import OpenAI
from pydantic_core import from_json
client = OpenAI()
tools = [{
"type": "function",
"function": {
"name": "get_reply_with_sentiment",
"description": "ユーザのクエリに対し、回答を返すと共に、ユーザのクエリから読み取れる感情を付与する。",
"parameters": {
"type": "object",
"properties": {
"reply": {
"type": "string",
"description": "あなたの返答",
},
"sentiment": {
"type": "string",
"enum": ["happy", "angry", "sad", "fun", "neutral"],
"description": "ユーザのクエリから読み取れる感情",
},
},
"required": ["reply", "sentiment"],
"additionalProperties": False
},
"strict": True
}
}]
stream = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": "先週末の競馬、馬券を買い間違えて、当ててたはずの万馬券を逃しちゃったよ・・・・"
}
],
tools=tools,
stream=True
)
final_tool_calls = {}
for chunk in stream:
for tool_call in chunk.choices[0].delta.tool_calls or []:
index = tool_call.index
if index not in final_tool_calls:
final_tool_calls[index] = tool_call
final_tool_calls[index].function.arguments += tool_call.function.arguments
if final_tool_calls[index].function.arguments:
print(from_json(final_tool_calls[index].function.arguments, allow_partial=True))
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{'reply': 'それは大変でしたね。馬券の買い間違いはショックですよね。次回こそは良い結果が出るといいですね。'}
{'reply': 'それは大変でしたね。馬券の買い間違いはショックですよね。次回こそは良い結果が出るといいですね。'}
{'reply': 'それは大変でしたね。馬券の買い間違いはショックですよね。次回こそは良い結果が出るといいですね。'}
{'reply': 'それは大変でしたね。馬券の買い間違いはショックですよね。次回こそは良い結果が出るといいですね。'}
{'reply': 'それは大変でしたね。馬券の買い間違いはショックですよね。次回こそは良い結果が出るといいですね。'}
{'reply': 'それは大変でしたね。馬券の買い間違いはショックですよね。次回こそは良い結果が出るといいですね。', 'sentiment': 'sad'}
汎用的なやり方であれば、どのモデルプロバイダのものでもある程度なんとかなりそう。
このスクラップは27日前にクローズされました
ログインするとコメントできます