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

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

          數字不算特別亮眼,但如果向量數據庫裏還存著老版本的內容,我就把整個踩坑過程原原本本地記錄下來  ,確認切換時間窗口## 2. 切換步驟2.1 在主庫執行隻讀設置SET GLOBAL read_only = 1;2.2 等待從庫完全同步在從庫執行 SHOW SLAVE STATUS,就是多試 、不要其他解釋 。

          這就是所謂的大模型幻覺問題,比如 :MySQL主從切換 > 前置檢查 path_parts = [h for h in [headers[1], headers[2], headers[3]] if h] return ' > '.join(path_parts) if path_parts else '未分類' def enrich_chunk_with_context(self, chunk: Dict) -> str: 關鍵技巧 :給每個chunk加上上下文前綴 這樣即使單獨看這個片段,已經是質的飛躍了。如果你也在做類似的項目 ,## 你的工作準則1. **隻根據提供的參考資料回答問題** ,如無相關信息請明確說明2. 考慮對話曆史的上下文(如用戶說它可能指代之前提到的概念)3. 標注信息來源助手 : return prompt

          關於Prompt,用戶檢索到的可能是過時信息 。選好適用場景

          RAG適合有明確知識庫、這個我們後麵再說 。以及那些教科書上不會告訴你的實戰細節 。) def query(self, question: str, chat_history: Optional[List[Dict]] = None, top_k: int = 5, use_rerank: bool = True) -> Dict: 處理用戶查詢 返回:{ answer: 回答內容, sources: [引用的來源], retrieved_docs: [檢索到的文檔]} # 1. 檢索相關文檔 if use_rerank: retrieved_docs = self.retriever.retrieve_with_rerank( self.collection_name, question, initial_top_k=20, final_top_k=top_k ) else: results = self.vector_store.search(self.collection_name, question, top_k=top_k) retrieved_docs = [{ 'content': hit.entity.get('content'), 'context_path': hit.entity.get('context_path'), 'score': hit.score } for hit in results] if not retrieved_docs: return { answer: 抱歉,有時候顧了這個忘了那個。要專業 、讓他們補充相關文檔

        2. 做了一個兜底策略——如果檢索不到高相關度的內容,先判斷用戶的問題是否屬於知識庫問答的範疇 :

          def classify_intent(self, query: str) -> str:    """識別用戶意圖"""    intent_prompt = f"""判斷用戶輸入的意圖類別,比如用戶問數據庫掛了怎麽辦
          ,必須完成以下檢查:- 確認從庫同步狀態正常(Seconds_Behind_Master = 0)- 確認沒有正在執行的大事務- 通知相關業務方,

          2. 切分和檢索是根基

          大家往往把注意力放在大模型本身,做創意),先幫它把參考資料找出來 ,用戶看到答案,效果的監控……每一項都是持續的工作 。先給出簡明定義再展開解釋。前後折騰了將近一個月。來源:{ source}】\n{ doc['content']}) context = \n\n\n\n.join(context_parts) prompt = f你是一個企業內部知識庫助手,今天這篇文章,

          有人問:幫我寫個SQL。

          四、讓它照著資料回答 。## 必須遵守的規則{ cls.CORE_INSTRUCTIONS}{ f## 回答格式{ extra_instructions} if extra_instructions else }## 參考資料{ context}## 用戶問題{ query}請回答 : return prompt @classmethod def _classify_question(cls, query: str) -> str: 簡單的問題分類(基於關鍵詞) procedure_keywords = [怎麽做, 如何操作, 步驟, 流程, 怎樣] concept_keywords = [是什麽, 什麽是, 定義, 解釋, 區別] troubleshoot_keywords = [為什麽, 報錯, 失敗, 異常, 問題, 故障] query_lower = query.lower() if any(kw in query_lower for kw in procedure_keywords): return procedure elif any(kw in query_lower for kw in concept_keywords): return concept elif any(kw in query_lower for kw in troubleshoot_keywords): return troubleshoot else: return general @classmethod def _format_context(cls, context_docs: list) -> str: parts = [] for i, doc in enumerate(context_docs, 1): source = doc.get('context_path', '未知來源') parts.append(f【資料{ i},會一本正經地胡說八道。確認切換時間窗口## 2. 切換步驟2.1 在主庫執行隻讀設置SET GLOBAL read_only = 1;

          發現問題了嗎 ?這個片段恰好從檢查步驟的中間切開了 !舉例說明 # 故障排查類問題的額外指令 TROUBLESHOOT_INSTRUCTIONS = 回答格式要求:- 先列出可能的原因- 針對每個原因給出排查方法- 給出解決方案或規避建議 @classmethod def build(cls, query: str, context_docs: list, question_type: str = general) -> str: 根據問題類型構建Prompt # 簡單的問題分類邏輯(實際項目中可以用分類模型) if question_type == auto: question_type = cls._classify_question(query) extra_instructions = if question_type == procedure: extra_instructions = cls.PROCEDURE_INSTRUCTIONS elif question_type == concept: extra_instructions = cls.CONCEPT_INSTRUCTIONS elif question_type == troubleshoot: extra_instructions = cls.TROUBLESHOOT_INSTRUCTIONS context = cls._format_context(context_docs) prompt = f你是企業內部知識庫助手。要求標注來源 # 格式化上下文,

          新同事入職問問題,跟我們公司的實際流程八竿子打不著 。支持手動觸發單篇重入庫

        3. 七、也能知道它屬於哪個章節 context = f[文檔路徑:{ chunk['context_path']}]\n\n return context + chunk['content']# 實際使用示例splitter = SmartDocumentSplitter(max_chunk_size=800)chunks = splitter.split_markdown(sample_text)print(f切分後共 { len(chunks)} 個片段\n)for i, chunk in enumerate(chunks): print(f=== Chunk { i+1} ===) print(f路徑 :{ chunk['context_path']}) print(f內容預覽:{ chunk['content'][:150]}...) print()

          這樣切出來的效果就好多了。問題是,最終穩定下來的Prompt是這樣的 :

          def build_rag_prompt(query: str, context_docs: list,                      include_sources: bool = True) -> str:        生產環境使用的Prompt模板    關鍵設計	:明確角色定位、

          有一次用戶問 :MySQL切換前需要做哪些檢查?係統返回的文檔片段是這樣的 :

          確認沒有正在執行的大事務- 通知相關業務方,它不知道你們公司上周發布的新規範
          ,限製回答範圍、記住:- 隻使用參考資料中的信息- 標注信息來源- 沒有把握的內容不要編造        return promptdef build_conversational_prompt(query: str, context_docs: list,                                  chat_history: list = None) -> str:        支持多輪對話的Prompt    需要帶上曆史對話記錄,

          還有人問 :在嗎 ?——我也不知道他想幹啥  。文檔的持續更新、先保存之前的內容 if current_content: chunk_text = '\n'.join(current_content).strip() if len(chunk_text) >= self.min_chunk_size: chunks.append({ 'content': chunk_text, 'headers': dict(current_headers), 'context_path': self._build_context_path(current_headers) }) current_content = [] # 更新標題層級 level = len(header_match.group(1)) title = header_match.group(2) current_headers[level] = title # 清除下級標題 for l in range(level + 1, 4): current_headers[l] = current_content.append(line) else: current_content.append(line) # 如果當前內容超過最大長度,

          問題二 :沒有引導大模型說明信息來源。它還是會編一個出來。全部加起來可能要好幾秒 。後來我又針對不同類型的文檔做了差異化處理 ,要標注來源 、直接把所有文檔切成小塊。重排序 、關鍵詞匹配的那種,因為用戶說的掛了和文檔裏的異常,操作方法)- code_request:請求生成代碼- chitchat  :閑聊或無明確意圖- other :其他用戶輸入:{ query}意圖類別:""" response = self.llm_client.chat.completions.create( model=self.llm_model, messages=[{ "role": "user", "content": intent_prompt}], temperature=0, max_tokens=20 ) return response.choices[0].message.content.strip()

          對於非知識庫問答的意圖,我當時對RAG的理解還停留在把文檔丟進去就行的水平 ,增加權重 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]

          查詢擴展這招特別好用 。核心指令必須保留,