第二章Agent 开发环境搭建与验证

📅 发布时间:2026/10/13 3:19:08
第二章Agent 开发环境搭建与验证
我们的目标是让开发环境达到能跑通一个最小 Agent的状态安装依赖、配置模型、封装工具、运行调用、保存轨迹、验证行为。同时所有示例代码都尽量补成可直接拷贝运行的版本并在需要特殊配置的地方给出运行方式说明。一、环境搭建前的三个选择在动手之前需要先确定三件事选择项说明建议开发语言目前 Python 生态最成熟初学者优先 Python模型接入决定 Agent 的推理能力先用一个稳定模型跑通框架层级决定后续扩展复杂度先轻量再逐步升级框架层面2026 年的选择已经比较清晰LangChain / LangGraph适合构建工具调用、RAG、多步工作流社区生态成熟。CrewAI适合快速搭建多角色 Agent 原型但复杂状态管理较弱。LlamaIndex Workflows适合知识库、文档检索、合规审查等数据密集型场景。Microsoft Agent Framework适合 .NET / Azure / M365 生态。OpenAI Agents SDK / Claude Agent SDK适合绑定单一模型栈、逻辑相对简单的 Agent。Dify / Coze适合快速验证、低代码搭建但定制能力和数据控制相对受限。对我们来说建议先用Python LangChain跑通最小流程如果要进入生产级复杂工作流再考虑迁移到LangGraph。二、Python 基础环境配置1. Python 版本推荐安装Python 3.10 ~ 3.12。Python 3.10 以上版本对类型提示、异步支持和主流 Agent 框架兼容性更好。安装时注意勾选1Add Python to PATH安装完成后验证1python --version 2pip --version2. 虚拟环境Agent 项目通常会安装较多依赖建议使用虚拟环境隔离避免污染全局 Python。1python -m venv .venv 2 3# Windows PowerShell 4.venv\Scripts\Activate.ps1 5 6# macOS / Linux 7source .venv/bin/activate激活成功后终端前面通常会出现(.venv)。如果 PowerShell 提示无法运行脚本可以先执行1Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned然后再激活环境。3. 虚拟环境工具怎么选工具特点适合场景venvPython 内置轻量新手、脚本、小型项目conda可管理 Python 版本和非 Python 依赖数据科学、机器学习poetry依赖锁定、打包发布能力强团队协作、开源项目uvRust 编写安装和解析速度很快追求效率、CI/CD、大型项目pipenv曾经流行目前新项目不优先推荐维护老项目建议新手入门venv pip数据科学 / 机器学习项目conda团队协作或需要发布包poetry追求安装速度和依赖锁定uv4. pip 镜像源如果下载依赖较慢可以临时使用国内镜像源例如清华源1pip install langchain langchain-openai python-dotenv -i https://pypi.tuna.tsinghua.edu.cn/simple注意选择可信镜像源避免安装来源不明的包。三、开发工具建议1. 代码编辑器 / IDE工具特点适合人群VS Code免费、轻量、插件生态丰富通用首选PyCharmPython 专业 IDE调试能力强大型项目、团队协作JupyterLab交互式编程适合数据探索数据分析、AI 实验CursorAI 深度集成支持跨文件重构追求效率的开发者Trae中文友好基础版免费国内开发者、快速原型Windsurf全局上下文感知强复杂项目重构Qoder适配后端工程化企业级后端开发CodeBuddy前端、小程序、H5 适配较好前端与微信生态开发推荐组合新手 / 通用开发VS Code Python Pylance 中文语言包。大型 Python 项目PyCharm 专业版。AI 辅助开发Cursor、Trae 或 Windsurf。数据探索JupyterLab VS Code。VS Code 必装插件建议PythonPylanceChinese (Simplified) Language PackGitLens可选Jupyter可选2. AI 编程辅助工具AI 编程工具可以分为三类AI 原生 IDECursor、Windsurf、Trae、Qoder、CodeBuddy、Devin Desktop 等。AI 插件GitHub Copilot、Tabnine、通义灵码、Kimi Code、Cline 等。代码安全与审查工具Sourcery、Snyk Code 等。选型建议想要稳定补全 多 IDE 支持GitHub Copilot。想要跨文件理解 Agent 模式Cursor。想要中文友好 免费体验Trae。想要企业级后端工程化Qoder。想要数据隐私优先Tabnine。对 Agent 开发来说AI 编程工具的价值主要在于快速生成工具函数、补全 Pydantic 模型、解释报错信息、生成测试用例以及辅助调试多步调用流程。四、核心依赖安装创建并激活虚拟环境后安装基础依赖1pip install langchain langchain-openai langchain-community python-dotenv如果需要本地模型可以继续安装1pip install langchain-ollama如果需要向量数据库1pip install chromadb辅助库可按需安装1pip install pydantic requests rich tiktoken验证环境1import sys 2import langchain 3 4print(fPython: {sys.version}) 5print(fLangChain: {langchain.__version__})如果正常输出版本号说明基础环境已经就绪。五、模型接入配置Agent 的核心推理能力来自大模型。配置时不要把 API Key 写进代码推荐使用.env文件管理。创建.env1OPENAI_API_KEYyour_api_key_here 2MODEL_NAMEgpt-4o 3MODEL_BASE_URL如果使用的是兼容 OpenAI 接口的模型服务可以填写1OPENAI_API_KEYyour_api_key_here 2MODEL_NAMEqwen-plus 3MODEL_BASE_URLhttps://your-api-endpoint/v1如果MODEL_BASE_URL为空代码会自动使用 OpenAI 默认地址。在代码中加载1from dotenv import load_dotenv 2import os 3 4load_dotenv() 5 6api_key os.getenv(OPENAI_API_KEY) 7model_name os.getenv(MODEL_NAME, gpt-4o) 8base_url os.getenv(MODEL_BASE_URL, ).strip()初始化模型1from langchain_openai import ChatOpenAI 2 3llm_kwargs { 4 model: model_name, 5 temperature: 0.2, 6 api_key: api_key, 7} 8 9if base_url: 10 llm_kwargs[base_url] base_url 11 12llm ChatOpenAI(**llm_kwargs)工具调用场景建议把temperature设低一些例如0到0.2减少随机输出。六、最小 Agent 结构一个最小 Agent 至少需要四部分1用户输入 2 - Prompt 定义角色与目标 3 - LLM 推理 4 - 工具调用 5 - 工具返回结果 6 - LLM 生成最终回答先定义一个简单工具例如天气查询工具1from langchain_core.tools import tool 2 3tool 4def get_weather(city: str) - str: 5 查询指定城市的天气信息。 6 7 参数 8 - city: 城市名称例如郑州北京上海 9 10 if not city: 11 return 缺少城市名称无法查询天气。 12 13 weather_data { 14 郑州: 晴22°C微风, 15 北京: 多云18°C北风2级, 16 上海: 小雨20°C东南风3级, 17 } 18 19 return weather_data.get(city, f未找到 {city} 的天气数据请确认城市名称。)然后创建 Agent1from langchain.agents import create_tool_calling_agent, AgentExecutor 2from langchain_core.prompts import ChatPromptTemplate 3 4tools [get_weather] 5 6prompt ChatPromptTemplate.from_messages([ 7 (system, 你是一个智能助手可以根据用户需求调用工具。), 8 (human, {input}), 9 (placeholder, {agent_scratchpad}), 10]) 11 12agent create_tool_calling_agent(llm, tools, prompt) 13 14agent_executor AgentExecutor( 15 agentagent, 16 toolstools, 17 verboseTrue, 18 max_iterations5, 19 handle_parsing_errorsTrue 20)运行测试1result agent_executor.invoke({input: 郑州今天天气怎么样}) 2print(result)verboseTrue可以打印 Agent 的思考过程、工具调用和返回结果非常适合调试。七、完整可运行脚本agent_demo.py下面把前面的片段整合成一个完整脚本可以直接拷贝运行。1 2Agent 开发环境最小验证脚本 3 4运行方式 51. 创建虚拟环境python -m venv .venv 62. 激活环境 7 - Windows PowerShell: .venv\Scripts\Activate.ps1 8 - macOS / Linux: source .venv/bin/activate 93. 安装依赖pip install langchain langchain-openai python-dotenv 104. 在项目根目录创建 .env 文件写入 OPENAI_API_KEY 115. 运行python agent_demo.py 12 13 14import os 15import json 16import time 17from datetime import datetime 18from dotenv import load_dotenv 19from langchain_openai import ChatOpenAI 20from langchain_core.tools import tool 21from langchain.agents import create_tool_calling_agent, AgentExecutor 22from langchain_core.prompts import ChatPromptTemplate 23 24# ---------------------------- 25# 1. 加载环境变量 26# ---------------------------- 27load_dotenv() 28 29OPENAI_API_KEY os.getenv(OPENAI_API_KEY, ) 30MODEL_NAME os.getenv(MODEL_NAME, gpt-4o) 31MODEL_BASE_URL os.getenv(MODEL_BASE_URL, ).strip() 32 33if not OPENAI_API_KEY: 34 raise RuntimeError( 35 未找到 OPENAI_API_KEY请在项目根目录创建 .env 文件并写入 API Key。 36 ) 37 38# ---------------------------- 39# 2. 初始化模型 40# ---------------------------- 41llm_kwargs { 42 model: MODEL_NAME, 43 temperature: 0.2, 44 api_key: OPENAI_API_KEY, 45} 46 47if MODEL_BASE_URL: 48 llm_kwargs[base_url] MODEL_BASE_URL 49 50llm ChatOpenAI(**llm_kwargs) 51 52# ---------------------------- 53# 3. 定义工具 54# ---------------------------- 55 56tool 57def get_weather(city: str) - str: 58 查询指定城市的天气信息。 59 60 参数 61 - city: 城市名称例如郑州北京上海 62 63 if not city: 64 return 缺少城市名称无法查询天气。 65 66 weather_data { 67 郑州: 晴22°C微风, 68 北京: 多云18°C北风2级, 69 上海: 小雨20°C东南风3级, 70 } 71 72 return weather_data.get(city, f未找到 {city} 的天气数据请确认城市名称。) 73 74 75tool 76def get_current_time(dummy: str ) - str: 77 获取当前日期和时间。 78 79 参数 80 - dummy: 可选占位参数不需要传入实际内容 81 82 now datetime.now() 83 return now.strftime(%Y年%m月%d日 %H:%M:%S) 84 85 86tools [get_weather, get_current_time] 87 88# ---------------------------- 89# 4. 创建 Agent 90# ---------------------------- 91 92prompt ChatPromptTemplate.from_messages( 93 [ 94 (system, 你是一个智能助手可以根据用户需求调用工具。), 95 (human, {input}), 96 (placeholder, {agent_scratchpad}), 97 ] 98) 99 100agent create_tool_calling_agent(llm, tools, prompt) 101 102agent_executor AgentExecutor( 103 agentagent, 104 toolstools, 105 verboseTrue, 106 max_iterations5, 107 handle_parsing_errorsTrue, 108) 109 110# ---------------------------- 111# 5. 运行测试 112# ---------------------------- 113 114test_cases [ 115 {input: 郑州今天天气怎么样}, 116 {input: 现在几点了}, 117 {input: 北京和上海今天的天气分别如何}, 118] 119 120traces [] 121 122for case in test_cases: 123 print(\n * 60) 124 print(f测试输入{case[input]}) 125 print( * 60) 126 127 start_time time.time() 128 result agent_executor.invoke(case) 129 elapsed round(time.time() - start_time, 2) 130 131 trace { 132 input: case[input], 133 output: result.get(output, ), 134 elapsed_seconds: elapsed, 135 timestamp: datetime.now().isoformat(), 136 } 137 138 traces.append(trace) 139 140 print(\n最终回答) 141 print(result.get(output, )) 142 print(f\n耗时{elapsed} 秒) 143 144# ---------------------------- 145# 6. 保存轨迹 146# ---------------------------- 147 148output_dir agent_traces 149os.makedirs(output_dir, exist_okTrue) 150 151output_file os.path.join(output_dir, traces.json) 152 153with open(output_file, w, encodingutf-8) as f: 154 json.dump(traces, f, ensure_asciiFalse, indent2) 155 156print(f\n轨迹已保存到{output_file})运行方式1python agent_demo.py八、轨迹检查脚本check_traces.py这个脚本用于验证 Agent 是否真的产生了输出以及输出是否包含预期信息。1 2Agent 轨迹检查脚本 3 4运行方式 51. 先运行python agent_demo.py 62. 再运行python check_traces.py 7 8 9import json 10import os 11 12TRACE_FILE os.path.join(agent_traces, traces.json) 13 14if not os.path.exists(TRACE_FILE): 15 raise FileNotFoundError( 16 f未找到轨迹文件 {TRACE_FILE}请先运行 agent_demo.py。 17 ) 18 19with open(TRACE_FILE, r, encodingutf-8) as f: 20 traces json.load(f) 21 22print(f共加载 {len(traces)} 条轨迹\n) 23 24for idx, trace in enumerate(traces, start1): 25 input_text trace.get(input, ) 26 output_text trace.get(output, ) 27 elapsed trace.get(elapsed_seconds, 0) 28 29 has_output bool(output_text and output_text.strip()) 30 mentions_weather 天气 in output_text 31 mentions_time 时间 in output_text or 日期 in output_text 32 mentions_uncertainty any( 33 word in output_text 34 for word in [无法确认, 未找到, 请确认, 数据为空] 35 ) 36 37 print(f轨迹 {idx}) 38 print(f输入{input_text}) 39 print(f输出{output_text}) 40 print(f耗时{elapsed} 秒) 41 print(f有输出{has_output}) 42 print(f包含天气信息{mentions_weather}) 43 print(f包含时间信息{mentions_time}) 44 print(f包含不确定性提示{mentions_uncertainty}) 45 print(- * 60)运行方式1python check_traces.py注意当前版本只做文本层面的基础检查。如果需要更严格地验证是否真正调用了某个工具可以在后续版本中接入 LangChain 的回调机制记录完整的工具调用事件。九、工具封装规范工具是 Agent 与现实世界交互的入口。封装工具时要注意几点名称清晰工具名要能表达用途例如get_weather、search_orders、send_email。描述完整docstring或描述字段要写清楚工具用途、参数含义和返回格式。模型会依赖这些信息判断是否调用工具。参数结构化尽量使用明确类型例如str、int、float、list[str]避免让模型猜测参数格式。错误可解释工具失败时应返回可读错误信息而不是直接抛出异常否则 Agent 可能无法继续规划。权限可控删除、修改、发送类工具需要额外增加权限校验不能直接暴露给所有用户。示例1tool 2def search_orders(user_id: str, order_id: str ) - str: 3 查询用户订单信息。 4 5 参数 6 - user_id: 用户ID 7 - order_id: 可选订单ID 8 9 if not user_id: 10 return 缺少用户ID无法查询订单。 11 return f用户 {user_id} 的订单查询成功十、记忆与上下文管理默认情况下Agent 每次调用都是无状态的。要实现多轮对话需要显式配置记忆。最简单的方式是使用对话历史1from langchain.memory import ConversationBufferMemory 2 3memory ConversationBufferMemory( 4 memory_keychat_history, 5 return_messagesTrue 6)如果对话很长可以使用摘要记忆避免上下文无限增长1from langchain.memory import ConversationSummaryMemory 2 3memory ConversationSummaryMemory( 4 llmllm, 5 memory_keychat_history, 6 return_messagesTrue 7)企业级场景中还可以把历史对话存入数据库或向量库实现长期记忆。需要注意记忆不是越多越好。过长的上下文会增加成本也可能引入噪声。生产环境通常需要设置最大轮数、摘要压缩或会话过期策略。十一、Agent 验证方法Agent 验证和普通接口测试不同。普通接口测试主要看返回结果是否正确但 Agent 还需要看过程是否可靠。一个看似正确的回答可能来自以下问题工具根本没有被调用工具参数传错了工具返回为空但模型编造了数据Agent 跳过了必要的校验步骤多轮对话后记忆出现偏差。所以我们验证 Agent 时至少要看三层层级验证内容典型问题工具层是否调用正确工具、参数是否正确参数错误、工具未调用轨迹层是否基于真实返回继续推理忽略失败、跳步、编造结果层最终回答是否满足任务遗漏条件、表达不准确十二、最小验证流程我们可以采用一个简化版的六步验证流程Plan定义任务目标明确 Agent 必须完成哪些动作。例如必须调用天气工具、必须引用真实数据、工具为空时必须提示无法确认。Data准备测试数据包括正常返回、空返回、错误返回、边界数据。Trace保存执行轨迹记录工具调用名称、参数、返回结果、模型思考过程。Run多次运行Agent 具有非确定性同一个输入可能产生不同路径。关键场景至少运行多次。Eval自动断言 人工评审可用代码检查工具名、参数、字段是否存在对开放式回答再用 LLM 做质量评审。Report定位问题报告不能只给分数要指出哪条用例失败、哪次工具调用异常、哪个参数错误。十三、一个简单轨迹检查示例这里把最小轨迹检查函数补全1def evaluate_trace(case, trace): 2 tool_calls trace.get(tool_calls, []) 3 final_text trace.get(output, ) 4 tool_results trace.get(tool_results, []) 5 6 expected_tool case[expected_tool] 7 expected_args case.get(expected_arguments, {}) 8 9 actual next((c for c in tool_calls if c[name] expected_tool), None) 10 11 tool_called actual is not None 12 params_ok tool_called and all( 13 actual[arguments].get(k) v for k, v in expected_args.items() 14 ) 15 16 has_data any(r for r in tool_results if r and str(r).strip()) 17 mentions_uncertainty any( 18 word in final_text 19 for word in [无法确认, 未找到, 请确认, 数据为空] 20 ) 21 22 if not tool_called: 23 return FAIL: 未调用预期工具 24 25 if not params_ok: 26 return FAIL: 工具参数不正确 27 28 if not has_data and not mentions_uncertainty: 29 return FAIL: 工具无数据但模型未提示不确定性 30 31 return PASS这个函数适合作为“轨迹检查”的入门示例。它不依赖特定框架我们可以先把 Agent 运行结果保存成统一格式再用这个函数做基础断言。十四、测试用例示例我们可以准备一组最小测试用例用来覆盖正常路径和异常路径1test_cases [ 2 { 3 name: 正常天气查询, 4 input: 郑州今天天气怎么样, 5 expected_tool: get_weather, 6 expected_arguments: {city: 郑州}, 7 }, 8 { 9 name: 未知城市天气, 10 input: 火星今天天气如何, 11 expected_tool: get_weather, 12 expected_arguments: {city: 火星}, 13 }, 14 { 15 name: 时间查询, 16 input: 现在几点了, 17 expected_tool: get_current_time, 18 expected_arguments: {}, 19 }, 20]运行检查时可以这样组织1results [] 2 3for case in test_cases: 4 trace run_agent(case[input]) 5 status evaluate_trace(case, trace) 6 results.append({case: case[name], status: status}) 7 8for r in results: 9 print(r[case], -, r[status])这里的run_agent需要根据实际使用的框架替换成真实调用。针对本章agent_demo.py中的 LangChain Agent我们可以这样写1def run_agent(user_input: str) - dict: 2 执行一次 Agent 调用并返回结构化轨迹。 3 4 result agent_executor.invoke({input: user_input}) 5 6 intermediate_steps result.get(intermediate_steps, []) 7 8 tool_calls [] 9 tool_results [] 10 11 for step in intermediate_steps: 12 if isinstance(step, (list, tuple)) and len(step) 2: 13 action step[0] 14 output step[1] 15 16 tool_calls.append({ 17 name: getattr(action, tool, None), 18 arguments: getattr(action, tool_input, None), 19 }) 20 tool_results.append(str(output)) 21 22 return { 23 input: user_input, 24 output: result.get(output, ), 25 tool_calls: tool_calls, 26 tool_results: tool_results, 27 intermediate_steps: intermediate_steps, 28 }需要注意的是intermediate_steps的具体结构会随 LangChain 版本变化。如果后续发现step[0]不是预期的 action 对象我们可以把run_agent改成只依赖result.get(output)做基础验证再逐步接入回调机制来记录完整工具调用事件。十五、完整验证脚本verify_agent.py把run_agent、evaluate_trace和测试用例整合到一个可直接运行的脚本中1 2Agent 轨迹验证脚本 3 4运行方式 51. 先运行python agent_demo.py 62. 再运行python verify_agent.py 7 8 9import os 10import json 11from dotenv import load_dotenv 12from langchain_openai import ChatOpenAI 13from langchain_core.tools import tool 14from langchain.agents import create_tool_calling_agent, AgentExecutor 15from langchain_core.prompts import ChatPromptTemplate 16 17# ---------------------------- 18# 1. 加载环境变量 19# ---------------------------- 20load_dotenv() 21 22OPENAI_API_KEY os.getenv(OPENAI_API_KEY, ) 23MODEL_NAME os.getenv(MODEL_NAME, gpt-4o) 24MODEL_BASE_URL os.getenv(MODEL_BASE_URL, ).strip() 25 26if not OPENAI_API_KEY: 27 raise RuntimeError( 28 未找到 OPENAI_API_KEY请在项目根目录创建 .env 文件并写入 API Key。 29 ) 30 31# ---------------------------- 32# 2. 初始化模型 33# ---------------------------- 34llm_kwargs { 35 model: MODEL_NAME, 36 temperature: 0.2, 37 api_key: OPENAI_API_KEY, 38} 39 40if MODEL_BASE_URL: 41 llm_kwargs[base_url] MODEL_BASE_URL 42 43llm ChatOpenAI(**llm_kwargs) 44 45# ---------------------------- 46# 3. 定义工具 47# ---------------------------- 48 49tool 50def get_weather(city: str) - str: 51 查询指定城市的天气信息。 52 53 参数 54 - city: 城市名称例如郑州北京上海 55 56 if not city: 57 return 缺少城市名称无法查询天气。 58 59 weather_data { 60 郑州: 晴22°C微风, 61 北京: 多云18°C北风2级, 62 上海: 小雨20°C东南风3级, 63 } 64 65 return weather_data.get(city, f未找到 {city} 的天气数据请确认城市名称。) 66 67 68tool 69def get_current_time(dummy: str ) - str: 70 获取当前日期和时间。 71 72 参数 73 - dummy: 可选占位参数不需要传入实际内容 74 75 from datetime import datetime 76 now datetime.now() 77 return now.strftime(%Y年%m月%d日 %H:%M:%S) 78 79 80tools [get_weather, get_current_time] 81 82# ---------------------------- 83# 4. 创建 Agent 84# ---------------------------- 85 86prompt ChatPromptTemplate.from_messages( 87 [ 88 (system, 你是一个智能助手可以根据用户需求调用工具。), 89 (human, {input}), 90 (placeholder, {agent_scratchpad}), 91 ] 92) 93 94agent create_tool_calling_agent(llm, tools, prompt) 95 96agent_executor AgentExecutor( 97 agentagent, 98 toolstools, 99 verboseFalse, 100 max_iterations5, 101 handle_parsing_errorsTrue, 102) 103 104# ---------------------------- 105# 5. 封装 run_agent 106# ---------------------------- 107 108def run_agent(user_input: str) - dict: 109 执行一次 Agent 调用并返回结构化轨迹。 110 111 result agent_executor.invoke({input: user_input}) 112 113 intermediate_steps result.get(intermediate_steps, []) 114 115 tool_calls [] 116 tool_results [] 117 118 for step in intermediate_steps: 119 if isinstance(step, (list, tuple)) and len(step) 2: 120 action step[0] 121 output step[1] 122 123 tool_calls.append({ 124 name: getattr(action, tool, None), 125 arguments: getattr(action, tool_input, None), 126 }) 127 tool_results.append(str(output)) 128 129 return { 130 input: user_input, 131 output: result.get(output, ), 132 tool_calls: tool_calls, 133 tool_results: tool_results, 134 intermediate_steps: intermediate_steps, 135 } 136 137# ---------------------------- 138# 6. 封装 evaluate_trace 139# ---------------------------- 140 141def evaluate_trace(case, trace): 142 对一次 Agent 调用轨迹做基础断言。 143 144 tool_calls trace.get(tool_calls, []) 145 final_text trace.get(output, ) 146 tool_results trace.get(tool_results, []) 147 148 expected_tool case[expected_tool] 149 expected_args case.get(expected_arguments, {}) 150 151 actual next((c for c in tool_calls if c[name] expected_tool), None) 152 153 tool_called actual is not None 154 params_ok tool_called and all( 155 actual[arguments].get(k) v for k, v in expected_args.items() 156 ) 157 158 has_data any(r for r in tool_results if r and str(r).strip()) 159 mentions_uncertainty any( 160 word in final_text 161 for word in [无法确认, 未找到, 请确认, 数据为空] 162 ) 163 164 if not tool_called: 165 return FAIL: 未调用预期工具 166 167 if not params_ok: 168 return FAIL: 工具参数不正确 169 170 if not has_data and not mentions_uncertainty: 171 return FAIL: 工具无数据但模型未提示不确定性 172 173 return PASS 174 175# ---------------------------- 176# 7. 测试用例 177# ---------------------------- 178 179test_cases [ 180 { 181 name: 正常天气查询, 182 input: 郑州今天天气怎么样, 183 expected_tool: get_weather, 184 expected_arguments: {city: 郑州}, 185 }, 186 { 187 name: 未知城市天气, 188 input: 火星今天天气如何, 189 expected_tool: get_weather, 190 expected_arguments: {city: 火星}, 191 }, 192 { 193 name: 时间查询, 194 input: 现在几点了, 195 expected_tool: get_current_time, 196 expected_arguments: {}, 197 }, 198] 199 200# ---------------------------- 201# 8. 运行验证 202# ---------------------------- 203 204print(开始 Agent 轨迹验证...\n) 205 206results [] 207 208for case in test_cases: 209 print(f运行用例{case[name]}) 210 print(f 输入{case[input]}) 211 212 trace run_agent(case[input]) 213 status evaluate_trace(case, trace) 214 215 results.append({case: case[name], status: status}) 216 217 print(f 状态{status}) 218 print(f 输出{trace[output][:100]}...) 219 print() 220 221# ---------------------------- 222# 9. 汇总结果 223# ---------------------------- 224 225print( * 60) 226print(验证结果汇总) 227print( * 60) 228 229for r in results: 230 print(f{r[case]} - {r[status]}) 231 232pass_count sum(1 for r in results if r[status] PASS) 233fail_count sum(1 for r in results if r[status] ! PASS) 234 235print(f\n总计{len(results)} 条用例{pass_count} 通过{fail_count} 失败) 236 237# ---------------------------- 238# 10. 保存验证报告 239# ---------------------------- 240 241output_dir agent_traces 242os.makedirs(output_dir, exist_okTrue) 243 244report_file os.path.join(output_dir, verify_report.json) 245 246with open(report_file, w, encodingutf-8) as f: 247 json.dump(results, f, ensure_asciiFalse, indent2) 248 249print(f\n验证报告已保存到{report_file})运行方式1python verify_agent.py十六、常见运行问题排查问题可能原因处理方式OPENAI_API_KEY缺失未创建.env或文件路径错误确认.env与脚本同目录模型调用失败API Key 无效或余额不足检查 Key、额度、服务状态工具未被调用工具描述不清晰完善docstring和参数说明返回空结果工具返回为空且模型未兜底增加不确定性提示逻辑依赖安装失败网络或镜像源问题使用可信国内镜像源虚拟环境未激活依赖装到全局环境重新激活.venv后运行中文输出乱码终端编码不一致使用 UTF-8 终端或 IDE 运行多轮对话丢失上下文未配置记忆启用对话历史或摘要记忆十七、本章可直接交付的脚本清单本章完成后我们应拥有以下文件1project/ 2├── .env 3├── agent_demo.py 4├── verify_agent.py 5├── check_traces.py 6└── agent_traces/ 7 ├── traces.json 8 └── verify_report.json运行顺序为1python agent_demo.py 2python verify_agent.py 3python check_traces.py如果后续要扩展我们可以把agent_demo.py拆成1project/ 2├── .env 3├── main.py 4├── tools/ 5│ └── weather.py 6├── agent/ 7│ └── executor.py 8├── traces/ 9│ └── traces.json 10└── tests/ 11 └── test_traces.py但教程初期不建议拆得太散。我们先用一个文件跑通完整流程更容易建立信心。十八、本章小结这一章我们完成了 Agent 开发环境的闭环选择了Python LangChain作为入门栈配置了虚拟环境、依赖和模型接入封装了可运行的天气查询和时间查询工具创建了一个最小 Agent并支持多轮测试保存了运行轨迹便于后续调试提供了run_agent封装、evaluate_trace断言和测试用例提供了轨迹检查脚本、验证脚本和常见问题排查表。到这里我们已经可以独立运行一个最小 Agent并初步理解输入—推理—工具调用—返回—轨迹—验证的基本链路。