news 2026/9/6 10:39:33

从RAG到Agent:Agentic RAG架构演进与工程实践指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从RAG到Agent:Agentic RAG架构演进与工程实践指南

1. 先把事情说清楚:RAG和Agent到底是什么关系

最近很多人在聊AI Agent,聊RAG,但说实话,大部分讨论都停留在概念层面——PPT里画个流程图,说“我们用RAG解决了幻觉问题”,再画个框,说“我们加了Agent实现自动规划”,真到落地的时候,一堆问题全冒出来了。

我先用一句大白话把两者的关系说清楚:RAG是给大模型装上一双可以随时翻书的手,Agent是给大模型装上一个会做决定的大脑。这两者不是二选一,而是层层递进的关系。

RAG(Retrieval-Augmented Generation,检索增强生成)解决的核心问题是:大模型的知识截止日期和领域深度都不够。你让它写一篇关于你公司内部流程的文档,它根本没见过你公司的流程,瞎编是必然的。RAG的做法是先检索,再生成——把用户的问题拿去知识库里找相关内容,找到之后塞进上下文,让模型“看着资料回答问题”。这样一来,答案有了依据,幻觉问题大幅缓解,你的知识库也能随时更新,不用动不动就重新训练模型。

Agent解决的问题则更进一步:当任务本身不是一个“问一句答一句”的简单问答,而是需要多步推理、调用外部工具、动态决策的时候,RAG单点检索就不够用了。比如你问“帮我分析一下今年Q3的销售数据,找出下滑最严重的区域,并生成一封提醒邮件”,这里面涉及数据查询、数据分析、邮件撰写三个步骤,每一步都需要不同的工具和不同的资料。Agent就是那个把这些步骤串起来、决定每步该干什么的角色。

所以,如果你只是想做一个“文档问答机器人”,RAG就够了;如果你要做的是一个“能自动干活的数字员工”,你需要的是Agent+RAG。现在行业里常说的Agentic RAG,本质就是把检索能力包装成Agent可以调用的工具,或者让Agent来决定什么时候检索、检索什么、检索几轮。

这篇文章适合正在做RAG落地、准备往Agent方向进阶的开发者。我会把自己踩过的坑、验证过的方案、以及目前比较靠谱的工程实践都摊开来讲,不吹概念,只讲能跑的东西。

2. 理解RAG的核心链路:从文档到可用知识库

RAG说起来简单,但真正落地的时候,你会发现80%的问题都出在“知识库构建”这一步,而不是模型调用上。很多人第一次搭RAG,拿几个PDF丢进去,用现成框架跑通demo,觉得也就那样。但一旦进入真实业务场景——几千份合同、几万条工单、上百个内部系统文档——问题就全冒出来了。

2.1 RAG向量化流程拆解:别小看“切文档”这一步

RAG的完整链路是:文档加载 -> 文本清洗 -> 分块(Chunking) -> 向量化(Embedding) -> 存储 -> 检索 -> 重排 -> 生成。链路不算长,但每一环都有坑。

先说文档加载。很多人用pdfminer或PyPDF直接抽文本,结果发现PDF里是扫描件,抽出来全是乱码。这种情况需要先做OCR。我自己的经验是,如果文档里有表格、图片、复杂排版,直接用文本抽取会丢失大量语义信息。现在比较靠谱的方案是用版面分析模型先把文档结构解析出来,区分标题、正文、表格、页眉页脚,然后按结构去抽取。开源的LayoutLMv3、PaddleOCR的版面分析能力都可以用,虽然比不上商用产品,但对中小规模场景足够了。

然后是文本清洗。这一步看起来不起眼,但直接影响向量化质量。我见过最典型的坑是:把页眉页脚、日期、页码这些噪音也向量化进去,导致检索的时候匹配到一堆无关片段。清洗环节至少要做三件事:去掉页眉页脚和页码、合并断行、统一编码格式。如果文档是HTML或Markdown,还要去掉标签只留文本。另外注意:不要过度清洗。有些人把所有标点都删了,结果句子语义变得支离破碎,检索效果反而变差。清洗的目的是去掉噪音,不是破坏语义。

关键的挑战在于分块。分块策略直接决定检索质量。我用过很多种分块方式,简单总结:

  • 固定长度分块(比如每512个字符切一块):实现最简单,但边界容易切断语义。比如一个句子的后半截到了下一块,检索的时候某块里只有半个意思,模型拿到这半个信息,回答自然不完整。
  • 段落级分块:按段落切分,语义相对完整,但段落长短不一,有的段落过短导致信息不足,有的段落又超长。
  • 语义分块(Semantic Chunking):用向量相似度来判断哪里该断开。这种方法效果最好,但计算成本高,适合对质量要求高的场景。
  • 递归字符分块:给定一个目标块大小,按照分隔符优先级递归切分。这是LangChain里常用的一种方式,兼顾了效率和效果。

我自己在实践中的经验是:分块大小不要拍脑袋定,要根据你的文档类型和下游模型的上下文窗口来决定。比如你用的是GPT-4级别的大窗口模型,块可以适当大一点;如果用的是小模型,块就小一点。常见的经验值是512到1024个token之间。但具体多少,一定要拿你自己的文档去测试——拿一批有代表性的问题,分别用不同的块大小跑一遍,看检索命中率,才能找到最优值。

2.2 向量化模型与向量数据库选型

分完块之后就是向量化。这一步的核心是选Embedding模型。选模型有两个关键指标:维度不是越多越好,检索效果才是王道;以及中英文混合场景下,要选多语言模型。

我自己对比过几个主流选择:OpenAI的text-embedding-3-small(1536维)、text-embedding-3-large(3072维),以及开源的BGE系列(中文场景很强)、M3E系列、以及智源的bge-m3。如果数据主要是中文,BGE和M3E的效果往往不比OpenAI差,而且本地部署没有数据泄露风险。

这里有一个“为什么”层面的道理要讲透:Embedding模型的质量决定了你的知识库“懂不懂”语义。它把一段文本映射到一个高维向量空间,语义相近的文本,向量距离也近。如果模型本身训练语料不够广,或者对垂直领域术语理解不够,再好的检索算法也救不回来。举个例子,医疗领域有大量专业术语,“CKD”和“慢性肾脏病”是同一个东西,如果Embedding模型没学过这些术语,它就无法把这两个词映射到相近的位置,检索召回就会失败。

向量数据库的选型也要讲策略。市面上的选择很多:Milvus、Qdrant、Chroma、Pinecone,还有传统数据库PostgreSQL的pgvector扩展。如果你只是做demo,Chroma和FAISS就够了,本地跑起来最快;如果是生产环境且数据量在千万级以下,pgvector是个不错的选择,省得再维护一套独立的向量库;如果数据量过千万且并发高,上Milvus或Qdrant是更稳的选择。

这里有个工程上的小建议:不要把向量检索当作唯一召回方式。实际业务中,混合检索(Hybrid Search,即向量检索+关键词检索)的效果往往远好于单一向量检索。原因在于,向量检索擅长处理语义相似但表述不同的情况,关键词检索擅长精确匹配专有名词、编号、型号。比如用户搜“A100显卡的功耗”,关键词检索能精确命中“A100”,而向量检索可能把它和“A800”“H100”混淆。业界比较成熟的方案是先用向量检索召回Top 50,再用BM25(关键词检索)召回Top 50,合并去重后交给重排模型。

2.3 重排(Rerank)为什么不能省

很多人做RAG做到检索就完了,直接把Top 5结果塞给大模型。这样做的结果是:模型输出的答案经常“文不对题”——检索回来的片段里确实有相关信息,但正确的信息排在第8位、第10位,没被选进上下文。

这就是为什么重排这一步不能省。召回阶段追求的是“尽量多地把可能相关的片段捞出来”,精度可以低一点,所以召回100条也不嫌多;但模型上下文窗口有限,你只能塞进去有限的片段。重排模型(Reranker)的作用是从这100条里选出和问题最相关的Top 5或Top 10。

重排模型和Embedding模型不同。Embedding模型是把问题和文档分别编码成向量,然后算相似度;重排模型是把问题和文档拼接在一起,用交叉编码器(Cross-Encoder)直接计算相关性分数。因为重排模型“同时看到了问题和文档的全部内容”,所以它能捕捉到更细腻的语义匹配信息,精度远高于向量相似度。代价是速度慢、计算成本高,这也是它只能用来重排候选集、不能用来做全库检索的原因。

推荐的组合方式是:召回阶段用Embedding模型(双塔架构,速度快,适合海量候选),精排阶段用Cross-Encoder重排模型(精度高,适合小规模精排)。开源的重排模型有BGE-Reranker系列、Cohere Rerank,实测下来都能有效提升RAG效果。

3. 从RAG到Agent:Agentic RAG的架构演进

如果你把RAG跑通了,下一个问题一定是:能不能让整个系统更智能一些?用户的问题不再只是“XX是什么”,而是“帮我对比一下这几个方案的差异”、“基于这些资料写一份报告”。这些问题没法靠一次检索解决,需要多次检索、多次推理、甚至调用其他工具。

这时候就需要引入Agent。

3.1 Agent框架选型:自己写还是用现成的?

Agent框架现在已经很成熟了,选型时主要看你的场景和团队的技术栈。我用过的几个主流选择:

  • LangChain/LangGraph:生态最全,文档多,踩坑的人也多,社区能找到各种案例。LangGraph比LangChain更偏底层,适合编排复杂的图结构流程。
  • AutoGen:微软出品,适合多Agent协作场景,多个Agent之间可以互相对话讨论。
  • Spring AI:如果你所在团队是Java技术栈,这是个好选择。它提供了类似LangChain的抽象能力,但用的是Java生态。
  • 自己写:如果你的场景不复杂,自己写一个Agent也不难。核心就是循环调用大模型,每次把工具调用的结果反馈给模型,让模型决定下一步做什么。这就是最朴素的ReAct模式。

我在工程实践中的建议是:如果你的流程相对固定(比如固定先检索再总结),用LangGraph或直接手写一个状态机就够了,不要上太重的框架。复杂框架带来的学习成本和维护成本,在早期会让项目进度拖慢一倍。反过来,如果你的业务场景有很多不确定性,Agent的行为需要非常灵活,那可以考虑LangGraph,尤其是它有持久化、人工介入、分支并行这些能力,更适合生产级应用。

3.2 Agent里面如何调用RAG工具

Agentic RAG和传统RAG的关键区别在于:谁来决定检索。

传统RAG是“问题进来就检索”,不管问题需不需要外部知识。Agentic RAG是“Agent先判断这个问题是否需要检索、需要检索什么、检索几轮”。这就带来一个核心问题:如何让Agent具备“是否检索”的决策能力?

常见做法是Function Calling。你把RAG检索功能封装成一个工具函数,比如knowledge_base_search(query: str) -> list[str],然后在给模型的消息里声明这个工具的存在。模型的输出如果是“需要调用工具”,就会返回一个结构化指令,格式大概是{"name": "knowledge_base_search", "arguments": {"query": "..."}}。你的代码检测到这样就执行函数,把结果作为新的消息再喂给模型,模型继续推理直到最终给出答案。

有一点值得注意:工具的描述信息非常关键。比如knowledge_base_search这个函数,你给模型的描述如果只是“搜索知识库”,模型不一定理解什么时候该用它。但如果你写“当你需要查询企业内部制度、产品文档、历史工单信息时使用此工具”,模型就能更准确地进行工具调用的决策。这一步我是在实际测试中发现的差异——描述从一句话改成一段话之后,工具调用的准确率大概提升了十几个百分点。

除了RAG检索,Agent里还可以挂很多其他工具:计算器、SQL查询、API调用、代码解释器等等。这就是Agent的威力所在——它不局限于“从资料里找答案”,而是能“调用各种工具完成一个完整任务”。

3.3 理解Skill和Agent之间的边界

热词里有一个搜索量很高的问题:“skill和agent的区别”。这个问题恰好是很多人刚接触Agent开发时会产生的疑惑。

用最朴素的话来解释:Skill是“能力”,Agent是“拥有能力的实体”。如果你在一个Agent开发平台里工作,Skill通常意味着某个特定领域的一组能力封装——比如“生成合同文本”是一个Skill,“做数据分析”是另一个Skill;而Agent则是把这些Skill组合起来,加上大模型的决策逻辑,为一个完整的业务目标服务的系统。

类比一下:Skill就像工具箱里的扳手、螺丝刀、电钻;Agent是那个会判断“现在该用扳手还是电钻”的工人。没有工具,工人效率低;没有人调度,工具就只是躺在工具箱里的死物。

在设计Agent系统时,我的建议是先梳理业务需要哪些Skill,再考虑Agent的编排逻辑。一个常见的错误是上来就画各种复杂的Agent流程图,结果连基础能力还没封装好。好的做法是:先把工具能力一个个做扎实,做成标准的函数或API,然后再设计Agent的决策逻辑去编排这些工具。

4. 实操环节:搭建一个可用的Agentic RAG系统

概念讲再多,不如上手跑一遍。这一节我把自己搭建一个Agentic RAG系统的完整过程拆开来讲。技术栈以Python为主,中间会穿插Java场景的说明。

4.1 基础技术栈搭建

我这次用的是LangGraph + OpenAI兼容接口 + BGE-M3 Embedding + Qdrant + BGE-Reranker。如果你有特殊原因用不了OpenAI,用开源的Qwen或DeepSeek模型也完全可以,Agent和RAG的核心逻辑是一样的。

先安装依赖:

pip install langgraph langchain langchain-openai qdrant-client fastembed sentence-transformers bge-reranker

注意fastembedsentence-transformers是两个不同的向量化库,fastembed更轻量,适合跑BGE系列;如果要用其他模型可以选sentence-transformers,这里有兼容性取舍,按需选择。

然后加载Embedding模型和向量数据库:

from sentence_transformers import SentenceTransformer from qdrant_client import QdrantClient embedding_model = SentenceTransformer("BAAI/bge-m3") client = QdrantClient(path="./local_qdrant") # 本地持久化模式 # 将文档向量写入集合 docs = [...] # 已经分块清洗好的文档列表 vectors = embedding_model.encode(docs) client.upload_points( collection_name="my_knowledge", points=[ {"id": i, "vector": vec, "payload": {"text": doc}} for i, (vec, doc) in enumerate(zip(vectors, docs)) ], )

这一步没什么黑科技,但有一个容易踩坑的地方:bge-m3的向量维度是1024,如果你之前用的是其他模型(比如OpenAI的1536维),同一个集合里只能用一种维度。所以向量库的集合设计要提前想好,不同模型的向量不能混存。

4.2 用代码实现Agentic RAG:一次完整流程

下载包里加了一条记录,标注了日期、文档内容和来源链接,方便后续审计。接下来看Agent的编排逻辑。

首先定义RAG检索工具:

def rag_search(query: str, top_k: int = 5) -> list[str]: """当你需要查询公司内部制度、产品文档、历史工单、FAQ等资料时使用此工具。""" query_vec = embedding_model.encode(query) hits = client.search( collection_name="my_knowledge", query_vector=query_vec, limit=top_k * 10 # 先召回50条 ) # 重排 reranker = CrossEncoder("BAAI/bge-reranker-v2-m3") pairs = [(query, hit.payload["text"]) for hit in hits] scores = reranker.predict(pairs) top_indices = sorted(range(len(scores)), key=lambda i: scores[i], reverse=True)[:top_k] return [hits[i].payload["text"] for i in top_indices]

然后是Agent的核心循环:

from langgraph.graph import StateGraph class AgentState(TypedDict): messages: list final_answer: str def agent_node(state): # 使用大模型判断是否需要调用工具 response = llm_with_tools.invoke(state["messages"]) if response.tool_calls: for call in response.tool_calls: if call["name"] == "rag_search": results = rag_search(call["arguments"]["query"]) state["messages"].append({"role": "tool", "content": results}) else: state["final_answer"] = response.content return state # 构建图 graph = StateGraph(AgentState) graph.add_node("agent", agent_node) graph.add_edge("agent", "agent") # 循环直到最终回答

这段代码看起来简单,但背后有个关键点值得多说几句:Agent的循环机制。大模型每一次输出要么是工具调用指令,要么是最终回答。你的代码要判断如果输出了工具调用指令,就把工具执行结果作为新的消息追加到对话里,再次调用模型,直到模型不再调用工具、给出最终答案。这个循环需要有上限控制(比如最多5轮),否则遇到复杂任务可能无限循环下去。

4.3 Java技术栈怎么落地:Spring AI实践

如果你的团队是Java技术栈,用Python搭一套RAG服务可能不太现实。这时候Spring AI是个不错的选择。Spring AI最近在Java社区讨论度很高,它提供了ChatClient、EmbeddingModel、VectorStore等抽象,用法和Spring Boot的风格很统一。

我在Java项目里的落地思路是:

  • 用Spring AI的EmbeddingModel接口对接BGE-M3或OpenAI的Embedding接口
  • PgVectorStore作为向量存储(如果团队已经有PostgreSQL实例,省得再引入其他中间件)
  • ChatClient对接大模型,传入系统提示词和检索结果

一段典型的Spring AI代码长这样:

@Service public class RagService { private final ChatClient chatClient; private final VectorStore vectorStore; public String answer(String question) { // 检索相关片段 List<Document> docs = vectorStore.similaritySearch( SearchRequest.builder() .query(question) .topK(5) .build() ); String context = docs.stream() .map(Document::getContent) .collect(Collectors.joining("\n---\n")); // 生成回答 return chatClient.prompt() .system("你是一个知识库助手。请仅基于以下资料回答问题,如果资料中没有相关信息,请明确告知用户。资料:\n" + context) .user(question) .call() .content(); } }

Java生态的好处是部署方便,和现有系统集成容易。缺点是很多新的Agent能力(比如复杂的LangGraph编排)在Spring AI里还不够成熟,如果需要复杂的Agent流程,还是需要自己实现状态机或引入其他编排框架。

5. RAG效果测评:怎么量化指标并看懂指标

热词里有两个高频问题:“rag测评怎么做”和“rag知识库指标有哪些,如何理解各指标”。这是非常现实的痛点——RAG系统上线前,你怎么证明它效果好?上线之后,怎么持续监控它的效果?没有量化手段,优化就是拍脑袋。

5.1 核心指标拆解:召回、答案质量、任务成功率

业界目前比较成熟的RAG评测框架是RAGAS(RAG Assessment),它把RAG系统的质量拆成几个维度,每个维度都可以用大模型自动评分:

  • 上下文相关性(Context Relevance):检索回来的片段和问题相关吗?如果检索结果和问题完全不相关,那就说明检索阶段有问题,可能是分块策略不对、Embedding模型不合适或查询改写不到位。
  • 忠实度(Faithfulness):最终答案的每个关键信息点都能在检索到的上下文里找到依据吗?如果答案里有上下文没有的信息,那说明模型在“自由发挥”,幻觉问题依然存在。
  • 答案相关性(Answer Relevance):最终答案和问题相关吗?有时候检索没问题,模型也能拿到正确上下文,但生成的答案偏了,这是生成环节的提示词问题。

在RAGAS之外,实际落地中还要看任务级别的指标:

  • 检索召回率(Recall@K):正确的信息片段是否在Top K里被召回到。
  • 准确率(Precision@K):召回的K个片段里到底有多少是真正相关的。
  • 端到端任务成功率:比如“工单分类正确率”“专利查新命中率”,这才是业务方真正关心的指标。

5.2 低成本可靠的自建评测流程

依赖现成工具是一方面,我更建议在自己的业务数据上构建一套小规模的评测集。做法是:

找业务方配合,整理50到100条典型问题,每条问题标注标准答案和答案对应的知识片段来源。然后建立评测流程:每次改动知识库处理流程或系统参数之后,用相同的问题集重新跑一遍,对比生成结果与标准答案的匹配度。这种方法不用大量人工,但能持续追踪系统质量的变化趋势。

实际操作中,我会这样做:先用RAGAS跑一遍自动评分,然后人工抽检Top 10和Bottom 10的问题,看看哪些问题评分不准,再根据具体现象去排查问题。检查顺序先是检索阶段——把问题输入到Retrieval工具,看看返回的Top 5片段靠不靠谱;如果检索不中,排查分块和Embedding环节;如果检索命中但答案不对,排查Prompt和生成环节。

5.3 指标看懂了之后:如何优化RAG效果

评测完的下一步是优化。这里有一个效率很高的优化优先级顺序(从成本低到高排列):

  • 先调Prompt:检查系统提示词是否清晰说明了“只能基于资料回答”,是否需要提示模型遇到不相关内容时选择“不知道”。这行代码成本最低,效果可能很明显。
  • 再调检索策略:尝试Top K从3改到5或8,或者加关键词搜索的混合召回,观察评测集指标的变化。
  • 然后调分块策略:如果某个常见问题检索不到,查看对应的文档分块结果,看信息是否被切碎了。
  • 最后才考虑换模型:Embedding模型和生成模型对效果影响很大,但模型更换成本也最高,建议留到确定其他环节都已稳定后再操作。

6. 常见问题与排查技巧实录

最后把我在这几年RAG/Agent项目里遇到的高频问题和排查经验整理出来,按问题的出现频率排序,方便你排查时对照。

6.1 检索质量太差:查不到或查不准

这是最常见的问题。现象:用户问的问题很明确,但返回的片段完全不相关。排查步骤:

  1. 先确认问题本身有没有歧义。有些用户问题很短,比如“如何部署”,范围太大,检索分不清方向。这时候可以用Agent做一个“查询改写”,把模糊问题拆成多个子查询,或者增加上下文信息。
  2. 确认分块粒度。如果你的文档一个块是2000字,一个块里包含多个主题,检索命中的块可能既有相关内容又有大量噪音。试试把块切小一点,让每个块只包含一个完整主题。
  3. 确认Embedding模型和你的业务领域匹配。如果用的通用Embedding模型,在专业术语多的场景(法律、医疗、专利)效果会打折。换领域专用的Embedding模型(比如法律领域、医疗领域的微调模型)往往能明显提升。

6.2 知识库更新了但检索不到新内容

常见原因:增量写入向量库时,没有删除旧版本。有些向量库的更新是追加模式——你上传了一份新版的制度文件,旧版也还在库里面,检索的时候新老版本混在一起,答案自然混乱。

解决方法是:写入新文档之前,先按文档ID或来源字段删除旧的向量记录,再写入新的。并且在Payload里带上版本号和生效日期,检索时可以做过滤。

6.3 模型幻觉:撤销不了怎么办

即使上了RAG,模型有时候还是会“强行输出”上下文里没有的信息。我的排查顺序是:

  1. 检查上下文是否真的覆盖了答案所需的信息。有时候检索返回了相关片段,但片段里的信息不足以回答用户的深度问题,模型只好自己发挥一部分。
  2. 检查Prompt里是否有明确的“不知道就直说”指令。很多模型如果没被明确告知“没有依据时不能说”,它宁愿编也不愿意承认自己不知道。
  3. 尝试降低temperature参数。这是最简单的操作,通常我建议RAG场景的temperature控制在0~0.3之间,过高会引入随机性,增加幻觉风险。

6.4 Agent卡死或报错:action execution terminated due to error

这个报错出现的场景很典型:Agent决定调用一个工具,但工具执行时抛了异常(比如参数格式不对、API超时),而Agent的循环机制没有捕获这个异常,导致整个流程终止。

排查思路:

  1. 工具函数的入参校验一定要做好。大模型生成JSON参数经常出现类型错误,比如把数字参数写成字符串。在工具函数入口处做严格校验,不符合就返回一个友好的错误消息给模型,让模型重新生成参数。
  2. 给Agent循环加异常捕获,工具出错时把错误信息反馈给大模型,让它重新尝试或调整策略,而不是直接终止。
  3. 设置最大迭代轮数,避免死循环。我一般设置5~8轮,超过就终止并返回当前结果。

6.5 上下文窗口不够用怎么办

当你用Agent处理复杂任务时,多轮工具调用的历史记录会占用大量上下文空间。常见做法是:

  • 对历史消息做截断,只保留最近的几轮。
  • 对检索回来的文档做压缩,用大模型把长段落总结成要点之后再送入上下文。
  • 用外部记忆存储长期特征信息,而不是全部堆在上下文里。

6.6 关于RAG评测和效果验证的一个实用技巧

这是我的一个习惯:每次改动RAG系统,我都不会只凭几个感觉上的例子判断效果好坏,而是固定跑同一套50个问题的评测集,记录每个问题在改动前后的答案质量和检索命中情况。这样能尽最大努力避免“改好了一个问题,结果带崩了另外几个问题”的情况。

我自己有一次把分块大小从400字改成800字,测试了3个“感觉不错”的样本觉得效果提升了,但跑了完整评测集后才发现召回率下降了不少。从此以后,任何改动都要过一遍评测集,这已经成为我个人的硬性要求。


最后再分享一个小技巧:做RAG/Agent项目时,尽量让你的知识库文档保留结构信息,不要把所有内容扁平化切成一个个块。如果可能,在块里加上标题层级路径(比如“第一章/第二节/3.1条款”),检索的时候不仅能返回内容,还能让模型知道这段内容在文档中的位置,回答问题时能附带引用来源,这在很多严肃场景(专利、法律、金融报告)里几乎是刚需。这一步看起来费事,但做完了,整个系统的可信度和可用性都会上一个台阶。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 10:37:44

开源RISC-V软核MCU在FPGA上的实现与实战解析

前段时间我在 GitHub 上刷到一个有意思的开源项目&#xff0c;标题一句话就戳中了我&#xff1a;“MCU 做到 FPGA 的实力”。乍看像营销话术&#xff0c;但点进去之后我发现&#xff0c;它其实是在做一件很有价值的事&#xff1a;把一个可编程的 MCU 软核完整跑在 FPGA 里&…

作者头像 李华
网站建设 2026/9/6 10:36:27

树莓派Pico ADC实战:用C语言面向对象封装PS2摇杆模块

做嵌入式这段时间&#xff0c;我最常被问到的一个问题就是&#xff1a;ADC 到底怎么学&#xff1f;直接啃手册太枯燥&#xff0c;做项目又不知道从哪里上手。如果你也有这种感觉&#xff0c;我强烈建议你从这个小项目开始&#xff1a;用树莓派 Pico 读取一个 PS2 摇杆模块的数据…

作者头像 李华
网站建设 2026/9/6 10:32:52

STM32 MPU6050滤波与姿态解算实战:滑动窗口、低通滤波到互补滤波

1. 项目概述与需求拆解1.1 MPU6050这颗传感器&#xff0c;到底难在哪玩过 stm32 的人&#xff0c;十有八九都碰过 mpu6050 这颗六轴传感器。它便宜、资料多、例程遍地都是&#xff0c;但也正因为用的人多&#xff0c;大家踩过的坑才格外五花八门——尤其是"滤波"这两…

作者头像 李华
网站建设 2026/9/6 10:30:47

基于MicroPython的ADS1115高精度ADC驱动与滤波实践

如果你手里正好有一块ADC模块&#xff0c;又刚好在MicroPython环境里做数据采集&#xff0c;那这篇内容应该能帮你少走不少弯路。我这次整理的是ADS1115这颗16位ADC从硬件接线、I2C通信、寄存器驱动&#xff0c;到采样触发和滤波处理的完整实践记录。文章里所有代码我都在ESP32…

作者头像 李华
网站建设 2026/9/6 10:30:35

用嵌入式开发DIY美人鱼主题智能手链:硬件拆解与制作指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 10:25:47

深入CMSIS-DSP:从源码审计到工业固件落地的完整实践指南

1. 这套库到底解决什么问题&#xff1a;从项目背景和架构全景说起如果你在 Cortex-M 内核上做过任何形式的数字信号处理&#xff0c;比如 FIR/IIR 滤波、FFT 频谱分析、矩阵求逆&#xff0c;或者 PID 控制器里的微分项平滑&#xff0c;那你大概率已经听说过 CMSIS-DSP。这是 AR…

作者头像 李华