
Building AI Search and Agentic Workflows Hybrid Search Agents with Elasticsearch, Elasticsearch, Jina, and A2A
How to give AI agents reliable memory and let them collaborate: hybrid retrieval, Jina v5 embeddings and reranking, and an open protocol for agent-to-agent discovery and delegation.
Building AI Search and Agentic Workflows with Elasticsearch, Jina, and A2A
Most agent demos fall over the moment they touch real data. The model reasons beautifully, then retrieves the wrong document, hallucinates a citation, or can't hand work off to another team's agent because there's no shared protocol. The hard part of agentic AI in 2026 isn't the reasoning loop — it's giving agents reliable memory and a way to collaborate across organizational boundaries.
This article walks through a stack that addresses both: Elasticsearch as the retrieval and memory layer, Jina AI models for embeddings and reranking, and the Agent2Agent (A2A) protocol for agent-to-agent interoperability. Each piece solves a distinct problem, and together they form a practical blueprint for production agentic search.
Why this combination
Think of the three layers by the job each one does:
- Elasticsearch is the brain's memory. It stores your documents and their vector embeddings, runs both keyword (BM25) and semantic (kNN) search in a single engine, and combines them with filters and aggregations. It scales embedding storage to billions of vectors and pairs lexical precision with semantic recall — something a standalone vector database can't match on its own.
- Jina supplies the language understanding. Its embedding and reranker models turn text (and increasingly images, audio, and video) into the vectors Elasticsearch searches over, then re-score the top candidates so the most relevant results rise to the top.
- A2A is the nervous system. It's an open standard, now governed by the Linux Foundation, that lets independent agents discover each other, delegate tasks, and exchange results — regardless of who built them or what framework they run on.
A useful mental model: A2A coordinates agents with each other; MCP connects each agent to its tools and data. They're complementary Linux Foundation projects, and a serious agentic system usually uses both. In what follows, Elasticsearch + Jina form a retrieval capability that an agent owns internally, and A2A is how that agent exposes the capability to the wider world.
The architecture at a glance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
┌───────────────────────────── ┐
A2A Client │ A2A Search Agent │
(any agent) ──┼──▶ - Agent Card (discovery) │
JSON-RPC/HTTPS│ - Task lifecycle │
│ │ │
│ ▼ │
│ Hybrid Retrieval (Elastic) │
│ BM25 + kNN ──▶ RRF fusion │
│ │ │
│ ▼ │
│ Jina Reranker (precision) │
│ │ │
│ ▼ │
│ Artifact ──▶ back to client│
└─────────────────────────────┘
Embeddings: Jina v5 via Elastic Inference Service
Hosting: Elastic Cloud / EKS / self-managed on AWSThe flow is: a calling agent discovers our search agent through its Agent Card, sends a task, the agent runs hybrid retrieval in Elasticsearch, reranks with Jina, and returns the result as an A2A artifact.
Part 1 — The retrieval layer: Elasticsearch + Jina
Generating embeddings without managing GPUs
The cleanest path in 2026 is the Elastic Inference Service (EIS), which hosts Jina's models so you don't have to stand up GPU infrastructure. The current generation is the
jina-embeddings-v5-text family — compact multilingual models that punch well above their parameter count. The -nano variant has roughly 239M parameters yet competes with models several times its size, and both variants support a 32K-token context window with Matryoshka truncation, so you can shrink embeddings to save storage with minimal quality loss.You create an inference endpoint, then attach it to a field via the
semantic_text field type (GA since Elasticsearch 8.18). That single field type handles chunking, embedding generation at ingest, and the vector mapping for you — eliminating the boilerplate of manually wiring an ingest pipeline, an inference processor, and dense_vector mappings.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
PUT _inference/text_embedding/jina-v5
{
"service": "elastic",
"service_settings": { "model_id": "jina-embeddings-v5-text-small" }
}
PUT support-docs
{
"mappings": {
"properties": {
"title": { "type": "text" },
"content": { "type": "text" },
"content_semantic": {
"type": "semantic_text",
"inference_id": "jina-v5"
}
}
}
}Now indexing a document automatically populates
content_semantic with embeddings. Note that content is still a plain text field — you want both, because the strongest results come from searching them together.Hybrid retrieval with Reciprocal Rank Fusion
Pure vector search is great at concepts but loses to BM25 on exact matches like error codes, SKUs, and proper nouns. The fix is hybrid search: run both, then fuse the rankings with Reciprocal Rank Fusion (RRF) using the retriever syntax (retrievers reached GA in 8.16).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
GET support-docs/_search
{
"retriever": {
"rrf": {
"retrievers": [
{
"standard": {
"query": {
"multi_match": {
"query": "payment fails after timeout",
"fields": ["title^2", "content"]
}
}
}
},
{
"standard": {
"query": {
"semantic": {
"field": "content_semantic",
"query": "payment fails after timeout"
}
}
}
}
],
"rank_window_size": 100,
"rank_constant": 60
}
},
"size": 20
}The lexical retriever catches documents that literally mention the terms; the semantic retriever catches documents that mean the same thing in different words ("transaction declined following request expiry"). RRF blends both ranked lists into one without you hand-tuning weights.
Reranking for the last mile of precision
Retrieval gets you a good candidate set; a reranker gets you the right order. A reranker reads each query–document pair together and re-scores them, capturing nuance that cosine similarity over independent embeddings misses. Jina's rerankers are available on EIS, with
jina-reranker-v3 being the current flagship — a listwise model that looks at the query and all candidates in one context window, enabling cross-document comparison before producing final scores.The pattern is retrieve broad, rerank narrow: pull ~50–100 candidates with hybrid search, rerank them, keep the top 5–10. This adds relevance without reindexing or disrupting your pipeline, which is exactly why it shines in RAG and agentic workflows where downstream answer quality depends on feeding the model the right context, not just related context.
1
2
3
4
5
POST _inference/rerank/jina-rerank-v3
{
"input": [ "...candidate doc 1...", "...candidate doc 2...", "..." ],
"query": "payment fails after timeout"
}At this point you have a retrieval capability that is multilingual, hybrid, reranked, and self-tuning enough for production. The next two parts make it an agent.
Part 2 — Wrapping retrieval as an agent skill
An A2A agent is, concretely, an HTTPS service that speaks JSON-RPC 2.0 and advertises what it can do. The internals are opaque to callers — they don't need to know you're running Elasticsearch and Jina underneath, only that you expose a skill they can invoke. That opacity is the whole point: it's what lets agents from different vendors collaborate without sharing implementation details.
So the work here is mostly defining a clean skill boundary. Our agent will expose one skill —
knowledge_search — that takes a natural-language query plus optional filters and returns ranked, cited passages. Internally it runs the hybrid-retrieve-then-rerank pipeline from Part 1.Part 3 — Exposing it over A2A
The Agent Card
Discovery in A2A happens through the Agent Card: a JSON document that acts as a machine-readable business card. It declares the agent's identity, service endpoint, capabilities, authentication requirements, and skills. A calling agent fetches this card to decide whether our agent is suitable and how to talk to it securely.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"name": "Knowledge Search Agent",
"description": "Hybrid semantic + keyword search over the support knowledge base.",
"url": "https://search-agent.example.com/a2a",
"version": "1.0.0",
"capabilities": { "streaming": true, "pushNotifications": true },
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain", "application/json"],
"skills": [
{
"id": "knowledge_search",
"name": "Knowledge base search",
"description": "Returns ranked, cited passages for a natural-language query.",
"tags": ["search", "rag", "retrieval"],
"examples": ["Why do payments fail after a timeout?"]
}
]
}A major hardening step landed with A2A v1.0 in early 2026: Signed Agent Cards. Adding a cryptographic signature lets a receiving agent verify the card was genuinely issued by the domain owner, which closes off card-forgery attacks where an impostor stands up a fake card to redirect traffic. If you're deploying A2A in production, treat signed cards as the baseline trust mechanism — decentralized discovery isn't safe without them. v1.0 also added multi-tenancy (one endpoint serving many agents), multi-protocol bindings (the same agent over JSON-RPC and gRPC), and version negotiation.
The task lifecycle
The fundamental unit of work in A2A is the Task, identified by a unique ID and progressing through a defined lifecycle. A client kicks things off with the
message/send method, passing a Message made of one or more Parts (text, structured data, or file references — A2A is deliberately modality-agnostic).1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"jsonrpc": "2.0",
"id": "req-1",
"method": "message/send",
"params": {
"message": {
"role": "user",
"messageId": "msg-001",
"parts": [
{ "kind": "text", "text": "Why do payments fail after a timeout?" }
]
}
}
}For a quick lookup the agent can answer immediately with a Message. For longer work it returns a Task in a working state and streams updates. The concrete result — our ranked, cited passages — comes back as an Artifact, which can be streamed incrementally and is composed of the same Part objects. Because A2A is async-first, long-running retrieval, human-in-the-loop review, or webhook-style push notifications all fit the same model: the client supplies a webhook, the agent POSTs state changes as they happen.
Under the hood A2A leans entirely on boring, well-understood standards — HTTP(S), JSON-RPC 2.0, and Server-Sent Events for streaming — which is exactly what makes it easy to drop into an existing AWS stack. Authentication stays in standard HTTP headers (OAuth tokens, API keys), declared in the Agent Card and kept separate from the protocol messages themselves.
Putting it together: a multi-agent workflow
Here's where the standard earns its keep. Imagine an incident-response orchestrator agent handling a production alert. It doesn't search anything itself — it delegates:
- The orchestrator reads our Agent Card, sees the
knowledge_searchskill, and sends a task: "Find runbooks for payment timeouts." - Our agent runs hybrid retrieval in Elasticsearch, reranks with Jina, and returns the top runbooks as an artifact.
- In parallel, the orchestrator delegates to a separate log-analysis agent (maybe built by a different team, in a different framework) over the same protocol.
- It fuses both artifacts and proposes a remediation.
No agent needed to know another's internals. That's the model A2A is built for, and adoption reflects it: by its one-year mark the project passed 150+ supporting organizations with production deployments across supply chain, financial services, insurance, and IT operations, plus integration across Google, Microsoft, and AWS platforms. For regulated, transactional flows, the AP2 extension layers on cryptographic evidence of user consent.
Production considerations
A few things separate a demo from something you'd put on call:
- Cost scales with vectors, so quantize. Float32 embeddings at 1024 dimensions cost roughly 4KB per document. Int8 quantization cuts that to ~1KB, and Better Binary Quantization (BBQ) reaches around 95% memory reduction while preserving ranking quality. Newer disk-based variants keep query latencies low without holding the whole index in RAM — meaning agent memory can grow large without infrastructure costs growing in lockstep.
- Relevance is not set-and-forget. Build a small judgment list, establish a BM25 baseline, then measure with metrics like nDCG@10 and MRR after adding semantic retrieval and reranking. Without offline evaluation you're guessing whether each change actually helped.
- Don't add vectors where BM25 already wins. If users search by exact SKUs, error codes, or names, semantic search adds latency for no gain. Start lexical; add vectors where keyword matching demonstrably fails.
- Treat cross-agent inputs as untrusted. Multi-agent systems introduce cross-agent prompt injection — a malicious payload riding inside a task or artifact. Validate and sandbox inputs from other agents the same way you'd validate user input, and lean on signed Agent Cards and scoped credentials.
- Hosting on AWS. Elastic Cloud runs on AWS, or you can self-manage on EKS/EC2; EIS via Cloud Connect even lets you keep data and indexing on-prem while bursting GPU inference to Elastic's fleet. Amazon Bedrock is also a supported inference provider if you want to mix embedding sources.
Wrapping up
The pattern here is layered and each layer is independently swappable. Elasticsearch gives agents durable, hybrid, billion-scale memory. Jina's v5 embeddings and v3 reranker give that memory genuine language understanding without a GPU fleet to babysit. A2A turns the whole thing into a peer that any other agent can discover and call over open standards.
Start small: stand up a
semantic_text index, wire hybrid retrieval with RRF, add a reranker, and measure the lift. Once retrieval is solid, wrap it in an Agent Card and expose one clean skill. You'll have a search capability that doesn't just answer your app — it can collaborate with an entire ecosystem of agents.Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article