Skip to content

Commit a44f3c6

Browse files
committed
spike always sending question to rephraser
1 parent 0f48dc5 commit a44f3c6

5 files changed

Lines changed: 155 additions & 87 deletions

File tree

lib/answer_composition/pipeline/question_rephraser.rb

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ def initialize(context)
1818
end
1919

2020
def call
21-
return if message_records.blank?
21+
return if message_records.blank? && model_name == :claude_sonnet_4_0
2222

2323
start_time = Clock.monotonic_time
2424
response = anthropic_bedrock_client.messages.create(
25-
system: [{ type: "text", text: config[:system_prompt] }],
25+
system: [{ type: "text", text: system_prompt }],
2626
model: model_id,
2727
messages:,
2828
**inference_config,
@@ -78,10 +78,27 @@ def inference_config
7878
}
7979
end
8080

81+
def system_prompt
82+
return config[:system_prompt] if model_name == :claude_sonnet_4_0
83+
84+
config[:system_prompt_always_rephrase]
85+
end
86+
8187
def user_prompt
82-
config[:user_prompt]
83-
.sub("{question}", question_message)
84-
.sub("{message_history}", message_history)
88+
if model_name == :claude_sonnet_4_0
89+
return config[:user_prompt].sub("{question}", question_message)
90+
.sub("{message_history}", message_history)
91+
92+
end
93+
94+
config_key = message_records.present? ? :user_prompt_with_history : :user_prompt_without_history
95+
96+
if config_key == :user_prompt_with_history
97+
config[config_key].sub("{question}", question_message)
98+
.sub("{message_history}", message_history)
99+
else
100+
config[config_key].sub("{question}", question_message)
101+
end
85102
end
86103

87104
def messages

spec/lib/answer_composition/pipeline/question_rephraser_spec.rb

Lines changed: 130 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -30,97 +30,99 @@
3030
end
3131
end
3232

33-
context "when the question is the beginning of the conversation" do
34-
let(:context) { build(:answer_pipeline_context) }
33+
it "includes the current question in the user prompt" do
34+
described_class.call(context)
35+
expect(stub).to have_been_requested
36+
end
3537

36-
it "returns nil" do
37-
expect(described_class.call(context)).to be_nil
38-
end
38+
it "includes the message_history in the user prompt" do
39+
message_history = <<~HISTORY.strip
40+
user:
41+
"""
42+
How do I pay my tax
43+
"""
44+
assistant:
45+
"""
46+
What type of tax
47+
"""
48+
user:
49+
"""
50+
What types are there
51+
"""
52+
assistant:
53+
"""
54+
Self-assessment, PAYE, Corporation tax
55+
"""
56+
HISTORY
57+
58+
anthropic_request = stub_claude_question_rephrasing(
59+
Regexp.new(message_history),
60+
rephrased,
61+
)
62+
63+
described_class.call(context)
64+
65+
expect(anthropic_request).to have_been_made
3966
end
4067

41-
context "when all other recent answers have statuses in Answer::STATUSES_EXCLUDED_FROM_REPHRASING" do
42-
it "returns nil" do
43-
conversation = create(:conversation)
44-
create(:question, conversation:)
45-
Answer::STATUSES_EXCLUDED_FROM_REPHRASING.sample(4) do |status|
46-
question = create(:question, conversation:)
47-
create(:answer, question:, status:)
48-
end
49-
latest_question = create(:question, conversation:)
50-
context = build(:answer_pipeline_context, question: latest_question)
68+
it "updates the context's question_message with the rephrased question" do
69+
described_class.call(context)
70+
expect(context.question_message).to eq(rephrased)
71+
end
5172

52-
expect(described_class.call(context)).to be_nil
53-
end
73+
it "assigns metrics to the answer" do
74+
allow(Clock).to receive(:monotonic_time).and_return(100.0, 101.5)
75+
76+
described_class.call(context)
77+
78+
expect(context.answer.metrics["question_rephrasing"])
79+
.to eq({
80+
duration: 1.5,
81+
llm_prompt_tokens: 10,
82+
llm_completion_tokens: 20,
83+
llm_cached_tokens: nil,
84+
model: BedrockModels.model_id(described_class::DEFAULT_MODEL),
85+
})
5486
end
5587

56-
context "when the question is part of an ongoing chat" do
57-
it "includes the current question in the user prompt" do
88+
it "assigns the llm response to the answer" do
89+
described_class.call(context)
90+
91+
expected_llm_response = claude_messages_response(
92+
content: [claude_messages_text_block(rephrased)],
93+
usage: claude_messages_usage_block(input_tokens: 10, output_tokens: 20),
94+
bedrock_model: described_class::DEFAULT_MODEL,
95+
).to_h
96+
97+
expect(context.answer.llm_responses["question_rephrasing"])
98+
.to eq(expected_llm_response)
99+
end
100+
101+
context "when the question is the first in the conversation" do
102+
let(:question) { create(:question) }
103+
let(:context) { build(:answer_pipeline_context, question:) }
104+
let!(:stub) { stub_claude_question_rephrasing(question.message, rephrased) }
105+
106+
it "calls the llm and rephrases the question" do
58107
described_class.call(context)
59108
expect(stub).to have_been_requested
60109
end
61110

62-
it "includes the message_history in the user prompt" do
63-
message_history = <<~HISTORY.strip
64-
user:
65-
"""
66-
How do I pay my tax
67-
"""
68-
assistant:
69-
"""
70-
What type of tax
71-
"""
72-
user:
73-
"""
74-
What types are there
75-
"""
76-
assistant:
77-
"""
78-
Self-assessment, PAYE, Corporation tax
79-
"""
80-
HISTORY
111+
it "doesn't include a message history in the prompt" do
112+
expected_prompt = AnswerComposition::Pipeline::Prompts.config(
113+
:question_rephraser, described_class::DEFAULT_MODEL
114+
)[:user_prompt_without_history]
115+
.sub("{question}", question.message)
81116

82117
anthropic_request = stub_claude_question_rephrasing(
83-
Regexp.new(message_history),
118+
expected_prompt,
84119
rephrased,
85120
)
86121

87122
described_class.call(context)
88123

89124
expect(anthropic_request).to have_been_made
90125
end
91-
92-
it "updates the context's question_message with the rephrased question" do
93-
described_class.call(context)
94-
expect(context.question_message).to eq(rephrased)
95-
end
96-
97-
it "assigns metrics to the answer" do
98-
allow(Clock).to receive(:monotonic_time).and_return(100.0, 101.5)
99-
100-
described_class.call(context)
101-
102-
expect(context.answer.metrics["question_rephrasing"])
103-
.to eq({
104-
duration: 1.5,
105-
llm_prompt_tokens: 10,
106-
llm_completion_tokens: 20,
107-
llm_cached_tokens: nil,
108-
model: BedrockModels.model_id(described_class::DEFAULT_MODEL),
109-
})
110-
end
111-
112-
it "assigns the llm response to the answer" do
113-
described_class.call(context)
114-
115-
expected_llm_response = claude_messages_response(
116-
content: [claude_messages_text_block(rephrased)],
117-
usage: claude_messages_usage_block(input_tokens: 10, output_tokens: 20),
118-
bedrock_model: described_class::DEFAULT_MODEL,
119-
).to_h
120-
121-
expect(context.answer.llm_responses["question_rephrasing"])
122-
.to eq(expected_llm_response)
123-
end
124126
end
125127

126128
context "with a long history" do
@@ -225,4 +227,60 @@
225227
expect(anthropic_request).to have_been_made
226228
end
227229
end
230+
231+
context "when the model is claude_sonnet_4_0" do
232+
let!(:stub) do
233+
stub_claude_question_rephrasing(
234+
question.message, rephrased, chat_options: { bedrock_model: :claude_sonnet_4_0 }
235+
)
236+
end
237+
238+
before { stub_const("#{described_class}::DEFAULT_MODEL", :claude_sonnet_4_0) }
239+
240+
it "uses the system prompt configured for claude_sonnet_4_0" do
241+
allow(AnswerComposition::Pipeline::Prompts.config(:question_rephraser, :claude_sonnet_4_0))
242+
.to receive(:[]).and_call_original
243+
244+
described_class.call(context)
245+
246+
expect(AnswerComposition::Pipeline::Prompts.config(:question_rephraser, :claude_sonnet_4_0))
247+
.to have_received(:[]).with(:system_prompt)
248+
end
249+
250+
it "calls the llm when there is message history" do
251+
described_class.call(context)
252+
253+
expect(stub).to have_been_requested
254+
expect(context.question_message).to eq(rephrased)
255+
end
256+
257+
context "when all other recent answers have statuses in Answer::STATUSES_EXCLUDED_FROM_REPHRASING" do
258+
it "returns nil" do
259+
conversation = create(:conversation)
260+
create(:question, conversation:)
261+
Answer::STATUSES_EXCLUDED_FROM_REPHRASING.sample(4) do |status|
262+
question = create(:question, conversation:)
263+
create(:answer, question:, status:)
264+
end
265+
latest_question = create(:question, conversation:)
266+
context = build(:answer_pipeline_context, question: latest_question)
267+
268+
expect(described_class.call(context)).to be_nil
269+
expect(stub).not_to have_been_requested
270+
end
271+
end
272+
273+
context "when there is no message history" do
274+
let(:conversation) { create(:conversation) }
275+
let(:question) { create(:question, conversation:) }
276+
let(:context) { build(:answer_pipeline_context, question:) }
277+
278+
it "returns nil" do
279+
result = described_class.call(context)
280+
281+
expect(stub).not_to have_been_requested
282+
expect(result).to be_nil
283+
end
284+
end
285+
end
228286
end

spec/support/system_spec_helpers.rb

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,13 @@ def given_i_am_an_admin_with_the_settings_permission
3535

3636
def stubs_for_mock_answer(question,
3737
answer,
38-
rephrase_question: false,
3938
sources_used: [],
4039
create_content_chunk: true)
4140
stub_claude_jailbreak_guardrails(question)
41+
rephrased_question = "Rephrased #{question}"
42+
stub_claude_question_rephrasing(question, rephrased_question)
4243

43-
if rephrase_question
44-
rephrased_question = "Rephrased #{question}"
45-
46-
stub_claude_question_rephrasing(question, rephrased_question)
47-
48-
question = rephrased_question
49-
end
44+
question = rephrased_question
5045

5146
stub_bedrock_titan_embedding(question)
5247

spec/system/conversation_js_features_spec.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ def when_the_second_answer_is_generated
182182

183183
stubs_for_mock_answer(@second_question,
184184
@second_answer,
185-
rephrase_question: true,
186185
sources_used: %w[link_1],
187186
create_content_chunk: false)
188187

spec/system/conversation_with_claude_structured_answer_spec.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ def when_the_second_answer_is_generated
6666

6767
stubs_for_mock_answer(@second_question,
6868
@second_answer,
69-
rephrase_question: true,
7069
sources_used: %w[link_1],
7170
create_content_chunk: false)
7271

0 commit comments

Comments
 (0)