Skip to content

fix(reasoner+eval): bound LLM reasoner requests; fix eval retrieval A/B path - #122

Closed
njfio wants to merge 1 commit into
mainfrom
fix/llm-reasoner-timeout-and-eval-retrieval-ab
Closed

njfio wants to merge 1 commit into
mainfrom
fix/llm-reasoner-timeout-and-eval-retrieval-ab

Conversation

@njfio

@njfio njfio commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary

The LLM write-path reasoner (LlmReasoner::http_chat_call) built its reqwest client with Client::new() (no timeout) and sent requests with no max_tokens. Consequences found while running write-side eval experiments:

  • A slow / hung / drip-streaming endpoint blocked the write path indefinitely (reqwest waits forever with no timeout). This caused hard livelocks during ingest.
  • An un-capped local model could run away generating for tens of seconds per call, making bulk ingest impractical (~hours).

Reasoner fixes (src/memory/reasoning/llm.rs)

  • Per-request timeout via Client::builder().timeout(...) — SYNAPTIC_LLM_TIMEOUT_SECS (default 90). On timeout the call errors and the reasoner fails open to its heuristic fallback, so ingest degrades rather than hangs.
  • max_tokens cap — SYNAPTIC_LLM_MAX_TOKENS (default 512). Extraction/resolution replies are small JSON, so this bounds per-call latency without truncating real output.

Eval harness fixes (tools/eval/src/bin/run_eval.rs)

  • --qtype NAME now drops conversations with no matching questions (previously only questions were filtered, so every conversation was still ingested — on the retrieval path, which spawns one task per conversation, this flooded the reasoner and wedged its HTTP client under concurrency).
  • Retrieval path uses bounded ingest concurrency (RETRIEVAL_CONCURRENCY, default 2) instead of one spawned task per conversation.
  • Retrieval path honors --exclude-superseded (bi-temporal A/B): ingest is unchanged (KG on marks supersessions), only retrieval drops superseded memories, so recall@k of the two arms is directly comparable.

Testing

  • Release build green (synaptic/static-embeddings synaptic/llm-reasoning synaptic-eval/llm-reasoning).
  • Behavior verified empirically: with the timeout+cap, a 2-instance knowledge-update retrieval A/B completes; both arms give R@10=1.0 on the oracle set (recall saturated — the bi-temporal effect is not a recall-level effect on oracle haystacks).

🤖 Generated with Claude Code

…/B path

The LLM write-path reasoner (LlmReasoner::http_chat_call) built its reqwest
client with `Client::new()` (no timeout) and sent requests with no `max_tokens`.
A slow, hung, or runaway endpoint could therefore block the write path
indefinitely, or a local model could generate for tens of seconds per call,
making bulk ingest impractical. Add:
- a per-request timeout (SYNAPTIC_LLM_TIMEOUT_SECS, default 90); on timeout the
  call errors and the reasoner fails open to its heuristic fallback, so ingest
  degrades rather than hangs.
- a max_tokens cap (SYNAPTIC_LLM_MAX_TOKENS, default 512); extraction/resolution
  replies are small JSON, so this bounds per-call latency without truncating.

Eval harness (run_eval):
- `--qtype NAME` now drops conversations with no matching questions (previously
  only questions were filtered, so all conversations were still ingested — on
  the retrieval path that spawned one task per conversation this flooded the
  reasoner and wedged its HTTP client).
- retrieval path: bounded ingest concurrency (RETRIEVAL_CONCURRENCY, default 2)
  instead of one spawned task per conversation, so a real LLM reasoner at ingest
  is not flooded with concurrent requests.
- retrieval path honors `--exclude-superseded` (bi-temporal A/B): ingest is
  unchanged (KG on marks supersessions), only retrieval drops superseded
  memories, so recall@k of the two arms is directly comparable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@njfio

njfio commented Jul 24, 2026

Copy link
Copy Markdown
Owner Author

Superseded by a fresh branch that includes the rustfmt fix (repo ruleset requires a new branch per iteration).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a8c3620e68

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +75 to +78
let cfg = synaptic::MemoryConfig {
enable_knowledge_graph: true,
retrieval_excludes_superseded: exclude_superseded,
..Default::default()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fetch replacements after excluding superseded results

When --exclude-superseded is used and a superseded memory ranks within the initial top 10, runner::run_question still calls search(..., K), while AgentMemory::search applies the supersession filter only after the retrieval pipeline has already limited its results. The excluded arm can therefore return fewer than 10 entries rather than the next eligible entries, artificially lowering its recall/precision and corrupting the intended retrieval A/B comparison whenever a valid evidence turn is just below a filtered stale result. Fetch enough candidates (or filter before applying the retrieval limit) before scoring.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant