[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-how-to-add-temporal-rag-in-production-en":3,"article-related-how-to-add-temporal-rag-in-production-en":31,"series-ai-agent-322ec8bc-61d3-4c80-bb9e-a19941e137c6":84},{"id":4,"slug":5,"title":6,"content":7,"summary":8,"source":9,"source_url":10,"author":11,"image_url":12,"cover_image":12,"category":13,"language":14,"translated_content":11,"related_article_id":15,"keywords":16,"key_takeaways":23,"views":27,"created_at":28,"published_at":29,"topic_cluster_id":30},"322ec8bc-61d3-4c80-bb9e-a19941e137c6","how-to-add-temporal-rag-in-production-en","How to Add Temporal RAG in Production","\u003Cp data-speakable=\"summary\">Add a temporal reranking layer to \u003Ca href=\"\u002Ftag\u002Frag\">RAG\u003C\u002Fa> so fresh, valid, and versioned facts rank correctly.\u003C\u002Fp>\u003Cp>This guide is for developers building RAG systems over content that changes over time, such as docs, policies, tutorials, alerts, and support knowledge bases. After following it, you will have a production-friendly temporal layer that filters expired facts, boosts active time-bound events, and prefers newer versions without rebuilding your retriever.\u003C\u002Fp>\u003Cp>You will also have a clear scoring path between vector search and the \u003Ca href=\"\u002Ftag\u002Fllm\">LLM\u003C\u002Fa>, plus a way to verify that stale documents no longer outrank current ones.\u003C\u002Fp>\u003Ch2>Before you start\u003C\u002Fh2>\u003Cul>\u003Cli>Python 3.11+\u003C\u002Fli>\u003Cli>Node.js 20+ only if your app shell or API layer is in Node\u003C\u002Fli>\u003Cli>A working RAG stack with a vector database such as Pinecone, Weaviate, pgvector, or FAISS\u003C\u002Fli>\u003Cli>Document metadata fields for \u003Ccode>created_at\u003C\u002Fcode>, \u003Ccode>updated_at\u003C\u002Fcode>, and optionally \u003Ccode>expires_at\u003C\u002Fcode>\u003C\u002Fli>\u003Cli>An LLM API key, such as OpenAI or Anthropic\u003C\u002Fli>\u003Cli>Access to the reference implementation on \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FEmmimal\u002Ftemporal-rag\u002F\">GitHub\u003C\u002Fa> and the original write-up on \u003Ca href=\"https:\u002F\u002Ftowardsdatascience.com\u002Frag-is-blind-to-time-i-built-a-temporal-layer-to-fix-it-in-production\u002F\">Towards Data Science\u003C\u002Fa>\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>Step 1: Map your time-sensitive documents\u003C\u002Fh2>\u003Cp>Your first outcome is a document inventory that separates timeless facts from replaced versions and active events. This matters because the temporal layer only works if it knows whether a document is static, versioned, or an event with a time window.\u003C\u002Fp>\n\u003Cfigure class=\"my-6\">\u003Cimg src=\"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1778667085221-0mox.png\" alt=\"How to Add Temporal RAG in Production\" class=\"rounded-xl w-full\" loading=\"lazy\" \u002F>\u003C\u002Ffigure>\n\u003Cp>Start by tagging each source record with a kind and a validity signal. A practical schema looks like this:\u003C\u002Fp>\u003Cpre>\u003Ccode>kind: STATIC | VERSIONED | EVENT\nvalid_from: ISO-8601 timestamp\nvalid_to: ISO-8601 timestamp or null\nexpires_at: ISO-8601 timestamp or null\nsupersedes_id: optional document id\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Verification: you should be able to point to any document and say whether it is timeless, replaced by a newer version, or only true during a live window.\u003C\u002Fp>\u003Ch2>Step 2: Add freshness metadata to your index\u003C\u002Fh2>\u003Cp>Your second outcome is an index that stores the timestamps needed for reranking. The vector store can still do semantic retrieval, but it must return metadata alongside embeddings so the temporal layer can make a decision.\u003C\u002Fp>\n\u003Cfigure class=\"my-6\">\u003Cimg src=\"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1778667052105-h0ir.png\" alt=\"How to Add Temporal RAG in Production\" class=\"rounded-xl w-full\" loading=\"lazy\" \u002F>\u003C\u002Ffigure>\n\u003Cp>When you ingest or update content, write the metadata into the same record you embed. If you already have a pipeline, add these fields without changing the embedding model.\u003C\u002Fp>\u003Cpre>\u003Ccode>doc = {\n  \"id\": \"policy_v2\",\n  \"text\": \"API rate limits are now 200 requests per minute\",\n  \"kind\": \"VERSIONED\",\n  \"created_at\": \"2026-01-10T09:00:00Z\",\n  \"updated_at\": \"2026-03-01T12:00:00Z\",\n  \"valid_from\": \"2026-03-01T12:00:00Z\",\n  \"valid_to\": null,\n  \"supersedes_id\": \"policy_v1\"\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Verification: you should see the metadata returned with each retrieved chunk, not just the text and similarity score.\u003C\u002Fp>\u003Ch2>Step 3: Classify validity before ranking\u003C\u002Fh2>\u003Cp>Your third outcome is a pre-ranker that removes expired facts and marks active time-bound facts before the LLM ever sees them. This is the key safety step, because expired content should not be down-weighted, it should be dropped.\u003C\u002Fp>\u003Cp>Use three states: EXPIRED, VALID, and TEMPORAL. In the pattern from the source article, only EVENT documents can become TEMPORAL. VERSIONED documents remain VALID until they are superseded, and then the old copy is excluded.\u003C\u002Fp>\u003Cpre>\u003Ccode>def classify(doc, now):\n    if doc.get(\"expires_at\") and doc[\"expires_at\"] &lt; now:\n        return \"EXPIRED\"\n    if doc[\"kind\"] == \"EVENT\" and doc.get(\"valid_from\") &lt;= now &lt;= doc.get(\"valid_to\"):\n        return \"TEMPORAL\"\n    return \"VALID\"\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Verification: you should see expired items removed from the candidate set and active alerts marked TEMPORAL rather than merely ranked lower.\u003C\u002Fp>\u003Ch2>Step 4: Rerank candidates with temporal decay\u003C\u002Fh2>\u003Cp>Your fourth outcome is a reranker that combines semantic similarity with freshness. The goal is not to let time override relevance, but to make recency matter when several documents are otherwise close matches.\u003C\u002Fp>\u003Cp>A practical scoring model is to normalize cosine similarity, apply exponential decay by age, and add a boost for active events. The source article uses a hybrid score so the newest relevant document wins without forcing every fresh document to the top.\u003C\u002Fp>\u003Cpre>\u003Ccode>decay = 0.5 ** (age_in_days \u002F half_life_days)\nfinal_score = (0.7 * vector_score) + (0.3 * decay)\nif state == \"TEMPORAL\":\n    final_score *= 1.2\nif state == \"EXPIRED\":\n    final_score = 0.0\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Verification: you should see a newer policy outrank an older policy with similar wording, while a live outage notice jumps above static docs during its active window.\u003C\u002Fp>\u003Ch2>Step 5: Wire the temporal layer between retriever and LLM\u003C\u002Fh2>\u003Cp>Your fifth outcome is a production path where the retriever stays unchanged and the temporal layer only rewrites the candidate order. That keeps the implementation low-risk and easy to slot into an existing system.\u003C\u002Fp>\u003Cp>Take the top-k semantic matches, classify them, rerank them, then pass only the final context to the LLM. This preserves your current retriever while fixing the time blindness at the last responsible moment.\u003C\u002Fp>\u003Cpre>\u003Ccode>candidates = retriever.search(query, top_k=20)\nscored = [score_candidate(c, now) for c in candidates]\nranked = sorted(scored, key=lambda x: x.final_score, reverse=True)\ncontext = [item.doc for item in ranked if item.state != \"EXPIRED\"]\nanswer = llm.generate(query, context)\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Verification: you should see the prompt context contain the newest valid version, not the oldest semantically similar chunk.\u003C\u002Fp>\u003Ch2>Step 6: Test stale-answer failures\u003C\u002Fh2>\u003Cp>Your sixth outcome is a repeatable test suite that proves the layer works on the cases that matter most. The right tests are not generic retrieval tests, but time-aware failures such as a replaced policy, an expired tutorial, and a live event that should outrank everything else.\u003C\u002Fp>\u003Cp>Build fixtures for at least three scenarios: a superseded document, an expired document, and a currently active event. Then assert both ranking order and exclusion behavior.\u003C\u002Fp>\u003Cpre>\u003Ccode>assert \"policy_v1\" not in final_context\nassert final_rank[0].id == \"announcement_today\"\nassert any(item.state == \"TEMPORAL\" for item in ranked)\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Verification: you should see the old version removed, the active notice surfaced, and the latest valid document outranking its predecessor.\u003C\u002Fp>\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Metric\u003C\u002Fth>\u003Cth>Before\u002FBaseline\u003C\u002Fth>\u003Cth>After\u002FResult\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd>Ranking behavior\u003C\u002Ftd>\u003Ctd>Old policy ranked first by cosine similarity\u003C\u002Ftd>\u003Ctd>Latest valid policy ranked first after temporal rerank\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>Expired content handling\u003C\u002Ftd>\u003Ctd>Expired doc remained in top results\u003C\u002Ftd>\u003Ctd>Expired doc removed before LLM context\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>Active event handling\u003C\u002Ftd>\u003Ctd>Live notice ranked below static docs\u003C\u002Ftd>\u003Ctd>Live notice boosted to the top during its window\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>Common mistakes\u003C\u002Fh2>\u003Cul>\u003Cli>Using one freshness rule for every document type. Fix: separate STATIC, VERSIONED, and EVENT so each gets the right behavior.\u003C\u002Fli>\u003Cli>Down-weighting expired facts instead of removing them. Fix: filter EXPIRED items before reranking or prompt assembly.\u003C\u002Fli>\u003Cli>Boosting every recent document as if it were urgent. Fix: reserve TEMPORAL boosts for true event windows, not for normal version updates.\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>What's next\u003C\u002Fh2>\u003Cp>Once this is working, extend it with source-specific half-lives, audit logs for ranking decisions, and user-facing explanations that say why one document beat another. From there, you can add live refresh hooks, policy-specific expiry rules, and evaluation sets that measure stale-answer reduction over time.\u003C\u002Fp>","Add a temporal reranking layer to RAG so fresh, valid, and versioned facts rank correctly.","towardsdatascience.com","https:\u002F\u002Ftowardsdatascience.com\u002Frag-is-blind-to-time-i-built-a-temporal-layer-to-fix-it-in-production\u002F",null,"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1778667085221-0mox.png","ai-agent","en","7095f05c-34f5-469f-a044-2525d2010ce9",[17,18,19,20,21,22],"RAG","temporal reranking","vector search","freshness scoring","document metadata","LLM",[24,25,26],"Time-aware retrieval needs validity states, not just semantic similarity.","Expired facts should be filtered out before the model sees them.","Versioned and event-driven content need different ranking rules.",3,"2026-05-13T10:10:31.619892+00:00","2026-05-13T10:10:31.607+00:00","c58956f2-0e6f-4be5-b68a-39eda67428b3",{"tags":32,"relatedLang":43,"relatedPosts":47},[33,35,37,39,41],{"name":17,"slug":34},"rag",{"name":19,"slug":36},"vector-search",{"name":21,"slug":38},"document-metadata",{"name":20,"slug":40},"freshness-scoring",{"name":18,"slug":42},"temporal-reranking",{"id":15,"slug":44,"title":45,"language":46},"how-to-add-temporal-rag-in-production-zh","如何在正式環境加入 Temporal RAG","zh",[48,54,60,66,72,78],{"id":49,"slug":50,"title":51,"cover_image":52,"image_url":52,"created_at":53,"category":13},"5efa67dd-b9f7-4a2f-8c68-3a4bc6a6b7d9","claude-code-dynamic-workflow-ai-harness-en","Claude Code 动态工作流：AI 自写 Harness","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1781035372495-9czj.png","2026-06-09T20:02:22.33375+00:00",{"id":55,"slug":56,"title":57,"cover_image":58,"image_url":58,"created_at":59,"category":13},"2bd28e0e-0f4b-4987-a961-28763c1e1926","agent-orchestration-enterprise-ai-layer-en","Agent orchestration is the missing layer for enterprise AI","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780984981174-08mj.png","2026-06-09T06:02:31.384174+00:00",{"id":61,"slug":62,"title":63,"cover_image":64,"image_url":64,"created_at":65,"category":13},"95684312-23dc-4a78-a917-df14d132c5fa","ai-agents-use-blockchain-trust-layer-en","AI agents use blockchain as a trust layer","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780980506080-ki4s.png","2026-06-09T04:48:01.710214+00:00",{"id":67,"slug":68,"title":69,"cover_image":70,"image_url":70,"created_at":71,"category":13},"0208e47f-7d4c-4473-a0f9-4cd193b5c139","8-rag-patterns-demos-into-prod-en","8 RAG patterns that turn demos into prod","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780971552707-qpl7.png","2026-06-09T02:18:36.760049+00:00",{"id":73,"slug":74,"title":75,"cover_image":76,"image_url":76,"created_at":77,"category":13},"b413d484-6786-4c32-abdc-77f010ac7eba","fine-tuning-beats-rag-style-not-facts-en","Fine-tuning beats RAG when the goal is style, not facts","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780924681800-5xji.png","2026-06-08T13:17:25.701649+00:00",{"id":79,"slug":80,"title":81,"cover_image":82,"image_url":82,"created_at":83,"category":13},"57beb8b4-c233-400f-b95b-a97be1cf9d02","openclaw-small-business-ai-staff-en","OpenClaw shows how small businesses use AI staff","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780904882032-yp13.png","2026-06-08T07:47:27.730921+00:00",[85,90,95,100,105,110,115,120,125,130],{"id":86,"slug":87,"title":88,"created_at":89},"03db8de8-8dc2-4ac1-9cf7-898782efbb1f","anthropic-claude-ai-agent-task-automation-en","Anthropic's Claude AI Agent: A New Era of Task Automation","2026-03-25T16:25:06.513026+00:00",{"id":91,"slug":92,"title":93,"created_at":94},"045d1abc-190d-4594-8c95-91e2a26f0c5a","googles-2026-ai-agent-report-decoded-en","Google’s 2026 AI Agent Report, Decoded","2026-03-26T11:15:23.046616+00:00",{"id":96,"slug":97,"title":98,"created_at":99},"e64aba21-254b-4f93-aa21-837484bb52ec","kimi-k25-review-stronger-still-not-legend-en","Kimi K2.5 review: stronger, still not a legend","2026-03-27T07:15:55.385951+00:00",{"id":101,"slug":102,"title":103,"created_at":104},"30dfb781-a1b2-4add-aebe-b3df40247c37","claude-code-controls-mac-desktop-en","Claude Code now controls your Mac desktop","2026-03-28T03:01:59.384091+00:00",{"id":106,"slug":107,"title":108,"created_at":109},"254405b6-7833-4800-8e13-f5196deefbe6","cloudflare-100x-faster-ai-agent-sandbox-en","Cloudflare’s 100x Faster AI Agent Sandbox","2026-03-28T03:09:44.356437+00:00",{"id":111,"slug":112,"title":113,"created_at":114},"04f29b7f-9b91-4306-89a7-97d725e6e1ba","openai-backs-isara-agent-swarm-bet-en","OpenAI backs Isara’s agent-swarm bet","2026-03-28T03:15:27.849766+00:00",{"id":116,"slug":117,"title":118,"created_at":119},"3b0bf479-e4ae-4703-9666-721a7e0cdb91","openai-plan-automated-ai-researcher-en","OpenAI’s plan for an automated AI researcher","2026-03-28T03:17:42.312819+00:00",{"id":121,"slug":122,"title":123,"created_at":124},"fe91bce0-b85d-4efa-a207-24ae9939c29f","harness-engineering-ai-agent-reliability-2026","Harness Engineering: From Bridle to Operating System, The Missing Link in AI Agent Reliability","2026-03-31T06:36:55.648751+00:00",{"id":126,"slug":127,"title":128,"created_at":129},"7a09007d-820f-43b3-8607-8ad1bfcb94c8","mcp-explained-from-prompts-to-production-en","MCP Explained: From Prompts to Production","2026-04-01T09:24:40.089177+00:00",{"id":131,"slug":132,"title":133,"created_at":134},"116d5ee9-a4f1-4b5a-aac5-5d035dd22bbe","amazon-bedrock-agents-multi-agent-workflows-en","Amazon Bedrock Agents Gets Multi-Agent Workflows","2026-04-01T09:30:30.197685+00:00"]