【智能体工具使用实战03】环境准备与最小Agent跑通
第3章 环境准备与最小Agent跑通
本章你将学到:
- 配置DeepSeek API Key,让你的Agent拥有调用大模型的能力
- 用Trae生成一个带
read_file工具的Agent脚本- 理解工具定义、工具调用循环、异常处理在完整脚本中的位置
- 首次运行Agent,让它真正读取你硬盘上的文件
本章你将产出:一个能读取CSV文件并描述其内容的Agent脚本
agent.py,以及成功运行后的一份终端日志
全部章节:收录在专栏《AI应用工程化实战教程》之【智能体工具使用实战】
3.1 DeepSeek API Key获取与配置
在第2章,你已经手写过 minimal_agent.py,在那里面你已经在 .env 文件中配置了DeepSeek的API Key。如果你已经完成了那一步,可以跳过3.1.1和3.1.2,直接进入3.1.3确认配置正确。
3.1.1 注册DeepSeek开放平台
打开浏览器,访问 platform.deepseek.com。
点击“注册”,使用手机号或邮箱完成注册。
注册完成后,进入控制台,在左侧菜单找到“API Keys”或“API密钥”页面。点击“创建API Key”,给密钥起个名字(比如 data-analyst-agent),然后复制生成的密钥。
密钥格式:通常以 sk- 开头,后面跟着一串字符。这个密钥只显示一次,请立即保存。
3.1.2 在项目中配置环境变量
打开你的 data-analyst-agent 项目文件夹。如果你还没有创建 .env 文件,现在创建一个。
在Trae的文件树中,右键项目根目录 → 新建文件 → 命名为 .env。
在 .env 文件中写入:
DEEPSEEK_API_KEY=sk-你的密钥
注意:sk-你的密钥 替换成你刚才复制的那一整串。等号两边不要有空格。
确认 .gitignore 已包含 .env。打开项目根目录下的 .gitignore 文件,确认其中有这一行:
.env
如果没有,加上。这是你在第一部第3章养成的习惯——绝不把API密钥提交到Git仓库。
3.1.3 安装依赖
在Trae底部打开终端,确认当前在 data-analyst-agent 目录下,执行:
pip install openai python-dotenv
如果你在第2章已经装过,可以跳过。
3.1.4 验证配置
创建一个临时测试脚本验证配置是否正确。在Trae终端中运行:
python -c "
import os
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI(
api_key=os.getenv('DEEPSEEK_API_KEY'),
base_url='https://api.deepseek.com'
)
response = client.chat.completions.create(
model='deepseek-chat',
messages=[{'role': 'user', 'content': '回复“配置成功”'}]
)
print(response.choices[0].message.content)
"
如果终端打印出“配置成功”(或类似的确认回复),说明DeepSeek API Key配置正确。
如果报 AuthenticationError 或 401 错误,检查:
.env文件中的密钥是否复制完整(没有多余空格).env文件是否在项目根目录- 密钥是否还在有效期内
3.2 一个重要的再次确认:谁在用哪个模型
在正式开始之前,回顾一下前言中提到的一个重要区分。
现在你的开发环境里涉及两种AI调用:
| Trae内置AI | 你的Agent调用的AI | |
|---|---|---|
| 谁在用 | 你(开发者),在Trae中写代码时 | 你写的 agent.py,在运行时 |
| 干什么 | 帮你生成代码、回答开发问题 | 执行数据分析任务、决定调用哪个工具 |
| 模型 | Trae自动选择,你不需要管 | DeepSeek(你在 .env 中配置的) |
| API Key | Trae自带 | 你刚才在 .env 中配置的 |
你在Trae的AI对话面板里输入指令时,是Trae内置AI在帮你干活——它生成 agent.py 的代码。而当 agent.py 运行起来、需要分析数据时,是DeepSeek在干活——它决定“该调用哪个工具”,生成分析结论。
Trae帮你写代码,DeepSeek帮你写的Agent完成任务。 别搞混。
3.3 用Trae生成第一个带工具的Agent脚本
环境就绪,现在用Trae帮你生成一个带 read_file 工具的Agent。
3.3.1 设计给Trae的指令
在Trae的AI对话面板中,输入以下指令:
在项目 data-analyst-agent 中,请帮我创建一个 agent.py 脚本。
这个脚本是一个带工具调用能力的Agent。要求:
## 模型配置
- 使用 openai 库调用 DeepSeek API
- 从 .env 读取 DEEPSEEK_API_KEY
- base_url 为 https://api.deepseek.com
- model 为 deepseek-v4-flash
## 系统提示词
- 角色:你是一个数据分析助手。你可以使用工具来读取文件、分析数据。
- 行为:当用户让你分析某个文件时,先使用 read_file 工具读取文件内容,再给出分析。
## 工具:read_file
- 功能:读取指定路径的文件内容
- 参数:
- path(必填):文件路径,字符串
- encoding(可选):编码,默认 "utf-8"
- 返回:文件内容的字符串。如果文件不存在或读取失败,返回错误信息字符串。
## 工具调用循环
- 实现完整的 Function Calling 循环
- 最多循环10次
- 每次调用后在终端打印工具名和参数
- 如果没有 tool_calls,打印模型回答并结束
## 核心函数
- 函数签名:run_agent(user_query: str) -> str
- 返回模型的最终回答
## 脚本底部测试
- 测试:用户请求为 "请读取 scores.csv 文件,告诉我这份数据的基本情况"
- 确保 scores.csv 存在(如果不存在,先生成一个包含学号、姓名、高数、线代、Python、英语列及10行模拟数据的文件)
## 代码风格
- 清晰注释
- 关键步骤用 print 输出日志
3.3.2 审查Trae生成的代码
Trae生成代码后,不要立刻运行。打开 agent.py,对照以下检查清单审查:
模型配置检查:
-
OpenAI客户端的api_key是否从环境变量读取? -
base_url是否指向https://api.deepseek.com? -
model是否为deepseek-v4-flash?
工具定义检查:
-
read_file工具的type是否为"function"? -
description是否清晰描述了工具的用途和限制? -
parameters中path是否为必填? -
encoding参数是否有默认值?
工具实现检查:
-
read_file函数是否用try...except包裹了文件操作? - 文件不存在时,是否返回了清晰的错误信息(而不是让程序崩溃)?
- 编码错误时,是否有处理逻辑?
工具调用循环检查:
- 是否有循环(
for turn in range(10))? - 每次循环是否调用了
client.chat.completions.create? - 是否检查了
msg.tool_calls是否为空? - 处理 tool_calls 时,是否正确解析了
function.name和function.arguments? - 工具执行结果是否以
role: "tool"追加到了messages? - 是否保留了
tool_call_id?
测试入口检查:
-
if __name__ == "__main__":是否调用了run_agent? - 测试的用户请求是否合理?
- 是否确保测试文件存在?
如果发现任何问题,在Trae对话面板中直接指出,要求修正。例如:
agent.py 中 read_file 函数在文件不存在时没有返回错误信息,而是抛出了异常。请改为返回字符串 "错误:文件 [路径] 不存在"。
3.4 首次运行:让Agent读取一个真实的CSV文件
3.4.1 准备测试数据
在项目目录下创建 scores.csv。你可以在Trae中新建文件,复制以下内容:
学号,姓名,高数,线代,Python,英语
2024001,张三,78,82,90,75
2024002,李四,55,68,72,80
2024003,王五,92,88,95,91
2024004,赵六,61,59,70,68
2024005,孙七,43,55,60,72
2024006,周八,88,90,85,93
2024007,吴九,72,71,68,70
2024008,郑十,95,89,92,88
2024009,陈一,60,61,58,65
2024010,林二,77,80,82,79
或者让Trae帮你生成:在对话面板中输入“请在项目根目录创建一个 scores.csv,包含10行模拟学生成绩数据”。
3.4.2 运行Agent
在Trae终端中执行:
python agent.py
观察终端输出。你应该看到类似以下的日志:
============================================================
用户: 请读取 scores.csv 文件,告诉我这份数据的基本情况
============================================================
--- 第 1 轮调用模型 ---
模型要求调用 1 个工具
→ 调用工具: read_file({'path': 'scores.csv'})
→ 工具返回: 学号,姓名,高数,线代,Python,英语
2024001,张三,78,82,90,75
2024002,李四,55,68,72,80
...
--- 第 2 轮调用模型 ---
模型回答: 这份数据是10名学生的期末考试成绩表,包含以下信息:
- 共有4门课程:高数、线代、Python程序设计、大学英语
- 10名学生中...
- 各科成绩分布情况...
如果你看到这样的日志,恭喜你——你的Agent第一次真正“看到了”你硬盘上的文件。
注意第1轮和第2轮的区别:
- 第1轮:Agent判断“我需要先读到文件内容”,于是它返回了
tool_calls,调用了read_file。是Python的open()函数真正打开了文件,不是AI在“猜测”文件内容。 - 第2轮:Agent拿到了真实的文件内容,基于这些内容生成了分析。
这和你在第1章的经历完全不同。第1章的Agent只能泛泛地说“你可以用pandas读取”,现在它真正读了。
3.4.3 如果运行出错
报错:FileNotFoundError 或 “错误:文件不存在”
→ scores.csv 可能不在项目根目录。确认文件位置,或者使用绝对路径测试。
报错:AuthenticationError
→ .env 中的 DEEPSEEK_API_KEY 配置有误。重新检查3.1.4节。
Agent反复调用同一个工具,陷入死循环
→ 模型的判断出了问题,或者工具返回的内容没有被正确解析。检查 role: "tool" 的那条消息是否正确追加到了 messages。
Agent没有调用工具,直接回答“我无法读取文件”
→ 检查工具定义是否在调用API时正确传入(tools 参数)。检查 read_file 的 description 是否清晰说明“这个工具可以读取本地文件”。
3.5 理解你的Agent脚本结构
现在花五分钟,重新打开 agent.py,理解它的完整结构。这个结构会成为你后续所有工具增强型Agent的基础模板。
agent.py
│
├── 1. 导入与初始化
│ ├── import os, json
│ ├── from dotenv import load_dotenv
│ ├── from openai import OpenAI
│ └── client = OpenAI(api_key=..., base_url=...)
│
├── 2. 工具定义(给AI看的描述)
│ └── tools = [read_file_tool, ...]
│ 每个工具: {"type": "function", "function": {"name": ..., "description": ..., "parameters": ...}}
│
├── 3. 工具实现(给代码执行的函数)
│ └── def read_file(path, encoding="utf-8"):
│ 实际的文件读取逻辑 + 异常处理
│
├── 4. 工具映射表
│ └── TOOL_MAP = {"read_file": read_file, ...}
│
├── 5. 工具调用循环
│ └── def run_agent(user_query):
│ ├── messages = [system_prompt, user_query]
│ └── for turn in range(10):
│ ├── response = client.chat.completions.create(messages, tools)
│ ├── if no tool_calls → break, return content
│ └── if tool_calls → execute, append result, continue
│
├── 6. 测试入口
│ └── if __name__ == "__main__":
│ run_agent("测试请求")
这个结构的核心设计原则是分离关注点:
- 工具定义和工具实现分离——前者是写给AI看的界面说明,后者是真正的业务代码。改工具描述不会影响工具实现,改工具实现不会影响AI对工具的理解(只要接口不变)。
- 工具调用循环和具体工具分离——循环只负责“调API→解析tool_calls→执行工具→追加结果”,它不关心具体工具的细节。新增一个工具,只需要在工具列表和TOOL_MAP里各加一项,循环不用改。
- 运行逻辑和测试分离——
run_agent是核心函数,可以在任何地方被调用。底部的if __name__ == "__main__"只用于本地测试。
3.6 本章小结
- DeepSeek API Key配置三步走:注册 → 创建Key → 写入
.env文件。 - Trae帮你写Agent代码:你给出清晰的指令(模型配置、工具定义、循环逻辑、测试需求),Trae生成完整脚本。你审查、修改、运行。
- Agent首次读取了真实文件:不是AI“想象”文件内容,是Python的
open()真正打开了scores.csv。你亲眼看到终端日志里read_file的调用和返回。 - Agent脚本的标准结构:六个模块(初始化、工具定义、工具实现、工具映射、调用循环、测试入口),关注点分离,易于扩展。
- 再次确认:Trae帮你生成
agent.py,DeepSeek帮你写的Agent分析数据。两个模型各干各的。
现在你的Agent只有一个工具——read_file。它能读文件,但还不能执行计算。下一章,我们将解决一个必须面对的问题:当Agent需要执行Python代码时,如何确保它生成的代码不会损害你的电脑?我们将设计一个执行沙盒,并为Agent添加第二个工具——execute_python。
课后练习
- 修改
agent.py中read_file工具的描述,把“读取文件内容”改成“读取本地图片文件”。然后用之前一样的请求(读取scores.csv)重新运行。Agent的行为会有什么变化?它还会调用read_file吗? - 在
scores.csv中增加一列“物理”成绩(随便填10个分数)。重新运行Agent。观察Agent能否自动识别新增的列并纳入分析? - 尝试让Agent读取一个不存在的文件(比如把测试请求中的
scores.csv改成nonexistent.csv)。Agent的处理方式是什么?它在第几轮发现了问题?错误信息清晰吗? - (预备思考)在
agent.py中,如果Agent调用read_file后拿到了一万行数据,直接全部塞进对话历史会发生什么?这引出了工具增强型Agent的一个重要工程挑战——上下文窗口管理。你能想到什么解决方案?记下你的想法,我们将在后续章节讨论。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)