Class: Llmemory::Retrieval::Engine
- Inherits:
-
Object
- Object
- Llmemory::Retrieval::Engine
- Defined in:
- lib/llmemory/retrieval/engine.rb
Constant Summary collapse
- RELEVANCE_THRESHOLD =
0.7- FEEDBACK_CAP =
5
Instance Method Summary collapse
-
#initialize(memory, llm: nil, feedback: nil) ⇒ Engine
constructor
A new instance of Engine.
-
#iterative_retrieve(user_message, user_id: nil, max_tokens: nil, max_hops: 2, reasoner: nil) ⇒ Object
Multi-hop retrieval (CoALA: integrating retrieval and reasoning).
-
#report_feedback(useful_ids: [], harmful_ids: [], user_id: nil) ⇒ Object
Records that previously-retrieved items were useful or harmful for the agent’s task.
- #retrieve_for_inference(user_message, user_id: nil, max_tokens: nil) ⇒ Object
Constructor Details
#initialize(memory, llm: nil, feedback: nil) ⇒ Engine
Returns a new instance of Engine.
15 16 17 18 19 20 21 22 23 |
# File 'lib/llmemory/retrieval/engine.rb', line 15 def initialize(memory, llm: nil, feedback: nil) @memory = memory @llm = llm || Llmemory::LLM.client @ranker = TemporalRanker.new @assembler = ContextAssembler.new @bm25_scorer = Bm25Scorer.new @mmr_reranker = MmrReranker.new(lambda: Llmemory.configuration.mmr_lambda) @feedback = feedback || FeedbackStore.new end |
Instance Method Details
#iterative_retrieve(user_message, user_id: nil, max_tokens: nil, max_hops: 2, reasoner: nil) ⇒ Object
Multi-hop retrieval (CoALA: integrating retrieval and reasoning). After each hop, a reasoner inspects what has been retrieved and proposes a follow-up query for the missing piece, enabling multi-hop questions a single retrieval would miss. Candidates accumulate (deduped) across hops.
‘reasoner` is a callable (user_message, accumulated_candidates, hop) -> next query String, or “DONE”/blank to stop. Defaults to an LLM that proposes the next sub-query. Converges on `max_hops`, “DONE”, a blank query, or a repeated query.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/llmemory/retrieval/engine.rb', line 41 def iterative_retrieve(, user_id: nil, max_tokens: nil, max_hops: 2, reasoner: nil) user_id ||= @memory.respond_to?(:user_id) ? @memory.user_id : nil reasoner ||= method(:default_followup_query) query = generate_query() seen = [] accumulated = [] hop = 0 while hop < max_hops && live_query?(query) && !seen.include?(query) seen << query accumulated = merge_candidates(accumulated, ranked_candidates(query, user_id, query)) hop += 1 break if hop >= max_hops query = reasoner.call(, accumulated, hop).to_s.strip end final = accumulated.sort_by { |c| -(c[:temporal_score] || c[:score] || 0) } @assembler.assemble(final, max_tokens: max_tokens) end |
#report_feedback(useful_ids: [], harmful_ids: [], user_id: nil) ⇒ Object
Records that previously-retrieved items were useful or harmful for the agent’s task. Repeatedly useful items rank higher in future retrievals; noisy ones are dampened. Item ids come from the candidates returned by the memory’s #read / #search_candidates.
67 68 69 70 71 72 |
# File 'lib/llmemory/retrieval/engine.rb', line 67 def report_feedback(useful_ids: [], harmful_ids: [], user_id: nil) user_id ||= @memory.respond_to?(:user_id) ? @memory.user_id : nil Array(useful_ids).each { |id| @feedback.record(user_id, id, 1) } Array(harmful_ids).each { |id| @feedback.record(user_id, id, -1) } true end |
#retrieve_for_inference(user_message, user_id: nil, max_tokens: nil) ⇒ Object
25 26 27 28 29 30 |
# File 'lib/llmemory/retrieval/engine.rb', line 25 def retrieve_for_inference(, user_id: nil, max_tokens: nil) user_id ||= @memory.respond_to?(:user_id) ? @memory.user_id : nil search_query = generate_query() ranked = ranked_candidates(search_query, user_id, ) @assembler.assemble(ranked, max_tokens: max_tokens) end |