NUMERATA

BLOG

Building an agentic research
assistant for a trading desk.

We have written about where private AI pays off on a trading desk in the abstract. This post picks the use case at the top of most desks' lists and builds it out properly: an agent that answers research questions against the firm's own material, with citations, fast enough to be useful before the analyst has moved on.

It is a good first agent for a specific reason. Every other AI workload on a desk is squeezed between two hard walls, a latency budget on one side and a compliance regime on the other. Research only has one of those walls. The question "what did management actually say about margin guidance, and how does that square with what we own" can take forty seconds to answer. Nothing about routing an order can.

That slack is the whole opportunity, and it is also the trap. Because the deadline is soft, the accuracy bar is the only thing holding, and a research agent that is confidently wrong twice in a month will be switched off by the desk regardless of what the pilot metrics said.

The short version

Research is the desk workload where you can afford to spend tokens. An analyst waiting forty seconds is fine. That buys you parallel retrieval and a verification pass, neither of which an execution path could absorb.

Retrieval sets the ceiling on everything downstream. No amount of orchestration recovers from a corpus the agent cannot find its way around, and financial text breaks the default recipe in specific, fixable ways.

Entitlements belong at the tool boundary, not in the prompt. A shared index with a "do not use restricted documents" instruction is an information barrier enforced by politeness.

The output is a record, so the trajectory is the record. Log the question, the caller, every tool call, every result, and the model version, from the first run rather than the first audit.

What an agentic research assistant is, and what it isn't

An AI agent for financial research is a system in which a language model plans a research question, decides which tools to call to gather evidence, reads what comes back, and iterates until it can answer with citations. The word doing the work in that sentence is "iterates". A chatbot answers from its weights. A retrieval pipeline answers from one round of passages that the pipeline chose. An agent chooses the next lookup based on what the last one returned, which is the only way to handle a question whose shape you did not know in advance.

That difference is not free. In a single-shot pipeline a bad retrieval produces one bad answer. In a loop, a wrong turn on step two quietly contaminates steps three through nine, and the agent still delivers something fluent at the end. We wrote up the eight ways that goes wrong separately; the short version is that compounding is the cost you pay for adaptivity, and you buy it back with verification and logging rather than with a better prompt.

Chat over a model Retrieval pipeline Agentic assistant
Who decides what to look up Nobody, it answers from weights The pipeline, once, up front The model, every turn
Retrieval rounds per question Zero One As many as the question needs
"Compare the last three 10-Qs" Fabricates plausibly Answers from whatever one query returned Fetches three, diffs them, cites each
Dominant failure mode Hallucination Missed context, right shape Compounding after one wrong turn
What you have to log Prompt and completion Prompt, retrieved chunks, completion The whole trajectory
Cost per question One call A call plus a search Tens of calls, and worth budgeting

Six jobs where the shape actually fits

Desks tend to arrive with a wish list of twenty things. These six are the ones where an agent's shape genuinely matches the work, which is to say the question needs several lookups, the sources are yours, and a human reads the output before anything happens because of it.

POSITION-AWARE NEWS TRIAGE

Overnight headlines crossed against the current book, so the first question of the morning is which of the forty stories touches something you actually hold, not which forty stories exist.

FILING AND TRANSCRIPT DIFFS

What changed between this quarter's language and last quarter's, on risk factors, guidance, and the phrasing around a specific segment. A multi-document question that a single retrieval round cannot answer.

ISSUER AND COUNTERPARTY DOSSIERS

Assemble what the firm already knows about a name, across internal memos, prior trades, credit notes, and public disclosure, instead of four analysts each rebuilding it from scratch.

STRATEGY ARCHIVE Q&A

Ask the backtest and research archive directly: has anyone tested this before, what did it show, and why was it shelved. The corpus that answers this exists at every firm and is readable at almost none.

P&L AND ATTRIBUTION NARRATIVE

Turn the attribution run into the paragraph a human would have written about it, grounded in the actual numbers from the risk system rather than in the model's arithmetic.

PRE-MEETING PREP

Everything the firm has touching a name, a sector, or a counterparty, gathered and cited ahead of a call, with an explicit list of what it could not find rather than a smooth omission.

The architecture, end to end

Six stages, and the sixth is not optional. Most published agent diagrams stop at "answer". On a desk, the record of how the answer was produced is a deliverable in its own right, so it belongs in the architecture rather than in a logging backlog.

Six-stage architecture for an agentic research assistant, with an append-only trajectory log underneath A question enters stage one, intake and entitlement resolution, which resolves who is asking and what they are allowed to see. Stage two plans the research. Stage three fans the plan out to three parallel workers, each with its own context window: one over the internal corpus of notes, memos and positions; one over market and reference data with as-of timestamps; one over filings and transcripts. Their condensed findings merge into stage four, which synthesizes an answer into citation slots rather than appending a bibliography. Stage five verifies, re-deriving every number from the tool call that produced it and tracing every claim to a source, and loops back to stage four on failure. Stage six either delivers the cited answer or refuses. Beneath all six stages runs an append-only trajectory log recording every prompt, tool call, result, caller, model version and timestamp. ONE QUESTION IN. ONE CITED ANSWER OUT. ONE RECORD OF HOW. 1 INTAKE + ENTITLEMENTS 2 PLAN 3 FAN OUT, ONE CONTEXT EACH INTERNAL CORPUS MEMOS · NOTES · POSITIONS MARKET + REFERENCE PRICES · CURVES · AS-OF FILINGS + TRANSCRIPTS 10-Q · CALLS · DISCLOSURE 4 SYNTHESIZE 5 VERIFY 6 ANSWER OR REFUSE FAILED CHECK GOES BACK, IT DOES NOT SHIP 4 CITATION SLOTS, NOT A BIBLIOGRAPHY  ·  5 RE-DERIVE EVERY NUMBER  ·  6 NO SOURCE, NO CLAIM APPEND-ONLY TRAJECTORY LOG EVERY PROMPT, TOOL CALL, RESULT, CALLER, MODEL VERSION, TIMESTAMP STAGE 6 IS THE ANSWER. THE LOG IS THE RECORD. THE DESK NEEDS BOTH.
Stages one and six are the ones missing from most agent diagrams, and the two a compliance team will ask about first.

Retrieval is most of the accuracy

The temptation with an agent is to spend the effort on orchestration, because that is the part that feels like engineering. In practice the ceiling is set earlier: if the right paragraph is not in the top twenty results, no planner recovers it, and the agent will instead produce a careful synthesis of the wrong twenty.

Financial text breaks the default retrieval recipe in four specific ways, and all four are fixable.

Identifiers are lexical, not semantic. A ticker, a CUSIP, an ISIN, a LEI, or a phrase like "Item 1A" is an exact string, and dense embeddings blur exact strings by design. This is the single strongest argument for hybrid retrieval on a financial corpus: keep a lexical index such as BM25 alongside the vector index, because the query "PRTA 4.75% 2029" is a string match problem wearing a semantic costume.

Chunks need their context carried with them. A paragraph pulled out of a 10-Q loses the fact that it sat under a particular item heading, for a particular segment, in a particular fiscal quarter. Anthropic's contextual retrieval work measured this directly: prepending a short generated description of where each chunk came from, before embedding it, cut the top-20 retrieval failure rate from 5.7% to 3.7% on their evaluation, and adding the same treatment to the lexical index took it to 2.9%. Reranking the candidates brought it to 1.9%.

Top-20 retrieval failure rate falling as contextual chunking and reranking are added Bar chart of the share of relevant documents missing from the top twenty results. A baseline embedding index fails 5.7 percent of the time. Adding contextual embeddings brings it to 3.7 percent. Adding a contextual lexical BM25 index brings it to 2.9 percent. Adding a reranking step brings it to 1.9 percent, a 67 percent reduction against the baseline. Figures are from Anthropic's 2024 contextual retrieval evaluation on their own corpora. SHARE OF RELEVANT DOCS MISSING FROM THE TOP 20 EMBEDDINGS ONLY 5.7% + CONTEXTUAL CHUNKS 3.7% + LEXICAL BM25 2.9% + RERANKING 1.9% ANTHROPIC'S 2024 CONTEXTUAL RETRIEVAL EVAL, ON THEIR CORPORA. A 67% DROP IN MISSES. RE-MEASURE ON YOURS.
The ordering is what transfers, not the numbers. Every one of these steps is cheap next to the orchestration people build instead.

Every retrieved fact needs an as-of stamp. A research answer that silently mixes yesterday's close with a six-month-old broker estimate is worse than no answer, because it looks exactly like a good one. Point-in-time correctness is not a nice-to-have on a desk: the retrieval layer should refuse to hand back a value it cannot date, and the synthesis step should surface the date next to the number.

Fetch late, not early. The instinct is to stuff everything potentially relevant into the context window and let the model sort it out. Long contexts degrade: as the token count climbs, recall from within that context falls, which Anthropic's context engineering guidance describes as an attention budget you are spending rather than a container you are filling. The better pattern is to hold lightweight references, document identifiers, queries, section pointers, and pull the full text only when the agent has decided it needs that specific thing.

Tools, and why yours are the hard part

The model has read every public API reference ever published and none of yours. Whatever it knows about calling a risk system, it is guessing from the shape of the name. Three rules cover most of the difficulty.

Keep the set small and unambiguous. If an engineer cannot say with certainty which of two tools a given question should use, the model will not do better. Overlapping endpoints with similar names are the most common cause of an agent that works in the demo and thrashes in production.

Never let the model do the arithmetic. Any figure in the output should have been computed by a tool and passed through verbatim. Give the agent a query tool and a calculation tool, then treat any number that does not trace back to one of them as a defect.

Do not let the model name the corpus. This one is easy to get wrong, because it is convenient to expose a corpus or scope parameter and let the planner choose. That hands the enforcement of an information barrier to a token predictor. Resolve the caller's entitlements once at intake and apply them inside the tool, where the model cannot reach them.

ONE TOOL DEFINITION, WITH THE TWO NON-NEGOTIABLES

{
  "name": "filings.search",
  "description": "Search filings and transcripts THE CALLER IS
                  ENTITLED TO READ. Returns spans with document
                  id, section, and as-of date.",
  "input_schema": {
    "type": "object",
    "properties": {
      "query":     {"type": "string"},
      "issuer":    {"type": "string"},   // LEI or ticker
      "doc_types": {"enum": ["10-K", "10-Q", "8-K", "TRANSCRIPT"]},
      "as_of":     {"type": "string", "format": "date"},
      "top_k":     {"type": "integer", "default": 20}
    },
    "required": ["query", "as_of"]       // no date, no call
  }
}
// NOTE WHAT IS ABSENT: there is no "corpus" or "barrier"
// parameter. The caller's entitlements are resolved server
// side from their identity. The model cannot ask for a
// corpus it is not allowed to see, because it cannot name one.

One agent, or a team of them

Fanning work out to parallel subagents is the single biggest quality lever available, and also the easiest place to spend money on nothing. The published evidence is fairly clear about which side of that line a research task falls on. Anthropic reported that an orchestrator-worker system, with a Claude Opus 4 lead directing Claude Sonnet 4 subagents, outperformed single-agent Claude Opus 4 by 90.2% on their internal research evaluations. They also reported that token usage alone explained 80% of the performance variance on a browsing benchmark, and that multi-agent systems consume roughly fifteen times the tokens of a chat interaction.

Read those two findings together, because the second one is the price of the first. The gain comes from giving each subagent its own clean context window rather than from any cleverness in the coordination, which is exactly why the same write-up notes that domains where every agent needs the same context, or where agents depend heavily on each other, are a poor fit for the pattern today.

That gives a usable rule for a desk. Fan out across independent evidence. Stay sequential across dependent reasoning. Three issuers, five filings, and two data vendors are independent: run them in parallel, let each worker return a condensed finding, and keep the raw search context out of the lead agent's window entirely. A chained calculation where step three needs step two's output is not independent, and splitting it across agents buys you coordination bugs instead of throughput.

The fifteen-times figure also lands differently depending on where you run. On metered per-token billing it is a budget conversation every month. On your own GPUs it is a utilization question, and a research assistant's load is bursty and daytime-shaped, which is close to the ideal profile for hardware you have already paid for. We worked through that arithmetic in self-hosted versus API cost.

Grounding, citations, and the refusal path

An answer with a bibliography at the bottom is not a cited answer. What the desk needs is a pointer per claim: document identifier, section, as-of date, attached to the specific sentence it supports. That is a structural choice in the synthesis step, not a formatting preference, because it is the only version you can check automatically.

Once claims carry pointers, verification becomes mechanical. A second pass re-opens each cited span and asks whether it actually contains the claim, and diffs every number in the draft against the tool result it came from. This costs another model call per answer and catches the failure that destroys trust fastest, which is a fluent paragraph with a citation that does not say what the paragraph says.

Refusal has to be a first-class output. "The corpus does not contain this, here is the closest thing it does contain" is a correct answer, and an agent that never produces it is not careful, it is guessing. This has to be scored explicitly: salt the evaluation set with questions your corpus genuinely cannot answer, because an agent tuned on answerable questions only will answer everything. The related trap is treating the model's stated confidence as a signal. It is poorly calibrated. Disagreement between two independent retrieval paths is a real signal, and it is cheap to compute.

Compliance is an architecture decision

This is the part that gets deferred and should not be, because almost every item on the list is cheap on day one and expensive to retrofit. Which of these actually bind you depends on your entity type and jurisdiction, and a registered broker-dealer and a buy-side fund are not in the same regime, so have compliance draw the map before the build rather than after the pilot.

The obligation What it means for the build
Recordkeeping
SEC RULE 17A-4
Preserve the trajectory, not just the answer. Since the amendments effective January 3, 2023, a broker-dealer can use either write-once-read-many storage or an audit-trail system that time-stamps every creation, modification, and deletion and can recreate an original record. An append-only log fits the second shape, if it exists from run one.
Misuse of MNPI
EXCHANGE ACT 15(G) · ADVISERS ACT 204A
Filter at retrieval, by the caller's entitlements, inside the tool. One index shared across information barriers is a hole in the wall that no prompt closes.
Research and communications
FINRA 2241 · FINRA 2210
Output that leaves the firm is a communication and inherits the review, approval, and disclosure obligations of one. Third-party research a member distributes must be reviewed and approved by a registered principal or supervisory analyst. Make the draft and approved states structurally different, not a checkbox.
Supervision
FINRA 3110
A named person owns what the agent produces. Decide who before the pilot, because the answer shapes the approval path you build.
Vendor data licenses Terminal entitlements are typically per named user rather than per service account, and feed agreements commonly restrict derived works and redistribution. Read the specific agreement before an agent reads the data.
Where inference runs The prompt plus retrieved context is the most sensitive text the firm produces all day. It names positions, counterparties, and intent. It should not leave the trust boundary to be answered.

The MNPI row is the one worth drawing, because the wrong version of it is the version most pilots ship.

Enforcing an information barrier in the prompt versus at the tool boundary Two panels. On the left, the wrong design: a public-side analyst's question goes to a single shared vector index containing public, desk, and deal room material, and a prompt instruction tells the model to ignore restricted documents, which means the barrier depends on the model complying. On the right, the correct design: the same question first passes through an entitlement resolver that maps the caller to allowed scopes, so the retrieval layer searches only the public and desk corpora and the deal room corpus is never queried at all. WRONG · ENFORCED IN THE PROMPT RIGHT · ENFORCED IN THE TOOL PUBLIC-SIDE ANALYST ASKS ONE SHARED INDEX PUBLIC + DESK + DEAL ROOM PROMPT: "IGNORE RESTRICTED DOCS" THE BARRIER IS NOW A REQUEST. THE RESTRICTED TEXT WAS ALREADY RETRIEVED BEFORE ANYONE OBJECTED. PUBLIC-SIDE ANALYST ASKS ENTITLEMENT RESOLVER IDENTITY → ALLOWED SCOPES PUBLIC DESK DEAL ROOM NOT QUERIED THE INDEX CANNOT RETURN WHAT THE CALLER MAY NOT SEE. NOTHING TO COMPLY WITH, SO NOTHING TO FAIL TO COMPLY WITH.
Left is one prompt injection away from an incident. Right cannot fail that way, because the restricted text is never fetched.

The recordkeeping row has a pleasant property: the log you need for an audit is the same log you need to debug a bad answer, and the same log you would later need as training data if you ever fine-tune on this work. Store the whole step, keep results by reference with a digest so the log stays queryable and the payload stays immutable, and you have all three for the price of one.

ONE STEP OF ONE TRAJECTORY, AS A RECORD

{
  "trajectory_id": "tr_01JQ8F3M2K",
  "step": 7,
  "ts": "2026-09-09T13:41:22.118Z",
  "caller": {
    "id": "a.okafor", "desk": "CREDIT-EU",
    "barrier": "PUBLIC",
    "entitlements": ["FILINGS", "DESK-NOTES", "PRICES"]
  },
  "actor": {
    "agent": "worker.filings",
    "model": "internal/research-7b-v3",
    "prompt_version": "research-v14"
  },
  "tool_call": {
    "name": "filings.search",
    "args": {"query": "margin guidance change",
             "issuer": "US1234567890", "as_of": "2026-09-08"}
  },
  "result_ref": "blob://runs/tr_01JQ8F3M2K/step-07.json",
  "result_digest": "sha256:9f2c1ab4...",
  "tokens": {"in": 4210, "out": 96}
}

What to measure before you trust it

A demo proves the thing can run. None of these numbers can be lifted from a vendor deck or a leaderboard, for reasons we went through in why public benchmarks don't transfer: the score belongs to the whole system, and your corpus, tools, and graders are all different. Build the small version of this before the agent, not after.

What you measure How The failure it catches
Answer accuracy A frozen set of 50 real desk questions with analyst-written answers, graded against a rubric Silent drift after a model, prompt, or index change
Citation validity Re-open every cited span programmatically and check the claim is in it Fluent prose with decorative citations
Numeric re-derivation Diff every figure in the output against the tool result it came from The model doing arithmetic in tokens
Appropriate refusal Salt the set with questions the corpus genuinely cannot answer An agent that will answer anything
Entitlement violations Adversarial questions asked as each caller class. The target is zero, not low A barrier that lives in the prompt
Staleness Share of dated facts whose as-of falls outside the question's window Yesterday's close beside last year's estimate
Tokens per accepted answer Total tokens divided by answers the desk actually used The pilot that is accurate and unaffordable
Time to answer, p50 and p95 Wall clock from question to delivery The agent that is right after the meeting ended

A build order that survives contact

Roughly a month of work for a small team, in an order chosen so that each step produces something you can measure rather than something you have to believe.

  1. Write the questions first. Fifty real ones, from the actual desk, with the answers an analyst would give. This is your evaluation set, and it is the single most useful artifact in the project.
  2. Build retrieval only, with no agent. Index the corpus, add the lexical half, and measure how often the passage that answers each of the fifty appears in the top twenty. Fix that number before anything else, because it caps everything downstream.
  3. Add one loop and one tool. A single agent, sequential, with the trajectory log wired in from the first run. Resist the parallelism until the single-threaded version is honest.
  4. Add the verifier before the parallelism. Citation checks and numeric re-derivation. This is the step teams skip, and it is the one that decides whether the desk keeps using the thing.
  5. Then fan out. Parallel workers over independent evidence, each with its own context window, each returning a condensed finding rather than raw search results.
  6. Only then consider training. By now you have a corpus of real trajectories and a checker that says pass or fail, which is to say you have both halves of a fine-tuning setup already. That is the point at which tool-use fine-tuning and agentic fine-tuning stop being speculative and start being the obvious next move.

Where this fits at Numerata

Every stage of this runs inside your own environment, which is not a philosophical preference on a desk. The prompt for a research question names the position, the counterparty, and the thing you are about to do about it, and that text is the firm's edge in plain language. Fine-tune on your own trajectories and research archive with P95, run the training and the bursty daytime inference load on Lupine compute that scales to zero overnight, and serve the assistant through NinetyFive inside your own trust boundary. Private cloud, on-premises, or fully air-gapped, and the trajectory log stays somewhere your own auditors can reach.

Related reading: the six places private AI pays off in trading, the same breakdown for finance more broadly, and the two posts this one leans on hardest, evaluating agents and agent failure modes.

Numerata runs inside your own environment: private cloud, on-prem, or fully air-gapped.  ·  Back to blog