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

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

从 100 行代码到生产级 Pipeline

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

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

要切分文本? 你那个朴素的 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_chaincreate_stuff_documents_chain 在 1.x 中已被移除。代码用的是 LCEL 原生语法(|> 管道符组合),功能完全等价,且不依赖特定版本的高层 API。


每个阶段的常见坑

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

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

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 XYZ博客