尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从零搭建AI智能体开发工具链:环境、测试、部署全流程实践

从零搭建AI智能体开发工具链:环境、测试、部署全流程实践 在实际 AI 应用开发中我们常常会遇到这样的困境一个基于大语言模型的智能体Agent在演示时表现惊艳但一旦试图将其集成到真实业务流、处理复杂逻辑或需要稳定运行就会暴露出配置混乱、依赖脆弱、调试困难、部署繁琐等一系列工程化问题。这背后的核心原因往往是缺乏一套标准、可靠、可复现的智能体工具链。工具链不仅仅是几个脚本的集合它定义了从环境准备、代码开发、测试验证到部署上线的完整工作流是智能体项目从“玩具”走向“工程”的关键。本文将带你从零开始亲手搭建一套面向生产环境的智能体开发工具链。这套工具链将覆盖智能体开发的核心生命周期环境隔离与依赖管理、代码与提示词工程、本地测试与调试、以及持续集成与部署准备。我们的目标不是介绍某个单一的框架而是构建一套可以适配不同 Agent 框架如 LangChain、Semantic Kernel、Spring AI 等的底层工程基础设施。通过实践你将理解如何将 AI 能力“工程化”使其具备可维护性、可测试性和可扩展性。1. 理解智能体工具链的核心构成与设计原则在动手之前我们需要明确智能体工具链应该解决哪些问题以及它的设计应该遵循哪些原则。这能帮助我们在选择具体工具时做出更合理的决策。1.1 智能体项目的特殊性与挑战与传统软件开发相比智能体项目引入了新的复杂度维度双重依赖不仅依赖传统的代码库Python/Java包更重度依赖外部的大模型 API如 OpenAI、通义千问等及其随时可能变化的接口和计费策略。非确定性输出大模型的输出具有概率性相同的输入可能产生不同的输出这使得单元测试和集成测试的断言Assertion变得困难。提示词即配置智能体的核心逻辑很大程度上由自然语言写成的提示词Prompt驱动。提示词的版本管理、效果评估和迭代优化是开发流程的重要组成部分。长上下文与状态管理智能体往往需要处理多轮对话维护会话状态和历史这对内存管理、持久化方案提出了要求。工具调用与编排高级智能体需要调用外部工具如搜索、数据库、API如何安全、可靠地管理这些工具的凭证、处理调用失败是工程难点。1.2 工具链的四大核心模块一套完整的智能体工具链应包含以下模块它们共同构成了开发-测试-部署的闭环模块核心职责关键产出物环境与依赖管理隔离项目环境精确锁定所有依赖包括Python包、模型SDK、系统工具的版本确保环境一致性。pyproject.toml,requirements.txt,Pipfile.lock,poetry.lock, Dockerfile代码与提示词工程提供智能体核心逻辑工具定义、流程控制和提示词的编写、版本管理、模板化与热加载能力。Agent 类定义 工具函数prompts/目录下的模板文件 配置文件如config.yaml本地开发与调试支持在本地快速启动、交互测试智能体并提供日志、追踪Trace、成本监控等调试信息。本地运行脚本 交互式 Notebook 结构化日志文件 LangSmith 或 OpenTelemetry 追踪视图测试与质量保障对智能体的确定性部分工具调用、流程分支和概率性输出进行不同维度的测试与评估。单元测试 集成测试 基于场景的评估Evaluation脚本 测试报告构建与部署将智能体及其所有依赖打包成可独立运行的镜像或服务并集成到 CI/CD 流水线中。Docker 镜像 Helm Chart CI 配置文件如.github/workflows/ci.yml1.3 设计原则稳定、透明、可观测搭建工具链时应始终秉持以下原则稳定性优先依赖版本必须锁定避免因上游更新导致不可预知的行为。关键操作如模型调用、工具执行必须有重试和降级策略。配置外置所有可能变化的参数如 API Key、模型名称、温度参数、提示词模板必须从代码中分离通过配置文件或环境变量管理。全面可观测每一次模型调用、工具执行、花费的 Token 数量、耗时和成本都必须有清晰的日志和追踪记录。这是调试和优化性能、成本的基础。渐进式复杂工具链本身不应成为负担。应从最小可行集开始随着项目复杂度提升再逐步引入更强大的工具如复杂的评估框架、分布式追踪系统。2. 搭建基础环境与依赖管理这是所有工程项目的起点对于智能体项目尤为重要。一个混乱的环境是后续所有问题的根源。2.1 选择并初始化项目管理工具我们推荐使用Poetry作为 Python 项目的依赖管理和打包工具。它比传统的pipvirtualenvsetup.py组合更现代、更一致。首先确保系统已安装 Python建议 3.9和 pip。然后安装 Poetry# 官方推荐安装方式Linux/macOS curl -sSL https://install.python-poetry.org | python3 - # Windows (Powershell) (Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py - # 安装后将 Poetry 添加到 PATH或使用 poetry config virtualenvs.in-project true 让虚拟环境创建在项目内创建一个新的智能体项目目录并初始化mkdir my_agent_project cd my_agent_project poetry init执行poetry init后会交互式地询问项目名称、版本、描述等信息并生成pyproject.toml文件。这个文件是项目的核心配置。2.2 定义项目依赖编辑生成的pyproject.toml文件或在初始化时直接添加依赖。一个典型的智能体项目依赖可能如下所示# pyproject.toml [tool.poetry] name my-agent-project version 0.1.0 description A production-ready AI agent project. authors [Your Name youexample.com] [tool.poetry.dependencies] python ^3.9 # 核心AI框架这里以 LangChain 为例 langchain ^0.1.0 langchain-openai ^0.0.5 # 可选其他模型提供商 langchain-community ^0.0.10 # 环境管理与配置加载 pydantic-settings ^2.0.0 python-dotenv ^1.0.0 # 异步支持 httpx ^0.25.0 # 日志 loguru ^0.7.0 # 测试框架 pytest ^7.4.0 pytest-asyncio ^0.21.0 [tool.poetry.group.dev.dependencies] # 开发工具代码格式化、静态检查 black ^23.0.0 isort ^5.12.0 mypy ^1.5.0 ruff ^0.1.0 # 交互式开发 jupyter ^1.0.0 ipython ^8.0.0 [build-system] requires [poetry-core] build-backend poetry.core.masonry.api然后安装依赖并创建虚拟环境poetry installpoetry install会读取pyproject.toml安装所有依赖并生成一个精确的版本锁文件poetry.lock。务必将poetry.lock提交到版本控制系统如 Git这是保证团队所有成员和生产环境依赖一致的关键。2.3 管理敏感配置与环境变量永远不要将 API Key 等敏感信息硬编码在代码中。使用pydantic-settings和.env文件来管理配置。首先安装pydantic-settings已在上一步添加。然后创建项目配置文件# config/settings.py from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic import SecretStr class Settings(BaseSettings): # 从 .env 文件或环境变量中加载 model_config SettingsConfigDict(env_file.env, env_file_encodingutf-8) # OpenAI 配置 openai_api_key: SecretStr openai_base_url: str https://api.openai.com/v1 # 支持兼容OpenAI的代理 openai_model: str gpt-3.5-turbo # 日志级别 log_level: str INFO # 项目特定配置 database_url: str sqlite:///./agent.db settings Settings()接着在项目根目录创建.env文件并添加到.gitignore中# .env OPENAI_API_KEYsk-your-actual-secret-key-here OPENAI_MODELgpt-4-turbo-preview LOG_LEVELDEBUG在代码中这样使用配置from config.settings import settings from langchain_openai import ChatOpenAI llm ChatOpenAI( api_keysettings.openai_api_key.get_secret_value(), base_urlsettings.openai_base_url, modelsettings.openai_model )注意.env文件绝不能提交到代码仓库。应在团队内通过安全的秘密管理工具如 Vault、AWS Secrets Manager或在 CI/CD 平台的环境变量中传递这些敏感值。pydantic-settings会优先读取系统环境变量这为生产部署提供了便利。3. 构建智能体核心与提示词工程有了稳定的环境我们可以开始构建智能体本身。这里我们以构建一个“天气查询助手”Agent为例展示如何组织代码和提示词。3.1 项目结构设计一个清晰的项目结构有助于长期维护。建议采用如下模块化结构my_agent_project/ ├── .env # 本地环境变量.gitignore ├── .gitignore ├── pyproject.toml # 项目依赖和配置 ├── poetry.lock # 锁定的依赖版本 ├── README.md ├── config/ │ ├── __init__.py │ └── settings.py # Pydantic 配置类 ├── src/ │ └── agent/ │ ├── __init__.py │ ├── core/ # 核心抽象、基类 │ │ ├── __init__.py │ │ └── base_agent.py │ ├── tools/ # 工具定义 │ │ ├── __init__.py │ │ └── weather_tool.py │ ├── prompts/ # 提示词模板 │ │ ├── __init__.py │ │ └── weather_agent.jinja2 │ ├── chains/ # 业务链或工作流 │ │ └── __init__.py │ └── run.py # 主运行入口 ├── tests/ # 测试目录 │ ├── __init__.py │ ├── test_tools.py │ └── test_agent.py ├── scripts/ # 辅助脚本 │ ├── evaluate.py │ └── deploy.sh └── notebooks/ # 探索性分析与原型 └── prototype.ipynb3.2 实现工具Tools工具是智能体扩展能力的手臂。我们实现一个简单的模拟天气查询工具# src/agent/tools/weather_tool.py import json from typing import Type, Optional from pydantic import BaseModel, Field from langchain.tools import BaseTool class WeatherToolInput(BaseModel): 查询天气工具的输入参数模型。 location: str Field(description城市名称例如北京、上海) date: Optional[str] Field(defaultNone, description查询日期格式 YYYY-MM-DD。默认为今天。) class WeatherTool(BaseTool): name get_current_weather description 根据城市名称和日期查询天气情况。 args_schema: Type[BaseModel] WeatherToolInput return_direct: bool False # 是否直接返回结果不经过LLM加工 def _run(self, location: str, date: Optional[str] None) - str: 同步执行工具逻辑。 # 这里模拟一个API调用。真实场景应替换为真正的天气API如和风、OpenWeatherMap等。 # 注意生产环境需要处理网络异常、API限流、认证等问题。 weather_data { location: location, date: date or 2023-10-27, temperature: 22°C, condition: 晴朗, humidity: 65%, wind: 微风 } return json.dumps(weather_data, ensure_asciiFalse) async def _arun(self, location: str, date: Optional[str] None) - str: 异步执行工具逻辑。对于IO密集型操作异步版本性能更好。 # 模拟异步调用 return self._run(location, date)关键点使用Pydantic模型定义输入参数并给出清晰的description这能帮助大语言模型更准确地理解何时以及如何调用该工具。return_direct参数控制工具输出是否直接返回给用户还是交给 LLM 总结后再输出。3.3 管理提示词模板将提示词从代码中分离出来使用模板引擎如 Jinja2进行管理便于迭代和 A/B 测试。首先安装 Jinja2poetry add jinja2。创建提示词模板文件{# src/agent/prompts/weather_agent.jinja2 #} 你是一个友好的天气查询助手。你的任务是帮助用户查询指定城市的天气信息。 你有以下工具可以使用 {{ tools }} 请根据用户的请求决定是否需要使用工具以及使用哪个工具。 如果你使用了工具请仔细阅读工具返回的结果并用友好、自然的方式总结给用户。 如果用户的请求不明确例如没有指定城市请礼貌地询问澄清。 历史对话 {{ chat_history }} 用户当前请求{{ input }} 请开始你的思考编写一个提示词加载器# src/agent/prompts/__init__.py from pathlib import Path from jinja2 import Environment, FileSystemLoader, select_autoescape # 设置模板环境 prompt_templates_dir Path(__file__).parent env Environment( loaderFileSystemLoader(prompt_templates_dir), autoescapeselect_autoescape() ) def load_prompt(template_name: str, **kwargs) - str: 加载并渲染指定的提示词模板。 template env.get_template(template_name) return template.render(**kwargs)3.4 组装智能体现在我们将工具、提示词和 LLM 组装成一个可运行的智能体。这里使用 LangChain 的AgentExecutor作为编排器。# src/agent/core/weather_agent.py import asyncio from typing import List, Optional from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_openai import ChatOpenAI from langchain.memory import ConversationBufferMemory from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from config.settings import settings from ..tools.weather_tool import WeatherTool from ..prompts import load_prompt class WeatherAgent: def __init__(self): # 1. 初始化LLM self.llm ChatOpenAI( api_keysettings.openai_api_key.get_secret_value(), base_urlsettings.openai_base_url, modelsettings.openai_model, temperature0.1, # 降低随机性使工具调用更稳定 streamingFalse, # 非流式响应简化示例 ) # 2. 初始化工具列表 self.tools [WeatherTool()] # 3. 构建提示词 # 使用我们之前定义的Jinja2模板 system_prompt load_prompt( weather_agent.jinja2, tools\n.join([f- {tool.name}: {tool.description} for tool in self.tools]), # chat_history 和 input 将在运行时动态传入 ) # 4. 创建LangChain提示词模板 # 注意这里将系统提示词和消息占位符组合起来 self.prompt ChatPromptTemplate.from_messages([ (system, system_prompt), MessagesPlaceholder(variable_namechat_history), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), # 用于记录Agent的思考过程 ]) # 5. 创建记忆用于多轮对话 self.memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 6. 创建Agent和Executor agent create_openai_tools_agent(llmself.llm, toolsself.tools, promptself.prompt) self.agent_executor AgentExecutor( agentagent, toolsself.tools, memoryself.memory, verboseTrue, # 开启详细日志便于调试 handle_parsing_errorsTrue, # 处理Agent输出解析错误 max_iterations5, # 限制最大迭代次数防止死循环 ) async def run(self, user_input: str) - str: 异步运行Agent处理用户输入。 try: result await self.agent_executor.ainvoke({input: user_input}) return result[output] except Exception as e: # 生产环境应有更细致的异常处理和日志 return f抱歉处理您的请求时出现了错误{str(e)} # 同步运行入口可选 def run_sync(self, user_input: str) - str: 同步运行Agent处理用户输入。 return asyncio.run(self.run(user_input))3.5 创建主运行入口# src/agent/run.py import asyncio import sys from loguru import logger from .core.weather_agent import WeatherAgent async def main(): logger.info(启动天气查询智能体...) agent WeatherAgent() # 示例交互式循环 if len(sys.argv) 1 and sys.argv[1] --interactive: logger.info(进入交互模式。输入 exit 或 quit 退出。) while True: try: user_input input(\n用户: ).strip() if user_input.lower() in [exit, quit]: break if not user_input: continue response await agent.run(user_input) print(f助手: {response}) except KeyboardInterrupt: break except Exception as e: logger.error(f处理输入时发生错误: {e}) else: # 单次查询示例 test_query 北京今天天气怎么样 logger.info(f测试查询: {test_query}) response await agent.run(test_query) logger.info(f助手回复: {response}) if __name__ __main__: asyncio.run(main())现在你可以通过以下命令运行你的智能体# 进入项目虚拟环境 poetry shell # 运行交互模式 python -m src.agent.run --interactive # 或运行单次测试 python -m src.agent.run4. 本地开发、调试与可观测性智能体开发不是一蹴而就的需要反复调试和观察其内部状态。强大的调试工具是高效开发的保障。4.1 结构化日志记录使用loguru或structlog替代标准的print和logging模块它们能输出更结构化、更易读的日志。配置loguru已在依赖中# 可以在 config/settings.py 中配置或在 run.py 开头初始化 import sys from loguru import logger logger.remove() # 移除默认配置 logger.add( sys.stderr, formatgreen{time:YYYY-MM-DD HH:mm:ss}/green | level{level: 8}/level | cyan{name}/cyan:cyan{function}/cyan:cyan{line}/cyan - level{message}/level, levelsettings.log_level ) logger.add( logs/agent_{time}.log, # 按时间轮转的日志文件 rotation1 day, retention30 days, levelDEBUG, encodingutf-8 )在代码关键位置添加日志# 在 WeatherAgent.run 方法中 async def run(self, user_input: str) - str: logger.info(f收到用户输入: {user_input}) try: result await self.agent_executor.ainvoke({input: user_input}) logger.success(fAgent执行成功输出: {result[output][:100]}...) # 截断长输出 # 记录Token消耗如果LLM支持 if hasattr(self.llm, last_response): usage self.llm.last_response.get(usage, {}) logger.debug(fToken消耗: 提示词 {usage.get(prompt_tokens)}, 补全 {usage.get(completion_tokens)}) return result[output] except Exception as e: logger.exception(fAgent执行失败: {e}) return f处理请求时出错: {str(e)}4.2 利用 LangSmith 进行追踪TracingLangSmith 是 LangChain 官方提供的可视化调试和监控平台。它能记录每一次链、工具、LLM调用的输入、输出、耗时和内部状态是调试复杂 Agent 逻辑的利器。注册并获取 API Key访问 LangSmith 官网注册在设置中创建 API Key。配置环境变量# .env LANGCHAIN_TRACING_V2true LANGCHAIN_ENDPOINThttps://api.smith.langchain.com LANGCHAIN_API_KEYlsv2_your_langsmith_api_key_here LANGCHAIN_PROJECTmy-weather-agent # 你的项目名运行 Agent现在当你运行 Agent 时所有的调用轨迹都会自动上传到 LangSmith 仪表盘。你可以查看每一步的详细输入输出分析错误原因优化提示词和工具逻辑。4.3 交互式调试与 Notebook对于快速原型和探索Jupyter Notebook 是无与伦比的工具。在项目根目录下创建notebooks/prototype.ipynb。# 在 notebook 单元格中 %load_ext autoreload %autoreload 2 import sys sys.path.append(..) # 将项目根目录加入路径 from src.agent.core.weather_agent import WeatherAgent import asyncio agent WeatherAgent() # 关闭verbose避免在notebook中输出过多信息 agent.agent_executor.verbose False # 测试单个查询 result await agent.run(上海明天天气如何) print(result) # 测试多轮对话 await agent.run(你好) await agent.run(我在北京。) result await agent.run(这里天气怎么样) print(result) # 检查记忆 print(agent.memory.load_memory_variables({}))使用 Notebook 可以快速试验不同的提示词、工具组合和参数观察中间结果而无需反复修改代码和重启服务。5. 测试、评估与质量保障智能体的非确定性使得传统单元测试面临挑战。我们需要分层测试策略。5.1 单元测试测试确定性组件工具函数、工具输入输出解析、配置加载等是确定性的应该用标准的单元测试覆盖。# tests/test_tools.py import pytest from src.agent.tools.weather_tool import WeatherTool, WeatherToolInput def test_weather_tool_input_validation(): 测试工具输入模型的验证逻辑。 # 正常输入 valid_input WeatherToolInput(location北京) assert valid_input.location 北京 assert valid_input.date is None # 无效输入Pydantic会自动抛出ValidationError with pytest.raises(Exception): WeatherToolInput() # 缺少必填字段 location def test_weather_tool_sync_run(): 测试天气工具的同步执行。 tool WeatherTool() result tool._run(上海, 2023-10-28) import json data json.loads(result) assert data[location] 上海 assert data[date] 2023-10-28 assert temperature in data pytest.mark.asyncio async def test_weather_tool_async_run(): 测试天气工具的异步执行。 tool WeatherTool() result await tool._arun(广州) import json data json.loads(result) assert data[location] 广州运行测试poetry run pytest tests/ -v5.2 集成测试测试 Agent 工作流集成测试关注组件间的协作。我们可以模拟 LLM 的响应来测试特定的 Agent 决策路径。# tests/test_agent.py import pytest from unittest.mock import AsyncMock, MagicMock, patch from src.agent.core.weather_agent import WeatherAgent pytest.mark.asyncio async def test_agent_uses_tool_for_weather_query(): 测试当用户询问天气时Agent 是否会正确调用工具。 # 创建 Agent 实例 agent WeatherAgent() # 模拟 LLM 的响应让它决定调用天气工具 mock_llm_response MagicMock() # 这里需要根据 LangChain Agent 内部的消息格式进行模拟较为复杂 # 更实际的做法是使用 LangChain 的测试工具或进行端到端测试 pass pytest.mark.asyncio async def test_agent_handles_unknown_query(): 测试 Agent 如何处理无法处理的查询。 agent WeatherAgent() # 可以临时替换 LLM让它返回一个不调用任何工具的响应 with patch.object(agent.llm, ainvoke, new_callableAsyncMock) as mock_llm: mock_llm.return_value.content 我无法处理这个请求。 response await agent.run(讲个笑话) assert 无法处理 in response or 抱歉 in response5.3 评估Evaluation测试非确定性输出对于 LLM 的文本生成我们需要用“评估”来代替断言。评估可以是基于规则的评估检查输出中是否包含特定关键词。基于模型的评估使用另一个 LLM如 GPT-4来评判输出是否相关、准确、无害。人工评估对于关键场景建立人工评估流程。可以编写一个评估脚本# scripts/evaluate.py import asyncio import pandas as pd from src.agent.core.weather_agent import WeatherAgent async def evaluate_agent(test_cases: list): 在测试用例集上评估Agent。 agent WeatherAgent() results [] for case in test_cases: query case[query] expected_intent case.get(intent) # 例如 use_weather_tool print(f测试查询: {query}) try: response await agent.run(query) # 这里可以添加各种评估逻辑 used_tool get_current_weather in str(agent.agent_executor.intermediate_steps) # 简化判断 results.append({ query: query, response: response, used_tool: used_tool, expected_intent: expected_intent, passed: used_tool (expected_intent use_weather_tool) }) except Exception as e: results.append({query: query, error: str(e), passed: False}) await asyncio.sleep(1) # 避免速率限制 df pd.DataFrame(results) print(df) accuracy df[passed].mean() if passed in df.columns else 0 print(f\n评估准确率: {accuracy:.2%}) return df if __name__ __main__: test_cases [ {query: 北京天气, intent: use_weather_tool}, {query: 你好, intent: chat}, {query: 明天上海气温多少度, intent: use_weather_tool}, {query: 11等于几, intent: chat}, # 期望不调用工具 ] asyncio.run(evaluate_agent(test_cases))6. 构建、部署与持续集成当智能体开发完成并通过基本测试后我们需要将其打包并部署到生产环境。6.1 容器化使用 Docker创建Dockerfile确保生产环境与开发环境一致。# Dockerfile # 使用官方 Python 镜像 FROM python:3.11-slim as builder # 安装 Poetry RUN pip install poetry1.7.0 # 设置工作目录 WORKDIR /app # 复制依赖定义文件 COPY pyproject.toml poetry.lock ./ # 配置 Poetry 不创建虚拟环境在容器内直接安装 RUN poetry config virtualenvs.create false \ poetry install --no-dev --no-interaction --no-ansi # 第二阶段运行阶段 FROM python:3.11-slim WORKDIR /app # 从构建阶段复制已安装的 Python 包 COPY --frombuilder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages COPY --frombuilder /usr/local/bin /usr/local/bin # 复制应用代码 COPY src/ ./src/ COPY config/ ./config/ COPY scripts/ ./scripts/ # 创建非 root 用户运行 RUN useradd -m -u 1000 agentuser chown -R agentuser:agentuser /app USER agentuser # 设置环境变量敏感信息应在运行时注入如通过K8s Secrets ENV PYTHONPATH/app/src ENV LOG_LEVELINFO # 运行应用 CMD [python, -m, src.agent.run]构建并运行 Docker 镜像# 构建镜像 docker build -t my-weather-agent:latest . # 运行容器注入环境变量 docker run -it --rm \ -e OPENAI_API_KEY$OPENAI_API_KEY \ -e OPENAI_MODELgpt-3.5-turbo \ my-weather-agent:latest6.2 持续集成CI流水线使用 GitHub Actions 或 GitLab CI 自动化测试和构建过程。创建一个.github/workflows/ci.yml文件# .github/workflows/ci.yml name: CI on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - name: Set up Python uses: actions/setup-pythonv4 with: python-version: 3.11 - name: Install Poetry run: pip install poetry - name: Install dependencies run: poetry install --with dev - name: Lint with ruff run: poetry run ruff check src/ --fix - name: Type check with mypy run: poetry run mypy src/ - name: Run unit tests run: poetry run pytest tests/ -v env: # 单元测试不应调用真实API应使用Mock。这里设置一个假Key防止误调用。 OPENAI_API_KEY: sk-dummy-key-for-test - name: Run evaluation script (smoke test) run: poetry run python scripts/evaluate.py env: OPENAI_API_KEY: ${{ secrets.TEST_OPENAI_API_KEY }} # 使用仓库Secrets中的测试Key build: needs: test runs-on: ubuntu-latest if: github.event_name push github.ref refs/heads/main steps: - uses: actions/checkoutv3 - name: Set up Docker Buildx uses: docker/setup-buildx-actionv2 - name: Login to DockerHub uses: docker/login-actionv2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_TOKEN }} - name: Build and push Docker image uses: docker/build-push-actionv4 with: context: . push: true tags: | ${{ secrets.DOCKER_USERNAME }}/my-weather-agent:latest ${{ secrets.DOCKER_USERNAME }}/my-weather-agent:${{ github.sha }}这个 CI 流水线会在每次推送或拉取请求时运行代码检查、类型检查、单元测试和冒烟测试。只有当代码合并到主分支时才会触发 Docker 镜像的构建和推送。6.3 部署考量部署智能体服务时除了常规的 Web 服务考量如健康检查、监控、日志收集还需特别注意API 密钥管理使用云服务商提供的秘密管理服务如 AWS Secrets Manager, Azure Key Vault或在 K8s 中使用 Secrets。速率限制与重试为模型 API 调用配置合理的重试和退避策略避免因瞬时故障或限流导致服务中断。成本监控记录每次调用的 Token 消耗和模型类型并集成到监控系统如 Prometheus中设置成本告警。可观测性确保 LangSmith 或其他追踪系统的配置在生产环境生效便于排查线上问题。会话状态管理如果是有状态的 Agent需要设计会话的存储如 Redis和过期策略。7. 常见问题排查与最佳实践在开发和运维过程中你会遇到一些典型问题。以下是一些快速排查指南和最佳实践。7.1 常见问题排查表问题现象可能原因检查步骤解决方案Agent 不调用工具总是直接回答。1. 工具描述不清晰。2. 提示词未明确指示使用工具。3. LLM 温度参数过高随机性太强。1. 检查工具description是否准确描述了功能和适用场景。2. 检查系统提示词是否列出了工具并鼓励使用。3. 查看 LangSmith 追踪看 LLM 的思考过程。1. 优化工具描述使其更具体。2. 在提示词中强化使用工具的指令例如“你必须使用工具来获取真实数据”。3. 将temperature调低如 0.1。工具调用失败返回解析错误。1. 工具输入参数格式不符合 Pydantic 模型要求。2. LLM 生成的参数无法被正确解析如 JSON 格式错误。1. 查看 LangSmith 中工具调用的raw输入。2. 检查工具args_schema的定义。1. 在工具定义中使用更严格的Field(..., json_schema_extra{})约束。2. 在 Agent 配置中启用handle_parsing_errorsTrue并提供友好的错误回退。响应速度慢。1. 网络延迟高特别是调用海外模型API。2. Agent 陷入思考循环max_iterations过大。3. 工具本身是慢 IO 操作。1. 检查单个请求在 LangSmith 中的总耗时和各步骤耗时。2. 检查intermediate_steps数量是否异常多。1. 考虑使用模型 API 的国内代理或区域端点。2. 合理设置max_iterations通常 3-10 足够。3. 对慢工具进行异步化、缓存或超时处理。生产环境配置不生效。1. 环境变量未正确注入容器。2..env文件被错误打包进镜像。3. 配置类加载顺序有误。1. 在容器内执行 envgrep OPENAI检查环境变量。br2. 检查 Dockerfile 是否复制了.env文件。br3. 检查pydantic-settings的model_config 优先级。内存或 CPU 使用率过高。1. 会话历史未清理导致内存累积。2. 工具或 LLM 调用未设置超时挂起连接占用资源。1. 监控服务的内存增长曲线。2. 检查是否有未结束的异步任务。1. 为ConversationBufferMemory设置max_token_limit或实现基于时间的记忆清理。2. 为所有网络调用LLM、工具设置超时timeout。3. 考虑使用无状态设计将会话存储在外置数据库。7.2 最佳实践清单提示词工程将提示词模板化、版本化与代码一同管理在 Git 中。为不同的任务或场景编写专用的提示词而不是一个巨型提示词走天下。使用少样本示例Few-shot在提示词中提供范例能显著提升模型表现。定期评估和迭代提示词建立提示词版本与模型效果的对应关系。工具设计工具功能应保持单一职责一个工具只做一件事。工具输入应使用强类型Pydantic定义并附带清晰的描述。工具实现必须考虑错误处理和超时避免因单个工具失败导致整个 Agent 挂起。对于耗时长或消耗资源的工具考虑增加缓存层。可观测性必须记录每一次 LLM 调用和工具调用的输入、输出、耗时和 Token 消耗。使用像LangSmith这样的专业平台它提供了链式调用的可视化追踪是调试复杂逻辑的必备工具。将 Agent 的运行指标如请求量、成功率、平均响应时间、Token 成本集成到现有的监控告警体系中。安全与成本永远不要在代码或版本库中硬编码 API Key。为模型 API 设置用量限额和告警防止意外成本。对用户输入进行必要的清洗和校验防止提示词注入攻击。仔细审查工具的能力避免执行危险操作如删除文件、调用未授权 API。测试策略单元测试覆盖所有工具函数和确定性业务逻辑。集成测试使用 Mock 来模拟 LLM 和外部服务验证 Agent 的决策流程。评估Evaluation用于衡量非确定性输出的质量建立自动化评估流水线。混沌测试模拟网络延迟、API 失败等异常情况检验 Agent 的健壮性。从零搭建一套智能体工具链初期看起来增加了不少工作量但它所带来的环境一致性、开发效率、调试便利性和部署可靠性会在项目复杂度提升后得到十倍百倍的回报。这套工具链是一个起点你可以根据项目需求引入更强大的组件如向量数据库用于记忆增强、更复杂的工作流引擎、或分布式多智能体协调框架。核心在于你已经建立了一个坚实、可扩展的工程基础让创新可以安全、高效地发生其上。
返回列表