从零构建AI智能体:基于LangChain与Spring AI的工程实践指南
2026/8/22 4:14:26 网站建设 项目流程

在实际技术项目中,AI 智能体(AI Agent)已经从概念走向了工程实践。它不再仅仅是聊天机器人,而是能够感知环境、规划决策、执行工具调用并持续学习的自主程序。对于开发者而言,理解如何从零搭建一个具备基础能力的智能体,是进入这一领域的关键一步。本文将以一个可运行的“AI 小镇”模拟项目为切入点,带你理解智能体的核心组件、工作流程,并动手实现一个简单的智能体系统。无论你是想探索智能体开发,还是希望将 AI 能力集成到现有业务中,本文提供的从环境搭建、框架选择到代码实现和问题排查的完整路径,都将为你提供一个坚实的起点。

我们将围绕一个开源模拟项目,拆解智能体的感知、决策、行动与学习循环。你会了解到如何选择合适的框架(如 LangChain、Spring AI),如何设计智能体的记忆与工具调用机制,以及如何处理开发中常见的“幻觉”(Hallucination)、工具调用失败等问题。最终,你将获得一个可以本地运行、观察其行为的智能体原型,并掌握将其扩展为更复杂应用(如自动化测试、合规检测)的基本方法。

1. 理解 AI 智能体的核心架构与工作循环

在开始编码之前,必须厘清智能体(Agent)与普通调用大模型 API 的程序有何本质区别。简单来说,一个普通程序是“你问,模型答”,而智能体是“你给目标,它自己想办法完成”。这背后的核心是一个经典的“感知-思考-行动”循环,在工程上通常体现为几个关键组件。

1.1 智能体与简单提示工程的区别

很多人接触 AI 应用是从写提示词(Prompt)开始的,例如让模型总结一段文本。这属于“零样本”或“少样本”提示,模型根据当前输入直接生成输出,没有状态记忆,也没有外部工具调用能力。

智能体则在此基础上增加了几个维度:

  • 状态与记忆(Memory):智能体能记住之前的对话历史、执行过的操作及其结果,从而在后续决策中保持上下文连贯性。这通常通过向量数据库、普通数据库或简单的会话缓存来实现。
  • 工具调用(Tool Calling):智能体可以理解用户指令,并决定调用哪个外部工具(如计算器、搜索引擎、数据库查询、API)来获取信息或执行操作。这是智能体扩展能力边界的关键。
  • 规划与决策(Planning):对于复杂任务,智能体需要将其分解为多个子步骤,并决定执行顺序。这通常由大模型本身的推理能力或外部的规划器(Planner)模块完成。
  • 学习与反思(Learning/Reflection):高级智能体能够从历史行动的结果中学习,评估行动的有效性,并在未来遇到类似情况时调整策略。

以一个“查询天气并建议穿衣”的任务为例:

  • 简单提示:用户输入“北京今天天气如何?我该穿什么?”,模型基于训练数据生成一个笼统的回答。
  • 智能体:1. 感知到用户问题;2. 思考后决定先调用“天气查询工具”获取北京实时温度、湿度;3. 根据工具返回的具体数据,结合“穿衣知识库”进行推理;4. 生成包含具体温度和建议的回复。如果用户追问“明天呢?”,它能记住刚才查询的是北京,并继续调用工具。

1.2 典型智能体框架的组件映射

目前主流的智能体开发框架(如 LangChain、LlamaIndex、Spring AI)都将上述抽象概念封装成了可编程的组件。了解这些组件有助于你选择适合的工具。

组件功能描述在 LangChain 中的对应在 Spring AI 中的对应
Agent智能体核心,协调其他组件工作。AgentExecutorAgent接口及其实现
LLM大语言模型,提供推理和生成能力。ChatOpenAI,ChatAnthropicChatClient(OpenAI, Azure, Ollama)
Tools可供智能体调用的外部函数或API。@Tool注解修饰的函数,或BaseTool子类Tool接口实现类
Memory存储和检索对话历史、工具调用结果。ConversationBufferMemory,VectorStoreRetrieverMemoryChatMemory接口实现
Prompt Template定义引导智能体行为的系统提示词。ChatPromptTemplatePromptTemplate
Output Parser解析模型输出,将其转换为结构化数据(如工具调用指令)。JsonOutputParser,StructuredOutputParser通常内置于 Agent 实现中

开源项目“AI 小镇”(如mewamew/my_ai_town这类模拟社会实验)通常是多个智能体在共享环境中交互的复杂系统。它放大了单个智能体的架构:每个居民是一个智能体,小镇环境是共享状态,居民间的对话是工具调用(信息交换),长期目标(如成为艺术家)是规划任务。研究这类项目能帮你理解多智能体协作和更复杂的记忆、规划机制。

2. 环境准备与开发框架选型

在动手实现之前,需要搭建一个稳定的开发环境,并选择适合你技术栈的框架。本节将提供两种主流路线的准备方案。

2.1 基础开发环境配置

无论选择哪种框架,以下环境是通用的:

  1. Python 环境:推荐使用 Python 3.10 或 3.11。使用condavenv创建独立的虚拟环境是最佳实践。

    # 使用 conda 创建环境 conda create -n ai-agent python=3.11 conda activate ai-agent # 或使用 venv python -m venv venv # Windows .\venv\Scripts\activate # Linux/Mac source venv/bin/activate
  2. 大模型访问权限:你需要一个能够访问的大语言模型 API。对于学习和原型开发,有以下选择:

    • OpenAI GPT 系列:稳定,工具调用能力强,但需付费。
    • 开源本地模型:如通过Ollama运行Llama 3QwenDeepSeek等模型。免费,但对本地硬件有要求。
    • 国内大模型 API:如智谱、月之暗面、百度文心等,需注册获取 API Key。

    将 API Key 设置为环境变量,避免硬编码在代码中:

    # Linux/Mac export OPENAI_API_KEY='your-api-key-here' # Windows (PowerShell) $env:OPENAI_API_KEY='your-api-key-here'

2.2 框架选型:LangChain vs Spring AI

根据你的主要开发语言和项目背景,可以选择不同的技术栈。

Python 路线:LangChainLangChain 是当前生态最丰富的智能体开发框架,社区活跃,教程和示例众多。它非常适合快速原型验证和学术研究。

# 安装核心库及OpenAI集成 pip install langchain langchain-openai # 如果需要使用更多社区工具或记忆存储 pip install langchain-community langchain-chroma

注意:LangChain 模块拆分较细,建议根据项目需要逐步安装,避免依赖冲突。

Java 路线:Spring AI如果你所在团队主要技术栈是 Java,或者项目需要集成到现有的 Spring Boot 微服务中,Spring AI 是官方支持的良好选择。它提供了统一的ChatClientAPI 来对接不同模型,并内置了智能体、向量库等模块。 在pom.xml中添加依赖:

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> <version>0.8.1</version> <!-- 请使用最新稳定版 --> </dependency>

然后在application.yml中配置:

spring: ai: openai: api-key: ${OPENAI_API_KEY} chat: options: model: gpt-4o-mini

选型建议

  • 快速学习、验证想法、数据科学背景:优先选择LangChain (Python)
  • 企业级应用、需要集成现有 Java 后端、强调工程规范:优先选择Spring AI (Java)
  • 其他DifyCoze等平台属于低代码/无代码智能体搭建平台,适合非开发者快速构建应用,但定制性和底层控制力较弱。Cursor等 AI 编程助手是开发工具,而非智能体开发框架。

本文后续示例将以LangChain (Python)为主,因为其受众更广,概念演示更直观。Spring AI 的思路基本一致,只是 API 不同。

3. 从零构建一个基础智能体:天气查询助手

我们将构建一个能够理解用户意图、调用天气查询工具并给出建议的智能体。这个例子涵盖了智能体最核心的要素。

3.1 项目结构与依赖

创建一个新的项目目录,结构如下:

weather_agent/ ├── tools/ │ └── weather_tools.py # 工具定义 ├── agents/ │ └── weather_agent.py # 智能体定义与执行 ├── main.py # 主程序入口 └── requirements.txt

requirements.txt内容:

langchain>=0.1.0 langchain-openai>=0.0.5 requests>=2.31.0 python-dotenv>=1.0.0

3.2 第一步:定义工具(Tools)

工具是智能体能力的延伸。这里我们定义一个模拟的天气查询工具。在实际项目中,你可以替换为真实的天气 API。tools/weather_tools.py:

from langchain.tools import tool import requests @tool def get_current_weather(location: str) -> str: """ 根据城市名获取当前的天气信息。 Args: location: 城市名称,例如“北京”、“上海”。 Returns: 一个描述天气的字符串。 """ # 注意:这是一个模拟函数。真实情况应调用如和风天气、OpenWeatherMap等API。 # 这里为了演示,返回固定格式的模拟数据。 print(f"[工具调用] 正在查询 {location} 的天气...") # 模拟API调用延迟 import time time.sleep(0.5) # 模拟不同城市的返回 weather_data = { "北京": "晴朗,温度 25°C,微风,湿度 40%。", "上海": "多云,温度 28°C,东南风2级,湿度 65%。", "广州": "阵雨,温度 30°C,南风3级,湿度 80%。", } return weather_data.get(location, f"未找到 {location} 的天气信息。目前模拟数据仅支持:{list(weather_data.keys())}") # 可以定义更多工具,如穿衣建议工具、湿度查询工具等。 # @tool # def get_clothing_advice(temperature: int, conditions: str) -> str: # ...

关键点:

  1. 使用@tool装饰器将普通函数声明为 LangChain 可识别的工具。
  2. 函数的文档字符串(""")非常重要!大模型会阅读它来理解工具的用途和参数。描述必须清晰准确。
  3. 工具应返回字符串或可序列化的数据,以便智能体理解。

3.3 第二步:构建智能体(Agent)

我们将使用 LangChain 的create_react_agent来构建一个智能体。ReAct 是一个经典的智能体推理框架(Reason + Act)。agents/weather_agent.py:

import os from langchain import hub from langchain.agents import create_react_agent, AgentExecutor from langchain_openai import ChatOpenAI from tools.weather_tools import get_current_weather def build_weather_agent(): """ 构建并返回一个天气查询智能体的执行器。 """ # 1. 初始化大模型 # 确保环境变量 OPENAI_API_KEY 已设置 llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0) # 如果使用本地模型,例如通过 Ollama: # from langchain_community.llms import Ollama # llm = Ollama(model="llama3") # 2. 定义智能体可用的工具列表 tools = [get_current_weather] # 3. 从 LangChain Hub 拉取一个预设的 ReAct 提示词模板 # 这个模板会指导模型按照“思考 -> 行动 -> 观察”的循环工作 prompt = hub.pull("hwchase17/react") # 4. 创建智能体 agent = create_react_agent(llm, tools, prompt) # 5. 创建智能体执行器,它负责运行循环,处理工具调用 agent_executor = AgentExecutor( agent=agent, tools=tools, verbose=True, # 开启详细日志,便于调试 handle_parsing_errors=True, # 优雅处理模型输出解析错误 max_iterations=5, # 限制最大循环次数,防止死循环 early_stopping_method="generate" # 当模型认为任务完成时停止 ) return agent_executor if __name__ == "__main__": # 本地测试 agent_executor = build_weather_agent() result = agent_executor.invoke({"input": "北京和上海的天气怎么样?"}) print("\n--- 最终回答 ---") print(result["output"])

代码解释:

  • ChatOpenAI: 封装了与 OpenAI API 的交互。temperature=0使输出更确定,适合工具调用。
  • create_react_agent: 将模型、工具和提示词模板组合成一个智能体对象。
  • AgentExecutor: 这是智能体的“发动机”。它运行 ReAct 循环:将用户输入和上下文传给模型 -> 模型返回思考结果和工具调用请求 -> 执行器调用工具 -> 将工具结果作为“观察”再次传给模型 -> 直到模型生成最终答案。
  • verbose=True:这是学习阶段最重要的参数,它会打印出智能体内部的思考链(Chain of Thought),让你看清它是如何决策的。

3.4 第三步:运行与验证

创建主程序入口main.py

from dotenv import load_dotenv from agents.weather_agent import build_weather_agent # 加载 .env 文件中的环境变量(如果你把 API KEY 放在 .env 文件里) load_dotenv() def main(): print("初始化天气查询智能体...") agent = build_weather_agent() while True: try: user_input = input("\n请输入您的问题 (或输入 'quit' 退出): ") if user_input.lower() in ['quit', 'exit', 'q']: print("再见!") break if not user_input.strip(): continue print(f"\n用户: {user_input}") print("-" * 50) result = agent.invoke({"input": user_input}) print("-" * 50) print(f"智能体: {result['output']}") except KeyboardInterrupt: print("\n程序被中断。") break except Exception as e: print(f"\n发生错误: {e}") if __name__ == "__main__": main()

运行程序:

python main.py

输入“北京今天天气如何?”,观察控制台输出。你应该能看到类似以下的详细日志(verbose=True的效果):

> 进入新的 AgentExecutor 链... 思考:用户想知道北京的天气,我需要使用天气查询工具。 行动:get_current_weather 行动输入:{"location": "北京"} [工具调用] 正在查询 北京的天气... 观察:晴朗,温度 25°C,微风,湿度 40%。 思考:我已经获取了北京的天气信息,可以直接回答用户。 最终答案:北京今天的天气是晴朗,温度 25°C,微风,湿度 40%。 > 链结束。

这表明智能体成功完成了“思考-行动-观察-再思考-回答”的完整循环。

4. 核心机制详解与高级配置

一个可用的基础智能体已经搭建完成,但要使其健壮、可靠,需要深入理解其内部机制并进行配置。

4.1 智能体的“思考”过程:ReAct 提示词剖析

LangChain Hub 上的hwchase17/react提示词模板是智能体行为的“宪法”。其核心结构如下(简化):

你是一个有帮助的助手,可以使用以下工具: {tools} 使用以下格式回答: 问题:用户输入的问题 思考:你需要一步步思考。如果需要使用工具,就在这里决定用哪个工具。 行动:要调用的工具名,必须是 [{tool_names}] 中的一个。 行动输入:工具的输入,必须是有效的 JSON 格式。 观察:工具返回的结果 ... (这个“思考/行动/行动输入/观察”循环可以重复多次) 思考:我现在知道了最终答案。 最终答案:对用户问题的最终回答。

这个模板强制模型以结构化格式输出,方便AgentExecutor解析。{tools}{tool_names}会在运行时被替换为你定义的工具列表和名称。

4.2 记忆(Memory)的集成

上面的例子是“无状态”的,每次对话都是独立的。为了让智能体记住上下文,需要集成记忆组件。 修改agents/weather_agent.py中的build_weather_agent函数:

from langchain.memory import ConversationBufferMemory def build_weather_agent_with_memory(): llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0) tools = [get_current_weather] prompt = hub.pull("hwchase17/react") # 1. 创建记忆对象 memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) # 2. 修改提示词模板,加入记忆变量 # ReAct 提示词本身不直接支持历史,我们可以自定义或使用其他支持记忆的Agent类型,如`conversational-react-description` # 这里为了演示,我们改用另一种方式 from langchain.agents import initialize_agent, AgentType agent_executor = initialize_agent( tools, llm, agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION, # 专为对话设计的Agent类型 verbose=True, memory=memory, # 传入记忆 max_iterations=3, handle_parsing_errors=True, ) return agent_executor

现在,当你连续问“北京天气怎么样?”和“那我该穿什么?”时,智能体会记得之前的对话地点是北京,从而在后续回答中保持连贯。

4.3 处理“AI 幻觉”与工具调用失败

“AI 幻觉”(Hallucination)指模型生成不准确或虚构信息。在智能体场景中,幻觉可能导致它调用不存在的工具或传入错误参数。

常见问题1:模型不调用工具,直接编造答案

  • 现象:用户问“北京温度多少?”,模型直接回答“北京气温大约20度”,而没有调用get_current_weather工具。
  • 原因:提示词指令不够强,或者模型在训练数据中“见过”类似问题,倾向于直接生成。
  • 解决
    1. 强化工具描述:在工具的文档字符串中明确写出“你必须使用此工具来获取准确的天气信息,不要凭空猜测”。
    2. 调整提示词:在系统提示词中强调“对于任何涉及天气的问题,你必须使用get_current_weather工具”。
    3. 使用更强的模型:GPT-4 在工具调用遵循指令上通常优于 GPT-3.5。

常见问题2:工具调用参数格式错误

  • 现象:日志显示Action Input: 北京(一个字符串),但工具期望{"location": "北京"}(一个JSON对象)。
  • 原因:模型没有严格按照 JSON 格式输出。
  • 解决
    1. 确保提示词模板中明确要求“必须是有效的 JSON 格式”。
    2. 使用handle_parsing_errors=True让执行器在解析失败时尝试修复或提示模型重试。
    3. 使用支持“结构化输出”(Structured Output)的模型,或使用JsonOutputParser对模型输出进行后处理。

常见问题3:智能体陷入死循环

  • 现象:智能体反复调用同一个工具,无法得出最终答案。
  • 原因:工具返回的结果可能无法让模型满意,或者模型逻辑陷入循环。
  • 解决
    1. 设置max_iterations(如5次),强制限制循环次数。
    2. 优化工具返回的信息,使其更清晰、更具结论性。
    3. 检查提示词中“最终答案”的触发条件是否明确。

5. 生产环境考量与最佳实践

将智能体从演示原型推向生产环境,需要关注稳定性、安全性和可维护性。

5.1 配置管理

切勿将 API Key 等敏感信息硬编码在代码中。使用环境变量或专业的配置管理工具(如python-dotenv, Spring Cloud Config)。

# .env 文件 OPENAI_API_KEY=sk-... OPENAI_BASE_URL=https://api.openai.com/v1 # 如果使用代理 WEATHER_API_KEY=your-real-weather-key
# 在代码中读取 import os api_key = os.getenv("OPENAI_API_KEY") if not api_key: raise ValueError("请在 .env 文件中设置 OPENAI_API_KEY")

5.2 日志与监控

生产环境必须关闭verbose=True,但需要将智能体的决策日志记录到文件或日志系统中,以便排查问题。

import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # 可以自定义回调函数来记录关键事件 from langchain.callbacks import StdOutCallbackHandler from langchain.callbacks.base import BaseCallbackHandler class CustomCallbackHandler(BaseCallbackHandler): def on_agent_action(self, action, **kwargs): logger.info(f"智能体行动: {action.log}") # 在创建 AgentExecutor 时传入 agent_executor = AgentExecutor(..., callbacks=[CustomCallbackHandler()])

5.3 安全与合规

这是企业级应用的重中之重。

  • 工具权限控制:不是所有工具都对所有用户开放。需要建立用户-工具权限映射,在执行前进行校验。
  • 输入输出过滤与审核:对用户输入和模型输出进行内容安全过滤,防止生成有害、偏见或敏感信息。
  • 数据隐私:确保用户对话数据、通过工具查询的业务数据符合隐私法规(如 GDPR)。考虑对数据进行脱敏或使用本地化模型。
  • 速率限制与熔断:对调用大模型 API 和内部工具的频率进行限制,防止滥用或意外高负载拖垮系统。

5.4 性能优化

  • 缓存:对频繁且结果不变的查询(如某些天气信息、知识库问答)实施缓存,减少不必要的模型调用和工具调用,降低成本与延迟。
  • 异步调用:如果智能体需要并行调用多个独立工具,使用异步模式(如 LangChain 的ainvoke)可以显著提升响应速度。
  • 模型选型:在精度和成本间权衡。简单的工具路由任务可以使用更小、更快的模型(如gpt-3.5-turbo),复杂的规划推理则可能需要gpt-4

6. 扩展方向:从单智能体到复杂应用

掌握了基础智能体搭建后,你可以向以下几个方向深入探索:

1. 多智能体系统(如 AI 小镇)研究mewamew/my_ai_town这类项目,学习如何让多个智能体共享环境、通过消息传递进行协作与竞争。关键点在于设计智能体间的通信协议和共享状态管理。

2. 智能体工作流(Workflow)对于需要严格步骤的任务(如数据处理流水线),可以将多个智能体或工具按固定顺序组织成工作流。Coze 扣子Dify等平台的可视化工作流设计器就是此概念的体现。在代码中,你可以用LangChain Expression Language (LCEL)或普通编程逻辑来编排。

3. 智能体与专业领域结合

  • AI 编程助手:类似CursorGitHub Copilot,智能体可以理解代码上下文,调用代码解析、搜索、生成、测试等工具。
  • 智能体测试:让智能体模拟用户操作 UI,或根据 API 文档自动生成并执行测试用例。
  • 合规自动化检测:如输入材料中提到的“企业级 AI 智能体安全合规自动化检测系统”,智能体可以调用代码扫描、配置检查、漏洞库查询等工具,自动化完成安全审计的一部分工作。

4. 处理复杂工具与长上下文当工具数量众多或文档复杂时,需要为智能体配备“工具检索”能力,即先根据用户问题从工具库中筛选出最相关的几个,再让模型决定调用哪一个。这通常结合向量数据库(Vector Store)和检索增强生成(RAG)技术来实现。

构建 AI 智能体的旅程始于一个简单的工具调用循环,但通往一个能可靠处理复杂任务、安全合规、易于维护的生产系统,还需要在架构设计、异常处理、监控运维上投入大量工程努力。建议从本文的小例子出发,逐个攻克记忆、规划、多智能体协作等进阶课题,并始终将测试和验证作为开发流程的核心环节。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询