fix: preserve responses reasoning history
This commit is contained in:
parent
b870a77a55
commit
8ed5939ebb
|
|
@ -62,8 +62,8 @@ pub(crate) struct ResponsesRequest {
|
|||
pub(crate) struct ReasoningConfig {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub effort: Option<String>,
|
||||
/// Reasoning encrypted_content は同一 user turn 内だけ再利用する。
|
||||
/// 古い turn の reasoning item は request input から除外する。
|
||||
/// API 側の reasoning retention policy。Insomnia はこの値を送るが、
|
||||
/// persisted reasoning item の client-side filtering はしない。
|
||||
pub context: &'static str,
|
||||
/// summary の出力制御。`"auto"` 固定で summary_text を受け取る。
|
||||
pub summary: &'static str,
|
||||
|
|
@ -240,9 +240,8 @@ impl OpenAIResponsesScheme {
|
|||
|
||||
/// `Item` 列を `input[]` に変換する。
|
||||
fn convert_items_to_input(items: &[Item]) -> Vec<InputItem> {
|
||||
let current_turn_start = current_turn_start_index(items);
|
||||
let mut out = Vec::with_capacity(items.len());
|
||||
for (idx, item) in items.iter().enumerate() {
|
||||
for item in items {
|
||||
match item {
|
||||
Item::Message { role, content, .. } => {
|
||||
let (role_str, text_variant): (&'static str, fn(String) -> InputContent) =
|
||||
|
|
@ -299,9 +298,6 @@ fn convert_items_to_input(items: &[Item]) -> Vec<InputItem> {
|
|||
encrypted_content,
|
||||
..
|
||||
} => {
|
||||
if idx < current_turn_start {
|
||||
continue;
|
||||
}
|
||||
let summary_parts = summary
|
||||
.iter()
|
||||
.filter(|s| !s.is_empty())
|
||||
|
|
@ -324,26 +320,6 @@ fn convert_items_to_input(items: &[Item]) -> Vec<InputItem> {
|
|||
out
|
||||
}
|
||||
|
||||
/// Responses の `reasoning.context = "current_turn"` に合わせ、直近の
|
||||
/// user message 以降だけを current turn とみなす。ToolResult は Responses
|
||||
/// wire 上では user 側 item だが、新しい人間/外部入力ではなく function-call
|
||||
/// chain の継続なので turn reset には使わない。System/developer notes も
|
||||
/// 同一 turn 内の補助入力になり得るため reset しない。
|
||||
fn current_turn_start_index(items: &[Item]) -> usize {
|
||||
items
|
||||
.iter()
|
||||
.rposition(|item| {
|
||||
matches!(
|
||||
item,
|
||||
Item::Message {
|
||||
role: Role::User,
|
||||
..
|
||||
}
|
||||
)
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
fn convert_tool(tool: &ToolDefinition) -> ResponseTool {
|
||||
ResponseTool {
|
||||
r#type: "function",
|
||||
|
|
@ -506,7 +482,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn old_turn_reasoning_items_are_omitted_for_current_turn_context() {
|
||||
fn persisted_reasoning_items_are_preserved_across_user_turns() {
|
||||
let scheme = OpenAIResponsesScheme::new();
|
||||
let old_reasoning = Item::reasoning("old").with_encrypted_content("OLD_ENC");
|
||||
let current_reasoning = Item::reasoning("current").with_encrypted_content("CURRENT_ENC");
|
||||
|
|
@ -527,7 +503,7 @@ mod tests {
|
|||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(encrypted, vec!["CURRENT_ENC"]);
|
||||
assert_eq!(encrypted, vec!["OLD_ENC", "CURRENT_ENC"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -85,9 +85,9 @@ reasoning トークンは各ターンの後に破棄される。次ターンに
|
|||
1. `previous_response_id` パラメータで過去のレスポンスを参照
|
||||
2. `response.output` の全アイテムを次の `input` に手動で渡す
|
||||
|
||||
ステートレス利用(`store=false`、ZDR組織)の場合は `include=["reasoning.encrypted_content"]` を指定すれば暗号化された推論コンテンツを受け取り、次リクエストに渡すことで推論を引き継げる。ただし Insomnia では Responses リクエストに `reasoning.context="current_turn"` を明示し、直近の user message 以降の同一ターン内 reasoning item だけを `input` に残す。過去ターンの persisted `encrypted_content` は、履歴に残っていても次ターンへ盲目的には再送しない。
|
||||
ステートレス利用(`store=false`、ZDR組織)の場合は `include=["reasoning.encrypted_content"]` を指定すれば暗号化された推論コンテンツを受け取り、次リクエストに渡すことで推論を引き継げる。Insomnia は Responses リクエストに `reasoning.context="current_turn"` を明示するが、このパラメータの正確な履歴境界 semantics は provider 側の責務として扱い、履歴から復元した reasoning item を client 側でターン境界に基づいて削除しない。
|
||||
|
||||
同一ターン内の function-call loop では、`reasoning item → function_call → function_call_output → 次の Responses request` の連続性を保つため、直近 user message 以降の reasoning item は保持する。ToolResult は wire 上で user 側 item に見えるが、新しい user turn ではなく function-call chain の継続なので reasoning reset の境界にはしない。
|
||||
同一ターン内の function-call loop でも、`reasoning item → function_call → function_call_output → 次の Responses request` の連続性を保つため、履歴上の reasoning item は通常の API message として保持する。ToolResult は wire 上で user 側 item に見えるが、reasoning item の削除境界としては扱わない。
|
||||
|
||||
#### モデル世代差
|
||||
|
||||
|
|
@ -187,7 +187,7 @@ Ollamaはローカル実行プラットフォームで、モデルごとに思
|
|||
|
||||
**ChatGPT を使うとき**
|
||||
- 新規実装は **Responses API** を選ぶ(Chat Completions は推論引き継ぎが弱い)
|
||||
- ZDR組織でも `reasoning.encrypted_content` で推論を引き継げるが、Insomnia では `reasoning.context="current_turn"` に合わせて同一 user turn / function-call loop 内だけ再送する
|
||||
- ZDR組織でも `reasoning.encrypted_content` で推論を引き継げる。Insomnia は `reasoning.context="current_turn"` を送るが、履歴上の reasoning item は通常の API message として扱い、独自の turn-boundary filtering はしない
|
||||
- raw reasoning の抽出を試みない(規約違反の可能性)
|
||||
|
||||
**Ollama を使うとき**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user