一个Agent的五种写法——踩坑记

文章标题其实应该叫——“调用function calling 功能的 ReACT + langchain 案例”。

根据前文,我们知道ReACT 范式,就是一套万金油小联招:

[思考-规划] – [执行] – [观察(反思)]。

在这个框架下,代码层面只需要循环,就可以实现用户复杂意图的需求。属于“投入小,产出大”的划算买卖!

但是,如果在真实应用中,只这样做就可以了么?

本文提供了五种实现方式,希望带大家一探究竟——

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
## 方式一:
- 提示词 + 工具 (最简单的Agent,但是缺少思考和规划)
- 结果:把复杂的任务,一次性交给AI,结果不满意。

## 方式二:
- CoT提示词 + 工具 (通过提示词 让 AI一步一步来)
- 结果:复杂度上去了,AI既要处理任务,还要反思规划,不稳定没法用

## 方式三:
- CoT提示词 + 工具 + 两次Agent 处理(一个负责构思、一个负责输出function calling 和 反思)
- 结果:稳定性进一步增强,一开始执行可能还行,循环次数多了后续就不稳定了

## 方式四:(偷懒方法一)
- 提示词 + (有思考模块的)工具
- 结果:稳定性进一步增强,内容也还不错,可以使用

## 方式五:(偷懒方法二)
- 提示词 + Langchain 自带的中间件模块(TodoList & Summarization)
- 结果:格式上大为简化(提示词、messages 消息整合和循环语句都大为简化)。执行结果上看,还是有点粗糙。

所以,所谓的Agent 自主分析 和判断,也不是一味地 将全部内容交给它。而是

循环是成功了,但是会发现一个难点: 中间状态的控制!!其实这也是Agent 中 “记忆”的部分的内涵。(这部分 除了关键步骤的输入和输出,还有)

彻底的解决办法:一次只做一件事情。例如:改写用户提问一个 Agent,web 检索 一个Agent,反思 一个 Agent,评估一个Agent,最终给出答复 一个Agent——

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
builder.add_node("generate_query", generate_query)
builder.add_node("web_research", web_research)
builder.add_node("reflection", reflection)
builder.add_node("evaluate_research", evaluate_research)
builder.add_node("finalize_answer", finalize_answer)

builder.add_edge(START, "generate_query")
builder.add_conditional_edges(
    "generate_query", continue_to_web_research, ["web_research"]
)
builder.add_edge("web_research", "reflection")
builder.add_conditional_edges(
    "reflection", evaluate_research, ["web_research", "finalize_answer"]
)
builder.add_edge("finalize_answer", END)

graph = builder.compile(name="pro-search-agent")

所以,后续的文章,我们会使用 langgraph 整一个web app 出来。大家保持关注就好。