<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Acadify Solution</title>
    <description>The latest articles on DEV Community by Acadify Solution (@acadify_fef2ecf72cca30a3d).</description>
    <link>https://dev.to/acadify_fef2ecf72cca30a3d</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3666900%2Fe517628d-5e91-4689-9951-f38268893313.png</url>
      <title>DEV Community: Acadify Solution</title>
      <link>https://dev.to/acadify_fef2ecf72cca30a3d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/acadify_fef2ecf72cca30a3d"/>
    <language>en</language>
    <item>
      <title>Turn an AI Bug Report into a Regression Case Someone Else Can Reproduce</title>
      <dc:creator>Acadify Solution</dc:creator>
      <pubDate>Wed, 14 Oct 2026 01:43:19 +0000</pubDate>
      <link>https://dev.to/acadify_fef2ecf72cca30a3d/turn-an-ai-bug-report-into-a-regression-case-someone-else-can-reproduce-li5</link>
      <guid>https://dev.to/acadify_fef2ecf72cca30a3d/turn-an-ai-bug-report-into-a-regression-case-someone-else-can-reproduce-li5</guid>
      <description>&lt;p&gt;“It gave the wrong answer yesterday” is useful feedback, but it is not yet a regression test.&lt;/p&gt;

&lt;p&gt;You need enough context to reproduce the problem, a reviewed definition of acceptable behaviour and a record of the version that produced it. Without those, a prompt edit can appear to fix the report simply because the next run used different evidence.&lt;/p&gt;

&lt;p&gt;Here is a small workflow for turning an AI bug report into a test case. The refund example is fictional. This article was generated by an AI agent for Acadify Solution and Acadify AI Lab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the user's task
&lt;/h2&gt;

&lt;p&gt;Ask what the person was trying to do. Separate that from the answer they disliked.&lt;/p&gt;

&lt;p&gt;For example: “Find out whether a purchase is eligible for a refund” describes a task. “The answer sounded too confident” describes an observation. Both belong in the investigation, but neither establishes the expected result on its own.&lt;/p&gt;

&lt;p&gt;Capture only the inputs you are authorised to retain. Do not ask for passwords, tokens or a dump of unrelated customer records. If you replace private details with synthetic ones, record the transformation and review whether the failure still reproduces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Freeze the conditions you can control
&lt;/h2&gt;

&lt;p&gt;Record the application build, prompt version, model identifier and configuration. For retrieval-based features, retain an authorised snapshot of the relevant context or a reproducible corpus/index reference.&lt;/p&gt;

&lt;p&gt;If your environment cannot reproduce a provider-side model version exactly, say so. “Same model name” may not establish an identical system. Record the date and the available version information, and limit your conclusions accordingly.&lt;/p&gt;

&lt;p&gt;A case file might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"case_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"refund-clarification-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"origin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"synthetic example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Explain refund eligibility"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Can I return this purchase?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fixture_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"refund-fixture-v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Refund eligibility requires the purchase date and item condition."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expected_behaviour"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Ask for the missing purchase date and item condition"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Do not claim that the customer is eligible yet"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"review_status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"needs human review"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an illustrative schema, not a complete evaluation format. Your system may also need conversation history, tool outputs, permission scope and language or accessibility requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review the expectation before scoring
&lt;/h2&gt;

&lt;p&gt;Do not turn the reported answer into the ground truth automatically. Review the governing source and the actual task.&lt;/p&gt;

&lt;p&gt;In the example, asking for the missing details is acceptable. Several phrasings could do that well. Exact string matching would reject many reasonable answers and may reward one that merely copies a reference response.&lt;/p&gt;

&lt;p&gt;Use explicit criteria: did the response request the needed information, avoid an unsupported eligibility claim and remain within the available policy? If reviewers disagree, resolve the ambiguity or label it. A disputed case should not quietly become a release gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Locate the failure stage
&lt;/h2&gt;

&lt;p&gt;For a RAG workflow, inspect the retrieved context before changing the generation prompt. Was the relevant policy present? Was it current? Did a filter exclude it? Did the application truncate the passage?&lt;/p&gt;

&lt;p&gt;For a tool-using workflow, inspect the arguments and result. A correct explanation of a failed lookup does not mean the underlying operation completed successfully.&lt;/p&gt;

&lt;p&gt;Give the case a failure category that helps the next investigation. “Bad answer” is less useful than “missing evidence,” “unsupported conclusion” or “tool target mismatch.” Avoid pretending the category proves a cause before you have checked it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compare versions on the same reviewed cases
&lt;/h2&gt;

&lt;p&gt;Run the current version and proposed version under stated conditions. Retain their outputs and the reviewer decisions. Add cases representing previously working tasks, rather than checking only the reported failure.&lt;/p&gt;

&lt;p&gt;Where output is stochastic, predefine an appropriate repeat count and report the individual outcomes as well as a summary. A single good response is weak evidence of a reliable fix.&lt;/p&gt;

&lt;p&gt;Do not repeatedly tune on every test you intend to use as an independent check. Keep a held-out set, and track which cases have influenced development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the result separate from the release decision
&lt;/h2&gt;

&lt;p&gt;A useful comparison table is small:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Case&lt;/th&gt;
&lt;th&gt;Current version&lt;/th&gt;
&lt;th&gt;Proposed version&lt;/th&gt;
&lt;th&gt;Review note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reported failure&lt;/td&gt;
&lt;td&gt;Pending review&lt;/td&gt;
&lt;td&gt;Pending review&lt;/td&gt;
&lt;td&gt;Expected behaviour agreed first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Previously working task&lt;/td&gt;
&lt;td&gt;Pending review&lt;/td&gt;
&lt;td&gt;Pending review&lt;/td&gt;
&lt;td&gt;Check for a meaningful regression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Missing information&lt;/td&gt;
&lt;td&gt;Pending review&lt;/td&gt;
&lt;td&gt;Pending review&lt;/td&gt;
&lt;td&gt;Clarification may be the correct outcome&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These cells intentionally contain no invented scores. Fill them with observations from your own authorised test run.&lt;/p&gt;

&lt;p&gt;Your release gate should reflect the product's consequences. An access violation or incorrect side effect may deserve a different gate from a wording issue. An aggregate average can hide a failure on a critical task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the case useful next month
&lt;/h2&gt;

&lt;p&gt;Give the case an owner and a reason it exists. When the policy or workflow changes, review whether the expected behaviour remains valid. Version the revision instead of changing the label invisibly.&lt;/p&gt;

&lt;p&gt;Set access and retention rules for stored traces. A regression suite should preserve useful evidence, not become an ungoverned archive of user data.&lt;/p&gt;

&lt;p&gt;The goal is a report that another engineer can investigate and a test that still means something after the immediate fix. That is a more useful handover than “we changed the prompt and it seems better.”&lt;/p&gt;

&lt;p&gt;What detail is most often missing from the AI bug reports your team receives?&lt;/p&gt;




&lt;p&gt;Acadify Solution provides software and AI engineering services. Acadify AI Lab supports scoped LLM evaluation and developer feedback with agreed tasks and rubrics.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://acadifysolution.com/" rel="noopener noreferrer"&gt;Acadify Solution&lt;/a&gt; · &lt;a href="https://ai.acadifysolution.com/" rel="noopener noreferrer"&gt;Acadify AI Lab&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ai</category>
      <category>debugging</category>
      <category>llm</category>
    </item>
    <item>
      <title>Testing AI Agent Tool Calls: A Release Checklist Beyond Task Completion</title>
      <dc:creator>Acadify Solution</dc:creator>
      <pubDate>Tue, 13 Oct 2026 02:16:37 +0000</pubDate>
      <link>https://dev.to/acadify_fef2ecf72cca30a3d/testing-ai-agent-tool-calls-a-release-checklist-beyond-task-completion-8np</link>
      <guid>https://dev.to/acadify_fef2ecf72cca30a3d/testing-ai-agent-tool-calls-a-release-checklist-beyond-task-completion-8np</guid>
      <description>&lt;p&gt;A task-completion score can hide an agent that reached the right answer through an unauthorised action. Evaluate &lt;strong&gt;what happened&lt;/strong&gt;, &lt;strong&gt;which actions occurred&lt;/strong&gt; and &lt;strong&gt;whether the system stayed within its authority&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article was generated by an AI agent for Acadify Solution and Acadify AI Lab. All scenarios are illustrative, not client results or benchmark measurements.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Write an action contract
&lt;/h2&gt;

&lt;p&gt;For each tool, define who may invoke it, the tenant and resource scope, required arguments, permitted state transitions, approval requirements and the meaning of success, failure or an unknown outcome.&lt;/p&gt;

&lt;p&gt;Enforce access in the application/tool layer. A prompt can describe a boundary; it does not replace an authorisation check. Reading an enquiry, proposing a CRM update and sending an external reply deserve separate contracts.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Test the target as well as the payload
&lt;/h2&gt;

&lt;p&gt;Use a disposable environment with synthetic data. Include two tenants and similarly named records. Verify that a supplied identifier does not grant access to a record outside the authorised scope.&lt;/p&gt;

&lt;p&gt;Validate types, required fields and business rules at execution time. Rejected calls should cause no state change. Record the attempt and rejection with appropriate redaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Inject an uncertain write outcome
&lt;/h2&gt;

&lt;p&gt;Test a service that commits a write but loses the response. A timeout does not prove that nothing changed.&lt;/p&gt;

&lt;p&gt;Where the API supports it, use a stable operation ID and status lookup. Reusing the ID with a different payload should detect a conflict. If there is no reliable status or deduplication mechanism, represent the unknown outcome and escalate according to the workflow's risk.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Injected condition&lt;/th&gt;
&lt;th&gt;What to check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Failure before commit&lt;/td&gt;
&lt;td&gt;No state change; bounded retry if permitted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit followed by timeout&lt;/td&gt;
&lt;td&gt;Status resolution or safe escalation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replayed request&lt;/td&gt;
&lt;td&gt;No unintended duplicate side effect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same operation ID, different payload&lt;/td&gt;
&lt;td&gt;Conflict detected&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A retry budget alone does not make a write safe. Expected behaviour must follow the API contract and business rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Bind approval to a proposal
&lt;/h2&gt;

&lt;p&gt;Show the reviewer the target and important arguments. Test changes to content, recipient or target after approval. The old approval must not silently cover a materially different action.&lt;/p&gt;

&lt;p&gt;Test rejection and expiry too. A delayed decision should not authorise a later, changed proposal. A blanket approval token disconnected from the proposal is difficult to audit.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Treat retrieved instructions as untrusted input
&lt;/h2&gt;

&lt;p&gt;Place conflicting instructions in a synthetic document—for example, a paragraph asking the assistant to send a message outside the requested workflow. Check both the model's behaviour and the application's permission enforcement.&lt;/p&gt;

&lt;p&gt;Record the input, selected context and attempted calls. Do not use real secrets or private customer records as test material. A single passing case does not show that prompt injection is solved; vary the cases and report the tested scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Exercise stopping and handover
&lt;/h2&gt;

&lt;p&gt;Test missing fields, invalid tool output, expired access, repeated failures and step limits. Define terminal states such as completed, awaiting approval, failed and unknown outcome.&lt;/p&gt;

&lt;p&gt;A handover should identify the last confirmed action and the unresolved step. A fluent final message is not evidence of a completed workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Retain useful, limited traces
&lt;/h2&gt;

&lt;p&gt;Record the case ID, workflow version, authorised scope, redacted arguments, approval decisions, tool results and state changes. Decide who can inspect traces and how long to retain them.&lt;/p&gt;

&lt;p&gt;A reviewer should be able to reconstruct the result without unrestricted access to every document the system encountered.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Separate release gates
&lt;/h2&gt;

&lt;p&gt;Report task outcome separately from policy and integration checks. Under a defined permission gate, an unauthorised write should fail the case even if the final answer is correct.&lt;/p&gt;

&lt;p&gt;Document case counts, fixture versions, model and prompt versions, stochastic repeats where appropriate and known gaps. Keep a held-out set when tuning.&lt;/p&gt;

&lt;p&gt;This checklist is a starting point, not a security certification or reliability guarantee. Adapt it to your system and the consequences of its actions.&lt;/p&gt;

&lt;p&gt;Which failure injection would you add first to your agent's release test?&lt;/p&gt;




&lt;p&gt;Acadify Solution provides software and AI engineering services. Acadify AI Lab supports scoped LLM and agent evaluations using agreed tasks, rubrics and reviewable findings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://acadifysolution.com/" rel="noopener noreferrer"&gt;Acadify Solution&lt;/a&gt; · &lt;a href="https://ai.acadifysolution.com/" rel="noopener noreferrer"&gt;Acadify AI Lab&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>agents</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>A Small RAG Evaluation Harness: Test Retrieval Before Blaming the LLM</title>
      <dc:creator>Acadify Solution</dc:creator>
      <pubDate>Mon, 12 Oct 2026 11:38:20 +0000</pubDate>
      <link>https://dev.to/acadify_fef2ecf72cca30a3d/a-small-rag-evaluation-harness-test-retrieval-before-blaming-the-llm-4na4</link>
      <guid>https://dev.to/acadify_fef2ecf72cca30a3d/a-small-rag-evaluation-harness-test-retrieval-before-blaming-the-llm-4na4</guid>
      <description>&lt;p&gt;A wrong RAG answer does not automatically mean the language model failed. The system may have retrieved the wrong document, omitted the relevant passage, or supplied conflicting evidence.&lt;/p&gt;

&lt;p&gt;This guide builds a small &lt;strong&gt;retrieval-only evaluation harness&lt;/strong&gt;. It separates one question—did we retrieve the expected evidence?—from answer quality. It is an illustrative example, not a measured result from an Acadify client project.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Define what the test can and cannot tell you
&lt;/h2&gt;

&lt;p&gt;Start with two retrieval measures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Recall@k:&lt;/strong&gt; the fraction of known relevant documents present in the first k results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reciprocal rank@k:&lt;/strong&gt; the inverse rank of the first relevant result, or zero if none appears.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recall@k helps detect missing evidence. Reciprocal rank helps distinguish evidence ranked first from evidence buried lower in the results. Neither measures whether the final answer is correct, safe, or grounded.&lt;/p&gt;

&lt;p&gt;Use document identifiers at the same granularity as your labels. If your retriever returns chunks but your labels refer to documents, map chunk IDs to document IDs before scoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Create reviewed cases
&lt;/h2&gt;

&lt;p&gt;Each answerable question needs a set of expected document IDs. Use questions representative of the actual workflow, and have someone review the labels.&lt;/p&gt;

&lt;p&gt;For an unanswerable question, an empty set does &lt;strong&gt;not&lt;/strong&gt; prove that any retrieved document is irrelevant. Here it means there is no known answer in the approved corpus. We report these separately and exclude them from recall and ranking averages.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Run a deterministic example
&lt;/h2&gt;

&lt;p&gt;The following uses only the Python standard library. Replace the fixture retrieval function with your own retrieval API when you are ready.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;case_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;relevant_ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;frozenset&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retrieved&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k must be positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Deduplicate while preserving rank. Score unique document results.
&lt;/span&gt;    &lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromkeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retrieved&lt;/span&gt;&lt;span class="p"&gt;))[:&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;relevant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relevant_ids&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;relevant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;case_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;case_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answerable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_ids&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recall&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;relevant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;first_hit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;doc_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;relevant&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;case_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;case_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answerable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_ids&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recall&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relevant&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;first_hit&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;first_hit&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cases&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
             &lt;span class="n"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cases&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;answerable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answerable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answerable_cases&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answerable&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unanswerable_cases&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answerable&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mean_recall&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recall&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;answerable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;answerable&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mrr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;answerable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;answerable&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;cases&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How do refunds work?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;frozenset&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund-policy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})),&lt;/span&gt;
    &lt;span class="nc"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cancel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How can I cancel?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;frozenset&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cancel-guide&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})),&lt;/span&gt;
    &lt;span class="nc"&gt;Case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;missing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is next year&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s price?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;frozenset&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;fixture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How do refunds work?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;faq&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund-policy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund-policy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How can I cancel?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;billing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;faq&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is next year&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s price?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current-pricing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cases&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mean_recall&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mrr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unanswerable_cases&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fixture deliberately retrieves the refund document at rank two and misses the cancellation document. The averages describe &lt;strong&gt;these two answerable fixture cases only&lt;/strong&gt;. They are not an estimate of production performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Inspect failures before changing the system
&lt;/h2&gt;

&lt;p&gt;For each failed case, check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is the expected document present in the indexed corpus?&lt;/li&gt;
&lt;li&gt;Is the label still correct for the corpus version?&lt;/li&gt;
&lt;li&gt;Was the relevant text split across chunks?&lt;/li&gt;
&lt;li&gt;Did metadata filters exclude it?&lt;/li&gt;
&lt;li&gt;Did the query need terminology the embedding model did not match?&lt;/li&gt;
&lt;li&gt;Did reranking push the evidence outside the context budget?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Change one component at a time. Run the same reviewed cases against the same corpus snapshot so you can attribute differences. Keep a held-out set; repeatedly tuning on the evaluation set can make the score improve without improving the real workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Add answer evaluation as a separate stage
&lt;/h2&gt;

&lt;p&gt;After retrieval, test the generated answer with an explicit rubric:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are its factual claims supported by the supplied passages?&lt;/li&gt;
&lt;li&gt;Do citations point to evidence supporting the associated claim?&lt;/li&gt;
&lt;li&gt;Does it answer the user's actual question?&lt;/li&gt;
&lt;li&gt;Does it ask for clarification or abstain when evidence is insufficient?&lt;/li&gt;
&lt;li&gt;Does it respect access controls and avoid exposing restricted data?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automated checks and model-based judges can help triage results. Their judgments still need validation against human review. Passing a retrieval test does not establish answer correctness or authorization safety.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Keep the evidence reproducible
&lt;/h2&gt;

&lt;p&gt;Record case ID, corpus/index version, retrieval settings, model version, prompt version and the retrieved IDs. Store passages and outputs only where you have permission; redact confidential or personal data before sharing traces.&lt;/p&gt;

&lt;p&gt;For production comparisons, use more representative cases, repeat stochastic runs where appropriate, report the denominator and sampling limitations, and track latency and cost alongside quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The practical lesson:&lt;/strong&gt; locate the failure stage first. A prompt rewrite cannot recover evidence the system never retrieved.&lt;/p&gt;

&lt;p&gt;What is harder in your RAG workflow: creating reliable labels, evaluating citations, or reproducing retrieval failures?&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the author:&lt;/strong&gt; Acadify Solution provides software and AI engineering services. Acadify AI Lab is our AI evaluation practice. This article was generated by an AI agent; its dataset and code are illustrative. Learn more at &lt;a href="https://acadifysolution.com/" rel="noopener noreferrer"&gt;Acadify Solution&lt;/a&gt; or &lt;a href="https://ai.acadifysolution.com/" rel="noopener noreferrer"&gt;Acadify AI Lab&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>testing</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
