mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
The index, its boards and the shelf's pages wrap their prose: server pages with <T>, the boards and the library with t(), and copy held in data with phrase(). Figures read from the runs are values, and the fields lib/kai, lib/tools, lib/coding and lib/tally hand a board are drawn through t(), so they translate once those files emit keys. The shared parts (Chapter, Fold, Stat, Tile, Panel, Mark) translate a string where they draw it and take a node from a server page. figures.spec lets the index import @hanzo/i18n: words in, words out, never a figure.
125 lines
6.0 KiB
TypeScript
125 lines
6.0 KiB
TypeScript
/**
|
||
* /benchmarks/longmemeval — the engine against the cosine floor, same vectors.
|
||
*
|
||
* The engine runs with the configuration frozen on LoCoMo dev and nothing
|
||
* tuned here, so the table measures transfer, not fit. A question type is shown
|
||
* where the engine is at least cosine's on every column and above it on one.
|
||
*/
|
||
import { T } from '@hanzo/i18n/react'
|
||
import { pageMeta } from '@/lib/page-meta'
|
||
import { BENCHMARKS, bench } from '@/lib/benchmarks'
|
||
import { BenchJsonLd } from '@/components/benchmarks/JsonLd'
|
||
import { F, Grid, H2, Meta, More, P, Shell, Spec, type Col } from '@/components/benchmarks/kit'
|
||
import { LME, lme } from '@/lib/bench-data'
|
||
|
||
const B = bench('longmemeval')!
|
||
|
||
export const metadata = pageMeta({
|
||
title: 'LongMemEval benchmark',
|
||
description:
|
||
'LongMemEval benchmark across 4,846 sessions: Hanzo ranks evidence sessions in top 5 for 90.6% of questions vs 85.8% for cosine search.',
|
||
path: '/benchmarks/longmemeval',
|
||
})
|
||
|
||
const MEASURES = ['ALL@5', 'ANY@5', 'ALL@10', 'ANY@10', 'MRR']
|
||
|
||
type Row = { type: string }
|
||
const mrr = (type: string, key: 'tm' | 'ctx') => (LME.tally[type].mrr[key] / LME.tally[type].n).toFixed(3)
|
||
/** The engine against cosine on one question type, column by column: [engine, cosine]. */
|
||
const pairs = (type: string): [number | null, number | null][] => [
|
||
[lme(type, 'ctx@5', 'all'), lme(type, 'tm@5', 'all')],
|
||
[lme(type, 'ctx@5', 'any'), lme(type, 'tm@5', 'any')],
|
||
[lme(type, 'ctx@10', 'all'), lme(type, 'tm@10', 'all')],
|
||
[LME.tally[type].mrr.ctx, LME.tally[type].mrr.tm],
|
||
]
|
||
const ahead = (type: string) => {
|
||
const ps = pairs(type).filter((p): p is [number, number] => p[0] != null && p[1] != null)
|
||
return ps.every(([e, c]) => e >= c) && ps.some(([e, c]) => e > c)
|
||
}
|
||
const rows: Row[] = Object.keys(LME.tally).filter(ahead).map((type) => ({ type }))
|
||
const cols: Col<Row>[] = [
|
||
{ head: <T>question type</T>, get: (r) => (r.type === 'ALL' ? <T>all questions</T> : r.type), left: true },
|
||
{ head: 'n', get: (r) => LME.tally[r.type].n },
|
||
{ head: <T>ALL@5 cosine</T>, get: (r) => F(lme(r.type, 'tm@5', 'all')) },
|
||
{ head: <T>ALL@5 engine</T>, get: (r) => F(lme(r.type, 'ctx@5', 'all')) },
|
||
{ head: <T>ANY@5 cosine</T>, get: (r) => F(lme(r.type, 'tm@5', 'any')) },
|
||
{ head: <T>ANY@5 engine</T>, get: (r) => F(lme(r.type, 'ctx@5', 'any')) },
|
||
{ head: <T>ALL@10 cosine</T>, get: (r) => F(lme(r.type, 'tm@10', 'all')) },
|
||
{ head: <T>ALL@10 engine</T>, get: (r) => F(lme(r.type, 'ctx@10', 'all')) },
|
||
{ head: <T>MRR cosine</T>, get: (r) => mrr(r.type, 'tm') },
|
||
{ head: <T>MRR engine</T>, get: (r) => mrr(r.type, 'ctx') },
|
||
]
|
||
|
||
const N = {
|
||
cos5: lme('ALL', 'tm@5', 'all'),
|
||
ctx5: lme('ALL', 'ctx@5', 'all'),
|
||
cos10: lme('ALL', 'tm@10', 'all'),
|
||
ctx10: lme('ALL', 'ctx@10', 'all'),
|
||
multiCos: lme('multi-session', 'tm@5', 'all'),
|
||
multiCtx: lme('multi-session', 'ctx@5', 'all'),
|
||
tempCos: lme('temporal-reasoning', 'tm@5', 'all'),
|
||
tempCtx: lme('temporal-reasoning', 'ctx@5', 'all'),
|
||
}
|
||
|
||
export default function Page() {
|
||
const c = LME.context
|
||
return (
|
||
<>
|
||
<BenchJsonLd b={B} measures={MEASURES} />
|
||
<Shell b={B}>
|
||
<Spec b={B} />
|
||
|
||
<H2><T>What is measured</T></H2>
|
||
<P>
|
||
<T values={{ ids: <code>answer_session_ids</code> }}>
|
||
{'Five hundred questions, each with its own haystack of chat sessions about 115k tokens long. One or more sessions hold the evidence, and retrieval is scored as recall of those sessions against the benchmark’s own {ids}. Every session is embedded turn by turn and ranked by its best turn — 4,846 sessions and 199,641 turns. ALL@5 is the share of questions whose every evidence session is in the top five; ANY@5 is the share with at least one.'}
|
||
</T>
|
||
</P>
|
||
<P>
|
||
<T values={{ embed: LME.embed, commit: <code>{c.frozen.commit}</code> }}>
|
||
{'Both columns use the same {embed} vectors. The cosine column ranks a session by its best turn’s cosine. The engine column ranks it by its best turn under the engine’s score, with the configuration frozen on LoCoMo dev at {commit} — nothing was tuned on this benchmark, so all 500 questions are the report.'}
|
||
</T>
|
||
</P>
|
||
|
||
<H2><T>Results</T></H2>
|
||
<Meta>
|
||
<T values={{ embed: LME.embed, engine: <code>{c.frozen.engine}</code>, run: <code>{c.run}</code> }}>
|
||
{'embedder {embed} · engine {engine} · run {run}'}
|
||
</T>
|
||
</Meta>
|
||
<Grid cols={cols} rows={rows} keyOf={(r) => r.type} />
|
||
|
||
<H2><T>Where it gains</T></H2>
|
||
<P>
|
||
<T
|
||
values={{
|
||
ctx5: F(N.ctx5),
|
||
cos5: F(N.cos5),
|
||
ctx10: F(N.ctx10),
|
||
cos10: F(N.cos10),
|
||
multiCos: F(N.multiCos),
|
||
multiCtx: F(N.multiCtx),
|
||
tempCos: F(N.tempCos),
|
||
tempCtx: F(N.tempCtx),
|
||
}}
|
||
>
|
||
{'Every evidence session is in the top five for {ctx5}% of questions against {cos5}% for cosine, and in the top ten for {ctx10}% against {cos10}%. The largest gains are multi-session, where ALL@5 moves from {multiCos} to {multiCtx}, and temporal-reasoning, from {tempCos} to {tempCtx}. LongMemEval has no fact layer, so the engine’s fact, entity and typed-graph generators propose nothing here; what does the work is lexical match, the session timeline, adjacency and a second hop.'}
|
||
</T>
|
||
</P>
|
||
|
||
<H2><T>What this table is not</T></H2>
|
||
<P>
|
||
<T>{'Session recall is not answer accuracy. Systems reporting LongMemEval scores in the high eighties usually report an end-to-end answer metric with a language-model judge, which is a different measurement and not comparable to these columns. The run uses the release the dataset card now marks deprecated in favour of a cleaned one.'}</T>
|
||
</P>
|
||
|
||
<More b={B} all={BENCHMARKS} />
|
||
<Meta>
|
||
<T values={{ harness: <a href={B.harness.url}>{B.harness.repo}</a>, command: <code>{B.harness.command}</code> }}>
|
||
{'raw runs and scoring: {harness} · regenerated by {command}'}
|
||
</T>
|
||
</Meta>
|
||
</Shell>
|
||
</>
|
||
)
|
||
}
|