DatabricksAdapter yields text content during tool-calling rounds, causing response duplication

オープン
#421 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 3 日以内に返信

まだ誰も着手していません。

  • #436 @MarioCadenas による — マージされずにクローズ

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
55/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
静か
技術スタック
typescript
領域
ai, api, backend

調査の方向性

DatabricksAdapter の streamCompletion() と、196 行目付近の run() メソッドから始め、次に maxSteps: 10 と describeTable や executeSql などの複数のツールを使って問題を再現します。ツール呼び出しの 1 ラウンドにわたって message_delta イベントと tool-call イベントを追跡します。完了の条件は、中間テキストによってユーザーに表示される回答が重複せず、最終応答が引き続き 1 回だけ表示されることです。

索引モデルが issue の本文から書いたものです。

説明

DatabricksAdapter yields text content during tool-calling rounds, causing response duplication

Problem

When using DatabricksAdapter with Claude models via Databricks Model Serving (OpenAI-compatible endpoint), the model produces substantial text content alongside tool calls in the same response turn. The adapter's streamCompletion() method yields all delta.content text as message_delta events regardless of whether the same response also contains tool calls.

In a multi-step ReAct loop, this causes the model's intermediate text (which often includes the full answer) to be emitted and displayed to the user on every tool-calling turn — resulting in the same answer appearing 3-4× in the final output.

Root Cause Analysis

Claude's native API uses a trained-in tool-use system prompt that shapes the model to produce brief commentary before tool_use blocks. The Databricks OpenAI-compatible translation layer does not include this trained-in prompt, so Claude produces more verbose text during tool-calling rounds.

The adapter loop (run() method, line ~196) correctly breaks when no tool calls are present, but during tool-calling rounds, streamCompletion() yields ALL delta.content as message_delta events — there's no mechanism to suppress or buffer text that arrives in a turn that also contains tool calls.

Expected Behavior

Text content from tool-calling rounds should either:

  1. Be suppressed (not yielded as message_delta) when the same response also contains tool_calls
  2. Be buffered until streamCompletion returns, and only yielded if no tool calls were detected
  3. Be marked with metadata so consumers can distinguish intermediate text from final-answer text
Current Workaround

We added:

  • A system prompt instruction telling the model to only write brief status notes during tool-calling turns
  • Client-side text buffering in the SSE transport layer that discards accumulated text when a function_call event arrives in the same round
Environment
  • AppKit version: 0.38.1
  • Model: databricks-claude-opus-4-6 via Model Serving
  • Adapter: DatabricksAdapter.fromServingEndpoint()
Reproduction
  1. Create an agent with maxSteps: 10 and multiple tools (e.g., describeTable, executeSql)
  2. Ask a question that triggers 3+ tool calls
  3. Observe that the assistant's text response contains the full answer repeated once per tool-calling round
主要言語
TypeScript
スター
119
フォーク
36
平均マージ
4日 16時間
マージ済み PR(30日)
37

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

databricks/appkit のほかの issue

databricks/appkit の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。