LangChain诀窍:LLM 应用框架事实标准。
LangChain 已经是 LLM 应用框架的事实标准了,但很多人还在用最笨的方法——写一堆重复代码、调 Prompt 调到崩溃、出了错都不知道哪里崩的。今天直接上干货,分享五个真正能提升你开发效率的技巧。
很多人还在用 LLMChain 或者 SimpleSequentialChain,但这些东西耦合太紧,改个步骤就得重写。RunnableSequence 才是亲儿子。
看个例子,你想写一个“先翻译,再总结”的流程:
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4")
chain = (
{"text": RunnablePassthrough()}
| llm.bind(stop=["\n"])
| (lambda x: f"请用中文总结以下内容:{x.content}")
| llm
)
关键好处:每个 | 后面的组件可以单独替换、测试、复用。比如把翻译步骤抽出来,还能用在别的链里。而且支持流式输出、并行执行,性能直接拉满。
很多人写 Agent 时,工具描述随便写两句,结果模型老是选错工具。工具描述就是 Agent 的导航仪,写得好能省 80% 的调试时间。
比如你有一个搜索工具和一个计算器工具:
@tool
def search_web(query: str) -> str:
"""当用户需要查找最新新闻、实时信息、或者不确定的事实性内容时使用。输入应为简洁的搜索关键词,不要用完整句子。"""
...
@tool
def calculator(expression: str) -> str:
"""执行数学运算,包括加减乘除、幂运算等。当用户问“多少”“计算”“等于几”这类问题时优先使用。输入必须是合法的数学表达式,如 '2+3*4'。"""
...
技巧点:描述里要包含 触发条件 + 输入格式要求 + 典型场景。这样模型就不会把“帮我算一下”丢给搜索工具了。
Prompt 写好了,但模型输出总不对?别靠猜,LangSmith 的 Trace 功能能让你看到每一步的输入输出和 Token 消耗。
操作很简单:在代码里加一行配置,所有调用都会被记录。
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "my-app"
然后去 LangSmith 后台,点开某次 Trace,你会看到:
比如发现模型总是把“用户地址”理解成“IP 地址”,一看 Trace 就知道是 Prompt 里没写清楚上下文。改完再跑一次,对比效果,效率翻倍。
业务逻辑里经常要“根据用户输入走不同流程”,很多人写一堆 if-else,代码又臭又长。RunnableBranch 专门解决这个问题。
假设用户输入可能是“查天气”、“算账”、“闲聊”,你想走不同链:
from langchain_core.runnables import RunnableBranch
weather_chain = ...
calculator_chain = ...
chat_chain = ...
branch = RunnableBranch(
(lambda x: "天气" in x, weather_chain),
(lambda x: any(c in x for c in "加减乘除计算"), calculator_chain),
chat_chain # 默认分支
)
每个分支是一个 (条件函数, 处理链) 对,条件为真就执行对应链。比 if-else 清晰多了,而且每个分支还能单独测试、复用。
生产环境里,LLM 调用慢、Token 超限、API 报错都是家常便饭。Callback 可以让你在链执行过程中插入自定义逻辑,比如实时打印进度、统计 Token、甚至自动重试。
from langchain_core.callbacks import BaseCallbackHandler
class MyCallback(BaseCallbackHandler):
def on_llm_start(self, serialized, prompts, **kwargs):
print(f"开始调用 LLM,Prompt 长度:{len(prompts[0])}")
def on_llm_end(self, response, **kwargs):
print(f"LLM 返回,Token 消耗:{response.llm_output['token_usage']}")
chain = ... # 你的链
result = chain.invoke({"input": "你好"}, config={"callbacks": [MyCallback()]})
更实用的是,你可以在 on_llm_start 里做限流检查,比如每分钟最多调 10 次,超了就排队或报错。这样不用等整个链跑完才发现崩了。
总结一下:LangChain 真正强大的地方不是“能调 LLM”,而是它的可组合性和可观测性。用好 Runnable 系列、优化工具描述、配上 LangSmith 的 Trace,你的 LLM 应用开发效率至少翻一倍。别再用老方法了。