ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

低成本搭建AI Agent:国产大模型与LangChain实战指南

低成本搭建AI Agent:国产大模型与LangChain实战指南

1. 项目概述:为什么从零搭建一个AI Agent?

最近AI Agent的概念火得不行,感觉身边搞技术的朋友都在聊。简单来说,AI Agent就是一个能自主理解目标、规划任务、调用工具并执行行动的智能体,它不只是个聊天机器人,更像一个能帮你干活的“数字员工”。看到网上各种炫酷的演示,我也心痒痒,想自己动手搭一个玩玩。但一查资料,发现很多方案要么对硬件要求高(比如需要高端GPU),要么调用商业API(如GPT-4)成本不菲,对于个人开发者或小团队试水来说,门槛不低。

我的核心诉求很明确:低成本、易上手、能跑通完整流程。我不想一开始就陷入复杂的架构设计和昂贵的资源消耗中。经过一番调研和折腾,我最终选定了一套以国产大模型为核心、结合轻量级开源框架的方案,总成本可以压到极低,甚至利用免费资源就能跑起来。这篇文章,我就把自己从零搭建一个基础AI Agent的完整过程、踩过的坑以及最省钱的配置方案分享出来。无论你是想学习AI Agent原理的学生,还是想尝试AI应用落地的开发者,这篇“接地气”的指南应该都能给你提供一条清晰的路径。

2. 核心思路与方案选型:为什么这么搭配?

搭建AI Agent,核心是让大语言模型(LLM)具备“思考-行动”的能力。一个典型的Agent系统包含几个关键部分:一个强大的“大脑”(LLM),一套让大脑能指挥“手脚”的框架(Agent Framework),以及各种可用的“工具”(Tools)。我的选型全部围绕“省钱”和“可行”这两个原则展开。

2.1 “大脑”选型:拥抱国产模型

模型是Agent的核心,也是成本大头。直接使用OpenAI的GPT-4系列,虽然效果顶级,但API调用费用对于频繁测试和长期运行来说是一笔不小的开支。因此,我将目光投向了国产大模型

目前,许多国产模型不仅提供了效果不错的API服务,价格也相对友好,甚至有针对开发者的免费额度。例如:

  • DeepSeek:近期热度很高,提供了丰富的API和开源模型,其免费额度对于个人项目初期完全够用。
  • 通义千问文心一言智谱GLM等:这些主流厂商的API也都提供了不同程度的免费试用包或非常低廉的计价方式。

选择国产模型API的优势在于:

  1. 成本可控:有明确的免费额度或极低的按量付费价格(如每百万tokens几元人民币),试错成本低。
  2. 网络稳定:无需考虑复杂的网络访问问题,延迟通常也更低。
  3. 功能适配:很多国产模型针对中文场景和国内生态做了优化。

注意:选择模型时,一定要仔细阅读其官方文档的计费规则Rate Limit(频率限制)。免费额度通常有每日或每月的上限,超过后可能会收费或服务中断。对于Agent这种可能需要多次调用模型的系统,要合理规划调用频率。

2.2 “骨架”选型:轻量级开源框架

有了大脑,还需要一个框架来组织它的思考逻辑和行动流程。我不想从零开始写所有的状态管理和工具调用逻辑,那样太耗时。因此,选择一个成熟的开源Agent框架是明智之举。

我最终选择了LangChainLangGraph的组合。虽然市面上还有AutoGPT、CrewAI等,但我的考虑是:

  • LangChain:生态最丰富,文档最完善,社区活跃。它提供了连接LLM、工具、记忆等组件的标准化方式,学习资源多,遇到问题容易找到解决方案。
  • LangGraph:是LangChain团队推出的用于构建有状态、多智能体应用的新库。它用“图”的概念来定义Agent的执行流程,非常适合描述那种“思考->行动->观察->再思考”的循环,比单纯的链(Chain)更灵活直观。

这个组合虽然不是唯一的,也不是最简单的,但它提供了足够的能力和灵活性,并且有强大的社区支持,对于学习Agent原理和构建复杂应用来说是一个很好的起点。

2.3 “手脚”准备:定义工具与技能

Agent需要通过工具来与世界交互。工具可以是任何东西:搜索网页、查询数据库、执行计算、调用某个软件接口等。为了快速演示,我准备了几个最简单的工具:

  1. 计算器:一个能进行数学运算的函数。
  2. 网络搜索:利用SerpAPI或DuckDuckGo搜索(注意有些服务可能需要注册或付费,初期可用模拟搜索代替)。
  3. 本地文件读写:让Agent能读取或生成文本文件。

定义工具的关键是,用清晰的描述告诉LLM这个工具是干什么的、输入什么、输出什么。框架会将这些工具的描述作为“系统提示词”的一部分交给模型,让模型学会在合适的时候调用它们。

3. 环境搭建与核心依赖安装

工欲善其事,必先利其器。我的开发环境选择了最普遍的组合:Python + VSCode。下面是最小化的环境准备步骤。

3.1 Python环境配置

我推荐使用Python 3.103.11版本,这是目前大多数AI库兼容性最好的版本。

  1. 安装Python:前往Python官网下载对应操作系统的安装包。安装时务必勾选“Add Python to PATH”,这样可以在命令行直接使用python命令。
  2. 验证安装:打开终端(Windows CMD/PowerShell, Mac/Linux Terminal),输入python --versionpip --version,确认版本信息正确显示。
  3. 使用虚拟环境(强烈推荐):为了避免不同项目的包版本冲突,一定要使用虚拟环境。
    # 安装虚拟环境管理工具(如果未安装) pip install virtualenv # 创建名为 `ai_agent_env` 的虚拟环境 python -m venv ai_agent_env # 激活虚拟环境 # Windows: ai_agent_env\Scripts\activate # Mac/Linux: source ai_agent_env/bin/activate
    激活后,命令行提示符前会出现(ai_agent_env)字样,表示你已进入该环境。

3.2 安装核心库

在激活的虚拟环境中,使用pip安装以下库。这里我使用了清华源加速下载。

pip install langchain langchain-community langgraph -i https://pypi.tuna.tsinghua.edu.cn/simple
  • langchain: 核心框架。
  • langchain-community: 包含大量社区贡献的工具、模型集成等。
  • langgraph: 用于构建有状态的Agent图。

接下来,安装你选择的LLM的集成包。例如,如果你用DeepSeek:

pip install langchain-deepseek -i https://pypi.tuna.tsinghua.edu.cn/simple

如果用智谱AI:

pip install langchain-zhipu -i https://pypi.tuna.tsinghua.edu.cn/simple

请根据所选模型的官方LangChain文档来安装对应的集成包。

3.3 获取并配置API密钥

国产模型的API密钥通常在其官方开放平台申请。以DeepSeek为例:

  1. 访问DeepSeek开放平台官网,注册并登录。
  2. 在控制台找到“API密钥”或类似栏目,创建一个新的密钥。
  3. 非常重要:不要将密钥直接硬编码在代码中!推荐使用环境变量管理。
    • 在项目根目录创建一个名为.env的文件。
    • 在文件中写入:DEEPSEEK_API_KEY=你的实际密钥
    • 在Python中安装python-dotenv库来读取:pip install python-dotenv
    • 在代码开头加载环境变量:
      from dotenv import load_dotenv load_dotenv() import os api_key = os.getenv("DEEPSEEK_API_KEY")

4. 核心代码实现:构建一个能思考的Agent

环境准备好后,我们开始写代码。我将分步构建一个能使用计算器和搜索工具的简单Agent。

4.1 第一步:初始化LLM(大脑)

首先,我们引入必要的模块并初始化LLM。这里以DeepSeek为例。

from langchain_deepseek import ChatDeepSeek from langchain_core.messages import HumanMessage, SystemMessage import os # 从环境变量读取API Key api_key = os.getenv("DEEPSEEK_API_KEY") if not api_key: raise ValueError("请在 .env 文件中设置 DEEPSEEK_API_KEY") # 初始化DeepSeek聊天模型 # 注意:这里使用 `base_url` 参数指定国内可访问的端点,具体URL需查阅最新文档 llm = ChatDeepSeek( api_key=api_key, base_url="https://api.deepseek.com", # 示例,请以官方文档为准 model="deepseek-chat", temperature=0.1, # 温度设低一些,让Agent的思考更稳定、更少“胡言乱语” )

关键参数解释

  • model: 指定使用的模型名称,如deepseek-chat
  • temperature: 控制输出的随机性。对于Agent执行任务,通常设置较低的值(如0.1-0.3),以保证其决策的稳定性和可重复性。值越高,回答越有创意但也越不可控。
  • base_url: 有些SDK会自动配置,但如果遇到网络问题,可能需要手动指定一个正确的API端点地址。

4.2 第二步:定义工具(手脚)

我们定义两个简单的工具:一个计算器和一个模拟搜索引擎。

from langchain.tools import tool from langchain_community.tools import DuckDuckGoSearchRun import math # 1. 自定义计算器工具 @tool def calculator(expression: str) -> str: """执行数学计算。输入一个数学表达式字符串,如 '3 + 5 * 2',返回计算结果。""" try: # 警告:使用eval有安全风险,仅用于演示。生产环境应使用更安全的解析库如 `ast.literal_eval` 或专门数学库。 result = eval(expression, {"__builtins__": None}, {"math": math}) return f"计算结果: {result}" except Exception as e: return f"计算错误: {e}" # 2. 使用社区提供的搜索工具(需要安装 langchain-community) # 注意:DuckDuckGoSearchRun 是免费的,但可能不稳定或在某些区域受限。也可以使用SerpAPI(付费但稳定)。 search_tool = DuckDuckGoSearchRun() # 将所有工具放入一个列表 tools = [calculator, search_tool]

实操心得

  • @tool装饰器是LangChain提供的便捷方式,它能自动将你的函数转化为Agent可识别的工具格式,包括生成描述、解析输入等。
  • 为工具函数编写清晰、准确的文档字符串(docstring)至关重要!LLM就是靠这个描述来理解何时以及如何使用该工具的。
  • 对于calculator工具,演示中使用了eval,这在实际项目中是高危操作,绝不能用于处理用户直接输入。这里仅为简化示例,真实场景应替换为安全的表达式求值库。

4.3 第三步:创建Agent执行器(组装大脑和手脚)

现在,我们将LLM和工具绑定,创建一个可以执行的Agent。这里使用LangChain的create_react_agent,它实现了经典的“ReAct”(Reasoning + Acting)范式。

from langchain.agents import create_react_agent, AgentExecutor from langchain import hub # 从LangChain Hub拉取一个优化过的ReAct提示词模板 # 这个模板会指导LLM如何按“思考->行动->观察”的步骤进行 prompt = hub.pull("hwchase17/react") # 创建ReAct Agent agent = create_react_agent(llm, tools, prompt) # 创建Agent执行器,它负责运行Agent并处理工具调用循环 agent_executor = AgentExecutor( agent=agent, tools=tools, verbose=True, # 设为True,可以看到Agent详细的思考过程,调试时非常有用 handle_parsing_errors=True, # 自动处理Agent输出解析错误,避免程序崩溃 max_iterations=5, # 限制最大迭代次数,防止Agent陷入死循环 )

4.4 第四步:运行与测试

让我们用一个需要综合运用知识和计算的问题来测试我们的Agent。

# 测试问题 question = “已知光在真空中的速度是每秒30万公里,那么光走完1.5亿公里需要多少分钟?请先搜索确认光速的准确值,再进行计算。” print(f"用户问题: {question}\n") print("="*50) try: # 运行Agent response = agent_executor.invoke({"input": question}) print("\n" + "="*50) print(f"最终答案: {response['output']}") except Exception as e: print(f"执行过程中出现错误: {e}")

当你运行这段代码,并将verbose=True时,会在控制台看到类似下面的输出,这清晰地展示了Agent的“思考”过程:

> 进入新的Agent执行链... 思考:用户需要计算光走完1.5亿公里所需的时间,单位是分钟。我需要先确认光在真空中的准确速度。 行动:使用搜索工具查询“光在真空中的速度 准确值”。 观察:[搜索工具返回结果:光在真空中的速度是299,792,458米/秒,约等于每秒30万公里。] 思考:好的,光速c ≈ 3.0 × 10^8 m/s。距离是1.5亿公里,即1.5 × 10^11米。时间 = 距离 / 速度。 行动:使用计算器工具计算表达式 “1.5e11 / 3.0e8”。 观察:计算结果: 500.0 思考:得到的时间是500秒。用户问的是多少分钟,所以需要将秒转换为分钟。 行动:使用计算器工具计算表达式 “500 / 60”。 观察:计算结果: 8.333333333333334 思考:所以,光走完1.5亿公里大约需要8.33分钟。 最终答案:光在真空中的速度约为每秒30万公里(精确值为299,792,458米/秒)。走完1.5亿公里需要约500秒,换算成分钟大约是8.33分钟。

这个过程完美诠释了ReAct Agent的工作流:它自主地规划了“先搜索确认数据 -> 再计算时间 -> 最后单位转换”的步骤,并正确地调用了相应的工具。

5. 进阶:使用LangGraph构建更可控的工作流

基础的AgentExecutor已经能工作,但有时我们需要更精细地控制Agent的流程,或者构建多Agent协作系统。这时LangGraph就派上用场了。它允许我们用“图”来定义状态机。

5.1 定义状态与节点

我们构建一个简单的、具有明确循环的Agent图。

from typing import TypedDict, Annotated, Sequence import operator from langchain_core.messages import BaseMessage from langgraph.graph import StateGraph, END # 1. 定义状态(State) # 状态是一个字典,包含所有在流程中传递和更新的信息 class AgentState(TypedDict): messages: Annotated[Sequence[BaseMessage], operator.add] # 消息历史,会自动追加 question: str # 用户原始问题 intermediate_steps: list # 记录工具调用和结果 # 2. 定义图节点(Nodes) # 节点1:调用LLM,决定下一步行动(思考) def llm_node(state: AgentState): # 从历史消息构造提示 prompt = f"""你是一个助手,需要回答这个问题:{state['question']} 你之前已经进行了这些步骤:{state.get('intermediate_steps', [])} 请根据以上信息,决定下一步是直接回答,还是调用工具。 如果你需要调用工具,请严格按照以下格式回复: 行动: [工具名称] 行动输入: [工具输入] 否则,直接给出你的最终答案。 """ # 调用LLM llm_response = llm.invoke([HumanMessage(content=prompt)]) return {"messages": [llm_response]} # 将LLM的回复添加到消息历史 # 节点2:执行工具调用(行动) def tool_node(state: AgentState): # 这里需要解析上一步LLM的输出,提取出“行动”和“行动输入” # 为简化,我们假设LLM的输出格式正确,并直接调用对应的工具 last_message = state['messages'][-1].content # ... (此处省略具体的解析和工具调用逻辑,实际应用需完善) # 模拟一个工具调用结果 tool_result = "模拟工具调用结果:计算完成。" return { "intermediate_steps": [(“模拟工具”, “模拟输入”, tool_result)], # 记录步骤 "messages": [HumanMessage(content=f"观察: {tool_result}")] # 将观察结果加入历史 } # 节点3:判断是否继续(路由) def decide_next_node(state: AgentState): last_message = state['messages'][-1].content # 简单的逻辑:如果LLM的回复中包含“最终答案”,则结束,否则继续调用工具 if "最终答案" in last_message: return "end" else: return "continue"

5.2 组装图并运行

# 3. 创建图并添加节点 workflow = StateGraph(AgentState) workflow.add_node("llm", llm_node) workflow.add_node("tool", tool_node) # 4. 设置边(Edges)和条件路由 workflow.set_entry_point("llm") # 入口是llm节点 # 从llm节点出来后,根据decide_next_node函数的返回值决定下一步 workflow.add_conditional_edges( "llm", decide_next_node, { "continue": "tool", # 如果继续,去tool节点 "end": END # 如果结束,直接到终点 } ) # 从tool节点出来后,总是回到llm节点进行下一轮思考 workflow.add_edge("tool", "llm") # 5. 编译图 app = workflow.compile() # 6. 运行图 initial_state = AgentState( messages=[], question="计算10的阶乘是多少?", intermediate_steps=[] ) final_state = app.invoke(initial_state) print(final_state["messages"][-1].content)

通过LangGraph,我们可以清晰地定义Agent的决策循环(LLM -> 判断 -> 工具 -> LLM),并且可以方便地扩展,例如加入检查工具调用结果是否满意的节点、支持多个专用Agent协作等。这为构建复杂的Agent应用提供了强大的基础。

6. 成本控制与优化实战

对于个人项目,成本控制是重中之重。以下是我总结的几个关键策略:

6.1 Token消耗分析与估算

LLM API的计费基本都与Token数量挂钩。Token可以理解为文本的“碎片”,对于中文,一个字大约对应1-2个Token。

  • 输入Token (Input/Prompt Tokens):你发送给模型的提示词、历史消息、工具描述等所占的Token。
  • 输出Token (Output/Completion Tokens):模型生成的回答所占的Token。

Agent场景的Token消耗特点

  1. 上下文长:每次调用都需要携带完整的对话历史、工具描述、系统指令,导致输入Token量很大。
  2. 调用频繁:一个任务可能需要多次“思考-行动”循环,意味着多次API调用。
  3. 工具描述是开销大头:每个工具详细的函数签名和描述都会占用大量Token。

省钱技巧

  • 精简工具描述:在保证模型能理解的前提下,尽可能缩短工具的函数名和描述。避免冗长的说明。
  • 管理对话历史:不要无限制地堆积历史消息。可以只保留最近几轮对话,或者对历史消息进行摘要(Summarization)后再放入上下文。LangChain提供了多种Memory组件来帮助管理。
  • 选择性价比高的模型:对于Agent的“思考”步骤,不一定需要能力最强、最贵的模型。可以尝试用较小、较便宜的模型(如DeepSeek的较小参数版本)来承担规划任务,只在需要生成最终答案时调用更强的模型。

6.2 利用免费额度与本地模型

  • 最大化免费额度:几乎所有国产模型平台都有免费额度。注册多个平台账号,在开发测试阶段轮换使用,可以极大延长免费使用时间。但要注意遵守平台的使用条款。
  • 本地模型兜底:对于开发环境或对响应速度要求不高的场景,可以考虑在本地部署一个轻量级开源模型(如Qwen2.5-1.5B-Instruct、Phi-3-mini等)。使用OllamaLM Studio可以非常方便地在本地运行这些模型。虽然能力不如云端大模型,但用于测试Agent流程逻辑、工具调用是否正常,是完全可行的,且零成本。你可以配置一个“回退”策略:优先使用免费API,额度用尽后自动切换到本地模型。

6.3 监控与日志

一定要养成监控开销的习惯。可以在代码中简单记录每次调用的时间、模型和预估Token数。

import time from langchain.callbacks import StdOutCallbackHandler class CostTrackingCallback(StdOutCallbackHandler): def on_llm_start(self, serialized, prompts, **kwargs): self.start_time = time.time() # 可以在这里估算prompts的token数(需要安装tiktoken或类似库) estimated_input_tokens = len(str(prompts)) // 4 # 非常粗略的估算 print(f"[成本跟踪] LLM调用开始,预估输入Token: {estimated_input_tokens}") def on_llm_end(self, response, **kwargs): elapsed = time.time() - self.start_time # 估算生成的token数 output_text = response.generations[0][0].text estimated_output_tokens = len(output_text) // 4 print(f"[成本跟踪] LLM调用结束,耗时{elapsed:.2f}秒,预估输出Token: {estimated_output_tokens}") # 在使用agent_executor时传入callback agent_executor = AgentExecutor(..., callbacks=[CostTrackingCallback()])

更专业的做法是使用LangChain的LangSmith平台,它能提供非常详细的链路追踪、Token计数和成本分析,不过这是付费服务。

7. 常见问题与避坑指南

在搭建和调试过程中,我遇到了不少典型问题,这里列出来供你参考。

7.1 模型不按预期调用工具

  • 症状:Agent一直在“思考”,说需要调用工具,但输出的文本格式不符合框架的解析要求(比如没有“行动:”关键字),导致框架无法识别并执行工具。
  • 根因:提示词(Prompt)不够清晰,或者模型本身对工具调用的指令遵循能力不足。
  • 解决方案
    1. 强化提示词:在系统指令中,用非常明确、格式化的例子告诉模型应该如何响应。参考hwchase17/react这个提示词模板,它就是专门为ReAct范式优化的。
    2. 选择适合的模型:有些模型在工具调用/函数调用(Function Calling)方面进行了专门优化,效果更好。可以查阅模型的官方文档,看是否强调此功能。
    3. 启用handle_parsing_errors:就像我们之前代码中设置的,这个参数能让AgentExecutor在解析失败时尝试让模型修正错误,而不是直接崩溃。

7.2 Agent陷入死循环

  • 症状:Agent不停地调用同一个工具,或者在不同的工具间来回切换,始终无法得出最终答案。
  • 根因:任务目标不清晰,或者工具返回的结果无法让模型推导出下一步。
  • 解决方案
    1. 设置max_iterations:这是最重要的安全阀。务必设置一个合理的上限(如10次),防止无限循环消耗大量Token和费用。
    2. 优化工具反馈:确保工具返回的结果是清晰、结构化、信息丰富的。如果工具返回错误或模糊信息,模型很可能无法正确理解。
    3. 在提示词中加入反思指令:例如,在每次行动后,提示模型“检查当前结果是否已足够回答问题,如果足够,请给出最终答案”。

7.3 API调用失败与Token失效

  • 症状:出现类似token exchange failedstatus 403 forbiddenyour access token could not be refreshed等错误。
  • 根因
    1. API密钥错误或失效:密钥填写错误、密钥被重置、免费额度用完。
    2. 网络或区域限制:某些API端点可能对访问IP有区域限制。
    3. 请求格式或频率问题:发送的请求不符合API要求,或触发了频率限制(Rate Limit)。
  • 排查步骤
    1. 检查密钥:确认环境变量中的密钥是否正确,并前往模型平台的控制台查看密钥状态、剩余额度。
    2. 检查base_url:确认代码中初始化模型时使用的base_url是否正确,特别是对于某些需要特定域名的国产模型。
    3. 查看完整错误信息:Python的报错信息通常很长,仔细阅读后半部分,里面往往有服务器返回的具体错误原因。
    4. 加入重试机制:对于网络波动或暂时的Rate Limit,可以在代码中加入简单的重试逻辑(如使用tenacity库),但重试间隔要合理,避免加重服务器负担。

7.4 本地环境配置问题

  • Python包冲突:这是最常见的问题。langchain及其生态包更新很快,不同版本间可能存在接口变化。
  • 解决方案
    • 坚持使用虚拟环境:为每个项目创建独立的虚拟环境,这是避免冲突的黄金法则。
    • 使用requirements.txt锁定版本:在项目稳定后,运行pip freeze > requirements.txt将当前环境的所有包及版本号导出。其他人或你在新环境部署时,使用pip install -r requirements.txt即可复现完全一致的环境。
    • 仔细阅读错误信息:安装或运行时出错,首先看错误信息的最后几行,它通常会明确指出是哪个包、哪个版本不兼容。

搭建这个AI Agent的过程,更像是一次对现有开源生态和云服务的“组合式创新”。最大的体会是,不要一开始就追求完美和强大。用最小的成本、最简单的工具链跑通核心流程,看到Agent真的能“动起来”,这个正反馈至关重要。之后,再根据具体需求,逐步替换更强的模型、增加更复杂的工具(如连接数据库、调用外部API)、设计更优雅的工作流(用LangGraph实现)。这套以国产模型+开源框架为基础的方案,无疑为个人开发者探索AI Agent世界打开了一扇低成本、可实操的大门。

返回列表