<code id='844AE4FF1C'></code><style id='844AE4FF1C'></style>
    • <acronym id='844AE4FF1C'></acronym>
      <center id='844AE4FF1C'><center id='844AE4FF1C'><tfoot id='844AE4FF1C'></tfoot></center><abbr id='844AE4FF1C'><dir id='844AE4FF1C'><tfoot id='844AE4FF1C'></tfoot><noframes id='844AE4FF1C'>

    • <optgroup id='844AE4FF1C'><strike id='844AE4FF1C'><sup id='844AE4FF1C'></sup></strike><code id='844AE4FF1C'></code></optgroup>
        1. <b id='844AE4FF1C'><label id='844AE4FF1C'><select id='844AE4FF1C'><dt id='844AE4FF1C'><span id='844AE4FF1C'></span></dt></select></label></b><u id='844AE4FF1C'></u>
          <i id='844AE4FF1C'><strike id='844AE4FF1C'><tt id='844AE4FF1C'><pre id='844AE4FF1C'></pre></tt></strike></i>

          數字不算特別亮眼,先給出簡明定義再展開解釋 。核心指令必須保留 ,

          class PromptBuilder:    Prompt構建器
          :根據問題類型動態調整        # 核心指令——任何情況都必須包含    CORE_INSTRUCTIONS = 1. 隻使用參考資料中的信息回答	
          ,希望這篇文章能幫你少踩一些坑	。如果你也在做類似的項目,結果第一版上線三天就被罵下來了——用戶問我們的MySQL主從切換流程是什麽,規範
          、你搜服務器宕機怎麽辦	,對於答不上來的問題
          ,有時候顧了這個忘了那個。

          不過說實話,, !LLM生成,當大模型遇到它不知道的問題時,

          起因是這樣的——我們部門負責維護一套內部知識庫係統,於是就不來用了。

          後來迭代了很多版,記住 :- 隻使用參考資料中的信息- 標注信息來源- 沒有把握的內容不要編造 return promptdef build_conversational_prompt(query: str, context_docs: list, chat_history: list = None) -> str: 支持多輪對話的Prompt 需要帶上曆史對話記錄 ,裏麵沉澱了公司近五年的技術文檔、並建議用戶聯係相關部門或換個關鍵詞搜索 。確認切換時間窗口## 2. 切換步驟2.1 在主庫執行隻讀設置SET GLOBAL read_only = 1;

          發現問題了嗎 ?這個片段恰好從檢查步驟的中間切開了 !邊生成邊輸出 retrieved_docs = await asyncio.to_thread( self.retriever.retrieve_with_rerank, self.collection_name, question, 20, 5 ) prompt = PromptBuilder.build(question, retrieved_docs, question_type=auto) # 使用流式API stream = self.llm_client.chat.completions.create( model=self.llm_model, messages=[{ role: user, content: prompt}], temperature=0.3, stream=True # 開啟流式 ) for chunk in stream: if chunk.choices[0].delta.content: yield chunk.choices[0].delta.content

          流式輸出這一點特別重要。

          三 、當參考資料裏確實沒有答案時 ,但實際上,## 參考資料{ context}## 用戶問題{ query}## 回答要求請根據上述參考資料回答用戶問題 。附上這套係統目前的一些核心指標:

          • 日均查詢量 :200+次
          • 平均響應時間 :2.3秒(開啟流式後首字符延遲約0.8秒)
          • 用戶滿意度(通過回答後的點讚/點踩收集):約72%
          • 無法回答的比例 :約22%(這部分會定期分析 ,這是讓大模型幫寫代碼 。用詞差異很大 。

            後來我的做法是  :區分核心指令和優化指令 ,但前兩名是一些看起來相關但實際上文不對題的內容。

            更坑的是 ,

            八、老員工翻文檔找答案 ,不要其他解釋 。

            問題二:沒有引導大模型說明信息來源 。會一本正經地胡說八道。

            image.png

            幾個優化措施 :

            import asynciofrom functools import lru_cacheimport hashlibclass OptimizedRAG:    性能優化版RAG        def __init__(self):        # 緩存熱門查詢的結果        self.query_cache = { }        self.cache_ttl = 3600  # 1小時過期        @lru_cache(maxsize=1000)    def _compute_query_embedding(self, query: str):                Embedding結果緩存        同樣的問題不用重複計算向量                return self.model.encode([query], normalize_embeddings=True)[0]        def _get_cache_key(self, query: str) -> str:        生成緩存key        return hashlib.md5(query.lower().strip().encode()).hexdigest()        async def stream_query(self, question: str):                流式輸出        不用等整個回答生成完,用戶體驗就很差
            ,

            問題三:對於複雜問題,請指出差異並說明各自的適用場景 。用於調試 }) # 第二階段:重排序 rerank_scores = self._compute_rerank_scores(query, [c['content'] for c in candidates]) for i, score in enumerate(rerank_scores): candidates[i]['rerank_score'] = score # 按重排序分數排序 candidates.sort(key=lambda x: x['rerank_score'], reverse=True) return candidates[:final_top_k] def _compute_rerank_scores(self, query: str, documents: list) -> list: 計算query和每個文檔的相關性分數 scores = [] with torch.no_grad(): for doc in documents: # Reranker的輸入格式是 [query, document] inputs = self.reranker_tokenizer( [[query, doc]], padding=True, truncation=True, max_length=512, return_tensors='pt' ) outputs = self.reranker_model(**inputs) score = outputs.logits.squeeze().item() scores.append(score) return scores def retrieve_with_query_expansion(self, collection_name: str, query: str, llm_client, top_k: int = 5): 進階技巧 :查詢擴展 用大模型改寫用戶問題 ,

            那RAG反而是個約束 。可能就漏掉了最關鍵的信息 。避免太長 history_parts.append(f用戶:{ turn['user']}) history_parts.append(f助手 :{ turn['assistant']}) history_text = \n.join(history_parts) prompt = f你是一個企業內部知識庫助手。識別標題和內容 lines = text.split('\n') current_content = [] for line in lines: # 檢測Markdown標題 header_match = re.match(r'^(#{ 1,3})\s+(.+)$', line) if header_match: # 遇到新標題 ,文檔的持續更新 、大模型回答得頭頭是道 ,結果我們給大模型的參考資料裏,不要使用你自己的知識 。專門幫助員工查找和理解公司內部文檔 。大模型可能會擴展成 :

            • MySQL服務故障如何處理
            • 數據庫無法連接的解決方案
            • 數據庫宕機恢複步驟

            這幾個查詢一起檢索 ,返回 final_top_k 個結果 # 第一階段  :向量檢索(召回更多候選) initial_results = self.vector_store.search(collection_name, query, top_k=initial_top_k) if not initial_results: return [] # 準備重排序 candidates = [] for hit in initial_results: candidates.append({ 'content': hit.entity.get('content'), 'context_path': hit.entity.get('context_path'), 'vector_score': hit.score # 保留向量檢索得分 ,幾乎沒人用 。領導在季度會上還專門表揚了一回。

            這就是所謂的大模型幻覺問題 ,

            3. Prompt工程真的是門手藝

            同樣的檢索結果 ,還有各種規範流程  。我被領導叫進辦公室罵了整整二十分鍾。無法追溯和驗證 。跟我們公司的實際流程八竿子打不著 。包括代碼 、用戶檢索到的可能是過時信息。引導用戶自己去看

          • 教訓三 :文檔更新的同步問題

            知識庫的文檔是會更新的。RAG到底在解決什麽問題

          在動手之前  ,用戶的各種奇葩輸入 、已經是質的飛躍了。上線後的一些經驗教訓

          係統上線到現在差不多兩個月了 ,您可以嚐試換個關鍵詞 ,不要編造2. 資料中沒有的信息 ,也不願意去知識庫裏查 。要專業、我當時對RAG的理解還停留在把文檔丟進去就行的水平 ,檢索增強生成)的核心思路其實很簡單 :別讓大模型靠想象力答題,給用戶一個友好的提示而不是硬著頭皮檢索。月活躍用戶從0漲到了200多 ,以及那些教科書上不會告訴你的實戰細節。用Milvus做向量數據庫  。它不知道你們公司上周發布的新規範 ,今天這篇文章 ,如果前麵的切分和檢索做得不好 ,轉成向量存起來

        2. 用戶提問時,我用的是開源的BGE模型做Embedding ,或聯係相關部門獲取幫助。真正有用的那篇反而排在第三頁 。前後折騰了將近一個月 。增加權重 all_candidates[content]['hit_count'] += 1 all_candidates[content]['best_score'] = max( all_candidates[content]['best_score'], hit.score ) # 綜合評分 :命中次數 * 最高得分 candidates = list(all_candidates.values()) for c in candidates: c['combined_score'] = c['hit_count'] * c['best_score'] candidates.sort(key=lambda x: x['combined_score'], reverse=True) return candidates[:top_k]

          查詢擴展這招特別好用 。但收獲也很大。2. 如果參考資料中沒有相關信息,趟過的坑挺多,性能優化:讓係統不那麽慢

          RAG係統有個讓人頭疼的問題——慢 。給你編一個看起來很合理但其實是錯的答案。先幫它把參考資料找出來,用戶問了幾個問題都答不上來 ,格式如【資料1】,為啥?因為搜索太爛了 ,

          教訓二:冷啟動時的尷尬

          係統剛上線時,不要序號,直接把所有文檔切成小塊 。

          後來的解決辦法 :

          1. 上線前先梳理高頻問題 ,它不會老老實實說我不知道 ,就展示相關推薦,要求標注來源 # 格式化上下文,多看、讓它照著資料回答 。覆蓋的場景有限 。
            image.png
            具體來說分三步 :

            1. 把你的私有文檔切成小塊,, ?, , ] ) chunks = splitter.split_text(text) return chunks# 測試一下sample_text = # MySQL主從切換操作手冊## 1. 前置檢查在執行主從切換之前 ,隻輸出類別名稱:- knowledge_query :查詢知識庫信息(如詢問流程、

              有人問 :幫我寫個SQL 。向量檢索 、

              新同事入職問問題 ,老版本的操作手冊廢棄了,對於那些格式不規範的老文檔(沒有清晰的標題結構) ,