news 2026/8/28 4:17:45

小白程序员轻松入门大模型RAG,让你的AI回答更靠谱!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
小白程序员轻松入门大模型RAG,让你的AI回答更靠谱!

大语言模型受限于训练数据,无法回答训练数据之外的最新信息。本文介绍了RAG(检索增强生成)技术,通过从指定知识库中检索相关依据,再基于这些真实文档来回答问题,有效解决大模型的幻觉问题。文章详细讲解了RAG的离线索引和在线查询流程,包括文档加载、切分、嵌入、入库、检索等关键步骤,并对比了2-Step和Agentic两种RAG实现方式,帮助读者快速掌握大模型应用的新技术。

生产环境里,第二种情况是不能接受的。

RAG 要解决的问题就是让模型在回答之前,先到指定的知识库里查一圈,找到相关依据,再基于这些真实文档来回答。

环境基线:Python 3.13、langchain>=1.3.2,另需langchain-text-splitterslangchain-community(Loader)、以及一家 Embedding 包(下文用langchain-openai举例,可换成别家)。聊天模型仍从common.models.get_model拿。

混合检索调参、大规模评测留给后续 RAG 专栏;本篇打通全流程,并写清 2-Step / Agentic、溯源 artifact、以及和长期记忆 Store 的差别。

一、概述

RAG(Retrieval-Augmented Generation,检索增强生成)名字拆开就三步:

  1. Retrieval(检索):从知识库找出和问题最相关的文档片段

  2. Augmentation(增强):把片段 + 用户问题拼进 prompt

  3. Generation(生成):模型基于增强后的上下文写回答

RAG = 检索 + 拼接 + 生成,让模型回答训练数据之外的事,靠的是真实文档当依据,不是指望模型按照概率来推断。

有以下一些场景,AI可能解决不了,需要RAG来优化:

痛点表现RAG 怎么顶上
知识过时训练截止后的政策/新闻它不知道,容易瞎编查库,库更新即「新知识」
没有私有数据内网制度、客户手册不在训练集里私有文档进自己的索引
幻觉不知道也硬答有片段才答;没有就拒答
微调太重改知识还要重训/继续训改知识库即可,不必重训模型
无法追责答完说不清依据片段带来源,可展示、可审计
塞不下全文几十万字不能整库进一次 prompt只取 top-k 相关块

两句话对照:

  • 传统:用户问题 → LLM → 答案(只靠训练记忆)
  • RAG:用户问题 → 检索 → 拼进 prompt → LLM → 答案(先给证据)

用检索替代微调,让模型以较低成本拿到最新、相关、可核对的外部知识。

若你已经有 SQL / 文档中台 / 搜索服务,不必为了「用 LangChain」重造库,可以把现成查询封成工具(Agentic),或查完把结果当 context 塞进提示(2-Step)。下面仍从用文件建向量库讲起,这是最常见的入门教学。

二、2-Step 与 Agentic

官方把常见接法分成三类,2-Step、Agentic、Hybrid,本篇重点讲2-Step 和 Agentic。

架构原理控制力灵活度延迟典型场景
2-Step RAG每次回答前固定先检索,再生成相对可预期FAQ、文档问答
Agentic RAGAgent 自己决定何时、用哪个检索工具、查几次波动大研究助手、多工具混用
Hybrid在中间加改写、检索 sufficiency、答案校验等视迭代次数要对齐质量门禁的领域问答

2-Step流水线写死一定查一次文档。实现简单,调用次数上限清楚,适合几乎每个问题都该看文档的客服知识库。

Agentic检索只是普通@tool。闲聊时可以不查文档;复杂问题可以改写 query 再查第二遍。代价是多几轮模型调用,也更依赖提示约束「没查到就说不知道」。

三、入库流水线

经典的RAG流程分为两个,离线索引与在线查询。

阶段什么时候跑干什么
离线索引(Indexing)建库时做一次,文档变更后再跑文档 → 加载 → 切分 → 嵌入 → 写入向量库
在线查询(Query)每次用户提问问题嵌入 → 相似度搜索 → Top-K → 拼进 prompt → 生成

检索好不好,很大程度在离线阶段就定了:文档切分好不好、Embedding 对不对很重要,前面的做不好,在线阶段再调 prompt 也效果不好。在线阶段要精确控制,只取相关片段,别试图把整库塞进窗口。

离线五步可以记成一条链:

  1. 加载(Load):文件/网页 → 标准Document

  2. 切分(Split):长文 → 小块 chunk

  3. 向量化(Embed):文本 → 稠密向量

  4. 入库(Store):向量 + 原文 + 元数据 → 向量库

  5. 检索器(Retrieve):查询时近邻搜索,返回相关Document(这一步挂在「在线」;as_retriever往往离线末尾配好)

在线阶段,输入的问题也要变成向量(或交给检索器封装),然后检索取出 top-k,再增强 prompt、生成回答。

为了更好的通用性和替换性,我们本项目做了很好的封装,可以随时换 Loader、换切分策略、换 Embedding 供应商、换 PGVector / Chroma,业务代码尽量只依赖接口或工具。

Document是全流程的基本单位:

from langchain_core.documents import Document doc = Document( page_content="退货须在签收后 7 日内申请。", # 真正被检索和塞进提示的正文 metadata={"source": "refund_policy.md", "section": "时限"}, # 溯源、过滤用 )

page_content是语义主体;metadata不参与(默认)向量计算,但回答时如果要引用出自哪份文件或者需要按目录过滤时,还得靠metadata

四、加载与切分

  1. 1 加载:先变成 Document 列表

本地纯文本最简单,用TextLoader

from langchain_community.document_loaders import TextLoader # encoding 按文件实际编码来;Windows 上中文常见 gb18030 / utf-8 loader = TextLoader("data/faq.txt", encoding="utf-8") docs = loader.load() # List[Document],通常一个文件一个 Document(未切分前)

其它常见入口(装对应依赖即可):PyPDFLoader(PDF)、WebBaseLoader(网页)、目录用DirectoryLoader批量加载。Loader 只负责读进来并尽量带上 source 等元数据,不管切多细。

  1. 2 为什么要切块

如果一个文档很大,几十万字整个丢进 大模型,不仅上下文窗口会爆,token消耗巨大,检索也无法准确命中段落。切块之后,检索单位是一小段话,生成时只拼 top-k 段,成本和噪声都可控。

  1. 3 RecursiveCharacterTextSplitter

LangChain 里最常用的通用切分器:按分隔符列表递归切,优先在段落边界断开,切不干净再退到行、空格、字符。默认分隔符顺序大致是:"/n/n""/n"" """

from langchain_text_splitters import RecursiveCharacterTextSplitter splitter = RecursiveCharacterTextSplitter( chunk_size=500, # 单块上限(默认按字符计,不是 token) chunk_overlap=80, # 相邻块重叠,减轻「一句话被砍两半」 add_start_index=True, # metadata 里记下在原文的起始偏移,方便调试 ) chunks = splitter.split_documents(docs) print(len(docs), "->", len(chunks))

Markdown / 代码还有更贴结构的 splitter;中文没有空格时,递归仍主要靠换行和标点附近的回退,不要照搬英文「按词」的直觉,以抽查看块是否完整为准。

  1. 4 chunk_size 与 chunk_overlap

这两个参数最容易混,用一张图对齐:

chunk_size:每一块允许的最大长度(该 splitter 默认是字符数)。文档 10000 字、chunk_size=4000,大约会切成多块,每块不超过 4000(实际还会尽量在分隔符处提前断开,所以常小于上限)。

chunk_overlap:相邻两块共享的一段尾巴/开头。例如chunk_size=1000chunk_overlap=200时,第一块若落到 1–1000,第二块会从大约 801 起——801–1000 这段两边都有。

为什么要重叠?语义经常骑在切分边界上:上一块结尾半句条件,下一块开头半句结论。没有 overlap,只命中一块时,模型可能看到残句。overlap 太小不管用;太大则冗余高、块数变多、索引和检索都变贵。

经验参考(需根据自己的项目调整):

场景chunk_sizechunk_overlap
短 FAQ、条目清晰300–60040–80
制度/手册段落500–100080–150
长叙事、需更多上下文1000–1500150–200

没有万能值。同一份文档用两三种 size 各建一小库,拿 20 个真实问题看「该中的段在不在 top-k」,拿实际结果作比较。Overlap 常见取 size 的 10%–20%。

切完务必print几块:有没有把表格砍碎、把「不适用情形」和「适用情形」拆到两个永远不同时召回的块里。这种问题改切分,比改 prompt 管用。

五、Embedding、向量库与元数据

  1. 1 Embedding

Embedding 把一段文本变成固定维向量,让「意思近」的文本在空间里也近。检索时:问题 → 向量,在库里找最近的 chunk 向量,取回原文。

聊天模型(get_model())和 Embedding 模型是不一样的,不要把 chat 模型的接口硬当成 embed 用。选 Embedding 时优先:

  1. 和文档语言匹配(中文语料用中文效果好的模型)。

  2. 维度、价格、是否可本地部署。

  3. 一经建库,换 Embedding 模型通常要整库重嵌,选型最好早定。

# 示例:OpenAI 兼容接口;换成 DashScope / 本地 bge 等均可 from langchain_openai import OpenAIEmbeddings embeddings = OpenAIEmbeddings(model="text-embedding-3-small") # 向量维度由模型决定;同一库全程必须用同一 embedding

本地可试HuggingFaceEmbeddings(如BAAI/bge-small-zh-v1.5);公司内网常见「OpenAI 兼容的 embedding HTTP 接口」,用OpenAIEmbeddings(base_url=...)指过去即可。

  1. 2 向量库

向量库保存向量、对应的page_contentmetadata,并提供相似度查询。自己做demo或者实验用内存库;生产要换 Postgres(pgvector)、Chroma、Milvus、云检索等。

from langchain_core.vectorstores import InMemoryVectorStore # 从 Document 列表一次性构建:内部会对 page_content 调 embeddings vector_store = InMemoryVectorStore.from_documents( documents=chunks, embedding=embeddings, ) # 等价分步:先 empty store,再 add_documents # vector_store = InMemoryVectorStore(embeddings) # vector_store.add_documents(chunks)
  1. 3 元数据

建库前尽量写好 metadata,例如sourcetitlepageproductlang。之后可以:

  1. 回答里写「依据:退货政策 §3」。

  2. 检索时按产品线过滤(若向量库支持 metadata filter)。

  3. 评测时统计「错在哪份文档」。

切分后 metadata 一般会从父 Document 继承;add_start_index=True时还能看到块在原文的偏移。

  1. 4 Retriever

向量库可以.similarity_search(query, k=3),我们也可以自己封装一个 Retriever类,方便以后换成其它实现而不改调用方:

# 默认:相似度 Top-K retriever = vector_store.as_retriever( search_kwargs={"k": 3}, # 过大噪声多,过小易漏;FAQ 常 3–5 ) # 可选:MMR(最大边际相关性)——在「相关」和「彼此不重复」之间折中 # fetch_k 先多取一些候选,再挑多样性更好的 k 条 mmr_retriever = vector_store.as_retriever( search_type="mmr", search_kwargs={"k": 3, "fetch_k": 20}, ) hits = retriever.invoke("签收后多久可以退货?") for d in hits: print(d.metadata.get("source"), d.page_content[:80])

检索质量大致由这些因素决定:

因素太偏会怎样常见方向
切分粒度太粗噪声多;太细上下文会断第四节的 size/overlap
嵌入模型语义对不齐中文语料选中文效果好的(如 bge 系)
搜索算法只追相似易重复similarityvsmmr
Top-K少则漏、多则无关内容变多3–5,必要时加相似度阈值
元数据过滤搜全库干扰大按类型/日期/权限收窄

k调完仍然有很多无关文档,再靠第八节的重排、压缩来优化。

排查时可以先printtop-k 原文,确认证据在不在,再怪生成。

六、2-Step RAG

流程固定:问题 → 检索 → 拼 context → 提示词约束「只根据上下文」→ 模型生成。控制力强,延迟相对稳。

把多块正文用空行拼起来,是为了让模型把每块当成独立证据,而不是粘成一团:

from langchain_core.prompts import ChatPromptTemplate from common.models import get_model prompt = ChatPromptTemplate.from_template( """你是客服助手。只能根据下面「参考资料」回答。 资料不足以回答时,直接说「资料中未找到依据」,不要编造。 参考资料: {context} 用户问题: {question} """ ) model = get_model(temperature=0) def format_docs(docs) -> str: """把检索结果收成提示里的 context;双换行分隔块。""" return "/n/n".join(d.page_content for d in docs) def ask_2step(question: str) -> str: docs = retriever.invoke(question) # LCEL:字典进提示 → 模型;第 2 篇讲过的 Runnable 组合 chain = prompt | model resp = chain.invoke( { "context": format_docs(docs), "question": question, } ) return resp.content print(ask_2step("签收后多久可以退货?")) def format_docs_with_source(docs) -> str: parts = [] for i, d in enumerate(docs, 1): src = d.metadata.get("source", "unknown") parts.append(f"[{i}] 来源: {src}/n{d.page_content}") return "/n/n".join(parts)

并在模板里加一句:「回答末尾用 [编号] 标注依据。」

2-Step 的缺点也清楚:寒暄也查库;多跳问题(先要找政策名再找细节)不会自动拆查询。这些交给下一节。

七、Agentic RAG

Agentic RAG 最重要的是 把「查知识库」做成工具,交给create_agent。模型在循环里自己判断要不要查、用什么 query、查完够不够、要不要再查一轮。多轮对话若要记住上下文,像别的 Agent 一样挂上 checkpointer(参考第 8 篇)。

  1. 1 手写@tool

from langchain.agents import create_agent from langchain.tools import tool from langgraph.checkpoint.memory import InMemorySaver from common.models import get_model @tool def search_knowledge(query: str) -> str: """从公司知识库检索相关段落。 回答制度、流程、产品规格问题时先调用本工具。 返回带过来源标记的文本;若为空说明库中无相关内容。 """ docs = retriever.invoke(query) if not docs: return "未检索到相关资料。" # 返回值进 ToolMessage.content,供模型下一轮阅读 parts = [] for i, d in enumerate(docs, 1): src = d.metadata.get("source", "unknown") parts.append(f"[{i}] 来源: {src}/n{d.page_content}") return "/n/n".join(parts) agent = create_agent( model=get_model(temperature=0), tools=[search_knowledge], checkpointer=InMemorySaver(), system_prompt=( "你是客服助手。涉及公司政策、流程、规格时必须先 search_knowledge," "只根据工具结果回答,并标明来源编号。" "检索为空或无关时,明确说不知道,禁止编造。" "普通寒暄不必查库。" ), ) config = {"configurable": {"thread_id": "rag-1"}} result = agent.invoke( { "messages": [ {"role": "user", "content": "签收后多久可以退货?依据是什么?"} ] }, config=config, ) print(result["messages"][-1].content)
  1. 2create_retriever_tool

不想手写拼接时,用官方工厂函数把 Retriever 直接封装车成工具。description仍是模型是否调用的关键信号,要写清「搜什么、何时用」。

from langchain.agents import create_agent from langchain_core.tools.retriever import create_retriever_tool from common.models import get_model # response_format="content_and_artifact" 时: # content → 给模型看的拼接文本;artifact → 原始 Document 列表给应用层 retriever_tool = create_retriever_tool( retriever, name="search_docs", description="搜索产品文档,获取与问题相关的段落", response_format="content_and_artifact", ) agent = create_agent( model=get_model(temperature=0), tools=[retriever_tool], system_prompt="政策/规格问题先 search_docs,按资料回答;无资料则拒答。", )

content_and_artifact的好处见下一小节:前端溯源不用再解析模型随机返回的「来源」字符串。

  1. 3 溯源:

content给模型,artifact给前端。

ToolMessage可以带两份数据:模型只读content;完整结构化结果放artifact,应用层拿来渲染「来源:退货政策 v2.pdf 第 3 页」。手写工具时也可以自己返回(content, artifact)(需工具声明对应 response_format),或在工具外根据Document.metadata组装:

from langchain.messages import ToolMessage # 概念示意:content 给模型,artifact 给 UI / 审计 ToolMessage( content="公司退货政策:签收后 7 日内可申请……", # 模型据此生成 tool_call_id="call_123", artifact={ # 应用层据此画「来源」卡片;默认不进模型注意力 "sources": [ {"source": "退货政策v2.pdf", "page": 3, "doc_id": "doc_456"}, ], }, )

create_retriever_tool(..., response_format="content_and_artifact")时,artifact 一般是List[Document],你从每条的metadata抽 source/page 即可。这和「把来源写进 content 让模型复述」不冲突,content 里仍可带简短引用,artifact 负责机器可读的溯源。

  1. 4 权限过滤

知识库不是人人能看全部。第 5、12 篇的context/store可以在检索工具里做过滤,先向量召回,再按用户允许的doc_id留下去。

通过在检索工具里接ToolRuntime实现:

from langchain.tools import ToolRuntime, tool @tool def search_with_context(query: str, runtime: ToolRuntime) -> str: """搜索知识库;只返回当前用户有权访问的文档。""" user_id = runtime.context.user_id # 调用 agent 时传入的 context # 从长期记忆 Store 读权限名单;没有 Store 时也可查自家权限服务 item = runtime.store.get(("permissions", user_id), "access") allowed = set((item.value or {}).get("allowed_docs", [])) if item else set() docs = retriever.invoke(query) filtered = [ d for d in docs if not allowed or d.metadata.get("doc_id") in allowed ] if not filtered: return "未检索到你有权查看的相关资料。" return "/n/n".join(d.page_content for d in filtered[:3])

原理:向量检索解决「相关」,权限过滤解决「能看」。两步都要做;只做相关、不做权限,等于检索成了旁路泄密。

八、失效补救与完整示例

  1. 1 基础 RAG 常见失效

失效可能原因先试什么
答非所问切块太碎/太大;k 不对;Embedding 偏科调切分与 k;抽查看 top-k
漏答用户说法和文档用词差太远查询改写;同义扩展
噪声太多k 过大;块里广告/目录太多减小 k;重排;压缩
胡编提示未强制依据;检索空仍硬答拒答话术;无命中直接返回
无法追责没 metadata / 没引用format 带 source;要求 [编号]

下面是一些建议:

查询改写:用户说「那个七天规定」,文档写「签收后 7 日内」。生成前让模型把问题改成检索友好句,再用新句子invokeretriever。2-Step 里加一个改写节点;Agentic 里写进 system:「先把问题改写成检索词再调用工具」。

Rerank:向量召回先取 20,再用交叉编码器或小模型按「与问题相关性」重排,截断前 3–5 送进生成。救的是「语义近但答不对题」的噪声。

上下文压缩:块很长时,只抽与问题有关的句子再进提示(LLMChainExtractor 一类,或自己用小模型摘要)。救的是窗口与注意力,不是召回率本身。

  1. 2 完整示例:建库 + 两路问答

下面用内存向量库跑通:一份迷你 FAQ → 切分入库 → 2-Step 与 Agent 各问一次。把faq_text换成TextLoader("xxx.txt").load()即接真实文件。

from langchain.agents import create_agent from langchain.tools import tool from langchain_core.documents import Document from langchain_core.prompts import ChatPromptTemplate from langchain_core.vectorstores import InMemoryVectorStore from langchain_openai import OpenAIEmbeddings from langchain_text_splitters import RecursiveCharacterTextSplitter from common.models import get_model # ---------- 1) 准备文档(演示用内联;生产改 Loader)---------- faq_text = """ # 退货政策 顾客可在签收后 7 日内申请退货。商品须未使用、包装完整。 虚拟商品、定制商品不适用 7 日退货。 # 运费 退货原因属于质量问题的,运费由商家承担;其余情况由顾客承担。 """ docs = [ Document( page_content=faq_text, metadata={"source": "faq.md", "product_line": "mall"}, ) ] splitter = RecursiveCharacterTextSplitter(chunk_size=120, chunk_overlap=30) chunks = splitter.split_documents(docs) # ---------- 2) 索引 ---------- embeddings = OpenAIEmbeddings(model="text-embedding-3-small") vector_store = InMemoryVectorStore.from_documents(chunks, embeddings) retriever = vector_store.as_retriever(search_kwargs={"k": 3}) def format_docs_with_source(docs: list[Document]) -> str: parts = [] for i, d in enumerate(docs, 1): src = d.metadata.get("source", "unknown") parts.append(f"[{i}] 来源: {src}/n{d.page_content.strip()}") return "/n/n".join(parts) if parts else "" # ---------- 3) 2-Step ---------- prompt = ChatPromptTemplate.from_template( """只根据参考资料回答;不足则说「资料中未找到依据」。 回答末尾用 [编号] 标注依据。 参考资料: {context} 问题: {question} """ ) rag_chain = prompt | get_model(temperature=0) def ask_2step(question: str) -> str: docs_hit = retriever.invoke(question) msg = rag_chain.invoke( { "context": format_docs_with_source(docs_hit), "question": question, } ) return msg.content # ---------- 4) Agentic ---------- @tool def search_knowledge(query: str) -> str: """检索商城 FAQ 知识库,返回带来源编号的段落。""" docs_hit = retriever.invoke(query) text = format_docs_with_source(docs_hit) return text or "未检索到相关资料。" agent = create_agent( model=get_model(temperature=0), tools=[search_knowledge], system_prompt=( "政策问题必须先 search_knowledge,按资料回答并引用 [编号];" "无资料则明确拒答。寒暄不必查库。" ), ) if __name__ == "__main__": q1 = "签收后多久能退货?" q2 = "今天天气怎么样?" # 应拒答或闲聊,不应编造政策 print("=== 2-Step ===") print(ask_2step(q1)) print("/n=== Agent ===") r = agent.invoke({"messages": [{"role": "user", "content": q1}]}) print(r["messages"][-1].content) r2 = agent.invoke({"messages": [{"role": "user", "content": q2}]}) print(r2["messages"][-1].content)

验收建议:

  1. q1两路都能答到「7 日」,并带来源。

  2. 把 FAQ 里「7 日」删掉重建索引后,应走拒答,而不是背训练记忆。

  3. 打印retriever.invoke(q1),确认命中块里真有退货句——生成错之前先看检索错没错。

  4. chunk_size=40400各建一次,看短问「虚拟商品能否退」谁更稳(体会切分影响)。

依赖安装示例:

pip install langchain langchain-openai langchain-text-splitters langchain-community

Embedding 与 chat 不必同一家,但都要配好各自的 API Key /base_url

最后

2026 年一晃已经过半,AI 大模型的热潮不仅没有降温,反而持续升温!

金融行业用大模型做风控、医疗依靠 AI 解析影像,电商、制造、教育各行各业,都在把 AI 融入日常业务。曾经热闹的 “百模大战”,早就告别单纯比拼模型参数,正式进入落地应用时代

现在企业疯狂紧缺一类人才:懂业务、懂 AI、能做出可上线项目的大模型开发工程师,岗位缺口大,薪资待遇十分可观。

风口再好,不如手握高薪 offer 实在。行情火热,普通人、程序员该怎样从零入门大模型,抓住这波机会?

今天整理好【2026 最新版】AI 大模型全套免费学习资源,覆盖零基础入门、项目实战、理论知识、大厂面试,从基础一路进阶。所有资料分类归档,没有多余杂料,无套路免费分享给想要入局 AI 赛道的程序员与零基础小白!

👇👇扫码免费领取全部内容👇👇

1、大模型系统化完整学习路线

2、大模型经典书籍&文档

3、AI 大模型最新行业研究报告

4、企业级实战项目 + 完整配套源码

5、大厂大模型面试真题汇总

6、这些资料真的有用吗?

这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理,现任上海殷泊信息科技CEO,其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证,服务航天科工、国家电网等1000+企业,以第一作者在IEEE Transactions发表论文50+篇,获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。

资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的技术人员,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。

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

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

拓扑排序与动态规划:从食物链计数到DAG依赖问题求解范式

1. 项目概述:从一道题到一种思维模型“P4017 最大食物链计数”这个名字,对于不熟悉算法竞赛的朋友来说,可能有点不知所云。但如果你点开任何一个主流的在线评测平台(OJ),输入这个编号,大概率会看…

作者头像 李华
网站建设 2026/8/28 4:17:38

收藏!AI时代,这三种人才最值钱,普通程序员也能抓住机遇

AI时代,真正有价值的人不是单纯会写代码或训练模型,而是具备行业经验的专家、能将AI技术落地应用的人才,以及具备数字素养、能判断AI输出可信度的普通人。麦肯锡报告指出,未来关键能力在于评估AI成果的实用性。行业经验是AI最稀缺…

作者头像 李华
网站建设 2026/8/28 4:14:15

SpringBoot+Mybatis+Thymeleaf+MySQL购书商城实战解析

简介:Java Web开发中,服务端渲染架构仍是管理后台与内部系统的主流选择。其核心在于后端如何高效协同数据库操作、业务逻辑封装与HTML模板渲染——这涉及ORM映射原理、SQL安全编写、模板引擎防XSS机制及关系型数据库索引优化等基础工程能力。SpringBoot通…

作者头像 李华
网站建设 2026/8/28 4:13:22

什么是 DeepSeek Harness?

什么是 DeepSeek Harness? 学习目标 完成本章后,你应该能够: 用自己的话区分 LLM、Agent 与 Agent Harness;说明 DeepSeek Harness(DSH)的项目定位与核心能力;识别标准模式、PTC 模式、极简模…

作者头像 李华
网站建设 2026/8/28 4:13:00

Python量化交易入门:从环境搭建到双均线策略回测实战

1. 项目概述:为什么用Python做量化交易? 如果你对股票市场有点兴趣,又恰好会点Python,那“量化交易”这个词对你来说,可能既熟悉又陌生。熟悉的是,它听起来很酷,像是用代码和数学在金融市场里“…

作者头像 李华
网站建设 2026/8/28 4:12:59

基于C#与.NET Core的OPC UA 1.03客户端开发实战指南

简介:在工业自动化与物联网领域,数据采集是连接物理设备与信息系统的关键技术。其核心原理在于通过标准化的通信协议,实现设备数据的可靠、安全读取与传输。OPC UA作为一种跨平台、支持语义信息模型的工业通信标准,其技术价值在于…

作者头像 李华