AI Agent工程化实战:从ReAct模式到工具调用,构建自动化日报生成器
最近几天,AI圈子里一个看似“平平无奇”的新闻,却让不少技术人和产品经理心里咯噔了一下。一个名为“科技日报生成器”的AI项目,或者更准确地说,一个AI Agent,在GitHub上火了起来。它的功能很简单:你只需要告诉它“生成一份今天的科技日报”,它就能自动抓取、分析、整合信息,最终输出一份结构清晰、内容丰富的日报。
这听起来不就是个RSS订阅器加个文本生成模型吗?有什么好大惊小怪的?
恰恰是这种“简单”,暴露了当前AI应用开发的一个核心困境: 我们手握GPT-4、Claude、DeepSeek等强大的大语言模型,但如何让它们稳定、可靠、自动化地完成一个哪怕是最简单的多步骤任务,依然需要开发者投入巨大的精力去“调教”。这个“科技日报生成器”项目,就是一个绝佳的观察样本。它表面上在解决信息聚合的问题,实际上,它完整地演示了一个AI Agent从“想法”到“落地”的全过程,其中涉及的 任务拆解、工具调用、流程编排、错误处理 ,正是所有想用AI做点实事的开发者必须跨过的坎。
如果你也尝试过用API写个自动周报机器人,结果发现它要么漏信息、要么格式乱、要么干脆“胡言乱语”,那么这篇文章就是为你写的。我们将彻底拆解这个“日报生成器”背后的技术逻辑,手把手还原一个可运行的AI Agent构建流程。你会发现, 真正的价值不在于那个日报本身,而在于构建这个自动化流程的“脚手架”和“方法论” 。
1. 这篇文章真正要解决的问题:从“玩具”到“工具”的Agent实践鸿沟
当前,关于AI Agent的讨论存在一个明显的断层。一边是媒体和厂商描绘的“全能数字员工”宏大叙事,另一边是开发者面对API时“连个稳定格式都输出不了”的骨感现实。这个鸿沟导致了两种现象:
- 概念热,落地冷 :人人都说Agent是未来,但除了聊天对话和简单文案生成,鲜有看到能在生产环境自动运行、创造稳定价值的案例。
- 教程多,实战少 :网上充斥着“用LangChain快速搭建Agent”的教程,但大多停留在调用一两个搜索工具的层面,一旦涉及复杂逻辑、状态维护和异常处理,教程就戛然而止。
“科技日报生成器”这个项目,恰好卡在一个非常有意思的位置:它的目标明确(生成日报),流程复杂(需串联多个步骤),结果可评估(内容是否全面、格式是否规范)。通过拆解它,我们可以回答几个核心问题:
- 一个实用的AI Agent,其内部工作流究竟该如何设计? 是让模型自由发挥,还是用严格的程序逻辑来约束?
- 如何让大语言模型(LLM)稳定地调用外部工具(如搜索、爬虫)? 工具调用的指令如何设计?结果如何解析?
- 任务失败或结果不理想时,如何设计重试、降级或人工干预机制?
- 最终产出的结构化数据(日报),如何保证其一致性和可用性?
本文将聚焦于 工程化实现 。我们不空谈架构,而是以一个可运行的项目为蓝本,带你走通从环境搭建、核心逻辑编码、工具集成到最终部署测试的完整路径。你将获得一套可以直接复用或修改的Agent构建框架。
2. 基础概念与核心原理:Agent、Planning与Tool Calling
在深入代码之前,我们需要统一几个关键概念的理解,这能帮助你看清项目每一步的设计意图。
2.1 AI Agent 是什么?
你可以把一个AI Agent理解为一个 具备自主规划、执行和反思能力的智能程序 。它与普通调用AI API的程序最大区别在于“自主性”。
- 普通程序 :
输入 -> 调用AI API -> 输出。流程固定,AI仅作为内容生成器。 - AI Agent :
接收目标 -> 自主规划步骤 -> 选择并调用工具 -> 评估结果 -> 调整计划 -> 直至完成目标。AI是决策核心。
在这个“日报生成器”里,Agent的目标是“生成一份高质量的科技日报”。它需要自己决定:先搜哪些关键词、去哪里搜、如何筛选信息、按什么结构组织、用什么语气撰写。
2.2 Planning(规划)与 ReAct 模式
Agent如何“自主规划”?目前最主流的范式是 ReAct (Reasoning + Acting) 。
- Reasoning (思考) :分析当前状态和目标,决定下一步该做什么。
- Acting (执行) :根据思考结果,执行一个具体动作,通常是调用一个工具(Tool)。
- 然后观察工具执行的结果,进入下一轮“思考-执行”循环。
例如,生成日报的ReAct循环可能是:
- 思考 :“要生成科技日报,我需要先获取最新的科技新闻。我应该使用搜索工具。”
- 执行 :调用
网络搜索工具,关键词为“今日 科技 重大突破 AI”。 - 观察 :获得10条搜索结果。
- 思考 :“这些结果太多,我需要筛选出最重要的3-5条,并获取详细信息。我应该调用‘内容提取工具’来分析每条结果的链接。”
- 执行 :对筛选出的链接,依次调用
内容提取工具。 - 观察 :获得每条新闻的详细内容。
- 思考 :“信息已收集完毕,现在需要按照‘要闻-深度-观点’的结构撰写日报。我应该调用‘文本合成工具’。”
- 执行 :调用
文本合成工具,输入所有收集到的信息,要求按模板生成日报。
2.3 Tool Calling(工具调用)
这是Agent与外界交互的核心能力。工具可以是:
- 搜索工具 :从搜索引擎或特定网站获取信息。
- 数据查询工具 :从数据库或API获取数据。
- 代码执行工具 :执行一段计算或处理。
- 内容提取工具 :从网页中提取正文。
- 文件操作工具 :读写本地文件。
大语言模型本身并不具备这些能力。因此,我们需要:
- 将工具的功能描述(名称、描述、参数格式)告诉LLM。
- 当LLM决定调用某个工具时,它会输出一个结构化的调用请求(如JSON)。
- 我们的程序解析这个请求,真正执行对应的工具函数。
- 将工具执行的结果(文本或数据)返回给LLM,供其下一步思考使用。
整个“科技日报生成器”的本质,就是搭建一个能流畅运行ReAct循环、并可靠管理工具调用的系统。
3. 环境准备与前置条件
我们将使用Python作为开发语言,这是构建AI Agent生态最成熟的选择。以下环境是项目运行的基础。
3.1 基础环境
- 操作系统 :macOS / Linux (推荐) 或 Windows (WSL2环境下)。
- Python版本 :>= 3.9。建议使用3.10或3.11以获得最佳兼容性。
- 包管理工具 :
pip。强烈建议使用虚拟环境(venv或conda)隔离项目依赖。
3.2 核心依赖库
我们将基于 LangChain 和 OpenAI API 来构建,因为它们的生态最完善,文档最清晰。你也可以替换为其他LLM提供商(如Anthropic Claude、DeepSeek等)。
创建一个 requirements.txt 文件,内容如下:
# 核心框架
langchain>=0.1.0
langchain-openai>=0.0.5
langchain-community>=0.0.10 # 包含许多社区工具
# OpenAI SDK (如果你使用GPT系列模型)
openai>=1.0.0
# 用于网页内容提取
beautifulsoup4>=4.12.0
requests>=2.31.0
playwright>=1.40.0 # 用于需要JS渲染的网页
# 用于搜索(我们使用DuckDuckGo作为示例,无需API Key)
duckduckgo-search>=5.0.0
# 用于结构化输出(确保日报格式规范)
pydantic>=2.0.0
# 环境变量管理
python-dotenv>=1.0.0
# 异步支持(可选,但推荐用于IO密集型任务)
asyncio
aiohttp>=3.9.0
在项目根目录下,使用以下命令安装依赖:
# 创建并激活虚拟环境(以venv为例)
python -m venv .venv
# macOS/Linux
source .venv/bin/activate
# Windows
# .venv\Scripts\activate
# 安装依赖
pip install -r requirements.txt
# 安装Playwright浏览器(用于网页抓取)
playwright install chromium
3.3 获取并配置API密钥
本项目需要一个大语言模型作为“大脑”。我们以OpenAI GPT-4为例。
-
访问 OpenAI平台 ,注册并获取API Key。
-
在项目根目录创建
.env文件,用于安全存储密钥:# .env 文件 OPENAI_API_KEY=你的sk-xxx密钥 # 可选:如果你使用其他模型或需要设置代理 # OPENAI_API_BASE=https://api.openai.com/v1 # HTTP_PROXY=http://your-proxy:port # HTTPS_PROXY=http://your-proxy:port重要 :确保
.env文件已被添加到.gitignore中,切勿提交到代码仓库。 -
在代码中加载环境变量:
# config.py import os from dotenv import load_dotenv load_dotenv() # 加载 .env 文件中的变量 OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") if not OPENAI_API_KEY: raise ValueError("请在 .env 文件中设置 OPENAI_API_KEY")
4. 核心流程拆解:Agent如何“思考”与“行动”
现在,我们来构建“科技日报生成器”Agent的核心逻辑。整个过程可以分解为以下六个关键步骤,下图清晰地展示了其工作流与决策循环:
flowchart TD
A[用户输入目标<br>“生成科技日报”] --> B[初始化Agent<br>加载工具与LLM]
B --> C{启动ReAct循环}
C --> D[LLM思考<br>分析现状,规划下一步]
D --> E{决策判断}
E -- 需要更多信息 --> F[调用工具<br>如:网络搜索、内容提取]
F --> G[获取工具执行结果]
G --> H[结果反馈给LLM]
E -- 信息已充足 --> I[调用总结生成工具]
I --> J[生成最终日报]
H --> C
J --> K[循环结束<br>输出结构化日报]
4.1 第一步:定义目标与产出格式
首先,我们必须明确告诉Agent我们要什么。一个模糊的“生成日报”指令会导致结果不可控。我们需要定义清晰的结构化输出格式。使用Pydantic模型是绝佳选择。
# schemas.py
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import date
class NewsItem(BaseModel):
"""单条新闻的模型"""
title: str = Field(description="新闻标题")
summary: str = Field(description="新闻摘要,约100字")
source: str = Field(description="来源,如‘央视新闻’、‘新浪科技’")
url: Optional[str] = Field(default=None, description="原文链接")
category: str = Field(description="分类,如‘人工智能’、‘半导体’、‘政策’")
importance: int = Field(description="重要性评分,1-5分", ge=1, le=5)
class TechDailyReport(BaseModel):
"""科技日报的完整模型"""
report_date: date = Field(default_factory=date.today, description="报告日期")
headline_news: List[NewsItem] = Field(description="今日头条新闻,1-3条")
industry_updates: List[NewsItem] = Field(description="行业动态,3-5条")
in_depth_analysis: Optional[str] = Field(default=None, description="深度分析段落")
editor_comment: Optional[str] = Field(default=None, description="编者按/今日观点")
generated_at: str = Field(description="生成时间戳")
这个模型有两个作用:1. 作为最终输出的容器;2. 在后续步骤中,我们可以使用LangChain的 StructuredOutputParser ,强制LLM按照这个格式思考和输出,极大提升稳定性。
4.2 第二步:构建Agent可用的工具集
Agent的“手脚”就是工具。我们来创建几个关键工具。
# tools.py
import asyncio
from duckduckgo_search import DDGS
from langchain.tools import tool
from langchain_community.document_loaders import AsyncHtmlLoader
from langchain_community.document_transformers import Html2TextTransformer
import logging
logger = logging.getLogger(__name__)
@tool
def search_web(query: str, max_results: int = 10) -> str:
"""
使用DuckDuckGo搜索网络信息。
参数:
query: 搜索关键词
max_results: 返回的最大结果数
返回:
格式化的搜索结果字符串,包含标题、链接和摘要。
"""
try:
with DDGS() as ddgs:
results = list(ddgs.text(query, max_results=max_results))
if not results:
return "未找到相关结果。"
formatted_results = []
for i, r in enumerate(results[:max_results], 1):
formatted_results.append(f"{i}. 【{r['title']}】\n 链接:{r['href']}\n 摘要:{r['body'][:150]}...")
return "\n\n".join(formatted_results)
except Exception as e:
logger.error(f"搜索失败: {e}")
return f"搜索工具执行出错: {e}"
@tool
async def fetch_webpage_content(urls: list[str]) -> str:
"""
异步抓取给定URL列表的网页正文内容。
参数:
urls: 网页URL列表
返回:
拼接后的网页正文文本。
"""
if not urls:
return "未提供有效URL。"
try:
# 异步加载
loader = AsyncHtmlLoader(urls)
docs = await loader.load()
# 转换HTML为纯文本
transformer = Html2TextTransformer()
docs_transformed = transformer.transform_documents(docs)
# 合并内容
all_content = "\n\n--- 下一个网页 ---\n\n".join([doc.page_content[:2000] for doc in docs_transformed]) # 限制长度
return f"已抓取 {len(docs_transformed)} 个网页内容:\n\n{all_content}"
except Exception as e:
logger.error(f"网页抓取失败: {e}")
return f"内容抓取工具执行出错: {e}"
# 可以继续添加更多工具,例如:
# @tool
# def get_tech_stock_news(): ...
# @tool
# def translate_text(text: str): ...
4.3 第三步:创建Agent执行器(ReAct循环的核心)
这是最复杂也最核心的部分。我们将使用LangChain的 create_react_agent 来构建一个具备规划能力的Agent。
# agent_executor.py
import asyncio
from langchain import hub
from langchain.agents import AgentExecutor, create_react_agent
from langchain_openai import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from tools import search_web, fetch_webpage_content
from schemas import TechDailyReport
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import PromptTemplate
import json
class TechDailyAgent:
def __init__(self, model_name="gpt-4-turbo-preview", temperature=0.1):
"""
初始化日报生成Agent。
参数:
model_name: 使用的LLM模型名称
temperature: 创造性,越低越稳定
"""
self.llm = ChatOpenAI(model=model_name, temperature=temperature, api_key=os.getenv("OPENAI_API_KEY"))
# 1. 定义工具列表
self.tools = [search_web, fetch_webpage_content]
# 2. 从LangChain Hub拉取一个优化的ReAct提示词模板
# 提示词模板指导LLM如何思考、调用工具和格式化输出
self.prompt_template = hub.pull("hwchase17/react")
# 3. 创建Agent
self.agent = create_react_agent(
llm=self.llm,
tools=self.tools,
prompt=self.prompt_template
)
# 4. 创建执行器,管理循环执行、工具调用和错误处理
self.agent_executor = AgentExecutor(
agent=self.agent,
tools=self.tools,
verbose=True, # 打印详细执行过程,调试时非常有用
handle_parsing_errors=True, # 优雅处理输出解析错误
max_iterations=10, # 防止无限循环
early_stopping_method="generate", # 达到满意结果时提前停止
)
# 5. 初始化输出解析器,用于将最终文本解析为结构化的日报对象
self.output_parser = PydanticOutputParser(pydantic_object=TechDailyReport)
# 6. 创建最终生成日报的提示词模板
self.final_report_prompt = PromptTemplate(
template="""
你是一位资深的科技媒体编辑。请根据以下收集到的所有信息和对话历史,生成一份完整、专业的《科技日报》。
要求:
1. 严格按照指定的JSON格式输出。
2. 日报日期为今天:{current_date}。
3. 头条新闻选择最具轰动性或突破性的1-3条。
4. 行业动态选择有代表性的3-5条。
5. 基于信息,撰写一段约300字的深度分析。
6. 最后,写一段约150字的编者按,提炼今日科技领域的核心主题或趋势。
收集到的信息:
{collected_information}
对话历史(Agent的思考过程):
{agent_history}
{format_instructions}
""",
input_variables=["current_date", "collected_information", "agent_history"],
partial_variables={"format_instructions": self.output_parser.get_format_instructions()}
)
async def run(self, initial_goal: str = "生成一份今日的科技日报") -> TechDailyReport:
"""
运行Agent,生成科技日报。
"""
print(f"🤖 开始执行任务: {initial_goal}")
# 步骤A: 启动ReAct Agent进行信息收集和规划
# 这里,Agent会自主调用搜索、抓取等工具
raw_result = await self.agent_executor.ainvoke({
"input": initial_goal,
"current_date": date.today().isoformat()
})
collected_info = raw_result.get("output", "")
print("✅ 信息收集阶段完成。")
# 步骤B: 将收集到的信息交给LLM,按照严格格式生成最终日报
final_chain = self.final_report_prompt | self.llm | self.output_parser
try:
final_report: TechDailyReport = await final_chain.ainvoke({
"current_date": date.today().isoformat(),
"collected_information": collected_info,
"agent_history": str(raw_result) # 将整个思考过程作为上下文
})
print("🎉 日报生成完成!")
return final_report
except Exception as e:
print(f"❌ 最终报告解析失败: {e}")
# 降级处理:返回一个包含错误信息的报告对象
return TechDailyReport(
report_date=date.today(),
headline_news=[],
industry_updates=[],
in_depth_analysis="报告生成过程中出现错误。",
editor_comment=f"错误详情: {e}",
generated_at=datetime.now().isoformat()
)
4.4 第四步:编写主程序,串联一切
创建一个主文件来启动整个流程。
# main.py
import asyncio
import json
from datetime import datetime
from agent_executor import TechDailyAgent
from dotenv import load_dotenv
load_dotenv()
async def main():
"""主函数:创建Agent并生成日报"""
print("🚀 启动科技日报生成器...")
# 1. 初始化Agent
agent = TechDailyAgent(model_name="gpt-4-turbo-preview") # 可根据需要换为 gpt-3.5-turbo
# 2. 运行Agent
start_time = datetime.now()
report = await agent.run("请生成一份今日(以当前日期为准)的科技日报,涵盖人工智能、半导体、新能源、生物技术等领域的重要动态。")
end_time = datetime.now()
# 3. 输出结果
print(f"\n⏱️ 任务总耗时: {(end_time - start_time).total_seconds():.2f}秒")
print("\n" + "="*50)
print("📰 生成的《科技日报》")
print("="*50)
# 转换为字典并美化打印
report_dict = report.dict()
report_dict['generated_at'] = report_dict['generated_at'] # 保持原样
print(json.dumps(report_dict, indent=2, ensure_ascii=False))
# 4. (可选) 保存到文件
filename = f"tech_daily_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(filename, 'w', encoding='utf-8') as f:
json.dump(report_dict, f, indent=2, ensure_ascii=False)
print(f"\n💾 日报已保存至文件: {filename}")
if __name__ == "__main__":
asyncio.run(main())
5. 运行结果与效果验证
5.1 如何运行
在终端中,确保位于项目根目录且虚拟环境已激活,运行:
python main.py
5.2 预期输出与解读
程序启动后,你将看到类似以下的输出(verbose模式开启):
🚀 启动科技日报生成器...
🤖 开始执行任务: 请生成一份今日(以当前日期为准)的科技日报...
> Entering new AgentExecutor chain...
思考:我需要先生成今天的科技日报。首先,我需要获取最新的科技新闻。我应该使用搜索工具来查找今天关于人工智能、半导体、新能源和生物技术的新闻。
行动:调用 `search_web` 工具,参数:`{"query": "2024年6月29日 人工智能 重大进展 新闻", "max_results": 8}`
观察:【OpenAI发布新一代模型...】链接:... 摘要:...
思考:我得到了一些关于AI的新闻。接下来,我需要获取半导体和新能源的新闻。
行动:调用 `search_web` 工具,参数:`{"query": "半导体 今日 行业动态 投资", "max_results": 6}`...
...
思考:我已经收集了足够的新闻标题和摘要。为了撰写深度分析,我需要获取一些关键新闻的详细内容。我将调用内容抓取工具。
行动:调用 `fetch_webpage_content` 工具,参数:`{"urls": ["https://example.com/news/123", ...]}`
观察:已抓取 3 个网页内容:...
思考:信息已收集完毕。现在我可以开始生成最终的结构化日报了。
> Finished chain.
✅ 信息收集阶段完成。
🎉 日报生成完成!
⏱️ 任务总耗时: 45.23秒
...
📰 生成的《科技日报》
...
{
"report_date": "2024-06-29",
"headline_news": [
{
"title": "OpenAI发布推理模型o1,逻辑能力大幅提升",
"summary": "OpenAI今日悄然推出新模型o1,该模型在数学、编程和逻辑推理基准测试中表现突出,被认为在复杂问题分步推理上取得突破。",
"source": "The Verge",
"url": "https://www.theverge.com/...",
"category": "人工智能",
"importance": 5
}
],
"industry_updates": [...],
"in_depth_analysis": "今日科技领域的焦点集中于AI基础模型的‘推理’能力突破...",
"editor_comment": "从今日动态看,‘可信推理’正成为AI竞争的新高地...",
"generated_at": "2024-06-29T14:30:25.123456"
}
如何判断成功?
- 流程成功 :Agent完整执行了“思考-行动”循环,没有陷入死循环或中途报错退出。
- 内容有效 :生成的日报包含具体新闻条目,标题、摘要、来源清晰,非胡编乱造。
- 结构合规 :最终输出是一个完美的JSON对象,完全符合我们定义的
TechDailyReportPydantic模型结构,可以直接被其他程序解析和使用。
6. 常见问题与排查思路
在构建和运行此类Agent时,你几乎一定会遇到下表所列的问题。这里提供了清晰的排查路径:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
运行报错 ModuleNotFoundError |
依赖未安装或虚拟环境未激活。 | 1. 运行 pip list 检查 langchain , openai 等包是否存在。 2. 确认终端提示符前有 (.venv) 字样。 |
1. 激活虚拟环境: source .venv/bin/activate 。 2. 重新安装依赖: pip install -r requirements.txt 。 |
错误 OPENAI_API_KEY not found |
API密钥未正确设置。 | 1. 检查项目根目录下是否存在 .env 文件。 2. 检查 .env 文件中 OPENAI_API_KEY 的赋值是否正确(无多余空格)。 3. 在代码中打印 os.getenv(“OPENAI_API_KEY”) 的前几位确认。 |
1. 确保 .env 文件存在且格式正确。 2. 在 main.py 开头调用 load_dotenv() 。 |
| Agent陷入循环,不停搜索 | 1. Agent未达到“任务完成”的判断条件。 2. max_iterations 设置过高。 3. 提示词未明确停止条件。 |
观察verbose日志,看Agent的“思考”步骤是否重复或无进展。 | 1. 降低 max_iterations (如设为6)。 2. 在初始提示词中明确说明:“当你认为已收集到足够撰写日报的信息时,请直接输出最终报告”。 3. 使用 early_stopping_method=”generate” 。 |
| 工具调用失败或返回空 | 1. 网络问题。 2. 搜索关键词太宽泛或太冷门。 3. 目标网站反爬。 |
1. 单独运行工具函数进行测试。 2. 检查工具函数内部的错误处理和日志。 |
1. 添加重试机制和更友好的错误返回。 2. 优化搜索query,如加上“最新”、“今日”等时间词。 3. 为 fetch_webpage_content 添加请求头(User-Agent)和延迟。 |
| 最终输出不是有效JSON | 1. LLM未遵循格式指令。 2. 输出被截断。 |
1. 捕获 final_chain.ainvoke 的原始输出,查看是什么文本。 2. 检查 PydanticOutputParser 的 get_format_instructions() 是否清晰。 |
1. 使用更低 temperature (如0.1)增加稳定性。 2. 强化提示词中的格式指令,使用 ````json 包裹示例。<br>3. 实现一个fallback,尝试用 json.loads()` 和字符串修复来解析。 |
| 生成内容空洞或重复 | 1. 搜索工具返回的信息质量低。 2. LLM的上下文不足以合成好内容。 |
检查 collected_information 变量的内容是否丰富。 |
1. 优化工具:使用更可靠的新闻源API(如NewsAPI)替代通用搜索。 2. 增加信息收集的轮次和多样性。 3. 在最终生成提示词中提供更具体的写作要求。 |
| 运行速度慢 | 1. 网络请求多且同步。 2. GPT-4模型本身较慢。 3. 迭代次数多。 |
使用异步工具(如 AsyncHtmlLoader )并记录各步骤耗时。 |
1. 确保所有IO密集型工具都是异步的。 2. 考虑使用更快的模型(如 gpt-3.5-turbo )进行信息收集,仅用GPT-4做最终合成。 3. 缓存搜索结果,避免短时间内重复查询。 |
7. 最佳实践与工程建议
将演示项目转化为一个健壮、可维护的生产级应用,你需要考虑以下方面:
7.1 提示词工程优化
- 系统提示词(System Prompt)是灵魂 :在创建Agent时,定义一个清晰的角色、目标和约束。例如:“你是一个严谨的科技日报编辑助理,你的目标是收集信息并生成报告。你必须使用提供的工具,且每一步行动前必须说明理由。”
- 分阶段提示 :不要指望一个提示词完成所有事。本项目的“信息收集”和“报告生成”分离就是很好的实践。复杂任务可以拆分成“规划-检索-分析-撰写-润色”多个阶段,每个阶段用专门的提示词和LLM调用。
- 提供少量示例(Few-Shot) :在提示词中给出一两个“思考-行动-观察”的完整示例,能极大提升Agent执行轨迹的稳定性。
7.2 工具设计的可靠性
- 工具需具备鲁棒性 :每个工具函数都必须有完善的
try-except错误处理,并返回对LLM友好的错误信息(如“搜索服务暂时不可用”),而不是抛出异常导致整个Agent崩溃。 - 工具结果需格式化 :返回给LLM的结果应该是清晰、简洁的文本。避免返回原始的JSON或HTML,LLM可能难以理解。
- 工具需有元信息 :使用
@tool装饰器的description参数,清晰描述工具的功能、输入和输出。这是LLM能否正确调用工具的关键。
7.3 状态管理与记忆
- ConversationMemory :对于多轮对话式的Agent,必须引入记忆机制。
ConversationBufferMemory、ConversationSummaryMemory或VectorStoreRetrieverMemory可以帮助Agent记住之前的交互历史。 - 本项目中的隐式记忆 :我们的Agent通过将整个执行历史 (
agent_history) 传递给最终生成步骤,实现了跨步骤的“记忆”,这是一种简单有效的方式。
7.4 生产环境部署考量
- 异步与并发 :如本项目所示,使用
async/await处理所有IO操作(网络请求、数据库查询),可以大幅提升吞吐量。 - 超时与重试 :为LLM API调用和工具调用设置超时(
timeout)和自动重试逻辑(使用tenacity等库)。 - 日志与监控 :记录Agent的每一步决策、工具调用和结果,这对于调试和优化至关重要。可以结构化的方式(如JSONL)记录到文件或日志系统。
- 成本控制 :监控Token使用量。可以通过设置
max_tokens、缓存结果、对非关键步骤使用更便宜的模型等方式来控制成本。 - 安全与合规 :
- 内容安全 :在最终输出前,加入内容审核环节(调用审核API或使用关键词过滤),防止生成不当内容。
- 数据隐私 :确保工具(如网页抓取)不获取和存储用户隐私数据。
- 合法合规 :遵守目标网站
robots.txt协议,控制抓取频率,避免对对方服务器造成压力。
通过这个“科技日报生成器”项目,我们完成了一次完整的AI Agent工程化实践。它远不止是一个信息聚合脚本,而是一个展示了 规划、工具使用、状态管理和结构化输出 的微型框架。你可以基于此框架,轻松地将目标替换为“竞品分析报告生成器”、“社交媒体内容规划Agent”或“内部知识库问答机器人”。记住,构建可靠Agent的关键,不在于追求完全无人干预的“全自动”,而在于设计一个 容错率高、边界清晰、人类可理解且易于干预 的智能协作流程。从这个项目出发,去探索和构建属于你自己的智能体应用吧。
更多推荐
所有评论(0)