上个月我把项目里的 LangChain 全删了。
不是因为它不好,是因为我发现自己花了 80% 的时间在跟框架抽象层打架,而不是在解决实际问题。
事情的起因
去年年底接了个内部工具需求:给客服团队做一个 AI 问答系统,能查公司知识库回答问题。需求很清晰,我想都没想直接上了 LangChain + RAG。
结果两周后,我的代码长这样:
python
from langchain.chains import RetrievalQA
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.llms import OpenAI
from langchain.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 还有七八个 import...
loader = DirectoryLoader('./docs')
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=1000)
chunks = splitter.split_documents(docs)
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(chunks, embeddings)
retriever = vectorstore.as_retriever()
qa = RetrievalQA.from_chain_type(llm=OpenAI(), retriever=retriever)
看起来挺整洁的对吧?但当我需要:
- 给检索结果加个相关性过滤
- 在 prompt 里加入用户历史对话
- 对某些问题走不同的处理逻辑
我就开始在文档里迷路了。每个需求都要找对应的 LangChain 抽象,每次升级版本都有 breaking change,调试的时候根本不知道哪一层出了问题。
我的重写版本
后来我花了两天把它重写了,核心逻辑大概 150 行:
python
import openai
from openai import OpenAI
client = OpenAI(
base_url="https://api.ofox.ai/v1",
api_key="sk-xxx"
)
def search_docs(query: str, top_k: int = 3) -> list[str]:
# 自己实现检索,清晰可控
query_embedding = client.embeddings.create(
model="text-embedding-3-small",
input=query
).data[0].embedding
results = vector_db.search(query_embedding, top_k=top_k)
return [r.content for r in results if r.score > 0.7] # 自己加过滤
def answer_question(question: str, history: list = None) -> str:
context = search_docs(question)
messages = []
if history:
messages.extend(history[-4:]) # 只保留最近4轮
messages.append({
"role": "user",
"content": f"根据以下资料回答问题:\n\n{chr(10).join(context)}\n\n问题:{question}"
})
response = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=messages,
max_tokens=1000
)
return response.choices[0].message.content
代码量差不多,但现在我能清楚地知道每一行在做什么。
什么时候该用框架
说了这么多,不是说 LangChain 没用。它在这些场景下确实省事:
1. 快速原型验证 如果你只是想验证一个想法,LangChain 的高层抽象能让你 30 分钟跑起来一个 demo。
2. 标准 RAG 流程 如果你的需求就是标准的「文档检索 + 问答」,不需要定制,LangChain 的默认实现已经够好。
3. 团队里有 LangChain 经验 学习成本是真实存在的,如果团队已经熟悉了,换原生 SDK 反而增加摩擦。
什么时候该直接用 SDK
1. 需要精细控制流程 任何需要「在第 N 步根据条件走不同分支」的逻辑,原生 SDK 写起来比框架清晰得多。
2. 生产环境 框架的抽象层在调试时是噩梦。出了问题你需要能快速定位,原生代码更容易加日志、加监控。
3. 性能敏感 框架有额外开销,虽然通常不大,但如果你的应用对延迟敏感,少一层抽象就少一层风险。
4. 多模型切换 如果你需要根据任务类型选不同模型(比如简单问题用便宜的模型,复杂推理用强模型),自己控制比框架更灵活。
python
def smart_route(question: str) -> str:
# 简单问题用快速模型
if len(question) < 50 and '?' in question:
model = "claude-haiku-4-5-20251001"
else:
model = "claude-sonnet-4-6"
return client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": question}]
).choices[0].message.content
我现在的工具链
重写之后的项目结构简单多了:
- 向量数据库:直接用 pgvector(PostgreSQL 插件),不用单独维护一个 Chroma 服务
- API 调用:OpenAI SDK,base_url 指向 ofox.ai,一个 key 能用所有主流模型
- Embedding:直接调 API,不套框架
- Prompt 管理:就是 Python 字符串,不需要 PromptTemplate
整个项目的 AI 相关代码从 400 行降到了 180 行,而且每一行我都能解释清楚它在做什么。
最后
框架是工具,不是信仰。LangChain 解决了它设计时要解决的问题,但不是所有问题都需要它。
下次开始新项目之前,先问自己:我真的需要这个抽象层吗?还是直接调 SDK 就够了?
大多数时候,答案是后者。