戰(zhàn):構(gòu)建AI應(yīng)用的上下文模式(context-mode)設(shè)計(jì)指南)
在寫這篇文章之前我先把話說在前頭“context-mode”這個(gè)名字你在 GitHub、技術(shù)博客或者 AI 編程工具里大概率都見過但大多數(shù)文章把它當(dāng)作某個(gè)具體工具的一個(gè)開關(guān)一帶而過。這很可惜。因?yàn)椤吧舷挛哪J健辈皇悄骋粋€(gè)軟件的小功能它是一類系統(tǒng)的底層設(shè)計(jì)思想——只要你的程序需要“理解用戶當(dāng)時(shí)在干什么”就繞不開這個(gè)問題。我做過的幾個(gè)項(xiàng)目里凡是涉及代碼補(bǔ)全、命令行工具、甚至是內(nèi)部文檔問答的最終都會(huì)回到“context-mode”這個(gè)核心概念上。這篇文章不打算講某一個(gè)具體產(chǎn)品怎么用而是想把我的設(shè)計(jì)思路和踩坑記錄完整地捋一遍給你一套可以直接參考的上下文模式實(shí)踐方案。1. 別急著寫代碼先搞清楚 context-mode 到底解決什么問題1.1 一個(gè)讓很多開發(fā)者抓狂的典型場(chǎng)景先給你還原一下我最初遇到這個(gè)問題的現(xiàn)場(chǎng)。當(dāng)時(shí)我在做一個(gè)面向開發(fā)者的內(nèi)部問答機(jī)器人技術(shù)棧是 LLM RAG向量庫(kù)、Prompt 模板都搭好了。結(jié)果試運(yùn)行的時(shí)候被同事連續(xù)幾個(gè)問題問懵了。他先問我“這段代碼里的 session 是什么意思”我答了然后他緊接著問“那這個(gè) session 的過期時(shí)間你剛才是從哪看到的”我就答不上來了——因?yàn)槲业?Prompt 體系里根本就不知道“剛才”發(fā)生了什么。問題的本質(zhì)不是模型能力不夠而是系統(tǒng)沒有把“當(dāng)前對(duì)話的上下文”和“代碼庫(kù)的上下文”建立關(guān)聯(lián)。在這個(gè)場(chǎng)景里每一次用戶提問都像是一個(gè)獨(dú)立的世界模型雖然能記住聊天窗口里的文字但它不知道該去代碼庫(kù)里找哪一部分信息、用哪些信息組合成答案。這就是典型的上下文缺失。1.2 context-mode 的正確定義“上下文模式”不是單指某一個(gè)變量、某一層緩存或者某一段 Prompt 拼接。它是一個(gè)系統(tǒng)級(jí)別的策略用來回答三個(gè)問題當(dāng)前任務(wù)是什么、需要哪些信息、這些信息從哪來、以什么優(yōu)先級(jí)組合。我更喜歡把它理解成“系統(tǒng)根據(jù)當(dāng)前任務(wù)意圖動(dòng)態(tài)調(diào)整信息采集、組織與注入策略的能力”。它通常包含四個(gè)組成部分感知層從交互、文件系統(tǒng)、命令行參數(shù)、歷史記錄等渠道收集原始信號(hào)。篩選層根據(jù)當(dāng)前模式規(guī)則過濾掉與任務(wù)無關(guān)的信息。組織層將篩選出的信息按順序、按權(quán)重組裝成模型可用的格式比如 Prompt。反饋層把模型輸出中的有效信息回寫進(jìn)上下文庫(kù)作為下一次交互的輸入。這四個(gè)部分合在一起才是一個(gè)完整的 context-mode。只做其中一兩步比如單純把文件內(nèi)容全塞進(jìn) Prompt那不叫上下文模式那叫上下文堆砌。1.3 為什么 2025 年這個(gè)設(shè)計(jì)比以往更重要你別看“上下文”三個(gè)字很基礎(chǔ)它的重要性是這兩年才被放大的。三個(gè)原因第一模型的上下文窗口變大了但成本也跟著變大了。過去的模型只有幾百 token 可用你必須把上下文當(dāng)成珍寶來分配現(xiàn)在的模型窗口動(dòng)輒幾十萬 token很多人又開始偷懶什么都往里塞。但實(shí)際測(cè)試下來垃圾信息不僅浪費(fèi)預(yù)算還會(huì)顯著拉低模型對(duì)關(guān)鍵信息的關(guān)注度。好的 context-mode 恰恰是在“信息充足”和“信息精簡(jiǎn)”之間找平衡。第二AI 編程工具開始深入開發(fā)工作流。從代碼自動(dòng)補(bǔ)全到自動(dòng)審查、自動(dòng)重構(gòu)工具需要理解的不再是“這個(gè)函數(shù)怎么調(diào)”而是“這個(gè)倉(cāng)庫(kù)的結(jié)構(gòu)、團(tuán)隊(duì)的規(guī)范、當(dāng)前的改動(dòng)目標(biāo)”。沒有上下文模式工具就是個(gè)只會(huì)接話茬的聊天機(jī)器人。第三多步驟工作流和 Agent 的興起?,F(xiàn)在的 Agent 要自主決定調(diào)用哪些工具、執(zhí)行哪些操作每一步的選擇都要依賴上一步的上下文。context-mode 成了一個(gè)核心的“狀態(tài)管理”機(jī)制它本質(zhì)上是在幫你維護(hù) Agent 的短期記憶和工作記憶。1.4 適合誰看能解決什么問題這篇文章主要寫給三類人正在做 AI 應(yīng)用、RAG 系統(tǒng)、Agent 開發(fā)發(fā)現(xiàn)模型回答質(zhì)量忽高忽低的開發(fā)者。做命令行工具、編輯器插件希望工具能感知用戶當(dāng)前位置和操作場(chǎng)景的開發(fā)者。純粹想理解“上下文工程”這個(gè)概念想知道哪些是概念炒作、哪些是能落地的核心功夫的讀者。如果你只是想知道某個(gè)具體軟件怎么開 context-mode建議直接看官方文檔但如果你想搞明白“為什么別人家的 AI 工具那么懂我自己的就那么傻”這篇文章會(huì)給你所有答案。2. 上下文模式的核心設(shè)計(jì)思路分層、分類與流轉(zhuǎn)2.1 先給你的上下文分個(gè)層我踩過最大的坑就是“把所有上下文都當(dāng)成同樣的東西處理”。文件內(nèi)容、對(duì)話歷史、用戶輸入、系統(tǒng)日志它們的時(shí)效性、重要性和體積完全不同混在一起處理既沒法做精確篩選也會(huì)讓 Prompt 變得臃腫。我的建議是把上下文分成三層全局層Global Context與具體任務(wù)無關(guān)、但長(zhǎng)期有效的穩(wěn)定信息。對(duì)應(yīng)到代碼場(chǎng)景包括項(xiàng)目整體架構(gòu)說明書、技術(shù)棧版本、編碼規(guī)范、代碼風(fēng)格指南。在工具場(chǎng)景里還包括工具的全局配置、用戶偏好。這一層的特點(diǎn)是“幾乎不變”可以預(yù)先加載、長(zhǎng)期緩存。會(huì)話層Session Context從當(dāng)前對(duì)話或當(dāng)前任務(wù)開始后產(chǎn)生的動(dòng)態(tài)信息。包括用戶在終端里執(zhí)行過的命令、AI 和用戶的對(duì)話記錄、當(dāng)前工作目錄的變更過程、已經(jīng)確認(rèn)過的決策。這一層的特點(diǎn)是“持續(xù)增長(zhǎng)”必須控制它的規(guī)模否則會(huì)話越長(zhǎng)上下文越亂。局部層Local Context完成當(dāng)前一步任務(wù)所必需的即時(shí)信息。比如當(dāng)前正在編輯的文件內(nèi)容、git diff 的結(jié)果、某次 API 調(diào)用報(bào)錯(cuò)的完整堆棧。這一層的特點(diǎn)是“強(qiáng)相關(guān)、短時(shí)效”優(yōu)先級(jí)最高但也最容易過期。三者的關(guān)系像一個(gè)大水池。全局層是水池底部的水持續(xù)但不變會(huì)話層是不斷流入的水會(huì)漲但是有原材料局部層是水面上的漣漪新鮮但瞬間就會(huì)消失。我的缺失就是不知道該怎么把這三層水按比例取出來倒進(jìn)模型里。2.2 上下文分類按內(nèi)容類型拆解除了按層次分我建議再按內(nèi)容類型做分類。這個(gè)分類直接影響“篩選層”的實(shí)現(xiàn)方式。我常用的分類體系長(zhǎng)這樣類型說明示例推薦處理方式指令性上下文用戶明確的意圖和約束“按 PEP8 風(fēng)格格式化”大語言模型輸入的最前端提高指令優(yōu)先級(jí)事實(shí)性上下文客觀存在的數(shù)據(jù)文件路徑、依賴版本、配置項(xiàng)結(jié)構(gòu)化提取存成字段/元數(shù)據(jù)歷史性上下文過去的狀態(tài)和決策之前的輸出、修改記錄摘要化只保留結(jié)論和關(guān)鍵決策點(diǎn)環(huán)境性上下文當(dāng)前運(yùn)行環(huán)境的信號(hào)操作系統(tǒng)、當(dāng)前 git 分支、語言版本按需加載不注入時(shí)不要帶上推理性上下文模型或系統(tǒng)進(jìn)行的中間思考Agent 的中間步驟、分析結(jié)果動(dòng)態(tài)管理及時(shí)清理避免污染這個(gè)分類表看著簡(jiǎn)單但有了它之后你寫篩選規(guī)則才有的放矢。比如“歷史性上下文”我會(huì)用摘要壓縮而不是直接拼接“環(huán)境性上下文”只在特定模式下才允許注入。沒有分類任何一條上下文你都舍不得扔最后 Prompt 里什么都有也什么都沒用。2.3 模式切換context-mode 的“動(dòng)態(tài)性”從哪來“上下文模式”最核心的設(shè)計(jì)就是“可以切換”。一個(gè)只有一種上下文策略的系統(tǒng)根本談不上 mode。我在實(shí)際項(xiàng)目里用過的模式大致有這幾種default 模式均衡的上下文策略適合日常通用問答。注入全局層 最近的會(huì)話層。debug 模式為排查問題設(shè)計(jì)。額外注入堆棧信息、詳細(xì)日志、依賴的源碼實(shí)現(xiàn)。此時(shí)事實(shí)性上下文優(yōu)先于指令性上下文。review 模式為代碼審查設(shè)計(jì)。注入 git diff、相關(guān)文件的變更歷史、團(tuán)隊(duì)規(guī)范文檔重點(diǎn)偏向歷史性上下文和指令性上下文。refactor 模式為重構(gòu)設(shè)計(jì)。注入文件依賴圖、API 調(diào)用鏈、測(cè)試用例側(cè)重結(jié)構(gòu)性和語義性信息。每種模式下同一個(gè)信息的權(quán)重都要重新計(jì)算。比如“編譯錯(cuò)誤日志”在 default 模式下權(quán)重可以很低但在 debug 模式下必須放在 Prompt 最顯眼的位置。這種“按模式做權(quán)重調(diào)整”的設(shè)計(jì)是 context-mode 能提升模型輸出質(zhì)量的關(guān)鍵。2.4 數(shù)據(jù)來源上下文不是天上掉下來的很多初學(xué)者會(huì)以為上下文就是“把數(shù)據(jù)庫(kù)里的字段讀出來拼成字符串”。真實(shí)的來源要復(fù)雜得多你至少要考慮以下四類用戶輸入和行為信號(hào)包括 chat 內(nèi)容、終端命令、光標(biāo)位置、選中的文本、操作頻率。工作區(qū)靜態(tài)數(shù)據(jù)文件目錄樹、配置文件、依賴清單、注釋文檔、API 定義。動(dòng)態(tài)運(yùn)行數(shù)據(jù)構(gòu)建日志、測(cè)試結(jié)果、報(bào)錯(cuò)堆棧、環(huán)境變量、進(jìn)程狀態(tài)。歷史沉淀數(shù)據(jù)過去對(duì)話的總結(jié)、以前的代碼提交、已解決的問題庫(kù)。在 architecture 上我習(xí)慣用事件總線或消息隊(duì)列去收集這些信號(hào)然后交給 context manager 統(tǒng)一處理。這種設(shè)計(jì)的好處是各數(shù)據(jù)源可以獨(dú)立擴(kuò)展比如某天你想接入一個(gè)新的監(jiān)控平臺(tái)只需要新增一個(gè)信號(hào)采集器不用改核心邏輯。3. 手寫一個(gè)最小可用的 context-mode 系統(tǒng)3.1 工具選型與環(huán)境準(zhǔn)備紙上談兵再多不如自己擼一個(gè)能跑的東西。下面我會(huì)帶你一步步實(shí)現(xiàn)一個(gè)“最小可用”的 context-mode 管理器。我們的目的在于展示核心抽象而不是寫出生產(chǎn)級(jí)代碼所以選型上不需要很重的框架。我建議的選型如下Python 3.11 以上用 dataclass 做數(shù)據(jù)模型用 asyncio 處理并發(fā)采集。存儲(chǔ)上先用內(nèi)存dict夠用就行后續(xù)可以替換成 Redis 或 SQLite。語言模型的接入先用一個(gè)“假模型”輸出 Prompt 內(nèi)容方便你直觀地看到上下文是怎么組裝的。整個(gè)項(xiàng)目我建議在一個(gè)文件里寫完這樣你能更快理解各模塊的耦合關(guān)系。文件結(jié)構(gòu)如下context_mode_demo/ ├── main.py # 入口和測(cè)試 ├── context_manager.py # 核心管理器 ├── models.py # 數(shù)據(jù)模型定義 └── config.yaml # 模式配置3.2 數(shù)據(jù)模型定義上下文數(shù)據(jù)可能來自不同渠道但最終都需要統(tǒng)一的格式。我用了ContextDocument類# models.py from dataclasses import dataclass, field import time import uuid dataclass class ContextDocument: doc_type: str # 例如: file, log, dialog, metadata content: str source: str # 例如: editor://main.py, cmd://ls metadata: dict field(default_factorydict) mode_tags: list[str] field(default_factorylist) weight: float 1.0 created_at: float field(default_factorytime.time) def to_prompt_segment(self) - str: header f## [{self.doc_type}] {self.source} meta fmetadata: {self.metadata} if self.metadata else return f{header}\n{meta}\n{self.content}\n這里有一個(gè)容易被忽略的點(diǎn)mode_tags字段。它是我們實(shí)現(xiàn)“模式切換過濾”的關(guān)鍵。每一條上下文文檔在進(jìn)入系統(tǒng)時(shí)就為他打好標(biāo)簽標(biāo)記這個(gè)文檔在哪些模式下可用。比如“git diff”的文檔帶有[review, debug]兩個(gè) tag那么在 default 模式下就不會(huì)被注入。3.3 核心管理器采集、篩選、注入一條龍核心管理器我分成三個(gè)方法collect()、filter_by_mode()、build_prompt()。這是最樸素也最清晰的抽象。# context_manager.py from models import ContextDocument from typing import Optional class ContextModeManager: def __init__(self, config: dict): self.config config self.global_docs: list[ContextDocument] [] self.session_docs: list[ContextDocument] [] self.local_docs: list[ContextDocument] [] self.mode default def set_mode(self, mode: str): if mode not in self.config[modes]: raise ValueError(f未知模式: {mode}) self.mode mode def add_document(self, doc: ContextDocument, layer: str local): if layer global: self.global_docs.append(doc) elif layer session: self.session_docs.append(doc) else: self.local_docs.append(doc) def filter_by_mode(self, docs: list[ContextDocument]): mode_config self.config[modes][self.mode] include_tags mode_config.get(include_tags, []) if include_tags: return [d for d in docs if set(d.mode_tags) set(include_tags)] # 沒設(shè)置 include_tags 時(shí)用文檔權(quán)重做排序裁剪 sorted_docs sorted(docs, keylambda d: d.weight, reverseTrue) return sorted_docs[: mode_config.get(max_docs, 10)] def build_prompt(self, user_query: str) - str: layers [] if self.config[modes][self.mode].get(use_global, True): layers.extend(self.filter_by_mode(self.global_docs)) if self.config[modes][self.mode].get(use_session, True): layers.extend(self.filter_by_mode(self.session_docs)) if self.config[modes][self.mode].get(use_local, True): layers.extend(self.filter_by_mode(self.local_docs)) prompt 你是我的編程助手。請(qǐng)結(jié)合以下上下文回答我的問題。\n\n for doc in layers: prompt doc.to_prompt_segment() prompt \n prompt f用戶問題: {user_query}\n return prompt代碼邏輯不復(fù)雜但有幾個(gè)地方我要特別提示你權(quán)重排序而不是簡(jiǎn)單拼接。哪怕做的是最簡(jiǎn)版也不要只按時(shí)間順序排上下文。我給每條文檔打了一個(gè)weight字段優(yōu)先注入高權(quán)重的文檔。分層的順序有講究。在我的實(shí)現(xiàn)里全局層在前、會(huì)話層居中、局部層最后。為什么因?yàn)榫植繉拥南嚓P(guān)性最強(qiáng)時(shí)效性也強(qiáng)放在 Prompt 靠后的位置正好能銜接用戶問題全局層是背景知識(shí)要放在最前面讓模型先“入腦”。這個(gè)順序我做過對(duì)照測(cè)試顛倒的話輸出質(zhì)量會(huì)下降。不要忽略 mode_config 的開關(guān)。像use_global這樣的配置看似多余但它給調(diào)用方提供了自由度。比如你在做一次純代碼審查根本不需要加載全局風(fēng)格指南關(guān)掉它反而能提速。3.4 模式配置文件怎么寫上面說的模式切換在config.yaml里的樣子是這樣的modes: default: use_global: true use_session: true use_local: true include_tags: [] max_docs: 10 debug: use_global: false use_session: true use_local: true include_tags: [debug, log, stack] max_docs: 8 review: use_global: false use_session: true use_local: true include_tags: [diff, history, style] max_docs: 15 refactor: use_global: false use_session: false use_local: true include_tags: [dependency, test, api] max_docs: 20這里我想多一句嘴很多開發(fā)者過度追求 max_docs 越大越好其實(shí)不對(duì)。上下文不是越大越強(qiáng)越大越容易產(chǎn)生“注意力稀釋”。以 GPT-4 級(jí)別的模型為例推薦有效上下文密度是“最多 50% 的窗口被背景信息占據(jù)其余留給對(duì)話和用戶新輸入”。我自己的經(jīng)驗(yàn)是每個(gè)模式默認(rèn)不要超過 15 個(gè)文檔。3.5 一次完整的前后調(diào)用流程有了上面這些代碼我們模擬一個(gè)場(chǎng)景用戶當(dāng)前在寫auth.py然后問了一句“幫我看看為什么登錄接口一直返回 401”。流程如下# main.py from models import ContextDocument from context_manager import ContextModeManager import yaml with open(config.yaml) as f: config yaml.safe_load(f) mgr ContextModeManager(config) mgr.set_mode(debug) # 采集模擬從編輯器插件收集上下文 mgr.add_document(ContextDocument( doc_typefile, content# auth.py 的核心代碼..., sourceeditor://auth.py, mode_tags[debug, review], weight0.9, ), layerlocal) mgr.add_document(ContextDocument( doc_typelog, contentHTTP 401 Unauthorized ... timestamp2025-01-15T10:00:00, sourcelog://api-service, mode_tags[debug, log], weight0.95, ), layerlocal) mgr.add_document(ContextDocument( doc_typedialog, content之前確認(rèn)過使用 JWT 做認(rèn)證私鑰可能存在 secrets/ 下, sourcedialog://session, mode_tags[session], weight0.8, ), layersession) prompt mgr.build_prompt(為什么登錄接口一直返回 401) print(prompt)運(yùn)行之后你會(huì)看到 Prompt 里有代碼片段、報(bào)錯(cuò)日志、歷史對(duì)話結(jié)論而且順序是“代碼 → 日志 → 歷史結(jié)論 → 用戶問題”。這種結(jié)構(gòu)化的 Prompt 比把整個(gè)項(xiàng)目塞進(jìn)去要合適得多。4. 工程化實(shí)踐把 context-mode 接入真實(shí)場(chǎng)景4.1 接入 AI 編程助手以 VSCode 插件為例子手寫代碼是第一步真正能用起來是第二步。我在實(shí)際開發(fā)中把一個(gè) Python 寫的 context-mode 服務(wù)封裝成了一個(gè)本地 HTTP 接口然后被 VSCode 插件調(diào)用。插件在用戶保存文件、切換標(biāo)簽、執(zhí)行命令時(shí)采集信號(hào)發(fā)給本地的 context-mode 服務(wù)。具體流程是插件監(jiān)聽編輯器事件把文件路徑、文檔選中區(qū)域、光標(biāo)偏移量發(fā)給本地服務(wù)。本地服務(wù)根據(jù)當(dāng)前模式由用戶在下拉框選擇調(diào)用add_document()存入上下文庫(kù)。用戶發(fā)起提問時(shí)插件把用戶輸入發(fā)給/generate接口服務(wù)端調(diào)用build_prompt()再喂給模型 API把結(jié)果返回給插件。這個(gè)架構(gòu)的好處是把“上下文管理”和“ UI 展示”解耦了。你想換編輯器、換模型都不影響核心邏輯。我在生產(chǎn)環(huán)境跑了大半年穩(wěn)定性和響應(yīng)速度都達(dá)標(biāo)。4.2 接入命令行工具多環(huán)境切換的上下文模式另一個(gè)真實(shí)的落地場(chǎng)景是 CLI 工具。我有一個(gè)多環(huán)境部署工具用戶經(jīng)常會(huì)問“為什么在 staging 環(huán)境跑測(cè)試失敗”這種問題在沒有上下文模式的時(shí)候特別難回答因?yàn)楣ぞ卟恢烙脩舢?dāng)前在哪個(gè)目錄、當(dāng)前在哪個(gè)環(huán)境、最近執(zhí)行了哪些命令。我加入 context-mode 后的做法是在終端初始化腳本里注冊(cè)一個(gè)context_hook每次用戶輸入命令前自動(dòng)收集當(dāng)前目錄、環(huán)境變量ENVIRONMENT、最近 git 分支。當(dāng)用戶輸入 “為什么 staging 掛了” 時(shí)CLI 自動(dòng)識(shí)別“staging 環(huán)境”這個(gè)意圖將模式切換為debug并把 staging 的日志上下文、最近部署記錄的 tag 注入到 Prompt。默認(rèn)沒有環(huán)境關(guān)鍵詞時(shí)走default模式只注入當(dāng)前目錄的說明和最近的命令記錄。這套方案上線后工具回答環(huán)境相關(guān)問題的準(zhǔn)確率大幅提高原因很簡(jiǎn)單以前模型靠猜現(xiàn)在它有了明確的上下文來源路徑。4.3 上下文緩存與性能優(yōu)化context-mode 不是只拼 Prompt它還涉及性能調(diào)優(yōu)。如果你每次請(qǐng)求都重新掃描整個(gè)項(xiàng)目的文件樹工具肯定慢到?jīng)]法用。我實(shí)踐的優(yōu)化手段有三板斧分層緩存全局層內(nèi)容可以做成靜態(tài)緩存只有在項(xiàng)目結(jié)構(gòu)變化時(shí)才失效。會(huì)話層可以保留增量記錄而不是每輪對(duì)話都全量重組。異步預(yù)取編輯器一打開項(xiàng)目后臺(tái)就把 package.json、README、目錄樹等基礎(chǔ)上下文預(yù)加載到本地服務(wù)的內(nèi)存里。用戶真正提問時(shí)省去了掃描時(shí)間。摘要降采樣當(dāng)會(huì)話層文檔數(shù)量超過閾值用模型把之前的會(huì)話內(nèi)容壓縮成摘要去掉過程細(xì)節(jié)只留結(jié)論。這樣即使會(huì)話很長(zhǎng)Prompt 也不會(huì)爆炸。性能這事我記得有一個(gè)數(shù)據(jù)可以參考在普通筆記本上如果你的項(xiàng)目是 1 萬文件以下本地服務(wù)單次構(gòu)建 Prompt 的耗時(shí)應(yīng)該控制在 50 ms 以內(nèi)。超過這個(gè)數(shù)就得檢查是不是有冗余掃描。4.4 安全與隱私context-mode 很容易被忽略的風(fēng)險(xiǎn)上下文模式投入使用時(shí)還有一類問題必須提前想清楚數(shù)據(jù)權(quán)限。為什么這么說因?yàn)?context-mode 的定位是“把盡可能相關(guān)的信息收集起來”但收集的過程中很可能把不該暴露的信息也塞進(jìn)去了。比如你在 debug 模式下加載了.env文件的堆棧日志然后 Prompt 里明晃晃地帶著數(shù)據(jù)庫(kù)密碼發(fā)給了外部模型 API。這是真實(shí)發(fā)生過的安全事故我當(dāng)時(shí)在后端加了非常多過濾規(guī)則才堵住漏洞。我給你三個(gè)安全建議敏感信息過濾器在add_document()里做正則檢查命中.env、password、secret、aws_access_key_id等模式的文檔直接丟棄或者做脫敏處理只保留類型不保留值。按模式授權(quán)在配置文件里加一層allowed_sources。比如 debug 模式不允許訪問某些財(cái)務(wù)目錄、review 模式不允許訪問生產(chǎn)環(huán)境配置。用戶可見的上下文預(yù)覽在 UI 側(cè)讓用戶看到“即將發(fā)送給模型的上下文清單”如果不滿意可以直接關(guān)閉某些選項(xiàng)。這既是用戶體驗(yàn)問題也是法律合規(guī)問題尤其是你的工具涉及企業(yè)客戶的時(shí)候。5. 常見問題、排查技巧與經(jīng)驗(yàn)總結(jié)5.1 上下文過載模型開始“裝傻”現(xiàn)象模型明明看到了所有信息但還是回答一些沒用的廢話甚至忽略掉 Prompt 里的關(guān)鍵代碼。原因大多時(shí)候不是模型傻而是上下文里的噪聲超過了信號(hào)。當(dāng)輸入中無關(guān)文件、無意義日志占比過高時(shí)模型會(huì)“注意力渙散”。排查方法在build_prompt()前后記錄 token 數(shù)和文檔數(shù)。手動(dòng)拼接并打印 Prompt看看里面有沒有占位垃圾。對(duì)照不同模式測(cè)試“去除某一層上下文”后輸出質(zhì)量的變化。我的經(jīng)驗(yàn)是調(diào) Prompt 之前先檢查上下文篩選規(guī)則。很多質(zhì)量問題的根子在采集和過濾環(huán)節(jié)不是模型指令寫得不夠好。5.2 上下文過期模型還在用舊信息現(xiàn)象用戶已經(jīng)改了代碼模型還在按舊代碼回答。這在編輯器場(chǎng)景里非常常見。原因緩存層做得太好導(dǎo)致 local 層更新不及時(shí)或者文檔沒有帶時(shí)間戳篩選時(shí)沒有考慮時(shí)效性。解決辦法在ContextDocument里把created_at納入排序字段filter_by_mode返回時(shí)按“時(shí)間衰減 權(quán)重”排序。文件類文檔必須在文件保存事件中觸發(fā)更新不能只在打開文件時(shí)加載一次。關(guān)鍵配置變化時(shí)要主動(dòng)清空會(huì)話層緩存比如用戶切換了 Python 版本或改了環(huán)境變量。5.3 多模式切換失敗系統(tǒng)死活在 default 模式現(xiàn)象配置了好幾個(gè)模式但切換時(shí)不生效debug 模式下還是不加載日志。原因多半是模式識(shí)別層沒有正確觸發(fā)。比如你想讓系統(tǒng)根據(jù)用戶的自然語言自動(dòng)切換模式就必須要有意圖識(shí)別模塊而不只是依賴用戶手動(dòng)點(diǎn)按鈕。解決辦法手動(dòng)切換模式時(shí)要把Set-Mode事件傳播到所有上下文采集器避免有的采集器還在按舊模式跑。自動(dòng)切換時(shí)我推薦給每個(gè)模式定義幾個(gè)“觸發(fā)關(guān)鍵詞/規(guī)則”。例如 debug 模式的觸發(fā)規(guī)則包含“報(bào)錯(cuò)”“失敗”“Exception”“stack trace”等詞的提問。規(guī)則匹配不到時(shí)再回退到 default 模式。5.4 上下文模式與 RAG 的關(guān)系很多做 AI 應(yīng)用的朋友會(huì)問context-mode 和 RAG 到底是不是一個(gè)東西這個(gè)問題我在前文沒有展開這里詳細(xì)說一下。它們的關(guān)系是context-mode 是上層策略RAG 是底層檢索手段之一。RAG 解決的是“從大語料庫(kù)中找到相關(guān)片段”的問題而 context-mode 解決的是“找出來的片段以及系統(tǒng)內(nèi)已有的其他信息如何組織起來、如何按任務(wù)調(diào)整優(yōu)先級(jí)”的問題。在實(shí)際工程里RAG 檢索出來的文檔會(huì)被當(dāng)成ContextDocument的一種放入local_docs層然后打上mode_tags再交給filter_by_mode和build_prompt。如果你的系統(tǒng)只有一個(gè) RAG 檢索然后直接拼接那你還缺一個(gè) context-mode 的殼。5.5 我的一些個(gè)人體會(huì)踩過這么多坑之后我最想分享的一條經(jīng)驗(yàn)是別把 context-mode 做成一個(gè)“萬能垃圾回收站”。它的作用是幫模型聚焦而不是幫模型記憶所有事情。剛開始做的時(shí)候我總擔(dān)心漏掉信息什么上下文都往里面裝結(jié)果模型的回答變得越來越“泛”越來越?jīng)]脾氣。后來痛下決心做減法每個(gè)模式下只保留最核心的 8-12 條上下文回答質(zhì)量反而肉眼可見地回升了。另外一點(diǎn)是關(guān)于團(tuán)隊(duì)協(xié)作的。如果你在一個(gè)團(tuán)隊(duì)里做這個(gè)功能一定要盡早定義好“上下文文檔格式”和“模式標(biāo)簽規(guī)范”。這個(gè)格式最好有一套顯式 schema比如用 JSON Schema 或者 protobuf 定義。因?yàn)樯舷挛膩碓捶浅6嗖寮⒚钚?、后臺(tái)服務(wù)各自都在采集沒有統(tǒng)一規(guī)范的話過濾層根本沒法寫。等你把這一步做扎實(shí)了后面的模式擴(kuò)展、新數(shù)據(jù)源接入都會(huì)順暢很多。這篇文章從概念、設(shè)計(jì)到實(shí)現(xiàn)、落地都過了一遍沒有藏著掖著。代碼片段你可以直接拿去改配置文件也給了參考。就到這里。