1. 项目概述:为什么选择Langchain与千帆SDK的组合?
最近和不少做AI应用开发的朋友聊天,发现一个挺普遍的现象:大家手里都有个不错的想法,比如想做个智能客服助手、自动生成周报的工具,或者一个能理解行业文档的问答机器人。想法很美好,但一到动手环节就卡住了。核心问题往往不是“用什么大模型”,而是“怎么把大模型用起来”。自己从零开始处理对话历史、管理工具调用、构建知识库,光是工程复杂度就让人望而却步。这正是我当初选择深入研究Langchain的原因。
简单来说,Langchain是一个帮你“组装”大模型应用的框架。它把那些繁琐但通用的环节,比如连接模型、管理对话记忆、调用外部工具(搜索、计算器、API)、处理长文本(RAG)等,都封装成了标准的、可插拔的组件。你不用再重复造轮子,而是可以像搭积木一样,快速构建出功能复杂的AI应用。这大大降低了LLM应用开发的门槛和初期的时间成本。
而千帆SDK,则是连接Langchain与国内主流大模型服务(如百度文心一言)的桥梁。对于国内开发者而言,直接使用OpenAI的API可能面临网络、合规和成本的多重考量。千帆平台提供了稳定、合规且功能丰富的国内大模型接入服务。通过千帆SDK,我们可以轻松地在Langchain框架内调用这些能力,享受本地化服务的便利与稳定。
所以,“通过Langchain接入千帆SDK”这个组合,解决的正是“快速、合规、高效地在中国大陆环境下落地LLM应用”的核心痛点。它让你能专注于业务逻辑和创新,而不是陷在基础设施的泥潭里。接下来,我就以一个实际的智能任务规划助手为例,带你走通从环境搭建到功能上线的全流程,分享其中每一步的关键决策和踩过的坑。
2. 环境准备与核心工具选型解析
工欲善其事,必先利其器。在开始编码之前,搭建一个清晰、可复现的开发环境至关重要。这里的选择会直接影响后续开发的效率和部署的稳定性。
2.1 Python环境与依赖管理
我强烈推荐使用Conda或venv创建独立的Python虚拟环境。这能避免不同项目间的包版本冲突。这里以Conda为例:
# 创建并激活一个名为`llm_app`的Python 3.9环境(3.8-3.11皆可,这是多数LLM库的兼容范围) conda create -n llm_app python=3.9 -y conda activate llm_app接下来是安装核心依赖。这里有一个关键点:Langchain社区活跃,版本更新较快,有时新版本会引入不兼容的改动。为了项目稳定,我通常会锁定一个经过验证的、功能完善的版本。同时,千帆SDK需要单独安装。
# 安装Langchain及其常用社区组件。指定版本是为了避免意外升级导致代码报错。 pip install langchain==0.1.0 langchain-community==0.0.10 # 安装千帆SDK,这是接入百度模型的关键 pip install qianfan # 安装其他实用工具库 pip install python-dotenv # 用于管理环境变量,保护AK/SK等密钥 pip install tiktoken # 用于精准计算Token消耗,控制成本注意:
langchain和langchain-community的版本需要匹配。0.1.x是一个重要的稳定版本分支。如果你看到教程中使用langchain-core、langchain等更细化的包,那是新版本(>=0.2.x)的模块化方案。对于快速入门,使用上述组合更为直接。
2.2 获取并配置千帆平台密钥
所有对千帆平台模型的调用都需要认证。你需要前往百度智能云千帆平台创建应用以获取密钥。
- 注册与登录:访问百度智能云,完成实名认证并开通千帆大模型平台服务。
- 创建应用:在千帆控制台,找到“应用接入”或“模型服务”相关页面,创建一个新应用。这一步的目的是获取一对
API Key和Secret Key(以下简称AK/SK)。 - 记录密钥:将获取到的AK和SK妥善保存。绝对不要将它们直接硬编码在代码中,尤其是计划开源或上传到GitHub时。
最佳实践是使用环境变量管理密钥。在项目根目录创建一个名为.env的文件:
# .env 文件 QIANFAN_AK=your_api_key_here QIANFAN_SK=your_secret_key_here然后在你的Python代码开头,通过python-dotenv加载:
from dotenv import load_dotenv import os load_dotenv() # 加载 .env 文件中的所有变量 # 现在可以通过os.environ安全地读取 qianfan_ak = os.getenv("QIANFAN_AK") qianfan_sk = os.getenv("QIANFAN_SK") if not qianfan_ak or not qianfan_sk: raise ValueError("请在 .env 文件中配置 QIANFAN_AK 和 QIANFAN_SK")这种方式既安全又方便,在不同环境(开发、测试、生产)中可以轻松切换不同的密钥配置。
2.3 模型选择与初始化策略
千帆平台提供了多种模型,从轻量到重量级,适用于不同场景和预算。初始化模型连接时,有两种主流方式,各有优劣。
方式一:使用Langchain内置的集成(推荐给初学者)Langchain-community库中已经封装了千帆的Chat模型。这种方式最直接,与Langchain的其他组件(如链、记忆)兼容性最好。
from langchain_community.chat_models import QianfanChatEndpoint from langchain.schema import HumanMessage # 初始化聊天模型,指定使用的底层模型(例如ERNIE-Bot-turbo) chat = QianfanChatEndpoint( model="ERNIE-Bot-turbo", qianfan_ak=qianfan_ak, qianfan_sk=qianfan_sk, ) # 进行简单对话 messages = [HumanMessage(content="你好,请介绍一下你自己。")] response = chat.invoke(messages) print(response.content)方式二:直接使用千帆SDK,再封装给Langchain(推荐给需要深度控制的开发者)有时你可能需要用到千帆SDK更底层或更独特的功能(如特定的参数配置、流式输出的精细控制)。这时可以先初始化千帆的客户端,再将其适配到Langchain的接口上。
import qianfan from langchain.adapters import openai as lc_openai # 注意:这里是一个适配思路 # 1. 初始化千帆客户端 client = qianfan.ChatCompletion(ak=qianfan_ak, sk=qianfan_sk) # 2. 定义一个包装函数,使其符合Langchain ChatModel的调用格式 # 这种方式更灵活,但需要自己处理一些适配逻辑,适合高阶用户。对于绝大多数快速落地场景,我强烈推荐使用方式一。它简单、稳定,能让你快速跑通流程,把精力集中在业务逻辑上。只有当你在后续开发中遇到特定需求,而内置集成无法满足时,才需要考虑方式二。
3. 构建第一个智能链:任务规划助手实战
现在,让我们用Langchain的核心概念——“链”(Chain),来构建一个实用的智能任务规划助手。这个助手能理解用户模糊的目标(如“我想学习Python”),并将其分解为具体、可执行的任务列表。
3.1 理解Langchain的核心:链与提示模板
链,顾名思义,是将多个组件按顺序连接起来,完成一个复杂任务。最基本的链通常包含一个提示模板(PromptTemplate)和一个大语言模型(LLM)。
- 提示模板:用于动态生成发送给模型的提示词。它包含变量,你可以在运行时填入具体内容。好的提示模板是发挥LLM能力的关键。
- LLM:接收提示并生成回复的模型。
我们的任务规划链可以这样设计:用户输入一个目标 -> 提示模板将目标填入预设的指令中 -> 发送给千帆模型 -> 模型返回结构化的任务列表。
首先,定义一个高效的提示模板:
from langchain.prompts import PromptTemplate # 定义提示模板 planning_template = """ 你是一个高效的任务规划专家。请根据用户提供的目标,将其分解为一个清晰、按顺序执行的任务列表。 每个任务应该具体、可操作,并且标明可能需要的资源或工具。 用户目标:{goal} 请以如下格式输出: 1. [任务一描述] 2. [任务二描述] ... """ # 创建PromptTemplate对象,声明输入变量为`goal` prompt = PromptTemplate.from_template(planning_template)这个模板有几个设计要点:
- 角色设定:明确告诉模型“你是一个...专家”,这能引导其进入特定语境。
- 指令清晰:要求“分解”、“具体、可操作”、“标明资源”。
- 结构化输出:指定了输出格式(数字列表),这能极大提高模型返回结果的规整度和可用性。
- 变量:
{goal}是一个占位符,运行时会被替换成真实的用户目标。
3.2 组装并运行任务规划链
有了模板和模型,就可以用LLMChain把它们“链”起来了。
from langchain.chains import LLMChain # 1. 初始化模型 (沿用之前的方式) chat = QianfanChatEndpoint(model="ERNIE-Bot-turbo", qianfan_ak=qianfan_ak, qianfan_sk=qianfan_sk) # 2. 创建链 planning_chain = LLMChain(llm=chat, prompt=prompt, verbose=True) # `verbose=True` 会打印链的执行细节,调试时非常有用 # 3. 运行链 goal = "我想在三个月内入门机器学习,并完成一个预测房价的小项目" result = planning_chain.run(goal=goal) print("生成的计划:") print(result)将verbose设置为True后,运行时会看到类似下面的输出,这有助于理解Langchain内部的工作流程:
> Entering new LLMChain chain... Prompt after formatting: 你是一个高效的任务规划专家。请根据用户提供的目标,将其分解为一个清晰、按顺序执行的任务列表。 每个任务应该具体、可操作,并且标明可能需要的资源或工具。 用户目标:我想在三个月内入门机器学习,并完成一个预测房价的小项目 请以如下格式输出: 1. [任务一描述] 2. [任务二描述] ... > Finished chain. 生成的计划: 1. 学习Python编程基础,特别是NumPy、Pandas和Matplotlib库(资源:菜鸟教程、廖雪峰Python教程、Coursera课程)。 2. 掌握机器学习基本概念,如监督学习、非监督学习、训练集/测试集、过拟合等(资源:吴恩达机器学习课程、周志华《机器学习》书籍)。 3. 学习使用Scikit-learn库,了解常用算法如线性回归、决策树(资源:Scikit-learn官方文档、Kaggle教程)。 4. 寻找并下载一个公开的房价数据集,例如波士顿房价数据集或Kaggle上的房价预测竞赛数据(资源:UCI机器学习仓库、Kaggle)。 5. 进行数据探索与预处理,包括处理缺失值、特征工程、数据可视化(工具:Jupyter Notebook, Pandas, Matplotlib)。 6. 选择线性回归模型,使用Scikit-learn进行模型训练与评估(工具:Scikit-learn)。 7. 尝试其他模型(如决策树、随机森林)进行对比,优化模型性能(工具:Scikit-learn)。 8. 将整个项目过程整理成文档或报告,包括问题定义、数据处理、模型构建、结果分析和总结。看,一个模糊的目标,被转化为了一个具有可操作性的八步计划。这就是链的威力。你可以尝试不同的目标,比如“策划一次周末团队建设”、“开发一个简单的个人博客网站”,观察模型的分解能力。
3.3 为链添加记忆能力
上面的链是“无状态”的,每次对话都是独立的。但一个真正的助手应该能记住之前的对话内容。这就需要引入记忆(Memory)组件。
Langchain提供了多种记忆后端,最简单常用的是ConversationBufferMemory,它会保存完整的对话历史。
from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationChain # 1. 创建带有记忆的链 memory = ConversationBufferMemory() conversation_chain = ConversationChain(llm=chat, memory=memory, verbose=True) # 2. 进行多轮对话 print("第一轮:") response1 = conversation_chain.predict(input="你好,我叫小明。") print(f"AI: {response1}") print("\n第二轮:") # 注意,这里不需要再传递名字,记忆模块已经记住了。 response2 = conversation_chain.predict(input="你还记得我的名字吗?") print(f"AI: {response2}") # 3. 查看当前记忆内容 print("\n当前记忆缓冲区:") print(memory.buffer)运行后,你会发现第二轮对话中,模型能准确回答出你的名字,因为它从记忆缓冲区中读取了历史信息。这对于构建聊天机器人、持续性的任务指导等场景至关重要。
实操心得:
ConversationBufferMemory简单易用,但缺点是对话越长,消耗的Token越多,成本也越高。对于长对话,可以考虑ConversationSummaryMemory(保存历史摘要)或ConversationBufferWindowMemory(只保留最近N轮对话)。选择哪种,取决于你对上下文长度的要求和成本预算。
4. 进阶集成:连接外部工具与知识库(RAG)
一个只会聊天的LLM应用价值有限。真正的生产力来自于让LLM能够“动手操作”,比如查询天气、搜索资料、计算数据,或者根据你提供的专属文档回答问题。这就涉及到工具调用(Tool Calling)和检索增强生成(RAG)。
4.1 使用Langchain Agent调用外部工具
Agent是Langchain中一个更高级的概念,它让LLM具备“思考”和“使用工具”的能力。其核心流程是:LLM根据用户问题,决定是否需要使用工具、使用哪个工具、传入什么参数,然后执行工具,最后根据工具返回的结果生成最终答案给用户。
我们以一个简单的“计算器”和“网络搜索”Agent为例。由于千帆模型对工具调用的格式可能有特定要求,这里我们使用一个更通用的模式:ReAct模式,它通过让模型输出“Thought/Action/Action Input/Observation”的格式来模拟推理和行动过程。
首先,我们需要定义工具。这里用两个模拟工具:
from langchain.agents import Tool, AgentExecutor from langchain.agents import initialize_agent from langchain.agents.react.base import ReActDocstoreAgent # 注意:ReAct agent的初始化方式在Langchain版本中可能有变化,以下是一种稳定实现思路。 # 1. 定义工具函数 def search_wikipedia(query: str) -> str: """模拟搜索维基百科。在实际应用中,这里应接入真正的搜索API(如SerpAPI)。""" # 这里返回模拟结果 return f“根据搜索‘{query}’,找到了相关摘要:这是一个关于{query}的模拟搜索结果。” def calculate(expression: str) -> str: """计算数学表达式。警告:直接使用eval有安全风险,仅用于演示。""" try: result = eval(expression) return str(result) except: return “无法计算该表达式。” # 2. 将函数包装成Langchain Tool对象 tools = [ Tool( name=“Search”, # 工具名,LLM会根据这个名字来选择工具 func=search_wikipedia, description=“当你需要回答关于实时信息、具体事实或最新事件的问题时使用此工具。输入应是一个搜索查询词。” ), Tool( name=“Calculator”, func=calculate, description=“当你需要进行数学计算时使用此工具。输入应是一个有效的数学表达式,例如‘(3 + 5) * 2’。” ) ] # 3. 初始化Agent(使用零样本ReAct代理,适用于通用指令) from langchain.agents import create_react_agent from langchain.agents import AgentExecutor # 创建ReAct代理提示模板(这是一个标准模板) from langchain import hub # 可以从Langchain Hub拉取一个标准的ReAct提示模板(需要网络) # react_prompt = hub.pull(“hwchase17/react”) # 或者,我们可以使用一个本地定义的基础版本(为了稳定性演示): from langchain.agents.react.agent import create_react_agent # 由于版本兼容性,更稳妥的方式是使用`initialize_agent`并指定agent_type # 但请注意,千帆模型可能需要特定的提示词调整才能完美适配ReAct格式。 # 以下是一种更兼容的简化版Agent创建方法(使用零样本聊天代理): from langchain.agents import initialize_agent, AgentType # 使用OPENAI_FUNCTIONS或CHAT_CONVERSATIONAL_REACT_DESCRIPTION等类型可能更稳定 # 但千帆模型可能不支持OpenAI的函数调用格式。因此,我们使用通用的ZERO_SHOT_REACT_DESCRIPTION。 # 这要求模型能够理解ReAct格式的指令。 agent = initialize_agent( tools, chat, # 使用之前初始化的千帆聊天模型 agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, # 使用零样本ReAct代理 verbose=True, handle_parsing_errors=True, # 处理模型输出格式解析错误 max_iterations=3, # 限制最大迭代次数,防止死循环 ) # 4. 运行Agent question = “珠穆朗玛峰的高度乘以2是多少米?” result = agent.run(question) print(result)运行这个Agent时,verbose=True会让你看到模型“思考”的过程:
- Thought: 模型会分析问题,识别出需要先知道珠峰高度,再进行计算。
- Action: 模型选择调用
Search工具。 - Action Input: 模型生成搜索词,如“珠穆朗玛峰 高度 米”。
- Observation: 工具返回模拟的搜索结果(例如“8848.86米”)。
- Thought: 模型根据搜索结果,决定调用
Calculator工具。 - Action: 调用
Calculator。 - Action Input: 输入“8848.86 * 2”。
- Observation: 工具返回计算结果“17697.72”。
- Final Answer: 模型整合信息,给出最终答案。
重要避坑指南:让千帆等国内模型完美运行ReAct Agent有时会面临挑战,因为其输出格式可能不完全符合Langchain的严格解析期望。如果遇到
OutputParserException,可以尝试:
- 使用
handle_parsing_errors=True参数让Agent更鲁棒。- 为模型选择更详细的描述(
description),帮助它更好地理解工具用途。- 考虑使用更简单的
AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION(如果模型支持聊天格式)。- 终极方案是自定义Agent的提示模板,使其指令更贴合所用模型的理解和输出习惯。这需要你对Langchain的Agent机制有更深理解。
4.2 构建本地知识库问答系统(RAG)
RAG是当前让LLM应用“拥有专业知识”最主流的技术。其原理并不复杂:将你的文档(PDF、Word、TXT等)切分成片段,转换成向量(一种数字表示)并存入向量数据库。当用户提问时,先从向量数据库中检索出与问题最相关的几个文档片段,然后将这些片段和问题一起组合成提示词送给LLM,让LLM基于这些“参考材料”生成答案。
下面我们构建一个基于本地TXT文件的简易RAG系统。
第一步:文档加载与分割
from langchain_community.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # 1. 加载文档(假设有一个`knowledge.txt`文件) loader = TextLoader(“./knowledge.txt”, encoding=“utf-8”) documents = loader.load() # 2. 分割文档 # 大模型有上下文长度限制,必须把长文档切分成小块。 text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, # 每个块大约500字符 chunk_overlap=50, # 块之间重叠50字符,避免语义被切断 separators=[“\n\n”, “\n”, “。”, “;”, “,”, “ “, “”] # 分割符优先级 ) split_docs = text_splitter.split_documents(documents) print(f“原始文档数:{len(documents)}, 分割后块数:{len(split_docs)}”)第二步:向量化与存储
我们需要一个向量数据库来存储和检索这些文档块。Chroma是一个轻量级、易上手的开源选择。
# 首先安装ChromaDB客户端和嵌入模型库 pip install chromadb langchain-chroma # 我们使用千帆的嵌入模型,也可以安装其他如`sentence-transformers` pip install sentence-transformers # 备用from langchain_chroma import Chroma from langchain_community.embeddings import QianfanEmbeddingsEndpoint # 1. 初始化嵌入模型(将文本转换为向量) # 使用千帆的嵌入模型 embeddings = QianfanEmbeddingsEndpoint( qianfan_ak=qianfan_ak, qianfan_sk=qianfan_sk, model=“Embedding-V1”, # 千帆的文本嵌入模型 ) # 2. 将分割后的文档存入Chroma向量库,并即时创建向量索引 # `persist_directory` 指定持久化目录,否则数据只在内存中 vectorstore = Chroma.from_documents( documents=split_docs, embedding=embeddings, persist_directory=“./chroma_db” # 数据将保存到此目录 ) vectorstore.persist() # 显式保存 print(“向量知识库构建完成!”)第三步:检索与生成
现在,我们可以从向量库中检索相关文档来回答问题。
from langchain.chains import RetrievalQA # 1. 将向量库转换为一个检索器 retriever = vectorstore.as_retriever(search_kwargs={“k”: 3}) # 检索最相关的3个片段 # 2. 创建检索问答链 qa_chain = RetrievalQA.from_chain_type( llm=chat, # 使用之前的千帆聊天模型 chain_type=“stuff”, # 最简单的方式,将所有检索到的文档“塞”进提示词 retriever=retriever, return_source_documents=True, # 返回参考来源,便于验证 verbose=True, ) # 3. 提问 query = “我的文档中提到了哪些关键步骤?” result = qa_chain.invoke({“query”: query}) print(“答案:”, result[“result”]) print(“\n参考来源:”) for doc in result[“source_documents”]: print(f“- {doc.page_content[:200]}...”) # 打印前200字符这个流程下来,你就拥有了一个能基于自己私有文档回答问题的智能助手。你可以通过更换TextLoader为PyPDFLoader、UnstructuredWordDocumentLoader等来支持更多格式。
性能与成本优化心得:
- 分块大小:
chunk_size是关键参数。太小会丢失上下文,太大会超出模型上下文限制且检索不精准。通常250-1000字符是常见范围,需要根据你的文档内容(技术文档、小说、报告)进行调试。- 嵌入模型:千帆的Embedding-V1模型效果不错且方便。如果对成本敏感或需要离线,
sentence-transformers库里的paraphrase-multilingual-MiniLM-L12-v2模型是一个轻量高效的免费选择。- 检索策略:
search_kwargs={“k”: 3}中的k值决定了参考片段的数量。增加k可以提高答案的全面性,但也会增加提示词长度和成本。通常3-5是个不错的起点。- 链类型:
chain_type=“stuff”适合文档块较小的场景。如果文档块很大或很多,可以考虑“map_reduce”或“refine”,它们能处理更多内容,但调用LLM的次数更多,更慢更贵。
5. 部署与优化:从脚本到服务
一个在本地运行的脚本和一个可供他人使用的服务之间,还差着“部署”这一步。同时,在真实使用中,我们还需要关注性能、成本和稳定性。
5.1 使用FastAPI封装为Web API
将你的Langchain应用封装成API是最常见的部署方式。FastAPI是一个现代、高性能的Python Web框架,非常适合这个任务。
首先安装FastAPI和Uvicorn(ASGI服务器):
pip install fastapi uvicorn创建一个main.py文件:
from fastapi import FastAPI, HTTPException from pydantic import BaseModel from typing import Optional import os from dotenv import load_dotenv from langchain_community.chat_models import QianfanChatEndpoint from langchain.chains import LLMChain from langchain.prompts import PromptTemplate # 加载环境变量 load_dotenv() # 初始化FastAPI应用 app = FastAPI(title=“LLM任务规划助手API”) # 定义请求体模型 class PlanningRequest(BaseModel): goal: str model: Optional[str] = “ERNIE-Bot-turbo” # 允许前端选择模型 # 全局初始化(简单示例,生产环境需考虑连接池和热更新) def get_planning_chain(model_name: str): """获取规划链的函数""" chat = QianfanChatEndpoint( model=model_name, qianfan_ak=os.getenv(“QIANFAN_AK”), qianfan_sk=os.getenv(“QIANFAN_SK”), ) template = “””你是一个任务规划专家。请将以下目标分解为具体步骤:{goal}””” prompt = PromptTemplate.from_template(template) return LLMChain(llm=chat, prompt=prompt) # 定义API端点 @app.post(“/plan”) async def create_plan(request: PlanningRequest): try: chain = get_planning_chain(request.model) result = chain.run(goal=request.goal) return {“goal”: request.goal, “plan”: result} except Exception as e: raise HTTPException(status_code=500, detail=f“规划生成失败:{str(e)}”) @app.get(“/health”) async def health_check(): return {“status”: “healthy”} # 本地运行: uvicorn main:app --reload然后,在终端启动服务:
uvicorn main:app --host 0.0.0.0 --port 8000 --reload现在,你就可以通过http://localhost:8000/docs访问自动生成的API文档,并测试/plan接口了。
5.2 关键配置与成本控制
在真实生产环境中,以下几个配置点需要仔细考量:
模型参数调优:
chat = QianfanChatEndpoint( model=“ERNIE-Bot”, qianfan_ak=ak, qianfan_sk=sk, temperature=0.1, # 控制创造性。越低(近0)输出越确定、保守;越高(近1)越随机、有创意。任务规划建议调低。 top_p=0.8, # 核采样参数,影响词汇选择的随机性。通常与temperature配合调整。 request_timeout=60, # 请求超时时间,网络不稳定时可调高。 # streaming=True, # 如果需要流式输出(逐字打印),可以开启 )temperature:对于事实性、逻辑性任务(如规划、总结),建议设置在0.1-0.3;对于创意生成(如写故事、想点子),可以设在0.7-0.9。request_timeout:根据网络状况和任务复杂度调整,避免因超时导致用户体验不佳。
Token消耗与成本监控: LLM API按Token收费。必须监控使用量。
- 估算Token:使用
tiktoken库(OpenAI开源的)可以近似估算千帆模型的Token数。注意,中文和英文的Token计算方式不同。
import tiktoken encoder = tiktoken.get_encoding(“cl100k_base”) # 使用一个通用的编码器估算 text = “你的提示词或回复内容” token_count = len(encoder.encode(text)) print(f“预估Token数: {token_count}”)- 设置预算:在千帆控制台可以为应用设置每日/每月调用额度预算,防止意外超支。
- 缓存:对于重复性较高的问题,可以考虑使用
Langchain的Cache组件(如InMemoryCache或RedisCache)来缓存结果,减少对API的调用。
- 估算Token:使用
异步与并发: FastAPI天然支持异步。对于高并发场景,应将LLM调用定义为
async函数,并使用asyncio.to_thread或专门的异步SDK(如果千帆提供)来避免阻塞事件循环。from langchain.chains import LLMChain import asyncio @app.post(“/plan_async”) async def create_plan_async(request: PlanningRequest): # 将同步的LLM调用放到线程池中执行,避免阻塞 chain = get_planning_chain(request.model) loop = asyncio.get_event_loop() result = await loop.run_in_executor(None, chain.run, request.goal) return {“plan”: result}
5.3 常见问题排查与调试技巧
在开发过程中,你一定会遇到各种问题。这里记录几个我踩过的坑和解决方法:
错误:
ModuleNotFoundError: No module named ‘langchain_community’- 原因:Langchain版本问题。新版本(0.2.x+)将很多社区集成移到了独立的
langchain-community包。 - 解决:确保安装了正确版本的
langchain和langchain-community(如本文开头所述),或查阅官方文档调整导入语句(例如从langchain.chat_models改为langchain_community.chat_models)。
- 原因:Langchain版本问题。新版本(0.2.x+)将很多社区集成移到了独立的
错误:
AuthenticationError或Permission denied- 原因:千帆AK/SK配置错误、未开通服务或余额不足。
- 解决:
- 检查
.env文件中的QIANFAN_AK和QIANFAN_SK是否正确,有无多余空格。 - 登录千帆控制台,确认应用状态正常,且有足够的额度。
- 尝试在代码中直接打印密钥(仅限临时调试)确认是否成功加载。
- 检查
Agent运行陷入死循环或输出格式错误
- 原因:模型无法稳定输出符合ReAct等严格格式的文本。
- 解决:
- 设置
max_iterations(如3-5次)强制限制循环次数。 - 设置
handle_parsing_errors=True,让Agent在解析失败时尝试继续。 - 简化工具描述,使其更精确。
- 考虑换用更简单的
AgentType.CONVERSATIONAL_REACT_DESCRIPTION或自定义更宽松的提示模板。
- 设置
RAG检索结果不相关
- 原因:文档分块策略不佳或嵌入模型不适合。
- 解决:
- 调整
chunk_size和chunk_overlap。对于技术文档,可能需要更小的块(如200-300字符)和基于标题的分割器(MarkdownHeaderTextSplitter)。 - 尝试不同的嵌入模型。千帆的
Embedding-V1对中文优化较好。也可以试试text2vec或m3e等开源中文嵌入模型。 - 在检索时使用
search_type=“mmr”(最大边际相关性),可以在相关性和多样性之间取得平衡。
retriever = vectorstore.as_retriever( search_type=“mmr”, search_kwargs={“k”: 4, “fetch_k”: 10} ) - 调整
API响应慢
- 原因:网络延迟、模型本身生成速度、或提示词过长。
- 解决:
- 为
QianfanChatEndpoint设置合理的request_timeout。 - 优化提示词,去除不必要的指令和上下文。
- 对于生成任务,适当调高
temperature有时反而能加快模型“决策”速度(减少思考时间),但会影响质量,需权衡。 - 考虑使用模型更小的版本(如
ERNIE-Bot-turbo比ERNIE-Bot快)。
- 为
从环境搭建到核心链构建,再到集成工具、知识库,最后部署上线并优化,这条路我走过不止一遍。最大的体会是,不要试图在第一天就构建一个完美的系统。最有效的方法是:先用最简单的方式(一个链、一个模型)跑通核心流程,解决一个最小可行问题。然后,像搭积木一样,根据需要逐步添加记忆、工具、检索等能力。每添加一个组件,都充分测试其效果和性能。Langchain和千帆SDK提供的正是这种模块化的便利,让你能快速迭代,将LLM的潜力转化为实实在在的应用价值。