[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-how-to-add-temporal-rag-in-production-zh":3,"article-related-how-to-add-temporal-rag-in-production-zh":30,"series-ai-agent-7095f05c-34f5-469f-a044-2525d2010ce9":83},{"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":22,"views":26,"created_at":27,"published_at":28,"topic_cluster_id":29},"7095f05c-34f5-469f-a044-2525d2010ce9","how-to-add-temporal-rag-in-production-zh","如何在正式環境加入 Temporal RAG","\u003Cp data-speakable=\"summary\">這篇教你在既有 \u003Ca href=\"\u002Ftag\u002Frag\">RAG\u003C\u002Fa> 中加入時間感知重排層，讓新版本、有效期間內的事件與最新資料優先被 \u003Ca href=\"\u002Ftag\u002Fllm\">LLM\u003C\u002Fa> 使用。\u003C\u002Fp>\u003Cp>這篇給正在做內容會隨時間變動的 RAG 系統開發者，像是文件、政策、教學、警報與客服知識庫。照著做完，你會得到一個可上線的時間層，能先排除過期資料、提高有效事件權重，並在不重建 retriever 的前提下偏好較新的版本。\u003C\u002Fp>\u003Cp>你也會建立一條清楚的分數路徑，介於向量搜尋與 LLM 之間，並能驗證舊文件不再壓過新文件。\u003C\u002Fp>\u003Ch2>開始之前\u003C\u002Fh2>\u003Cul>\u003Cli>Python 3.11+\u003C\u002Fli>\u003Cli>Node 20+，僅當你的應用外殼或 API 層使用 Node 時需要\u003C\u002Fli>\u003Cli>可用的 RAG 堆疊，搭配 Pinecone、Weaviate、pgvector 或 FAISS 其中之一\u003C\u002Fli>\u003Cli>文件中已有 \u003Ccode>created_at\u003C\u002Fcode>、\u003Ccode>updated_at\u003C\u002Fcode>，以及可選的 \u003Ccode>expires_at\u003C\u002Fcode> 欄位\u003C\u002Fli>\u003Cli>LLM API key，例如 OpenAI 或 Anthropic\u003C\u002Fli>\u003Cli>可存取參考實作的 \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FEmmimal\u002Ftemporal-rag\u002F\">GitHub repo\u003C\u002Fa>，以及原始說明文的 \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: 標記時間敏感文件\u003C\u002Fh2>\u003Cp>這一步的產出是文件清單，能把永不過期的事實、已被新版本取代的內容、以及有時間窗口的事件分開。時間層只有在知道文件屬於哪一類時，才會正確工作。\u003C\u002Fp>\n\u003Cfigure class=\"my-6\">\u003Cimg src=\"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1778667053844-osvs.png\" alt=\"如何在正式環境加入 Temporal RAG\" class=\"rounded-xl w-full\" loading=\"lazy\" \u002F>\u003C\u002Ffigure>\n\u003Cp>先替每筆來源資料加上類型與有效性欄位。實用的結構如下：\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>驗收：你應該能指向任一文件，並說出它是永恆事實、已被新版本取代，或只在某段時間內有效。\u003C\u002Fp>\u003Ch2>Step 2: 把新鮮度欄位寫進索引\u003C\u002Fh2>\u003Cp>這一步的產出是可供重排使用的索引記錄。向量資料庫仍然負責語意搜尋，但它必須把 metadata 一起回傳，讓時間層能做判斷。\u003C\u002Fp>\n\u003Cfigure class=\"my-6\">\u003Cimg src=\"https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1778667053085-3mg1.png\" alt=\"如何在正式環境加入 Temporal RAG\" class=\"rounded-xl w-full\" loading=\"lazy\" \u002F>\u003C\u002Ffigure>\n\u003Cp>在資料匯入或更新時，把時間欄位寫進同一筆嵌入資料。若你已經有 pipeline，只要補欄位，不必更換 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>驗收：你應該看到每個被取回的 chunk 都帶著 metadata，而不只是文字與相似度分數。\u003C\u002Fp>\u003Ch2>Step 3: 在排序前先判定有效性\u003C\u002Fh2>\u003Cp>這一步的產出是前置判定器，會先移除過期事實，並把正在生效的時間事件標記出來，然後才交給 LLM。這是關鍵安全步驟，因為過期內容不該只是降權，而是要直接移除。\u003C\u002Fp>\u003Cp>你可以用三種狀態：EXPIRED、VALID、TEMPORAL。依照原始實作模式，只有 EVENT 文件才會變成 TEMPORAL。VERSIONED 文件在未被取代前都維持 VALID，舊版一旦被 supersede 就排除。\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>驗收：你應該看到過期項目從候選集合中移除，而活躍警報被標成 TEMPORAL，不只是排得比較後面。\u003C\u002Fp>\u003Ch2>Step 4: 用時間衰減重排候選項\u003C\u002Fh2>\u003Cp>這一步的產出是結合語意相似度與新鮮度的重排器。目標不是讓時間壓過相關性，而是在多個近似匹配時，讓較新的內容更有優勢。\u003C\u002Fp>\u003Cp>實作上可以先正規化 cosine similarity，再依年齡套用指數衰減，並對有效事件加上額外提升。原始文章採用混合分數，讓最新且相關的文件勝出，但不會把所有新文件都推到最前面。\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>驗收：你應該看到較新的政策壓過語意相近但較舊的政策，而在事件有效期間內，直播告警會跳到靜態文件前面。\u003C\u002Fp>\u003Ch2>Step 5: 把時間層接在 retriever 與 LLM 之間\u003C\u002Fh2>\u003Cp>這一步的產出是可上線的資料流，保留原本 retriever 不動，只在最後一段改寫候選順序。這樣風險低，也容易塞進既有系統。\u003C\u002Fp>\u003Cp>做法是先取 top-k 語意結果，再分類、重排，最後只把最終 context 傳給 LLM。這會保留你目前的 retriever，同時在最後一個責任點修正時間盲點。\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>驗收：你應該看到 prompt context 內是最新有效版本，而不是語意最像但最舊的 chunk。\u003C\u002Fp>\u003Ch2>Step 6: 測試舊答案失敗情境\u003C\u002Fh2>\u003Cp>這一步的產出是一組可重複執行的測試，專門驗證最重要的時間錯誤。重點不是一般 retrieval 測試，而是被取代的政策、已過期的教學，以及應該壓過其他資料的即時事件。\u003C\u002Fp>\u003Cp>先建立至少三種 fixtures：一個被 supersede 的文件、一個過期文件、以及一個正在生效的事件。接著同時檢查排序結果與排除行為。\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>驗收：你應該看到舊版本被移除、活躍通知被提到前面，且最新有效文件排在前一版之前。\u003C\u002Fp>\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>指標\u003C\u002Fth>\u003Cth>基準／優化前\u003C\u002Fth>\u003Cth>結果／優化後\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd>排序行為\u003C\u002Ftd>\u003Ctd>舊政策因 cosine similarity 排第一\u003C\u002Ftd>\u003Ctd>最新有效政策在 temporal rerank 後排第一\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>過期內容處理\u003C\u002Ftd>\u003Ctd>過期文件仍留在前幾名\u003C\u002Ftd>\u003Ctd>過期文件在送進 LLM 前被移除\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>活躍事件處理\u003C\u002Ftd>\u003Ctd>即時通知排在靜態文件後面\u003C\u002Ftd>\u003Ctd>通知在有效期間內被提升到最前面\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>常見錯誤\u003C\u002Fh2>\u003Cul>\u003Cli>把所有文件都套用同一個新鮮度規則。修法：分開 STATIC、VERSIONED、EVENT，讓每種文件有自己的處理方式。\u003C\u002Fli>\u003Cli>只把過期事實降權，沒有真正移除。修法：在 rerank 或組 prompt 前先過濾 EXPIRED 項目。\u003C\u002Fli>\u003Cli>把每個較新的文件都當成緊急事件。修法：只對真正有時間窗口的事件套用 TEMPORAL 提升，不要套用到一般版本更新。\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>接下來可以看什麼\u003C\u002Fh2>\u003Cp>當這套流程能跑之後，可以再加上來源別 half-life、排序決策的 \u003Ca href=\"\u002Fnews\u002Fanthropic-adds-12-claude-tools-for-legal-work-zh\">aud\u003C\u002Fa>it l\u003Ca href=\"\u002Fnews\u002Fgoogle-gemini-android-center-before-wwdc-zh\">og\u003C\u002Fa>，以及對使用者可讀的解釋，說明為\u003Ca href=\"\u002Fnews\u002Fwhy-ibm-bob-right-kind-ai-coding-assistant-zh\">什麼\u003C\u002Fa>某份文件勝過另一份。接著就能加入即時刷新、政策專屬過期規則，還有衡量舊答案下降幅度的評估集。\u003C\u002Fp>","這篇教你在既有 RAG 中加入時間感知重排層，讓新版本、有效期間內的事件與最新資料優先被 LLM 使用。","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-1778667053844-osvs.png","ai-agent","zh","322ec8bc-61d3-4c80-bb9e-a19941e137c6",[17,18,19,20,21],"RAG","temporal reranking","vector database","Python","LLM",[23,24,25],"先把文件分成 STATIC、VERSIONED、EVENT，再決定誰該被保留或排除。","把時間欄位寫進索引 metadata，讓向量搜尋後還能做時間重排。","過期內容要直接移除，活躍事件才加權，最後再送進 LLM。",9,"2026-05-13T10:10:30.930982+00:00","2026-05-13T10:10:30.886+00:00","e3b68196-9e64-4c18-a3b6-a73e73bfb367",{"tags":31,"relatedLang":42,"relatedPosts":46},[32,34,36,38,40],{"name":20,"slug":33},"python",{"name":17,"slug":35},"rag",{"name":21,"slug":37},"llm",{"name":18,"slug":39},"temporal-reranking",{"name":19,"slug":41},"vector-database",{"id":15,"slug":43,"title":44,"language":45},"how-to-add-temporal-rag-in-production-en","How to Add Temporal RAG in Production","en",[47,53,59,65,71,77],{"id":48,"slug":49,"title":50,"cover_image":51,"image_url":51,"created_at":52,"category":13},"83c2f8f6-3710-466e-b52c-473b811f0535","how-to-set-up-openclaw-safely-zh","如何安全架設 OpenClaw","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780549368665-1t2l.png","2026-06-04T05:02:21.26625+00:00",{"id":54,"slug":55,"title":56,"cover_image":57,"image_url":57,"created_at":58,"category":13},"0ba5b1a8-82c5-464a-bea5-9a2c8730da74","aws-devops-agent-turns-incident-chaos-into-triage-zh","AWS DevOps Agent 把事故排查變成三步","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780466689960-g1sv.png","2026-06-03T06:03:14.154923+00:00",{"id":60,"slug":61,"title":62,"cover_image":63,"image_url":63,"created_at":64,"category":13},"841eac88-b0f0-4a4c-9e1e-efc3b5c16281","kimi-k26-live-300-agent-workflows-zh","Kimi K2.6 上線：300 代理工作流","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780430574285-hqpn.png","2026-06-02T20:02:24.972179+00:00",{"id":66,"slug":67,"title":68,"cover_image":69,"image_url":69,"created_at":70,"category":13},"f0411957-bcdb-42d9-a267-3e90ae7d9cb1","how-to-take-a-sabbatical-at-openai-zh","怎麼申請 OpenAI sabbatical","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780398216422-8fi7.png","2026-06-02T11:02:25.74372+00:00",{"id":72,"slug":73,"title":74,"cover_image":75,"image_url":75,"created_at":76,"category":13},"37a5e429-4235-439c-9b05-bb377085462c","8-steps-build-production-rag-with-langchain-zh","8 步驟打造可上線的 LangChain RAG","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780178597493-4hz7.png","2026-05-30T22:02:48.14022+00:00",{"id":78,"slug":79,"title":80,"cover_image":81,"image_url":81,"created_at":82,"category":13},"e73c041b-852b-44c3-85aa-0f1e2e5848e3","ai-agents-hit-chaos-mode-claude-code-openclaw-zh","Claude Code＋OpenClaw 讓 AI 代理失控升溫","https:\u002F\u002Fxxdpdyhzhpamafnrdkyq.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fcovers\u002Finline-1780160576178-yqcs.png","2026-05-30T17:02:25.725767+00:00",[84,89,94,99,104,109,114,119,124,129],{"id":85,"slug":86,"title":87,"created_at":88},"4ae1e197-1d3d-4233-8733-eafe9cb6438b","claude-now-uses-your-pc-to-finish-tasks-zh","Claude 開始幫你操作電腦","2026-03-26T07:20:48.457387+00:00",{"id":90,"slug":91,"title":92,"created_at":93},"5bede67f-e21c-413d-9ab8-54a3c3d26227","googles-2026-ai-agent-report-decoded-zh","Google 2026 AI Agent 報告解讀","2026-03-26T11:15:22.651956+00:00",{"id":95,"slug":96,"title":97,"created_at":98},"2987d097-563f-46c7-b76f-b558d8ef7c2b","kimi-k25-review-stronger-still-not-legend-zh","Kimi K2.5 評測：更強，但還不是神作","2026-03-27T07:15:55.277513+00:00",{"id":100,"slug":101,"title":102,"created_at":103},"95c9053b-e3f4-4cb5-aace-5c54f4c9e044","claude-code-controls-mac-desktop-zh","Claude Code 也能操控 Mac 了","2026-03-28T03:01:58.58121+00:00",{"id":105,"slug":106,"title":107,"created_at":108},"dc58e153-e3a8-4c06-9b96-1aa64eabbf5f","cloudflare-100x-faster-ai-agent-sandbox-zh","Cloudflare 的 AI 沙箱跑超快","2026-03-28T03:09:44.142236+00:00",{"id":110,"slug":111,"title":112,"created_at":113},"1c8afc56-253f-47a2-979f-1065ff072f2a","openai-backs-isara-agent-swarm-bet-zh","OpenAI 挺 Isara 的 agent swarm …","2026-03-28T03:15:27.513155+00:00",{"id":115,"slug":116,"title":117,"created_at":118},"7379b422-576e-45df-ad5a-d57a0d9dd467","openai-plan-automated-ai-researcher-zh","OpenAI 想做自動化 AI 研究員","2026-03-28T03:17:42.090548+00:00",{"id":120,"slug":121,"title":122,"created_at":123},"48c9889e-86df-450b-a356-e4a4b7c83c5b","harness-engineering-ai-agent-reliability-2026-zh","駕馭工程：從「馬具」到「作業系統」，AI Agent 可靠性的終極密碼","2026-03-31T06:42:53.556721+00:00",{"id":125,"slug":126,"title":127,"created_at":128},"96d8e8c8-1edd-475d-9145-b1e7a1b02b65","mcp-explained-from-prompts-to-production-zh","MCP 怎麼把提示詞變工作流","2026-04-01T09:24:39.321274+00:00",{"id":130,"slug":131,"title":132,"created_at":133},"f2ca7720-b471-4ce5-9336-2a9ac2a876fd","amazon-bedrock-agents-multi-agent-workflows-zh","Amazon Bedrock Agents 進入多代理工作流","2026-04-01T09:30:29.945429+00:00"]