feat(captain): improve contextual chunk retrieval quality

This commit is contained in:
aakashb95
2026-02-20 10:16:46 +05:30
parent 8dc9789f12
commit 3df4dbf114
6 changed files with 275 additions and 15 deletions
@@ -53,5 +53,30 @@ RSpec.describe Captain::Documents::ChunkingService do
expect(result.size).to eq(2)
expect(result.last[:content]).to include('nine ten')
end
it 'removes obvious boilerplate navigation sections before chunking' do
content = <<~TEXT
# Account deletion
You can delete your account from Settings.
## Related articles
- [How to block someone](https://example.com/block)
- [How to report someone](https://example.com/report)
- [How to update profile](https://example.com/profile)
TEXT
result = described_class.new(
content,
target_tokens: 30,
min_tokens: 10,
max_tokens: 50,
overlap_tokens: 0
).chunk
combined_content = result.map { |chunk| chunk[:content] }.join("\n")
expect(combined_content).to include('You can delete your account from Settings')
expect(combined_content).not_to include('How to block someone')
expect(combined_content).not_to include('Related articles')
end
end
end
@@ -28,6 +28,19 @@ RSpec.describe Captain::Documents::ContextGenerationService do
expect(result).to eq('Pricing page context.')
end
it 'uses retrieval-oriented context instructions' do
service = described_class.new(
document_content: 'Document text',
chunk_content: 'Chunk text',
account_id: 1
)
service.generate
expect(chat).to have_received(:with_instructions).with(include('user intents this chunk can answer'))
expect(chat).to have_received(:with_instructions).with(include('make this chunk easier to find'))
end
it 'uses explicit model when provided' do
service = described_class.new(
document_content: 'Doc text',
@@ -54,5 +54,42 @@ RSpec.describe Captain::Documents::HybridChunkSearchService do
expect(results.first.document_id).to eq(ready_document.id)
expect(results.first.content).to include('reset password')
end
it 'uses BM25 scoring to prioritize stronger lexical matches' do
ready_document = create(
:captain_document,
account: account,
assistant: assistant,
status: :available,
chunking_status: :ready
)
weaker_chunk = create(
:captain_document_chunk,
document: ready_document,
account: account,
assistant: assistant,
position: 0,
content: 'Incognito mode exists for profile visibility.',
context: 'Privacy and safety settings.'
)
stronger_chunk = create(
:captain_document_chunk,
document: ready_document,
account: account,
assistant: assistant,
position: 1,
content: 'Incognito mode allows hidden browsing. Incognito mode keeps your profile hidden.',
context: 'Incognito mode details and hidden profile behavior.'
)
embedding_service = instance_double(Captain::Llm::EmbeddingService, get_embedding: [])
allow(Captain::Llm::EmbeddingService).to receive(:new).and_return(embedding_service)
results = service.search('how does incognito mode work')
expect(results.first.id).to eq(stronger_chunk.id)
expect(results.map(&:id)).to include(weaker_chunk.id)
end
end
end