【AI大模型】万字长文讲透 RAG 在实际落地场景中的优化

告别手动标注!PDMS NakiToolkit插件安装与初体验:以Pipeline工具为例 本文详细介绍了PDMS NakiToolkit插件的安装与使用,特别是其Pipeline工具如何通过自动化标注和材料统计功能大幅提升三维工厂设计效率。从环境准备到实战演示,帮助工程师告别繁琐的手动标注工作,实现项目交付周期的大幅缩短。 阅读详情

前言

在过去两年中,检索增强生成(RAG,Retrieval-Augmented Generation)技术逐渐成为提升智能体的核心组成部分。通过结合检索与生成的双重能力,RAG能够引入外部知识,从而为大模型在复杂场景中的应用提供更多可能性。但是在实际落地场景中,往往会存在检索准确率低,噪音干扰多,召回完整性,专业性不够,导致LLM幻觉严重的问题。本文将聚焦RAG在实际落地场景中的知识加工和检索细节,如何去优化RAG Pineline链路,最终提升召回准确率。

快速搭建一个RAG智能问答应用很简单,但是在实际业务场景落地还需要做大量的准备工作。

1、RAG关键流程源码解读

主要分为知识加工和RAG 部分关键流程:

1. 知识加工

知识加载 -> 知识切片 -> 信息抽取 -> 知识加工(embedding/graph/keywords) -> 知识存储

  • 知识加载
# 知识工厂进行实例化
KnowledgeFactory -> create() -> load() -> Document
- knowledge
- markdown
- pdf
- docx
- txt
- html
- pptx
- url
- ...

如何扩展:

class Knowledge(ABC):
    def load(self) -> List[Document]:
        """Load knowledge from data loader."""
    @classmethod
    def document_type(cls) -> Any:
        """Get document type."""
    def support_chunk_strategy(cls) -> List[ChunkStrategy]:
        """Return supported chunk strategy."""
        return [
            ChunkStrategy.CHUNK_BY_SIZE,
            ChunkStrategy.CHUNK_BY_PAGE,
            ChunkStrategy.CHUNK_BY_PARAGRAPH,
            ChunkStrategy.CHUNK_BY_MARKDOWN_HEADER,
            ChunkStrategy.CHUNK_BY_SEPARATOR,
        ]
    @classmethod
    def default_chunk_strategy(cls) -> ChunkStrategy:
        """Return default chunk strategy.

        Returns:
            ChunkStrategy: default chunk strategy
        """
        return ChunkStrategy.CHUNK_BY_SIZE
  • 知识切片

  • ChunkManager: 通过加载后的知识数据,根据用户指定的分片策略和分片参数路由到对应的分片处理器进行分配。

class ChunkManager:
    """Manager for chunks."""

    def __init__(
        self,
        knowledge: Knowledge,
        chunk_parameter: Optional[ChunkParameters] = None,
        extractor: Optional[Extractor] = None,
    ):
        """Create a new ChunkManager with the given knowledge.

        Args:
            knowledge: (Knowledge) Knowledge datasource.
            chunk_parameter: (Optional[ChunkParameter]) Chunk parameter.
            extractor: (Optional[Extractor]) Extractor to use for summarization.
        """
        self._knowledge = knowledge

        self._extractor = extractor
        self._chunk_parameters = chunk_parameter or ChunkParameters()
        self._chunk_strategy = (
            chunk_parameter.chunk_strategy
            if chunk_parameter and chunk_parameter.chunk_strategy
            else self._knowledge.default_chunk_strategy().name
        )
        self._text_splitter = self._chunk_parameters.text_splitter
        self._splitter_type = self._chunk_parameters.splitter_type

如何扩展:如果你想在界面上自定义一个新的分片策略

  • 新增切片策略

  • 新增Splitter实现逻辑

class ChunkStrategy(Enum):
    """Chunk Strategy Enum."""

    CHUNK_BY_SIZE: _STRATEGY_ENUM_TYPE = (
        RecursiveCharacterTextSplitter,
        [
            {
                "param_name": "chunk_size",
                "param_type": "int",
                "default_value": 512,
                "description": "The size of the data chunks used in processing.",
            },
            {
                "param_name": "chunk_overlap",
                "param_type": "int",
                "default_value": 50,
                "description": "The amount of overlap between adjacent data chunks.",
            },
        ],
        "chunk size",
        "split document by chunk size",
    )
    CHUNK_BY_PAGE: _STRATEGY_ENUM_TYPE = (
        PageTextSplitter,
        [],
        "page",
        "split document by page",
    )
    CHUNK_BY_PARAGRAPH: _STRATEGY_ENUM_TYPE = (
        ParagraphTextSplitter,
        [
            {
                "param_name": "separator",
                "param_type": "string",
                "default_value": "\\n",
                "description": "paragraph separator",
            }
        ],
        "paragraph",
        "split document by paragraph",
    )
    CHUNK_BY_SEPARATOR: _STRATEGY_ENUM_TYPE = (
        SeparatorTextSplitter,
        [
            {
                "param_name": "separator",
                "param_type": "string",
                "default_value": "\\n",
                "description": "chunk separator",
            },
            {
                "param_name": "enable_merge",
                "param_type": "boolean",
                "default_value": False,
                "description": "Whether to merge according to the chunk_size after "
                "splitting by the separator.",
            },
        ],
        "separator",
        "split document by separator",
    )
    CHUNK_BY_MARKDOWN_HEADER: _STRATEGY_ENUM_TYPE = (
        MarkdownHeaderTextSplitter,
        [],
        "markdown header",
        "split document by markdown header",
    )
  • 知识抽取

  • 向量抽取 -> embedding, 实现`Embeddings`接口
    
@abstractmethod
    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        """Embed search docs."""

    @abstractmethod
    def embed_query(self, text: str) -> List[float]:
        """Embed query text."""

    async def aembed_documents(self, texts: List[str]) -> List[List[float]]:
        """Asynchronous Embed search docs."""
        return await asyncio.get_running_loop().run_in_executor(
            None, self.embed_documents, texts
        )

    async def aembed_query(self, text: str) -> List[float]:
        """Asynchronous Embed query text."""
        return await asyncio.get_running_loop().run_in_executor(
            None, self.embed_query, text
        )
    # EMBEDDING_MODEL=proxy_openai
# proxy_openai_proxy_server_url=https://api.openai.com/v1
# proxy_openai_proxy_api_key={your-openai-sk}
# proxy_openai_proxy_backend=text-embedding-ada-002


## qwen embedding model, See dbgpt/model/parameter.py
# EMBEDDING_MODEL=proxy_tongyi
# proxy_tongyi_proxy_backend=text-embedding-v1
# proxy_tongyi_proxy_api_key={your-api-key}

## qianfan embedding model, See dbgpt/model/parameter.py
#EMBEDDING_MODEL=proxy_qianfan
#proxy_qianfan_proxy_backend=bge-large-zh
#proxy_qianfan_proxy_api_key={your-api-key}
#proxy_qianfan_proxy_api_secret={your-secret-key}
  • 知识图谱抽取 -> knowledge graph
class TripletExtractor(LLMExtractor):
    """TripletExtractor class."""

    def __init__(self, llm_client: LLMClient, model_name: str):
        """Initialize the TripletExtractor."""
        super().__init__(llm_client, model_name, TRIPLET_EXTRACT_PT)

TRIPLET_EXTRACT_PT = (
    "Some text is provided below. Given the text, "
    "extract up to knowledge triplets as more as possible "
    "in the form of (subject, predicate, object).\n"
    "Avoid stopwords. The subject, predicate, object can not be none.\n"
    "---------------------\n"
    "Example:\n"
    "Text: Alice is Bob's mother.\n"
    "Triplets:\n(Alice, is mother of, Bob)\n"
    "Text: Alice has 2 apples.\n"
    "Triplets:\n(Alice, has 2, apple)\n"
    "Text: Alice was given 1 apple by Bob.\n"
    "Triplets:(Bob, gives 1 apple, Bob)\n"
    "Text: Alice was pushed by Bob.\n"
    "Triplets:(Bob, pushes, Alice)\n"
    "Text: Bob's mother Alice has 2 apples.\n"
    "Triplets:\n(Alice, is mother of, Bob)\n(Alice, has 2, apple)\n"
    "Text: A Big monkey climbed up the tall fruit tree and picked 3 peaches.\n"
    "Triplets:\n(monkey, climbed up, fruit tree)\n(monkey, picked 3, peach)\n"
    "Text: Alice has 2 apples, she gives 1 to Bob.\n"
    "Triplets:\n"
    "(Alice, has 2, apple)\n(Alice, gives 1 apple, Bob)\n"
    "Text: Philz is a coffee shop founded in Berkeley in 1982.\n"
    "Triplets:\n"
    "(Philz, is, coffee shop)\n(Philz, founded in, Berkeley)\n"
    "(Philz, founded in, 1982)\n"
    "---------------------\n"
    "Text: {text}\n"
    "Triplets:\n"
)
  • 倒排索引抽取 -> keywords分词

  • 可以用es默认的分词库,也可以使用es的插件模式自定义分词

  • 知识存储

整个知识持久化统一实现了IndexStoreBase接口,目前提供了向量数据库、图数据库、全文索引三类实现

  • VectorStore,向量数据库主要逻辑都在load_document(),包括索引schema创建,向量数据分批写入等等。
- VectorStoreBase
    - ChromaStore
    - MilvusStore
    - OceanbaseStore
    - ElasticsearchStore
    - PGVectorStore

class VectorStoreBase(IndexStoreBase, ABC):
    """Vector store base class."""

    @abstractmethod
    def load_document(self, chunks: List[Chunk]) -> List[str]:
        """Load document in index database."""
    @abstractmethod
    async def aload_document(self, chunks: List[Chunk]) -> List[str]:
        """Load document in index database."""

    @abstractmethod
    def similar_search_with_scores(
        self,
        text,
        topk,
        score_threshold: float,
        filters: Optional[MetadataFilters] = None,
    ) -> List[Chunk]:
        """Similar search with scores in index database."""
    def similar_search(
        self, text: str, topk: int, filters: Optional[MetadataFilters] = None
    ) -> List[Chunk]:
        return self.similar_search_with_scores(text, topk, 1.0, filters)
  • GraphStore ,具体的图存储提供了三元组写入的实现,一般会调用具体的图数据库的查询语言来完成。例如TuGraphStore会根据三元组生成具体的Cypher语句并执行。

  • 图存储接口GraphStoreBase提供统一的图存储抽象,目前内置了MemoryGraphStore和TuGraphStore的实现,我们也提供Neo4j接口给开发者进行接入。

- GraphStoreBase
    - TuGraphStore
    - Neo4jStore

def insert_triplet(self, subj: str, rel: str, obj: str) -> None:
    """Add triplet."""
    ...TL;DR...
    subj_query = f"MERGE (n1:{self._node_label} {{id:'{subj}'}})"
    obj_query = f"MERGE (n1:{self._node_label} {{id:'{obj}'}})"
    rel_query = (
        f"MERGE (n1:{self._node_label} {{id:'{subj}'}})"
        f"-[r:{self._edge_label} {{id:'{rel}'}}]->"
        f"(n2:{self._node_label} {{id:'{obj}'}})"
    )
    self.conn.run(query=subj_query)
    self.conn.run(query=obj_query)
    self.conn.run(query=rel_query)
  • FullTextStore: 通过构建es索引,通过es内置分词算法进行分词,然后由es构建keyword->doc_id的倒排索引。

{
            "analysis": {"analyzer": {"default": {"type": "standard"}}},
            "similarity": {
                "custom_bm25": {
                    "type": "BM25",
                    "k1": self._k1,
                    "b": self._b,
                }
            },
        }
        self._es_mappings = {
            "properties": {
                "content": {
                    "type": "text",
                    "similarity": "custom_bm25",
                },
                "metadata": {
                    "type": "keyword",
                },
            }
        }
    - FullTextStoreBase
    - ElasticDocumentStore
    - OpenSearchStore   

2.知识检索

question -> rewrite -> similarity_search -> rerank -> context_candidates

接下来是知识检索,目前社区的检索逻辑主要分为这几步,如果你设置了查询改写参数,目前会通过大模型给你进行一轮问题改写,然后会根据你的知识加工方式路由到对应的检索器,如果你是通过向量进行加工的,那就会通过EmbeddingRetriever进行检索,如果你构建方式是通过知识图谱构建的,就会按照知识图谱方式进行检索,如果你设置了rerank模型,会给粗筛后的候选值进行精筛,让候选值和用户问题更有关联。

  • EmbeddingRetriever
class EmbeddingRetriever(BaseRetriever):
    """Embedding retriever."""

    def __init__(
        self,
        index_store: IndexStoreBase,
        top_k: int = 4,
        query_rewrite: Optional[QueryRewrite] = None,
        rerank: Optional[Ranker] = None,
        retrieve_strategy: Optional[RetrieverStrategy] = RetrieverStrategy.EMBEDDING,
    ):


    async def _aretrieve_with_score(
        self,
        query: str,
        score_threshold: float,
        filters: Optional[MetadataFilters] = None,
    ) -> List[Chunk]:
        """Retrieve knowledge chunks with score.

        Args:
            query (str): query text
            score_threshold (float): score threshold
            filters: metadata filters.
        Return:
            List[Chunk]: list of chunks with score
        """
        queries = [query]
        new_queries = await self._query_rewrite.rewrite(
                    origin_query=query, context=context, nums=1
                )
                queries.extend(new_queries)
        candidates_with_score = [
                self._similarity_search_with_score(
                    query, score_threshold, filters, root_tracer.get_current_span_id()
                )
                for query in queries
            ]
            ...

        new_candidates_with_score = await self._rerank.arank(
                new_candidates_with_score, query
            )
            return new_candidates_with_score
  • index_store: 具体的向量数据库

  • top_k: 返回的具体候选chunk个数

  • query_rewrite:查询改写函数

  • rerank:重排序函数

  • query:原始查询

  • score_threshold:得分,我们默认会把相似度得分小于阈值的上下文信息给过滤掉

  • filters:Optional[MetadataFilters], 元数据信息过滤器,主要是可以用来前置通过属性信息筛掉一些不匹配的候选信息。

class FilterCondition(str, Enum):
   """Vector Store Meta data filter conditions."""
   AND ="and"
   OR ="or"
class MetadataFilter(BaseModel):
   """Meta data filter."""
   key: str = Field(
       ...,
       description="The key of metadata to filter.",
   )
   operator: FilterOperator = Field(
       default=FilterOperator.EQ,
       description="The operator of metadata filter.",
   )
   value: Union[str, int,float, List[str], List[int], List[float]] = Field(
       ...,
       description="The value of metadata to filter.",
   )

  • Graph RAG

首先通过模型进行关键词抽取,这里可以通过传统的nlp技术进行分词,也可以通过大模型进行分词,然后进行关键词按照同义词做扩充,找到关键词的候选列表,最好根据关键词候选列表调用explore方法召回局部子图。

KEYWORD_EXTRACT_PT = (
    "A question is provided below. Given the question, extract up to "
    "keywords from the text. Focus on extracting the keywords that we can use "
    "to best lookup answers to the question.\n"
    "Generate as more as possible synonyms or alias of the keywords "
    "considering possible cases of capitalization, pluralization, "
    "common expressions, etc.\n"
    "Avoid stopwords.\n"
    "Provide the keywords and synonyms in comma-separated format."
    "Formatted keywords and synonyms text should be separated by a semicolon.\n"
    "---------------------\n"
    "Example:\n"
    "Text: Alice is Bob's mother.\n"
    "Keywords:\nAlice,mother,Bob;mummy\n"
    "Text: Philz is a coffee shop founded in Berkeley in 1982.\n"
    "Keywords:\nPhilz,coffee shop,Berkeley,1982;coffee bar,coffee house\n"
    "---------------------\n"
    "Text: {text}\n"
    "Keywords:\n"
)

def explore(
    self,
    subs: List[str],
    direct: Direction = Direction.BOTH,
    depth: Optional[int] = None,
    fan: Optional[int] = None,
    limit: Optional[int] = None,
) -> Graph:
    """Explore on graph."""
  • DBSchemaRetriever这部分是ChatData场景的schema-linking检索

    主要是通过schema-linking方式通过二阶段相似度检索,首先先找到最相关的表,然后再最相关的字段信息。

    优点:这种二阶段检索也是为了解决社区反馈的大宽表体验的问题。

   def _similarity_search(
        self, query, filters: Optional[MetadataFilters] = None
    ) -> List[Chunk]:
        """Similar search."""
        table_chunks = self._table_vector_store_connector.similar_search_with_scores(
            query, self._top_k, 0, filters
        )

        not_sep_chunks = [
            chunk for chunk in table_chunks if not chunk.metadata.get("separated")
        ]
        separated_chunks = [
            chunk for chunk in table_chunks if chunk.metadata.get("separated")
        ]
        if not separated_chunks:
            return not_sep_chunks

        # Create tasks list
        tasks = [
            lambda c=chunk: self._retrieve_field(c, query) for chunk in separated_chunks
        ]
        # Run tasks concurrently
        separated_result = run_tasks(tasks, concurrency_limit=3)

        # Combine and return results
        return not_sep_chunks + separated_result

  • table_vector_store_connector: 负责检索最相关的表。

  • field_vector_store_connector: 负责检索最相关的字段。

2、知识加工,知识检索优化思路

目前RAG智能问答应用几个痛点:

  • 知识库文档越来越多以后,检索噪音大,召回准确率不高

  • 召回不全,完整性不够

  • 召回和用户问题意图相关性不大

  • 只能回答静态数据,无法动态获取知识,导致答疑应用比较呆,比较笨。

1 . 知识处理优化

非结构化/半结构化/结构化数据的处理,准备决定着RAG应用的上限,因此首先需要在知识处理,索引阶段做大量的细粒度的ETL工作,主要优化的思路方向:

  • 非结构化 -> 结构化:有条理地组织知识信息。

  • 提取更加丰富的, 多元化的语义信息。

1.1 知识加载

目的:需要对文档进行精确的解析,更多元化的识别到不同类型的数据。

优化建议:

  • 建议将docx、txt或者其他文本事先处理为pdf或者markdown格式,这样可以利用一些识别工具更好地提取文本中的各项内容。

  • 提取文本中的表格信息。

  • 保留markdown和pdf的标题层级信息,为接下来的层级关系树等索引方式准备。

  • 保留图片链接,公式等信息,也统一处理成markdown的格式。

1.2 切片Chunk尽量保持完整

目的:保存上下文完整性和相关性,这直接关乎回复准确率。

保持在大模型的上下文限制内,分块保证输入到LLMs的文本不会超过其token限制。

优化建议:

  • 图片 + 表格 单独抽取成Chunk,将表格和图片标题保留到metadata元数据里

  • 文档内容尽量按照标题层级或者Markdown Header进行拆分,尽可能保留chunk的完整性。

  • 如果有自定义分隔符可以按照自定义分割符切分

1.3 多元化的信息抽取

除了对文档进行Embedding向量抽取外,其他多元化的信息抽取能够对文档进行数据增强,显著提升RAG召回效果。

  • 知识图谱

  • 优点:1. 解决NativeRAG的完整性缺失,依然存在幻觉问题,知识的准确性,包括知识边界的完整性、知识结构和语义的清晰性,是对相似度检索的能力的一种语义补充。

  • 适用场景:适用于严谨的专业领域(医疗,运维等),知识的准备需要受到约束的并且知识之间能够明显建立层级关系的。

  • 如何实现:

    1.依赖大模型提取(实体,关系,实体)三元组关系。

    1. 依赖前期高质量,结构化的知识准备,清洗,抽取,通过业务规则通过手动或者自定义SOP流程构建知识图谱。

  • Doc Tree

  • 适用场景:解决了上下文完整性不足的问题,也能匹配时完全依据语义和关键词,能够减少噪音

  • 如何实现:以标题层级构建chunk的树形节点,形成一个多叉树结构,每一层级节点只需要存储文档标题,叶子节点存储具体的文本内容。这样利用树的遍历算法,如果用户问题命中相关非叶子标题节点,就可以将相关的子节点数据进行召回。这样就不会存在chunk完整性缺失的问题。

这部分的Feature我们也会在明年年初放到社区里面。

  • 提取QA对,需要前置通过预定义或者模型抽取的方式提取QA对信息

  • 适用场景:

  • 能够在检索中命中问题并直接进行召回,直接检索到用户想要的答案,适用于一些FAQ场景,召回完整性不够的场景。

  • 如何实现:

  • 预定义:预先为每个chunk添加一些问题

  • 模型抽取:通过给定一下上下文,让模型进行QA对抽取

  • 元数据抽取

  • 如何实现:根据自身业务数据特点,提取数据的特征进行保留,比如标签,类别,时间,版本等元数据属性。

  • 适用场景:检索时候能够预先根据元数据属性进行过滤掉大部分噪音。

  • 总结提取

  • 适用场景:解决这篇文章讲了个啥,总结一下等全局问题场景。

  • 如何实现:通过mapreduce等方式分段抽取,通过模型为每段chunk提取摘要信息。

1.4 知识处理工作流

目前DB-GPT知识库提供了文档上传 -> 解析 -> 切片 -> Embedding -> 知识图谱三元组抽取 -> 向量数据库存储 -> 图数据库存储等知识加工的能力,但是不具备对文档进行复杂的个性化的信息抽取能力,因此希望通过构建知识加工工作流模版来完成复杂的,可视化的,用户可自定义的知识抽取,转换,加工流程。

知识加工工作流:

https://www.yuque.com/eosphoros/dbgpt-docs/vg2gsfyf3x9fuglf

2. RAG流程优化

RAG流程的优化我们又分为了静态文档的RAG和动态数据获取的RAG,目前大部分涉及到的RAG只覆盖了非结构化的文档静态资产,但是实际业务很多场景的问答是通过工具获取动态数据 + 静态知识数据共同回答的场景,不仅需要检索到静态的知识,同时需要RAG检索到工具资产库里面工具信息并执行获取动态数据。

2.1 静态知识RAG优化

(1)原始问题处理

目的:澄清用户语义,将用户的原始问题从模糊的,意图不清晰的查询优化为含义更丰富的一个可检索的Query

  • 原始问题分类,通过问题分类可以

  • LLM分类(LLMExtractor)

  • 构建embedding+逻辑回归实现双塔模型,text2nlu DB-GPT-Hub/src/dbgpt-hub-nlu/README.zh.md at main · eosphoros-ai/DB-GPT-Hub

  • tip:需要高质量的Embedding模型,推荐bge-v1.5-large

  • 反问用户,如果语义不清晰将问题再抛给用户进行问题澄清,通过多轮交互

  • 通过热搜词库根据语义相关性给用户推荐他想要的问题候选列表

  • 槽位提取,目的是获取用户问题中的关键slot信息,比如意图,业务属性等等

  • LLM提取(LLMExtractor)

  • 问题改写

  • 热搜词库进行改写

  • 多轮交互

(2)元数据过滤

当我们把索引分成许多chunks并且都存储在相同的知识空间里面,检索效率会成为问题。比如用户问"浙江我武科技公司"相关信息时,并不想召回其他公司的信息。因此,如果可以通过公司名称元数据属性先进行过滤,就会大大提升效率和相关度。

async def aretrieve(
    self, query: str, filters: Optional[MetadataFilters] = None
) -> List[Chunk]:
    """Retrieve knowledge chunks.

        Args:
            query (str): async query text.
            filters: (Optional[MetadataFilters]) metadata filters.

        Returns:
            List[Chunk]: list of chunks
        """
    return await self._aretrieve(query, filters)

(3) 多策略混合召回
  • 按照优先级召回,分别为不同的检索器定义优先级,检索到内容后立即返回

  • 定义不同检索,比如qa_retriever, doc_tree_retriever写入到队列里面, 通过队列的先进先出的特性实现优先级召回。

class RetrieverChain(BaseRetriever):
    """Retriever chain class."""

    def __init__(
        self,
        retrievers: Optional[List[BaseRetriever]] = None,
        executor: Optional[Executor] = None,
    ):
        """Create retriever chain instance."""
        self._retrievers = retrievers or []
        self._executor = executor or ThreadPoolExecutor()
            for retriever in self._retrievers:
            candidates_with_scores = await retriever.aretrieve_with_scores(
                query=query, score_threshold=score_threshold, filters=filters
            )
            if candidates_with_scores:
                return candidates_with_scores 
  • 多知识索引/空间并行召回

  • 通过知识的不同索引形式,通过并行召回方式获取候选列表,保证召回完整性

(4) 后置过滤

经过粗筛候选列表后,怎么通过精筛过滤噪音呢

  • 无关的候选分片剔除

  • 时效性剔除

  • 业务属性不满足剔除

  • topk去重

  • 重排序 仅仅靠粗筛的召回还不够,这时候我们需要有一些策略来对检索的结果做重排序,比如把组合相关度、匹配度等因素做一些重新调整,得到更符合我们业务场景的排序。因为在这一步之后,我们就会把结果送给LLM进行最终处理了,所以这一部分的结果很重要。

  • 使用相关重排序模型进行精筛,可以使用开源的模型,也可以使用带业务语义微调的模型。

## Rerank model
#RERANK_MODEL=bce-reranker-base
#### If you not set RERANK_MODEL_PATH, DB-GPT will read the model path from EMBEDDING_MODEL_CONFIG based on the RERANK_MODEL.
#RERANK_MODEL_PATH=/Users/chenketing/Desktop/project/DB-GPT-NEW/DB-GPT/models/bce-reranker-base_v1
#### The number of rerank results to return
#RERANK_TOP_K=5
  • 根据不同索引召回的内容进行业务RRF加权综合打分剔除
score = 0.0
for q in queries:
    if d in result(q):
        score += 1.0 / ( k + rank( result(q), d ) )
return score

# where
# k is a ranking constant
# q is a query in the set of queries
# d is a document in the result set of q
# result(q) is the result set of q
# rank( result(q), d ) is d's rank within the result(q) starting from 1
(5) 显示优化+兜底话术/话题引导
  • 让模型使用markdown的格式进行输出
基于以下给出的已知信息, 准守规范约束,专业、简要回答用户的问题.
规范约束:
    1.如果已知信息包含的图片、链接、表格、代码块等特殊markdown标签格式的信息,确保在答案中包含原文这些图片、链接、表格和代码标签,不要丢弃不要修改,
如:图片格式:![image.png](xxx), 链接格式:[xxx](xxx), 表格格式:|xxx|xxx|xxx|, 代码格式:```xxx```.
    2.如果无法从提供的内容中获取答案, 请说: "知识库中提供的内容不足以回答此问题" 禁止胡乱编造.
    3.回答的时候最好按照1.2.3.点进行总结, 并以markdwon格式显示.

2.2 动态知识RAG优化

文档类知识是相对静态的,无法回答个性化以及动态的信息, 需要依赖一些第三方平台工具才可以回答,基于这种情况,我们需要一些动态RAG的方法,通过工具资产定义 -> 工具选择 -> 工具校验 -> 工具执行获取动态数据。

(1) 工具资产库

构建企业领域工具资产库,将散落到各个平台的工具API,工具脚本进行整合,进而提供智能体端到端的使用能力。比如,除了静态知识库以外,我们可以通过导入工具库的方式进行工具的处理。

(2) 工具召回

工具召回沿用静态知识的RAG召回的思路,再通过完整的工具执行生命周期来获取工具执行结果。

  • 槽位提取:通过传统nlp获取LLM将用户问题进行解析,包括常用的业务类型,环境标,领域模型参数等等

  • 工具选择:沿用静态RAG的思路召回,主要有两层,工具名召回和工具参数召回。

  • 工具参数召回,和TableRAG思路类似,先召回表名,再召回字段名。

  • 参数填充:需要根据召回的工具参数定义,和槽位提取出来的参数进行match

  • 可以代码进行填充,也可以让模型进行填充。

  • 优化思路:由于各个平台工具的同样的参数的参数名没有统一,也不方便去治理,建议可以先进行一轮领域模型数据扩充,拿到整个领域模型后,需要的参数都会存在。

  • 参数校验

  • 完整性校验:进行参数个数完整性校验

  • 参数规则校验:进行参数名类型,参数值,枚举等等规则校验。

  • 参数纠正/对齐,这部分主要是为了减少和用户的交互次数,自动化完成用户参数错误纠正,包括大小写规则,枚举规则等等。eg:

2.3 RAG评测

在评估智能问答流程时,需要单独对召回相关性准确率以及模型问答的相关性进行评估,然后再综合考虑,以判断RAG流程在哪些方面仍需改进。

评价指标:

EvaluationMetric
├── LLMEvaluationMetric
│   ├── AnswerRelevancyMetric
├── RetrieverEvaluationMetric
│   ├── RetrieverSimilarityMetric
│   ├── RetrieverMRRMetric
│   └── RetrieverHitRateMetric
  • **RAG**召回指标(RetrieverEvaluationMetric):

  • RetrieverHitRateMetric:命中率衡量的是RAGretriever召回出现在检索结果前top-k个文档中的比例。

  • RetrieverMRRMetric:Mean Reciprocal Rank通过分析最相关文档在检索结果里的排名来计算每个查询的准确性。更具体地说,它是所有查询的相关文档排名倒数的平均值。例如,若最相关的文档排在第一位,其倒数排名为 1;排在第二位时,为 1/2;以此类推。

  • RetrieverSimilarityMetric: 相似度指标计算,计算召回内容与预测内容的相似度。

模型生成答案指标:

  • AnswerRelevancyMetric:智能体答案相关性指标,通过智能体答案与用户提问的匹配程度。高相关性的答案不仅要求模型能够理解用户的问题,还要求其能够生成与问题密切相关的答案。这直接影响到用户的满意度和模型的实用性。

3、RAG落地案例分享

1. 数据基础设施领域的RAG

1.1 运维智能体背景

在数据基础设施领域,有很多运维SRE,每天会接收到大量的告警,因此很多时间来需要响应应急事件,进而进行故障诊断,然后故障复盘,进而进行经验沉淀。另外一部分时间又需要响应用户咨询,需要他们用他们的知识以及工具使用经验进行答疑。

因此我们希望通过打造一个数据基础设施的通用智能体来解决告警诊断,答疑的这些问题。

1.2 严谨专业的RAG

传统的 RAG + Agent 技术可以解决通用的,确定性没那么高的,单步任务场景。但是面对数据基础设施领域的专业场景,整个检索过程必须是确定,专业和真实的,并且是需要一步一步推理的。

右边是一个通过NativeRAG的一个泛泛而谈的总结,可能对于一个C端的用户,对专业的领域知识没那么了解时,可能是有用的信息,然后对于专业的人员来说,这部分解答就没有什么意义了。

因此我们比较了通用的智能体和数据基础设施智能体在RAG上面的区别:

  • 通用的智能体:传统的RAG对知识的严谨和专业性要求没那么高,适用于客服,旅游,平台答疑机器人这样的一些业务场景。

  • 数据基础设施智能体:RAG流程是严谨和专业的,需要专属的RAG工作流程,上下文包括(告警->定位->止血->恢复),并且需要对专家沉淀的问答和应急经验,进行结构化的抽取,建立层次关系。因此我们选择知识图谱来作为数据承载。

1.3 知识处理

基于数据基础设施的确定性和特殊性,我们选择通过结合知识图谱来作为诊断应急经验的知识承载。我们通过SRE沉淀下来的应急排查事件知识经验 结合应急复盘流程,建立了DB应急事件驱动的知识图谱,我们以DB抖动为例,影响DB抖动的几个事件,包括慢SQL问题,容量问题,我们在各个应急事件间建立了关系。

最后通过我们通过规范化应急事件规则,一步一步地建立了多源的知识 -> 知识结构化抽取 ->应急关系抽取 -> 专家审核 -> 知识存储的一套标准化的知识加工体系。

1.4 知识检索

在智能体检索阶段,我们使用GraphRAG作为静态知识检索的承载,因此识别到DB抖动异常后,找到了与DB抖动异常节点相关的节点作为我们分析依据,由于在知识抽取阶段每一个节点还保留了每个事件的一些元数据信息,包括事件名,事件描述,相关工具,工具参数等等。

因此我们可以通过执行工具的执行生命周期链路来获取返回结果拿到动态数据来作为应急诊断的排查依据。通过这种动静结合的混合召回的方式比纯朴素的RAG召回,保障了数据基础设施智能体执行的确定性,专业性和严谨性。

1.5 AWEL + Agent

最后通过社区AWEL+AGENT技术,通过AGENT编排的范式,打造了从意图专家-> 应急诊断专家 -> 诊断根因分析专家。

每个Agent的职能都是不一样的,意图专家负责识别解析用户的意图和识别告警信息诊断专家需要通过GraphRAG 定位到需要分析的根因节点,以及获取具体的根因信息。分析专家需要结合各个根因节点的数据 + 历史分析复盘报告生成诊断分析报告

2. 金融财报分析领域的RAG

可以围绕各自领域构建属于自己的领域资产库包括,知识资产,工具资产以及知识图谱资产

  • 领域资产:领域资产包括了知识库,API,工具脚本。

  • 资产处理,整个资产数据链路涉及了领域资产加工,领域资产检索和领域资产评估。

  • 非结构化 -> 结构化:有条理地归类,正确地组织知识信息。

  • 提取更加丰富的语义信息。

  • 资产检索:

  • 希望是有层级,优先级的检索而并非单一的检索

  • 后置过滤很重要,最好能通过业务语义一些规则进行过滤。

    最后的最后

感谢你们的阅读和喜欢,作为一位在一线互联网行业奋斗多年的老兵,我深知在这个瞬息万变的技术领域中,持续学习和进步的重要性。

为了帮助更多热爱技术、渴望成长的朋友,我特别整理了一份涵盖大模型领域的宝贵资料集。

这些资料不仅是我多年积累的心血结晶,也是我在行业一线实战经验的总结。

这些学习资料不仅深入浅出,而且非常实用,让大家系统而高效地掌握AI大模型的各个知识点。如果你愿意花时间沉下心来学习,相信它们一定能为你提供实质性的帮助。

这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】

大模型知识脑图

为了成为更好的 AI大模型 开发者,这里为大家提供了总的路线图。它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
在这里插入图片描述

经典书籍阅读

阅读AI大模型经典书籍可以帮助读者提高技术水平,开拓视野,掌握核心技术,提高解决问题的能力,同时也可以借鉴他人的经验。对于想要深入学习AI大模型开发的读者来说,阅读经典书籍是非常有必要的。

在这里插入图片描述

实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

面试资料

我们学习AI大模型必然是想找到高薪的工作,下面这些面试题都是总结当前最新、最热、最高频的面试题,并且每道题都有详细的答案,面试前刷完这套面试题资料,小小offer,不在话下

在这里插入图片描述

640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

在这里插入图片描述

这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】

从权限对象到业务角色:把 SAP Authorization Object 讲清楚,并用 ABAP 写对一次 AUTHORITY-CHECK 摘要:SAP权限管理的核心在于Authorization Object(授权对象),它通过组合最多10个授权字段来精确控制用户访问权限。关键要点包括:1) 授权对象与ACTVT字段(如01创建/02修改/03显示)的配合使用;2) ABAP中AUTHORITY-CHECK语句的四种常见返回码(0通过/4字段不匹配/12无权限/40无效用户);3) 系统自动执行的S_TCODE事务码检查;4) 自定义授权对象时应遵循"最少且足够"原则,优先复用标准对象。在RAP和OData场景中,权限检查 阅读详情

相关推荐

QT播放器插件内嵌浏览器配合流媒体实现国标摄像头网页端播放

基本原理在浏览器⽹页中的指定播放窗口的位置和⼤⼩,实现⼀个内嵌到⽹页中显⽰的播放窗⼝,前端还必须可对这个内嵌播放窗⼝进⾏控制,⽽且播放窗⼝必须跟随浏览器窗⼝的移动和缩放、⽹页滚动、标签页切换、关闭等操作进⾏⾃动联动。播放器可以通过QT实现。这个播放窗⼝同时提供Web Socket的服务端和JSON打包命令的解析执⾏模块,前端就可以通过Web Socket连接后发送JSON打包的控制命令实现控制播放窗⼝。

cameravision的博客 562

【AI落地应用实战】DeepSeek大模型应用探讨与RAG技术全景——从实验室榜单看向真实业务场景

当我们将视线从实验室的Benchmark榜单转向真实业务场景时,大模型落地应用的"最后一公里"挑战正逐渐浮出水面。尽管DeepSeek在技术上取得了显著的突破,但将其应用于现实世界的过程中,仍有许多问题亟待解决。

白洞,白色的明天在等着我们 2万+

【雷达成像实战】RD、CS、RMA算法对比与Matlab实现:从信号处理到高清成像

本文深入对比了雷达成像中三种核心算法:经典的距离多普勒算法(RD)、基于稀疏重建的压缩感知算法(CS)以及高精度的快速多通道获取算法(RMA)。通过详细的Matlab实战代码,从原理拆解到实现步骤,分析了各自在计算效率、成像精度、数据需求和适用场景上的优劣,为工程选型与算法实践提供了清晰指南。

weixin_29095587的博客 447

【收藏指南】RAG技术重生:从知识库问答到企业AI核心基础设施

本文深入分析了RAG技术在2026年的发展现状,指出尽管长上下文窗口出现,RAG并未消亡,反而从简单问答工具演变为企业AI核心基础设施。文章系统梳理了RAG的前沿研究方向(检索优化、生成优化、强化学习、多模态RAG等),剖析了数据质量、分块策略等落地难点,并提供了全链路优化方案。同时展望了RAG与Agent融合、视觉原生检索普及等未来趋势,强调RAG成功80%取决于数据工程和产品设计。

2401_85154887的博客 1192

Anaconda安装教程(超详细版)

目录 一、Anaconda简介 二、运行环境 三、安装Anaconda 四、手动配置环境变量(重点) 五、测试Anaconda环境是否配置成功 一、Anaconda简介 Anaconda,一个开源的Python发行版本,可用于管理Python及其相关包,包含了conda、Python等180多个科学包及其依赖项。 二、运行环境 Windows11 (Window10用户亦可参考,仅环境变量打开位置不同)。 三、安装Anaconda (1)百度“Anaconda”或者输入网址

m0_61607990的博客 22万+

Matlab处理气象数据(六)数据的面积加权

由于地理投影导致导致每个像元实际地面面积不同,越靠近北极实际面积越小,越靠近赤道实际面积越大,如果不进行面积加权就简单平均,会导致温度较实际温度偏低。 用以下公式计算地理投影每个像元的面积: double pi = 3.1415926; double R = 6371007.181; //units - m double area = (pi/180.0)*R*R*fabs(sin(dLat1/180.0*pi) - sin(dLat2/180.0*pi)) * fabs(dLon1 - dLo

设计の诗 1万+

大语言模型落地的关键技术:RAG

RAG 是检索增强生成(Retrieval-Augmented Generation)的简称,是当前最火热的大语言模型应用落地的关键技术,主要用于提高语言模型的效果和准确性。

产品老A,8年互联网大厂AIPM,专注探索新型人机交互 4335

IDM更改下载路径的详细指南

Internet Download Manager(IDM)是一款功能全面的下载加速工具,它支持多种浏览器和协议,能够显著提升下载速度,同时提供断点续传、多线程下载等实用功能。IDM的用户界面简洁明了,操作便捷,使得用户能够轻松管理下载任务。此外,IDM还支持自动分类下载文件、定时下载等高级功能,进一步提升了用户的下载体验。通过本文的介绍,相信用户已经掌握了如何在IDM中更改下载路径的方法。这一功能不仅提升了下载效率和文件管理便捷性,还满足了用户的个性化需求。

nntxthml的博客 1761

万字长文讲透 RAG 在实际落地场景中的优化

在过去两年中,检索增强生成(RAG,Retrieval-Augmented Generation)技术逐渐成为提升智能体的核心组成部分。通过结合检索与生成的双重能力,RAG能够引入外部知识,从而为大模型在复杂场景中的应用提供更多可能性。但是在实际落地场景中,往往会存在检索准确率低,噪音干扰多,召回完整性,专业性不够,导致LLM幻觉严重的问题。本文将聚焦RAG在实际落地场景中的知识加工和检索细节,如何去优化RAG Pineline链路,最终提升召回准确率。

xx_nm98的博客 2330

A*(star)算法原理讲解以及程序实现(基于Python)

本文将以迷宫探索最优路径为例,讲解A *搜索算法原理及其程序实现。在原理讲解部分,首先从为什么要使用A *搜索算法和A *搜索算法的全局最优逻辑出发,讲解A *算法的原理。其次对A *的行动函数g(n)和启发函数h(n)的细节进行了讲解说明,并补充了启发函数的选择对于A *算法的影响。在程序实现部分,首先从程序流程框图出发,解释A *算法的流程。其次按函数的类划分并讲解主要代码,接着展示程序的运行结果,最后对A *算法进行总结分析。

m0_73366745的博客 8281

基于Lora的一主多从监测与控制系统

题目:基于Lora的远程农业监测与控制系统 目的:通过Lora子节点采集好各种传感器的信息,发送给汇聚节点,汇聚节点将数据通过ESP8266上传至云端,使用了微信小程序进行监测与控制

热爱生活、奋斗前行 7841

万字长文讲透 RAG在实际落地场景中的优化

大模型很多技术干货,都可以共享给你们,如果你肯花时间沉下心去学习,它们一定能帮到你!

2401_85373691的博客 1154

第一节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门

vben5 快速入门。 Vben Admin 框架新出的版本V5.5.4,而之前的Vben Admin 2.x 目前已存档,仅进行重大问题修复。之前在2.x版本曾经简单完成了一版专栏文章,当时也是收获了一些好评和建议。本次决定在v5 版本基础上再完成一次前后端的搭建。希望大家继续多多支持。项目精简后,再次启动项目,执行 pnpm run dev点击登录,可以看到接口报错,现在前端请求的后端有报错,下一节处理这部分逻辑。

cuiwin的专栏 7065

阿里云 AI 搜索 RAG 大模型优化实践

第三种方案,也就是我们采用的 RAG 方法,它不改变大模型本身,而是通过检索领域知识,然后结合问题和检索到的知识,用大模型生成答案。此外,由于它不是直接生成答案,而是基于搜索结果,所以可以提供生成答案的依据,解决了可溯源的问题。第一个例子是,当用户询问如何修改云盘的 UUID 时,搜索回来的结果可能是“修改云盘的 UUID 步骤如下”,但接下来的步骤可能被切到了下一个切片。然而,我们发现许多客户的数据中,不同层级的标题可能使用了相同的字号,这就需要我们在数据中进行层级的合并和构造,以模拟客户的实际数据。

张伟的专栏 1190

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

万字长文,彻底讲透Agentic RAG!从架构到实践,这一篇就够了

随着我们从2024年进入2025年,AI领域的焦点正从检索增强生成(RAG)转向更具突破性的技术——智能体式RAG。

pythonhy的博客 1325

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

万字长文,彻底讲透RAG多模态!从入门到实战,收藏这一篇就够了!

大型语言模型(LLMs)在回答问题方面表现出色,但它们缺乏特定领域的知识,并且容易产生幻觉。RAG是一种解决这些挑战的方法,而多模态模型作为处理文本和图像的AI助手,显示出了潜力。

m0_59163425的博客 1665

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

万字长文,彻底讲透RAG!从核心原理到实战应用,看这一篇就够了!

人工智能生成内容(AIGC)的进步,得益于模型算法的进步、基础模型的增长以及高质量数据集的获取。尽管取得了显著的成功,AIGC仍然面临着更新知识、处理长尾数据、减少数据泄露以及管理高昂的训练和推理成本等挑战。

m0_59164520的博客 1500

3分钟搞懂AI大模型高频词:Token、RAG、RL…(附应用场景)

Token是AI处理文本的最小单位,相当于自然语言中的“字词片段”。例如“人工智能”可能被拆分为“人工”+“智能”两个Token,或保留为单个Token(不同模型分词规则不同)。DeepSeek官方也给出Token数和字数的大致换算比例如下:1 个英文字符 ≈ 0.3 个 token。1 个中文字符 ≈ 0.6 个 token。

优快云_430422的博客 3204

大语言模型RAG vs. 长文本

​ 在学习完大语言模型中最热门的两个概念大语言模型落地的关键技术:RAG和大语言模型上下文窗口初探后,关于RAG和长文本(long-context)的优劣比较引起了广泛的讨论,本文整理了大语言模型RAG vs. 长文本争论的5种类观点。

产品老A,8年互联网大厂AIPM,专注探索新型人机交互 3891
上一篇: 构建企业私有RAG大模型: (可商用)DeepSeek-V3开源部署,真的强吗?
下一篇: 【AI大模型面试真题】Llama为何要采用RoPE旋转位置编码?
Agent学习路线
博客等级 码龄6年 1万+粉丝 1902原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值