RAG 系列(二):用 LangChain 搭建你的第一个 RAG Pipeline

作者:冬奇Lab日期:2026/4/30

从 100 行代码到生产级 Pipeline

上一篇我们用手写 Python 搭了一个最小 RAG,100 行代码跑通了核心逻辑。但如果你想把那套代码搬到生产环境,很快就会撞上一堵墙。

要加载 PDF? 你需要 PyPDF2 或 pdfplumber,然后发现表格、页眉页脚的解析是一场噩梦。

要切分文本? 你那个朴素的 text.split("\n\n") 会把句子拦腰截断、破坏代码块,或者切出超长的块直接把 Token 上限撑爆。

想换个向量数据库? 祝你下午愉快——每个数据库的 API 都不一样,距离度量不一样,元数据处理也不一样。

想换个 LLM 提供商? OpenAI 的客户端、Anthropic 的客户端、本地 llama.cpp……每个都有自己的消息格式、Token 计算方式、错误处理逻辑。

这正是 LangChain 存在的意义。它不搞什么魔法,也不替代底层的模型或数据库。它只做一件简单但有价值的事:给所有组件提供一个统一的接口,让你专注于 RAG 系统的业务逻辑,而不是 plumbing( plumbing 指的是那些连接管道的脏活累活)。

这篇文章,我们用 LangChain 的现代 API 重建 RAG Pipeline。读到最后,你会拥有一个完整的、可运行的项目:它能读取 PDF、智能切分、存入 ChromaDB、用多 Provider LLM 回答问题——而真正的 Pipeline 代码只有大约 30 行。

LangChain 版本说明: 本文代码基于 langchain 1.2.x(当前主流稳定版)。langchain 1.x 对 0.3.x 做了破坏性重组,部分高层 API(如 create_retrieval_chain)被移除。代码改用 LCEL 原生语法(| 管道符)组合 Chain,功能完全等价,且不依赖版本。完整源码:github.com/chendongqi/…


RAG Pipeline 的六大组件

LangChain 把 RAG 拆解成六个组件。理解每个组件是做什么的、质量风险藏在哪里——这是以后调试 RAG 系统的关键。

组件职责质量风险
Document Loader读取原始文件(PDF、Word、Markdown、HTML)并提取文本表格、图片、奇怪格式会被搞砸
Text Splitter把长文档切成语义连贯的小块块太大 = 精度低;块太小 = 丢失上下文
Embedding Model把文本块转换成高维向量模型选错 = 语义不相关的文本聚到一起
Vector Store持久化向量,支持快速相似度检索距离度量选错、没有元数据过滤 = 检索质量差
Retriever接收查询,检索向量库,返回相关块Top-K 太小 = 漏信息;太大 = 引入噪声
Chain编排完整流程:查询 → 检索 → 组装 Prompt → LLM → 答案Prompt 设计和上下文组装决定回答质量

把六个组件想象成工厂里的一条流水线:Document Loader 是原材料进料口,Text Splitter 是精密切割站,Embedding Model 和 Vector Store 是仓库和库存系统,Retriever 是拣货员,Chain 是车间主任——协调一切并交付最终产品。

流水线上任何一个工位配置错了,最终产品都会受影响——而棘手的是,失败看起来经常是 LLM 的问题,实际上是检索的问题。


实战:完整的 LangChain RAG 项目

我们来动手搭建。这个项目会读取一个目录下的 PDF 文件,建立索引,然后让你用自然语言提问。

项目结构

1rag-project/
2├── requirements.txt
3├── data/
4│   └── sample.pdf          # 把你的 PDF 文档放这里
5└── rag_pipeline.py
6

Step 0:安装依赖

1langchain>=0.3.0
2langchain-text-splitters>=0.3.0
3langchain-openai>=0.2.0
4langchain-chroma>=0.1.0
5langchain-community>=0.3.0
6pypdf>=4.0.0
7python-dotenv>=1.0.0
8

完整源码(可直接运行): github.com/chendongqi/…支持智谱 AI / OpenAI / Ollama 多 LLM Provider,Embedding 支持 SiliconFlow 和本地 Ollama。

安装:

1pip install -r requirements.txt
2

还需要配置 API Key(复制 .env.example 为 .env 后填入):

1cp .env.example .env
2# 编辑 .env,填入 LLM_API_KEY 和 EMBEDDING_API_KEY
3

支持的 Provider:

  • LLM:智谱 AI(默认)、OpenAI、SiliconFlow、Ollama、Azure
  • Embedding:SiliconFlow(默认)、OpenAI、Ollama

Step 1:加载文档

PyPDFLoader 帮我们处理 PDF 解析。它按页提取文本,返回一个 Document 对象列表,每个对象包含页面内容和元数据(页码、来源文件等)。

1from langchain_community.document_loaders import PyPDFLoader
2from pathlib import Path
3
4def load_pdfs(data_dir: str = "./data"):
5    """从数据目录加载所有 PDF 文件"""
6    documents = []
7    pdf_paths = list(Path(data_dir).glob("*.pdf"))
8
9    for pdf_path in pdf_paths:
10        loader = PyPDFLoader(str(pdf_path))
11        pages = loader.load()
12        documents.extend(pages)
13        print(f"已加载 '{pdf_path.name}':{len(pages)} 页")
14
15    print(f"共加载 {len(documents)} 个文档片段")
16    return documents
17

真实世界提示: PDF 是文档格式里的"狂野西部"。如果你的 PDF 是扫描件(图片),你需要 OCR(通过 pdfplumber + Tesseract 或 Azure Document Intelligence)。如果 PDF 里有很多表格,考虑用 UnstructuredPDFLoader,它对表格结构的保留比纯文本提取好得多。

Step 2:切分文档

还记得第一篇里的分块问题吗?LangChain 的 RecursiveCharacterTextSplitter 能成为行业默认不是没道理的。它会尝试按自然边界切分——先按段落、再按换行、再按句子、再按单词——尽量避免在句子中间切断。

1from langchain_text_splitters import RecursiveCharacterTextSplitter
2
3def split_documents(documents, chunk_size=200, chunk_overlap=30):
4    """
5    将文档切分为有重叠的块
6    chunk_overlap 确保相邻块之间有上下文连续性
7    """
8    splitter = RecursiveCharacterTextSplitter(
9        chunk_size=chunk_size,
10        chunk_overlap=chunk_overlap,
11        length_function=len,
12        separators=["\n\n", "\n", ". ", " ", ""]
13    )
14
15    chunks = splitter.split_documents(documents)
16    print(f"切分为 {len(chunks)} 个块(chunk_size={chunk_size},overlap={chunk_overlap})")
17    return chunks
18

为什么 chunk_overlap 很重要: 如果一个关键概念横跨两个块——比如"API 速率限制是每分钟 100 次请求。超过限制会返回 429 状态码"——50 个字符的重叠能确保第二个块里还保留着"每分钟 100 次请求"的上下文。没有重叠的话,Retriever 可能只召回一个块,漏掉因果关系。

Chunk size 的权衡:

Chunk 大小精度上下文适合场景
256 tokens高最少事实查询、结构化文档问答
512 tokens平衡中等通用 RAG(推荐默认值)
1024 tokens较低丰富长文摘要、叙事类文档
2048+ tokens低非常丰富仅当 LLM 上下文窗口很大且查询范围很广时

大多数场景下,512 tokens + 50 token 重叠 是一个稳妥的起点。

Step 3:Embedding 并存入 ChromaDB

现在把每个块转成向量并存起来。这里选 ChromaDB,因为它支持持久化(数据不会随重启丢失)、支持元数据过滤、而且零配置——作为嵌入式数据库本地运行。

1from langchain_openai import OpenAIEmbeddings
2from langchain_chroma import Chroma
3import os
4
5persist_directory = "./chroma_db"
6
7def build_vector_store(chunks):
8    """创建 Embedding 并存入 ChromaDB"""
9    embeddings = OpenAIEmbeddings(
10        model="BAAI/bge-large-zh-v1.5",  # SiliconFlow 中文模型
11        api_key=os.getenv("EMBEDDING_API_KEY"),
12        base_url="https://api.siliconflow.cn/v1",
13        dimensions=1024,
14        chunk_size=32  # SiliconFlow 限制每批最多 32 条
15    )
16
17    if os.path.exists(persist_directory):
18        import shutil
19        shutil.rmtree(persist_directory)
20
21    vector_store = Chroma.from_documents(
22        documents=chunks,
23        embedding=embeddings,
24        persist_directory=persist_directory
25    )
26    print(f"向量库构建完成:{vector_store._collection.count()} 个向量已持久化")
27    return vector_store
28

Embedding 模型说明: 这里用 SiliconFlow 上的 BAAI/bge-large-zh-v1.5(中文效果优秀),通过 langchain_openai 的 OpenAI 兼容接口接入。如果用 OpenAI 官方,换成 text-embedding-3-small 即可。chunk_size=32 是 SiliconFlow 的批次限制(每批最多 32 条),其他 Provider 通常默认 1000 条。

Step 4:构建 Retriever

Retriever 是向量库的一个薄封装,负责处理搜索逻辑。默认情况下,它做相似度搜索,返回最相关的 Top-K 个块。

1def get_retriever(vector_store, search_k=4):
2    """配置相似度检索的 Retriever"""
3    retriever = vector_store.as_retriever(
4        search_type="similarity",
5        search_kwargs={"k": search_k}
6    )
7    return retriever
8

Step 5:构建 RAG Chain

这里是 LangChain 现代 API 最亮眼的地方。不用老旧的 RetrievalQA 类,我们用 LCEL(LangChain Expression Language,LangChain 表达式语言)来组合 Chain——代码更直观、更容易调试、也更容易修改。

1from langchain_openai import ChatOpenAI
2from langchain_core.prompts import ChatPromptTemplate
3from langchain_core.output_parsers import StrOutputParser
4from langchain_core.runnables import RunnablePassthrough
5
6def build_rag_chain(retriever):
7    """
8    构建完整 RAG Chain(langchain 1.x 兼容写法,不依赖 create_retrieval_chain)
9    检索 → format_docs → 塞进 Prompt → LLM → StrOutputParser
10    """
11    llm = ChatOpenAI(
12        model="glm-4-flash",  # 智谱 AI 模型,通过 SiliconFlow 或直连
13        api_key=os.getenv("LLM_API_KEY"),
14        base_url="https://open.bigmodel.cn/api/paas/v4",
15        temperature=0
16    )
17
18    # System Prompt,{context} 由 format_docs 填充,{question} 是用户原始问题
19    system_prompt = (
20        "你是一个精准的知识助手。请仅根据下方提供的参考内容回答用户问题。"
21        "如果参考内容中没有答案,请明确说明——不要编造。\n\n"
22        "参考内容:\n{context}"
23    )
24
25    prompt = ChatPromptTemplate.from_messages([
26        ("system", system_prompt),
27        ("human", "{question}")
28    ])
29
30    # 辅助函数:把 Document 列表转成字符串
31    def format_docs(docs: list) -> str:
32        return "\n\n".join(doc.page_content for doc in docs)
33
34    # LCEL Chain:用管道符 | 组合各个组件
35    # 1. {"context": retriever | format_docs, "question": RunnablePassthrough()}
36    #    → retriever 检索文档,format_docs 把 Document 对象列表转成字符串
37    # 2. | prompt → 组装成完整的 Prompt
38    # 3. | llm → LLM 生成答案
39    # 4. | StrOutputParser() → 输出纯文本(而不是 AIMessage 对象)
40    rag_chain = (
41        {
42            "context": retriever | format_docs,
43            "question": RunnablePassthrough()
44        }
45        | prompt
46        | llm
47        | StrOutputParser()
48    )
49
50    return rag_chain
51

这里发生了什么? 我们用的是 LCEL(LangChain Expression Language)原生语法,用 | 管道符把各个组件串联起来,而不是用高层的 create_retrieval_chain(该函数在 langchain 1.x 中已被移除)。

关键在于 retriever | format_docs:Retriever 返回的是 Document 对象列表,format_docs 把它转成字符串填入 {context} 占位符。RunnablePassthrough() 把用户的原始问题透传到 {question} 占位符。这三行代码等价于第一篇里的手写检索 + 组装 + 生成逻辑。

Step 6:查询 Pipeline

1def query(rag_chain, question: str, retriever):
2    """把问题丢进 RAG Pipeline 跑一遍,打印答案和来源"""
3    print(f"\n问题:{question}")
4
5    answer = rag_chain.invoke(question)  # LCEL Chain 直接返回纯文本
6    print(f"\n答案:\n{answer}")
7
8    # 单独检索一次来源(rag_chain 不直接暴露 retrieved docs)
9    docs = retriever.invoke(question)
10    print("\n检索到的来源:")
11    for i, doc in enumerate(docs, 1):
12        source = doc.metadata.get("source", "未知")
13        page = doc.metadata.get("page", "?")
14        preview = doc.page_content[:120].replace("\n", " ")
15        print(f"  [{i}] {source}(第 {page} 页):{preview}...")
16
17    return answer
18

组装起来

1if __name__ == "__main__":
2    # 1. 加载
3    docs = load_pdfs("./data")
4
5    # 2. 切分(PDF 每页内容短,用较小的 chunk_size)
6    chunks = split_documents(docs, chunk_size=200, chunk_overlap=30)
7
8    # 3. Embedding & 存储
9    vector_store = build_vector_store(chunks)
10
11    # 4. 检索器
12    retriever = get_retriever(vector_store, search_k=4)
13
14    # 5. 构建 Chain(LCEL 方式)
15    rag_chain = build_rag_chain(retriever)
16
17    # 6. 交互式提问
18    while True:
19        user_input = input("\n你的问题(输入 quit 退出):").strip()
20        if user_input.lower() in ("quit", "exit", "q"):
21            break
22        if user_input:
23            query(rag_chain, user_input, retriever)
24

运行 Pipeline

把 PDF 放到 data/sample.pdf,然后运行:

1python rag_pipeline.py
2

示例输出:

1RAG Pipeline 启动
2  LLM Provider    : zhipu
3  LLM Model       : glm-4-flash
4  Embedding       : openai / BAAI/bge-large-zh-v1.5
5  数据目录        : ./data
6  向量库          : ./chroma_db
7==================================================
8已加载 'Automotive-SPICE-PAM-v40.pdf':153 页
9共加载 153 个文档片段
10切分为 2000 个块(chunk_size=200,overlap=30)
11[Embedding] Provider: openai | Model: BAAI/bge-large-zh-v1.5 | Base: https://api.siliconflow.cn/v1
12已清除旧向量库:./chroma_db
13向量库构建完成:2000 个向量已持久化
14==================================================
15RAG Pipeline 构建完成!输入问题开始问答(输入 'quit' 退出)
16==================================================
17
18你的问题:什么是 Automotive SPICE?
19
20==================================================
21问题:什么是 Automotive SPICE?
22==================================================
23
24答案:
25Automotive SPICE(Automotive Software Process Improvement and
26Capability Determination)是一种用于评估和改进汽车软件
27开发过程能力的框架。它定义了软件开发生命周期中的关键
28过程域,并建立了过程能力的等级评估标准...
29
30检索到的来源:
31  [1] ./data/Automotive-SPICE-PAM-v40.pdf(第 5 页):Automotive
32      SPICE Process Assessment Model The Process Assessment Model
33      (PAM) defines the processes...(正文来自 RAG 实际运行)
34

注意答案里带有来源引用——我们清楚知道信息来自哪几页。这种可追溯性对生产级 RAG 系统至关重要,因为用户需要验证答案的可靠性。


和 100 行手写版相比,变了什么?

对比一下第一篇的手写 RAG 和现在的 LangChain Pipeline:

对比项手写版(第一篇)LangChain 版(第二篇)
PDF 加载不支持一行 PyPDFLoader
文本切分没有(整篇传入)RecursiveCharacterTextSplitter 智能边界
向量持久化仅存内存,重启丢失ChromaDB 落盘持久化
换 Embedding 模型重写 API 调用改一个参数
换 LLM重写客户端代码改一个参数
换向量数据库重写存储 + 检索Chroma 换 Qdrant / Pinecone
Prompt 工程原始字符串拼接ChatPromptTemplate 模板化
来源引用手动维护元数据自动传递
Chain 构建手写 retrieve + generate 逻辑LCEL `` 管道符组合
Pipeline 代码量~80 行~25 行

这些抽象没有隐藏复杂性——而是隔离了它。当你需要调试检索质量时,你知道该调哪个组件。当你想换更便宜的 Embedding 模型时,改一行代码。当你的数据量超出 ChromaDB 的能力时,切到 Qdrant 不用动 Pipeline 的其他部分。

关于 LangChain 版本兼容性: 本文的代码基于 langchain 1.x(当前稳定版)。langchain 1.x 对 0.3.x 做了破坏性重组,create_retrieval_chain 和 create_stuff_documents_chain 在 1.x 中已被移除。代码用的是 LCEL 原生语法(|> 管道符组合),功能完全等价,且不依赖特定版本的高层 API。


每个阶段的常见坑

Loader 坑:"我的 PDF 里有表格,解析出来是一团糟"

原始 PDF 文本提取会把表格拍扁成一串数字。表格多的文档,用 UnstructuredPDFLoader 或 AzureAIDocumentIntelligenceLoader,它们能保留结构关系。

Splitter 坑:"答案被切成了两半,模型只看到了一半"

把 chunk_overlap 提高到 100-150,或者减小 chunk_size 让关键概念能放进一个块。更好的方案是 Parent-Document Retrieval(后续文章会讲)——用小块做检索,但返回完整的父文档作为上下文。

Embedding 坑:"问题和文档明明相关,就是匹配不上"

这是"非对称检索"问题。用户问"怎么重置密码?",文档写的是"要重置密码,请前往 设置 → 安全"。问题和答案的表面文本差异大,向量距离也远。解法:用针对 Q&A 检索微调的模型(如 BGE-M3),或者生成假设答案来做检索(HyDE——后续也会讲)。

Retriever 坑:"Top-K=4 不够用,复杂问题漏信息"

如果一个问题需要综合文档里五个不同部分的信息,k=4 就会漏掉一个。但盲目增大 k 会引入噪声。更好的做法:Multi-Query Retrieval(生成 3 个问题的变体,分别检索,去重)或者 Reranking(先召回 20 个,再用 Cross-Encoder 挑出最好的 5 个)。

Chain 坑:"模型无视上下文,开始 hallucinate"

Prompt 设计很重要。系统 Prompt 必须明确指示模型只用提供的上下文回答。加上"如果参考内容中没有答案,请明确说明——不要编造"能显著提升忠实度。我们会在评估篇里用 RAGAS 定量测量这个指标。


小结

这篇文章把第一篇的裸奔 RAG 概念,包上了一个生产级框架。我们讲了:

  1. LangChain RAG Pipeline 的六大组件——Loader、Splitter、Embedding、Vector Store、Retriever、Chain,每个组件藏了什么质量风险。
  2. 一个完整可运行的项目——加载 PDF、用 RecursiveCharacterTextSplitter 切分、OpenAI Embedding、ChromaDB 存储、LangChain LCEL Chain 问答。
  3. Chunk size 的权衡——实际项目中 PDF 每页内容可能很短(200 字符),这时候 512 的默认值会产生 0 个块。200 + 30 重叠是实测可用的安全值。
  4. 每个阶段的常见坑——从 PDF 表格解析失败,到非对称检索失配。

这篇文章的代码是一个扎实的基础。它能处理真实 PDF、持久化数据、还能给出来源引用。但它仍然是一个朴素 RAG(Naive RAG)——一次查询、一次检索、一次回答。后面的文章会逐步加入区分玩具 Demo 和生产系统的组件:混合检索、Reranking、查询优化、评估框架。


参考资料


《RAG 系列(二):用 LangChain 搭建你的第一个 RAG Pipeline》 是转载文章,点击查看原文。


相关推荐


告别 jq 噩梦!这款 JSON 神器 fx 让你在终端体验“丝滑”的数据操作
GetcharZp2026/4/21

还在为复杂的 jq 语法抓狂?antonmedv/fx 带着交互式 TUI 和纯正 JavaScript 语法来了!JSON 调试、过滤、转换,一个工具全搞定。 在程序员的日常摸鱼……哦不,日常开发中,JSON 绝对是出现频率最高的朋友。 不管是调用后端接口、查看 K8s 配置,还是分析爬虫数据,面对满屏密密麻麻、甚至没有缩进的原始 JSON 字符串,我们的第一反应通常是: 打开浏览器,搜索“JSON 在线格式化”。 把数据粘进去,点一下“美化”。 忍受网页弹窗广告,或者担心敏感数据泄露。


实测对比:哪款开源 Kubernetes MySQL Operator 最值得用?(2026 深度评测)
小猿姐2026/4/13

本文基于作者在 AWS EKS 上对四款 MySQL Operator 的真实部署与测试,覆盖集群搭建、高可用切换、弹性扩缩容、动态参数、TLS 等维度,适合正在评估 MySQL Kubernetes 方案的工程师参考。 一、为什么要做这次对比测试? 过去两年,越来越多的团队开始将 MySQL 从虚拟机迁移到 Kubernetes。驱动力很直接:统一的基础设施管控、更快的弹性扩容、以及 GitOps 风格的声明式运维。 但随之而来的问题是:MySQL Operator 怎么选? 我们决定不依赖


Claude Code 的权限系统是如何工作的
candyTong2026/4/5

在 agent runtime 的实现里,权限从来不是外围配置项,而是执行系统的一部分。只要模型开始改文件、跑命令、调用外部工具,系统就必须回答一个核心问题:这一步是否允许执行,以及这个判断应该在执行链路的哪个位置完成。 Claude Code 的权限系统很适合作为分析样本。它不是在工具外面额外包一层确认框,而是把权限判断直接嵌入工具调用链路,让一次工具调用从发起到落地,始终伴随一套可组合、可回写的运行时裁决。 文章从一个常见工作场景切入,分析权限系统实际解决的问题、内部层次划分,以及这些设计对


阿里云服务迁移实战(二)——网关迁移与前后端分离配置
KD2026/3/27

一、背景 由于业务原因,需要把服务器从外部阿里云账号迁移到阿里云账号 原阿里云是在服务器上部署Nginx做网关,迁移后改用阿里云CLB 同时对前后端分离逻辑做梳理,调整为更高效合理的配置 二、Nginx迁移至CLB 1.采用阿里云CLB原因 高可用性:会自动做健康检查,如果服务出现问题,会自动做流量切换 自动化管理:部署后阿里云会处理CLB的监控、更新和运维,无需手动维护 2.迁移前 迁移前Nginx部署在一台ECS服务器上 3.迁移后 迁移后单独部署负载均衡CLB 4.迁移


我让 AI 操作网页之后,开始不想点按钮了
糟糕好吃2026/3/19

每天在后台系统填表单、在电商网站筛商品、在管理后台点来点去……如果有一天,你只需要说一句话,AI 就能替你干完这些活,你会不会觉得:我的双手终于可以解放了? 说实话,我第一次看到阿里开源的 PageAgent 时,脑子里蹦出的就是上面那句话。这是一个能听懂人话、然后直接帮你操作网页的小工具——不需要写脚本,不需要装插件(甚至可以用书签),只需要一行代码,或者一句话。 它让我突然意识到:我们和网页的交互方式,可能正在迎来一次真正的变革。 一、体验下三个让你“哇塞”的场景 场景一:后台系统创建用


【OpenClaw养虾】从零开始部署安装,接入QQ机器人
卷福同学2026/3/11

从零开始的养虾记 1.OpenClaw是什么 OpenClaw最近非常的火,友友们可以在各种地方刷到它,但是还是有很多人不知道这是个什么东西,能做啥 简单总结,它真正解决了一个问题:让AI从”能聊天“变成”能干活“ 2.OpenClaw能做啥 OpenClaw是一个开源的AI Agent框架,让AI拥有了手和脚,能自动执行任务、调用浏览器、操作工具等等。 以运营自媒体账号为例,用OpenClaw搭建自动化系统,AI可完成的工作: 自动选题 自动写作 自动配图 自动发文,一键发布到公众号、小


我把大脑开源给了AI
风象南2026/3/3

前段时间遇到个很烦人的问题:随着用 AI 的频率越来越高,我发现自己每天都在做重复的“填表”工作。 代码在 GitHub,笔记在语雀,灵感在手机微信备忘录。每次开一个新的 AI 对话框,我都要不厌其烦地重新给它喂背景信息:“我是谁”、“我的项目规范是什么”、信息需要从各个系统同步到AI,效率极低。 为了解决这个问题,我干脆把这些散落的东西整合了起来,建了一个纯文本的本地知识库——我叫它 AIStudio。 一开始只是想弄个集中的仓库,方便AI找到它需要的东西,但用着用着,这套架构演变成了一个我和


LeetCode 762.二进制表示中质数个计算置位:位运算(mask O(1)判断)
Tisfy2026/2/22

【LetMeFly】762.二进制表示中质数个计算置位:位运算(mask O(1)判断) 力扣题目链接:https://leetcode.cn/problems/prime-number-of-set-bits-in-binary-representation/ 给你两个整数 left 和 right ,在闭区间 [left, right] 范围内,统计并返回 计算置位位数为质数 的整数个数。 计算置位位数 就是二进制表示中 1 的个数。 例如, 21 的二进制表示 10101 有 3


Flutter 正在计划提供 Packaged AI Assets 的支持,让你的包/插件可以更好被 AI 理解和选择
恋猫de小郭2026/2/14

如何让开源项目能够持续获得资金支持,2025 - 2026 的答案肯定是紧跟 AI 。 2025 年 Dart/Flutter MCP 和 Flutter GenUI 的出现,无疑让 Flutter 在 AI 上刷新了存在感,特别是谷歌核心项目 NotebookLM 在 Flutter 上的成功,也让 Flutter 在 AI 应用场景证明了可行性,这从第三方 appfigures 提供的数据也可以有明显体现: 数据是 appfigures 分析数百万个 iOS 和 Android 应用和游


JavaScript的数据类型 —— Boolean类型
橘朵2026/2/6

Boolean(布尔值)类型有两个字面值:true和false。 这两个布尔值不同于数值,因此 true 不等于 1,false 不等于 0。 虽然布尔值只有两个,但所有其他类型的值都有相应布尔值的等价形式,可以调用特定的Boolean() 转型函数: let message = "Hello world!"; let messageAsBoolean = Boolean(message); Boolean()转型函数可以在任意类型的数据上调用,而且始终返回一个布尔值。 下面是不同类型与布尔

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读