Home Master Prep STAR Stories Evals & Guardrails Eval Deep Dive Guardrails Deep Dive Core Concepts Intent Recognition 中文

Concepts first, then the code

Memory, Context Management, Orchestration

Three terms that get used interchangeably and are not interchangeable. This page builds each one from the problem it solves, then shows exactly where it lives in the Mines Financial codebase — file by file, number by number.

Start here · the two facts that create all three problems

Everything on this page follows from two properties of a language model. Neither is a bug, and neither can be fixed by choosing a better model.

One: the model is stateless. When your program calls a model, it sends some text and gets some text back. The model keeps nothing. The next call knows nothing about the previous one. When ChatGPT appears to remember your earlier message, that is not the model remembering — the application re-sent the whole conversation, invisibly, as part of the new request. Every bit of apparent memory is something the surrounding program built.

Two: the model has a fixed input limit. There is a maximum amount of text it can read in one call, called the context window. And because the model keeps nothing, the entire content you want it to consider must fit inside that limit on every call, and you pay for all of it every time.

Put those together and three separate engineering problems fall out, which is exactly the three topics of this page:

Memory systems

The model keeps nothing, so what do we store outside it, and where? A storage and lifetime problem.

Context management

The window is finite and costly, so of everything we have stored, what goes into this one call? A selection and assembly problem.

Orchestration

One call cannot do multi-step work reliably, so what sequence of calls runs, and who decides? A control-flow problem.

How to read this page Main text is the explanation — it is meant to be read straight through. Anything with a small question mark opens a definition on click, and side digressions are folded behind + buttons so the main thread stays continuous.

Telling the three apart · the distinction most explanations skip

These three overlap in practice, which is why people blur them. The cleanest way to keep them separate is to ask what each one owns.

 OwnsTime scaleFails by
Memory What we keep, and for how long Across calls, sessions, weeks Remembering something wrong, or forever
Context management What we send in one specific call One call Sending too much, too little, or in the wrong order
Orchestration Which calls happen, in what order One request, start to finish Wrong branch, infinite loop, unobservable failure

A concrete example using all three at once. A user asks "what about their dividends?".

  • Memory supplies the fact that the previous question was about BHP and FY2024. That fact was stored earlier and is being read now.
  • Context management decides that the routing model gets only the enriched question and its instructions — not the conversation history, not the retrieved documents, because that model's only job is to classify.
  • Orchestration decides that because this question needs report data, the retrieval subgraph runs before the answering step, and that the answering step is skipped entirely if a cached answer already matched.
The sentence to hold on to Memory is what you have. Context is what you send. Orchestration is what runs. A retrieved document that is stored but not sent is memory without context. A model call that receives perfect context but happens at the wrong point in the flow is a context success and an orchestration failure.

1 · Memory systems

Storage outside the model, with an explicit lifetime.

The concept · starting from the dumbest version

The naive solution to statelessness is obvious and it is where nearly every project starts: keep the entire conversation in a list, and send the whole list every time. That genuinely works, for a while. It is the right first version.

It breaks in three stages as the conversation grows.

  • Cost, first. If turn twenty re-sends all nineteen previous turns, you are paying for the same text twenty times. Cost grows with the square of conversation length, not linearly.
  • Quality, second — and this surprises people. Models attend most reliably to the start and end of their input. A crucial figure buried in the middle of a very long input is measurably less likely to be used than the same figure in a short one. So a longer context can produce a worse answer.
  • Hard failure, last. Eventually the input exceeds the window and the call errors outright.

So a memory system is what you build once "send everything" stops working. And the central insight is that "memory" is not one thing. It is four different requirements that share a name, with different storage, different lifetimes, and different consequences when they go wrong. Designing them as one component is the most common mistake.

The four kinds · and what each one is for

1
Working state — memory within a single request

While one request is being processed, the steps need to pass things to each other: the rewritten query, the retrieved documents, the draft answer, the verdicts. This is memory in the same sense a local variable is memory. It exists for one request and then it should be gone.

It gets confused with the other kinds constantly, and the confusion goes both ways: people store long-lived facts here and lose them when the request ends, or push per-request scratch data into a database and never clean it up.

In this project A single MainState typed dictionary in state.py — around twenty fields including query, aggregated_context, needs_retrieval, guardrails_passed, confidence. The retrieval subgraph has its own separate RetrievalState, so its internal working fields never leak into the parent.
2
Session persistence — surviving a restart

A conversation has to outlive the process handling it. The server restarts, a deployment happens, the user comes back tomorrow — the thread must still be there. So working state has to be written somewhere durable.

The pattern that solves this is checkpointing. It buys something beyond durability, which is often the more valuable half: because every intermediate state was written down, you can reconstruct exactly what the system saw at each step, long after the fact.

In this project graph.py wires a PostgreSQL checkpointer over a connection pool (max 10, autocommit on). The full state is written after every node, keyed by thread id. This is also what makes the clarification pause possible — see orchestration below.
3
Long-term memory — facts that outlive the session

Things that should be known next week: user preferences, entities under discussion, conclusions previously reached. The agent literature usually splits this three ways — episodic, semantic and procedural — but the engineering question is simpler: what is the key, and what invalidates the entry?

This is the kind with the worst failure mode, because a wrong long-term memory is stated with total confidence and never re-examined.

In this project Only partially built, and worth being precise about. There is no user profile and no cross-session fact store. What exists is entity carry-over within a conversation — company tickers and financial years scanned from the last 6 messages in nodes/memory.py — plus the answer cache below, which is long-lived but keyed by question rather than by user.
4
Cache — not repeating work already done

Strictly this is an optimisation rather than memory, but it is stored, it is read back later, and it can be wrong — so it behaves like memory and needs the same discipline.

An ordinary cache matches exact text, which is useless for questions: "BHP revenue FY2024" and "How much did BHP earn in FY2024?" are different strings asking one thing. A semantic cache compares meaning instead.

In this project memory/semantic.py holds a separate vector collection called conclusions, distinct from the reports collection of source documents — so the system can never cite its own past answer as if it were an annual report. Two tiers: at or above 0.95 similarity return the stored answer and skip retrieval; between 0.80 and 0.95 run the full pipeline but pass the old answer in as reference material.
Why the write path matters more than the read path — cache poisoning

A cache of retrieved documents can only be stale. A cache of the system's own answers can be wrong — and once written, it is served confidently to everyone who asks a similar question, faster than a correct answer would be, because it skips the work that would have caught the error.

There is no error and nothing in the logs. The system looks like it is performing unusually well.

So in this project the write is gated: an answer is stored only if the quality grader passed it and the groundedness check did not fail. A low-confidence answer still reaches the user, with its warning, and is never written to memory. The write also happens before the warning text is appended, so what gets cached is the clean answer rather than a stale caveat about a verification run that has nothing to do with the next user's question.

Stated as a rule: the read path is optimistic, the write path is pessimistic. A cache miss costs seconds. A poisoned cache costs a wrong figure about a listed company, repeatedly, until somebody notices.

In this project · four layers, in a fixed order

Every request passes through all four before any retrieval happens, and the order is load-bearing rather than incidental.

OrderLayerWhereKey numbers
always on Durable session state — full state written after every step, keyed by thread graph.py · PostgreSQL pool max 10
1st History compression — summarise older messages, keep recent ones verbatim nodes/compress_context.py trigger at 10 msgs, keep 4
2nd Entity carry-over — fill a missing company or year from recent messages nodes/memory.py scan 6 msgs
3rd Semantic answer cache — two-tier lookup against past questions memory/semantic.py 0.95 hit · 0.80 seed

Why that order

Compress first so the entity scan reads a clean, bounded history rather than fifty messages. Enrich second so the cache lookup uses the completed question — looking up "what about their dividends?" would match nothing useful, whereas "dividends [BHP, FY2024]" might. Cache last so that a hit can skip everything downstream, which is the entire point of having it.

One detail worth understanding properly

The cache stores the question as the searchable text, and keeps the answer, the companies, the year and the source list alongside it as metadata. That sounds backwards — the answer is the valuable part — but at lookup time all you have is a question, so storing the answer as the search key would mean comparing a question against an answer.

Those are different shapes of text. A question is short and interrogative; an answer is long, full of figures and qualifications. Their embeddings sit in different regions even when they belong together, so similarity scores become noisy and any threshold you pick becomes meaningless. Storing the question makes it a question-to-question comparison, which is the comparison you actually want.

What this memory system does not do No expiry and no invalidation — if the reports are re-ingested, cached answers derived from the old version stay live. No per-user namespace, so entries are globally readable; harmless here because there is no customer data, but a blocker in any real financial product. And both thresholds were chosen by judgement rather than fitted on labelled question pairs, so there is no measured false-hit rate.

2 · Context management

Deciding what goes into one specific model call. Often called context engineering.

The concept · the part people assume is trivial

Suppose memory is solved: you have the conversation history, a set of retrieved documents, a cached answer, and a summary of earlier turns. Now you have to make one model call. What do you put in it?

The naive answer is all of it, and it is naive for a reason worth stating precisely. It is not just that you might exceed the limit. It is that irrelevant content actively degrades the answer. Give a model eight documents where two are relevant, and it has to work out which two. Give it the same two alone, and it does not. Extra context is not free even when it fits.

So context management is assembly, not concatenation. And the thing that makes it a real discipline is that it is a decision per call, not per application — different steps in the same pipeline want completely different context.

Context as concatenation

Build one context blob and pass it to every step. Simple, and every step pays for text it does not need while the important part gets diluted. A routing decision does not improve for having seen eight annual-report chunks.

Context as assembly

Each call receives a purpose-built input: only the fields that step needs, at the fidelity that step needs, in a deliberate order, with untrusted content clearly fenced. More code, and every call gets sharper.

How this differs from retrieval — they are neighbours, not the same job

Retrieval finds candidate documents. Context management decides which candidates make it into the call, in what form, and where in the input they sit.

The distinction becomes obvious at the point of failure. If the correct document was never found, that is a retrieval problem — no amount of clever assembly helps. If the correct document was found, ranked fourth, and then truncated away or buried in the middle of a long input where the model under-weighted it, retrieval did its job and context assembly lost the answer.

They also need separate measurement, which is why this project measures retrieval on its own — did a document containing the known figure arrive, and at what rank — rather than inferring retrieval quality from the final answer.

The five jobs · what context management actually consists of

1
Selection — what is relevant to this step

The narrowest useful input is usually right. A classifier needs the question and its rules. A verifier needs the draft and the evidence. Giving either one the other's context makes it worse, not more informed.

2
Ordering — position changes behaviour

Attention is not uniform across a long input; the beginning and end are used more reliably than the middle. So ordering is a real decision: instructions and the current question at the edges, bulk evidence in between.

3
Compression — deliberately losing detail

Summarising ten messages into two sentences is lossy on purpose. Which means the summarising instruction must name what to preserve, or the model decides for you and drops the part you needed.

4
Isolation — fencing content by trust level

Your instructions and text extracted from a third-party PDF end up in the same input. The model has no built-in notion of which is authoritative. Labelling and fencing the untrusted part is what stops a document being read as an instruction — the risk called prompt injection.

5
Budgeting — an explicit priority order

When space runs short, something must go. Deciding that order in advance — and writing it down — is the difference between a designed system and one where whatever the code appended last happens to win.

In this project · nine calls, nine different contexts

This is the part of the project I would point at if someone asked what context engineering looks like in practice. A single request can involve up to nine model calls, and no two receive the same context. Each one gets the narrowest input that lets it do its job.

Three cross-cutting decisions first, because they explain the table below:

  • Two model clients, deliberately. utils/llm.py is capped at 1,000 output tokens and used for routing, grading and rewriting. utils/llm_large.py allows 5,000 and is used only for synthesis and the final answer. A routing decision cannot accidentally be budgeted like a synthesis call. Both run at temperature 0.
  • Different fidelity for different jobs. Relevance grading sees each document truncated to 1,200 characters — enough to judge topic, cheap across twenty candidates. Synthesis sees full content, because a figure could be anywhere in a table. Same documents, two fidelities, chosen per purpose.
  • Structure is added, not hoped for. Retrieved documents are converted to plain dictionaries with company, year, page and source type promoted to top-level keys, so every step formats headers like [3] FMG FY2024, p.39 [table] consistently — and the model can attribute a claim to a company without inferring it.

Every model call, and what it is given

CallReceivesDeliberately does not receiveWhy
compress_context Older messages, formatted by role, plus an instruction naming what to keep: companies, metrics, fiscal years, conclusions Documents, retrieval state Compression is lossy, so the instruction has to name the survivors
retrieve_decision Routing rules, seven worked examples, and the enriched question alone The conversation history; any documents It is a classifier. History would add cost and drift without improving the four booleans it returns
query_rewrite Rewriting rules, five examples, the question History; documents Turning a question into search keywords needs the question, not the past
grade_docs The rewritten query plus every candidate, each truncated to 1,200 chars and labelled with index, company, year, page and a table marker Full document text; the draft answer Judging relevance needs breadth across candidates, not depth in each
synthesize Graded documents at full length with numbered company headers, the question, and any cached answer explicitly labelled "for reference only" Rejected candidates; news; conversation history Drafting needs complete evidence, and the label stops reference material being treated as a source
grade_answer Question, graded documents with an injected unit annotation for tables, and the draft History; news; rejected candidates Verification must compare the draft against exactly the evidence it was written from — no more, no less
aggregate → calc? Question and the merged context Raw documents Whether arithmetic is needed depends on the numbers actually retrieved, not on how the question was worded
calculator agent Question, merged context, and its own growing tool-call transcript Raw documents; history It works only on numbers already present in the context, by instruction
answer Section-tagged merged context, plus a system prompt assembled at runtime: base rules, then a citation block containing the numbered source list, then a chart block — each included only if it applies Raw documents; the rejected candidates The instruction set matches what is actually available, so the model is never told to cite sources that do not exist

Isolation, concretely

Content of different trust levels is fenced with visible markers rather than merged. The merged context uses bracket headers — 【Annual Report Data】, 【Recent News】, 【Calculation Result】 — and the final prompt instructs the model to prefer report data and to note the discrepancy if the sections disagree. Cached answers carry "for reference only". Each document carries its own company header so a figure cannot drift between companies.

Where this is still weak Fencing by convention is not enforcement. Nothing scans ingested PDF text for content that reads as an instruction, so retrieved text is trusted input sitting next to my own instructions. Low risk for published annual reports; unacceptable for any document a user can upload. And there is no token accounting anywhere — the priority order described above is implicit in the code rather than an explicit budget that drops the lowest-priority material when space runs short.

3 · Orchestration

Deciding which steps run, in what order, and who makes that decision.

The concept · two naive versions, failing in opposite directions

A question like "compare BHP and Rio on FY2024 revenue growth" cannot be one model call. It needs: work out what is being asked, turn it into searches, search for two companies, judge what came back, draft, verify, compute a growth rate, format with citations. Multi-step work needs something coordinating the steps — that is orchestration.

There are two obvious ways to do it, and they fail in opposite directions.

Naive version A — one giant prompt

Put all the instructions in one call and hope. No branching, so a vague question and a precise one take the same path. No retry, because there is no step to retry. And when the answer is wrong you cannot tell which part of the reasoning failed — there are no parts.

Naive version B — a fully autonomous loop

Give the model tools and let it decide everything, repeatedly, until it stops. Maximum flexibility, and: unbounded cost, a different path every run so nothing is reproducible, no way to unit-test a decision, and an execution trace that is different every time you look at an incident.

Real systems sit between these, and the choice is per component, not per application. That is the single most useful idea in this section. Steps whose order you know go in a fixed graph; steps whose order genuinely depends on intermediate results get a bounded loop.

The spectrum · three levels of who decides

1
Fixed chain — the code decides everything

Step A, then B, then C, always. Completely predictable, trivial to test, and incapable of adapting. Correct whenever you actually do know the order.

2
Graph with conditional edges — the code decides, using model output

Steps are nodes; the connections between them are chosen at runtime by plain functions reading state. A model may have produced the value being read, but the branch is taken by ordinary code.

This is the sweet spot for most production work, and the reason is worth being explicit about: the model contributes a judgement, the code retains control of the flow. You get adaptivity, and the routing stays readable, testable and identical every time for the same state.

3
Agent loop — the model decides, within limits

The model repeatedly chooses a tool, sees the result, and chooses again until done — commonly a ReAct loop. Right when the number and order of steps genuinely cannot be known in advance. Always needs an iteration bound.

The building blocks · vocabulary you need to read the code

  • State. One typed object every node reads from and writes to. Nodes return only the fields they changed, and the framework merges them in — so a node cannot accidentally clobber a field it never touched.
  • Node. One step. A plain function: state in, partial update out.
  • Edge and conditional edge. A fixed connection, or a function that reads state and returns which node comes next.
  • Reducer. The rule for combining writes to the same field from parallel branches. The default is overwrite — which silently loses data when branches run concurrently, so lists usually need to append and dictionaries to merge.
  • Fan-out and fan-in. Split one request into parallel branches, then merge. The same shape as map-reduce.
  • Subgraph. A graph used as a single node inside a bigger one, with its own private state — so its internals stay out of the parent.
  • Checkpoint and interrupt. Persisting state after each step, which is what makes it possible to stop mid-run, wait for a human, and resume in place.
  • Supervisor pattern. A top-level graph that dispatches to specialist sub-agents and merges their results, rather than one agent doing everything.

In this project · all three levels at once

The architecture is a supervisor graph of 11 nodes, containing a retrieval subgraph of 5 nodes, containing a ReAct agent for arithmetic. So all three points on the spectrum appear in one system, each chosen for a different reason.

LevelWhereWhy there
Fixed chain compress_context → memory; and every path into guardrails before answer The order is genuinely known and must not vary. Putting the guard on the boundary means a future branch inherits it automatically
Conditional graph Four routing functions in graph.py — after memory, after the routing decision, after aggregation, after guardrails The path depends on the question, but the decision must be reproducible and testable. Every one is plain Python reading state
Agent loop agents/calculator_agent.py How many arithmetic steps a question needs — normalise units, then subtract, then divide — genuinely cannot be known in advance

The separation that makes it work

The routing model does not choose the next node. It returns four booleans — is_out_of_scope, needs_retrieval, needs_news, needs_clarification — into state. A plain function then reads those and decides the branch.

That separation is the whole design. The model contributes the judgement it is good at, which is understanding what a question is asking. The code keeps control of the flow, which means the routing is a function you can unit-test with a dictionary and no network — and there are tests in tests/test_graph_routing.py doing exactly that.

Parallel fan-out, and why it needs explicit merge rules

A comparison question is decomposed into one search per company, and the graph dispatches one retrieval branch per company to run concurrently. Two things then have to be stated explicitly, because the defaults are wrong for concurrency:

  • Retrieved documents accumulate by list concatenation rather than overwrite, so five branches produce a combined pool instead of only the last one's results.
  • The per-company found flags merge as dictionaries via a small custom reducer, so branches write their own key without erasing the others. With the default overwrite, the last branch to finish would delete every other company's status — a bug that would appear only under concurrency and only sometimes.

On retry, the fan-out naturally targets only the still-missing companies, because the rewrite step has already narrowed the list of queries.

Bounded loops

The retrieval subgraph can loop: if graded documents are unusable, or the draft fails, or two or more claims came back unverified, it goes back to query rewriting. Three constraints keep that safe. A counter in state caps it at 2 attempts. Every retry must change its input — the failed claim labels become additional search terms — because a retry with identical input only spends money. And exhausting the retries is a defined outcome routing to the fallback response, not an error.

Two smaller decisions that are easy to miss

  • The subgraph declares an output schema, so only the finished retrieval_result crosses back into the parent state. Its dozen internal working fields — retry counts, ungraded candidates, per-company queries — stay private. That is state isolation as a design choice rather than a naming convention.
  • The clarification pause is durable. The clarify node interrupts execution and returns the question to the caller; the API resumes with the user's reply against the same thread, and the node merges the reply into the original question before routing again. It works only because state was already checkpointed after every step — the pause is simply the absence of a next step. Without persistence, "ask the user something" is a dead end whenever the process restarts.
Where this is still weak Routing rests on a single model call with no deterministic backstop, so a classification error is unguarded — it fails safe by defaulting to retrieval, but nothing catches the mistake. There is no per-request cost or step ceiling, so an unusually expensive path is possible without an alarm. And node-level failures are swallowed individually rather than being reported through one place, which means a consistently failing step degrades quality silently.

One request, end to end

The same question traced through all eleven steps, marking which of the three topics is doing the work at each point. This is the section to re-read if the three still feel blurred.

The question Turn one: "What was BHP's FY2024 revenue?" — answered normally. Turn two: "What about their dividends?" — traced below.
StepWhat happensDoing the work
0 · load Thread state is read back from PostgreSQL, including turn one's messages Memory — session persistence
1 · compress_context Four messages, under the threshold of ten, so nothing is compressed Context — compression, declining to act
2 · memory No company or year in the question. Scanning back six messages finds BHP and FY2024, so the query becomes What about their dividends? [BHP, FY2024] Memory — entity carry-over
3 · memory (cache) The enriched query is embedded and compared with past questions. Best match scores 0.71 — below both tiers, so no hit and no seed Memory — semantic cache
4 · route A plain function reads cache_hit. False, so continue to the routing decision rather than jumping to the answer Orchestration — conditional edge
5 · retrieve_decision The model receives the rules, seven examples, and the enriched question only. Returns needs_retrieval true, everything else false Context — selection · Orchestration — the model judges, not routes
6 · route Code reads the four booleans and dispatches one parallel branch to the retrieval subgraph Orchestration — fan-out
7 · query_rewrite Becomes BHP FY2024 dividends, companies ["BHP"], and the per-company found flag is initialised to false Context — reshaping input for retrieval
8 · retrieve_company Keyword and vector search each return 20 candidates from BHP's own indexes; fused, then reranked by a model that reads the text, down to 8 Retrieval — with orchestration owning the per-company branch
9 · grade_docs Each candidate truncated to 1,200 characters for judging. Irrelevant ones dropped; the found flag is corrected to true because graded documents exist Context — fidelity choice · Guardrail — relevance filter
10 · synthesize Surviving documents at full length with numbered company headers. A draft is written with [N] markers Context — assembly at full fidelity
11 · grade_answer Draft plus the same documents, now with unit annotations injected for tables. Zero unsupported claims, so grounded = yes and confidence = high Context — injected annotation · Guardrail — groundedness
12 · aggregate Draft wrapped under 【Annual Report Data】. A narrow model call decides no arithmetic is needed Context — fencing · Orchestration — branch data
13 · guardrails → answer Deterministic length check passes. The final prompt is assembled with the citation block and its numbered source list; uncited sources are then removed and markers renumbered Orchestration — boundary gate · Context — runtime prompt assembly
14 · save Grade passed and groundedness is not "no", so the clean answer is written to the cache — before the confidence note would have been appended. State is checkpointed Memory — gated write, decided by the evaluator
What the trace shows The three are interleaved at every step rather than layered. Memory supplies BHP and FY2024 at step 2, which changes what context is assembled at step 5, which changes which branch orchestration takes at step 6 — and at step 14 the quality check decides what memory is allowed to keep. Get the boundaries wrong and the failures cross over: a context bug looks like a memory bug, and an orchestration bug looks like a bad model.

Glossary

Every term used above, in plain words.

Unfold all definitions — 26 terms
Stateless
The model keeps nothing between calls. Every appearance of memory is the surrounding program re-sending earlier text.
Token
The unit models read and are billed in — very roughly three-quarters of a word. Limits and prices are expressed in tokens, not characters.
Context window
The maximum tokens a model can read in one call. A hard ceiling, and everything inside it is re-charged on every call.
Prompt
The text sent to the model. Usually split into a system prompt (instructions and rules) and a user message (the actual input).
Working state
Data passed between steps of a single request. Memory in the sense a local variable is memory — it should not outlive the request.
Checkpointing
Writing the full state to durable storage after every step, so a run survives a restart and can be replayed exactly afterwards.
Thread
One conversation, identified by an id. All of its checkpoints share that id.
Episodic / semantic / procedural memory
Past events, general facts, and learned procedures. A useful taxonomy borrowed from cognitive science; most systems implement only one or two.
Embedding
A list of numbers representing the meaning of a piece of text. Similar meaning gives numerically nearby lists, which is what makes meaning-based search possible.
Vector store
Storage that quickly finds the embeddings nearest to a query embedding.
Semantic cache
Reusing a past answer when the new question means the same thing, judged by embedding similarity rather than exact text match.
TTL — time to live
How long a stored item stays valid before it must be discarded or recomputed. Missing from this project's cache, which is a real gap.
Cache poisoning
A wrong entry being written, then served confidently and repeatedly. The reason a cache of your own output needs a gated write path.
Summary buffer
Keeping recent messages verbatim and replacing older ones with a generated summary. Preserves follow-up references that a plain sliding window destroys.
Coreference
A phrase pointing at something named earlier — "their dividends", "that one". Search cannot resolve it, because the entity is absent from the text.
Context engineering
Deliberately choosing what goes into each model call, in what order and at what fidelity. Prompt engineering is one part of it.
Lost in the middle
The observed effect that models use the beginning and end of a long input more reliably than the middle. The reason ordering is a design decision.
Prompt injection
Text inside retrieved content that the model reads as an instruction. Matters because retrieved documents sit next to your own instructions in one input.
Orchestration
Coordinating multiple model calls and tools into one flow: which step runs, in what order, with what retries.
Node / edge / conditional edge
A step; a fixed connection between steps; and a function that reads state to decide which step comes next.
Reducer
The rule for combining writes to the same state field from parallel branches. The default overwrite silently loses data under concurrency.
Fan-out / fan-in
Splitting a request into parallel branches and merging the results. Same shape as map-reduce.
Subgraph
A graph used as one node inside a larger graph, with its own private state.
Interrupt / resume
Pausing execution to wait for a human, then continuing from the same point. Durable only because state was already checkpointed.
ReAct loop
The model alternates between reasoning and calling a tool, feeding each result back, until it has an answer. Needs an iteration bound.
Supervisor pattern
A top-level graph that dispatches to specialist sub-agents and merges their output, instead of one agent doing everything.