关于Agent的一些思考
关于Agent的一些思考
前情提要:该篇文章是撰写在飞书上的,基于我个人项目,本人才疏学浅,如有错误请见谅

在飞书上的观感或许会更好些,如有需要可以评论找我要,都会分享的,目前飞书并不支持导出markdown,在这里用的AI强转然后发布
RAG知识库设计
RAG是什么
RAG是构建Agent的核心技术,Retrieval-Augmented Generation,也就是检索增强生成
为什么需要RAG?
为了解决:大模型回答缺少依据
假如没用RAG:把大量知识数据都塞给模型–→会导致注意力偏移,真实提问内容的权重降低,容易产生幻觉
用了RAG:从知识库里取出最相关的数据塞给模型,减少Tokens消耗,降低幻觉率
RAG的核心流程:两条链路
提问前(数据准备):分片→Embedding(向量化)→存储
1.上传文件→2.文件分片→3.Embedding向量化→4.存储到Vector Database(Milvus)
提问后(回答生成):召回→重排→生成
1.提出问题→2.Embedding向量化→3.召回→4.重排→5.增强(将input和召回的content一起发送给大模型)→6.生成答案
什么是向量?
向量就是一组数字,比如[0.8,0.2,-0.5]就是一个三维向量(三个数字,所以是三维)—在三维空间里,这个点的位置就是 (0.8, 0.2,-0.5)
低维的向量(1到3维)我们可以在坐标轴上画出来,但实际使用中,Embedding模型生成的向量维度非常高,可能有几百甚至上千维。虽然我们没法想象一个1000维的空间长什么样,但 维度越高,能表达的信息就越丰富,对文本特征的刻画就越细腻。
意思相近的文字,经过Embedding转化出来的向量也会很相近。
召回时的向量相似度计算?
常用的算法有两种:
余弦相似度:
计算两个向量夹角的余弦值,结果在-1到1之间
夹角越小,余弦值越接近1,说明两个向量方向越一致,语义越相近
它只看方向,不看长度,所以特别适合文本语义匹配(因为我们关心的是"意思像不像",不关心"文本长不长")
欧式距离:
两个点的直线距离,越小越相似,既看方向也看长度
为什么要重排?
召回阶段速度快、成本低,但精度有限。
重排阶段是把问题和片段拼在一起输入模型,让模型直接判断相关性
重排模型:采用Cross Encoder
对话Agent设计
设计范式:什么是ReAct?
ReAct的本质是Reasoning推理+ Acting行动。核心是让大模型像人类一样,通过先思考,再行动来解决复杂的问题。
核心:是一个 思考→行动→观察→再思考的闭环机制
ReAct是怎么实现的
早期版:
靠的是Prompt工程+字符串解析
System Prompt 大概长这样:在System Prompt严格规定AI的输出格式
你是一个 ReAct 代理,遵循 思考→行动→暂停→观察 的循环来解决问题。
工作流程:
1.Thought:描述你的推理过程
2.Action:执行个动作(格式:Action:工具名:输入)
3.PAUSE:停下来,等待工具返回结果
4.Observation:分析工具返回的结果
可用工具:
-calculation:数学计算(如"5*7/4")
planet_mass:查询星质量(如 “Mars”)
现代ReAct(Function Call版)
什么是Function Call
FunctionCall(函数调用)就是把"古法 ReAct的手工活"标准化了一一用JSON 来统一工具的定义和调用格式。
举个例子,以前古法 ReAct 里,工具描述是这样的(写在 Prompt 文本里) :
可用工具:
- calculation:数学计算(如"5*7/4")
- planet_mass:查询行星质量(如"Mars")
现在用 Function Call,工具描述变成了标准的 JSON:
{
"name": "planet_mass",
"description": "查询太阳系行星的质量",
"parameters": {
"type": "object",
"properties": {
"planet": {
"type": "string",
"description": "行星名称,如 Earth、Mars"
}
},
"required": ["planet"]
}
}
AI要调用工具时,也不再输出Action:planet_mass:Earth 这样的字符串了,而是直接返回:
{
"tool_calls": [{
"function": {
"name": "planet_mass",
"arguments": "{\"planet\": \"Earth\"}"
}
}]
}
区别:从"人约定的文本格式"变成了"机器可以直接解析的JSON结构”。
用Function Call 之后,ReAct 的循环变得简洁多了:
- 把工具的 JSON 描述 + 用户问题 一起发给大模型
(不需要在 Prompt 里写 “Action:xxx:xxx” 这种格式说明了)
- 大模型自己判断要不要调用工具
→ 需要调用 → 返回标准 JSON 格式的 tool_calls
→ 不需要 → 直接返回文本答案
-
我们解析 JSON,执行对应的工具函数,拿到结果
-
把工具结果按规定格式加到对话里,开始下一轮循环
-
直到大模型不再返回 tool_calls → 循环结束,输出最终答案
ReAct模式使大模型具备了处理复杂多步骤任务的能力
在项目中:
我们项目里没有手写传统 ReAct 的 while 循环,而是使用 LangChain 的 create_agent() 来创建 Agent。这个方法底层基于 LangGraph,会自动构建一个 Agent 执行图。
它的大致流程是:先把用户消息交给模型,模型判断是否需要调用工具;如果模型返回了 tool_calls,LangGraph 就会进入工具节点执行对应工具,然后把工具返回结果作为 ToolMessage 追加到上下文里,再回到模型节点继续推理。这个过程会循环进行,直到模型不再返回工具调用,而是返回最终答案。
我们代码里看不到显式的 while 循环,是因为这部分被 create_agent() 封装了。我们主要负责提供模型、工具列表、checkpointer 和 thread_id。
什么是SSE技术?()
SSE是实现实时通信的技术,也就是服务器发送事件,它是基于HTTP协议的。
它的工作方式是:客户端发起一个普通的HTTP请求,但服务器不立即关闭连接,而是保持这个连接打开,并按照特定的格式(text/event-stream)持续地、一段一段地向客户端推送数据。
为什么不用WebSocket?
WebSocket是一个独立的协议,它在初次连接时通过HTTP协议进行握手,握手成功后,连接就升级为WebSocket协议,之后双方就可以在这个连接上进行全双工的双向通信了,服务器可以随时发消息给客户端,客户端也可以随时发消息给服务器。
在选择时,我会考虑:如果需要双向实时交互,比如在线聊天、协同编辑,肯定选WebSocket。如果只需要服务器向客户端推送实时数据,比如股票行情、通知、或者像我项目里的AI对话流,SSE就足够且更简单,因为它基于HTTP,不需要处理新的协议,后端实现和调试也方便一些。选择SSE主要是出于简单和够用的考虑,我们的场景主要是服务器向浏览器单向推送AI生成的文本,不需要双向通信,SSE的协议比WebSocket更轻量,实现起来也简单,对于流式文本这种场景非常适。用户体验就像是在看一个人实时打字。
你是如何实现SSE技术的?
SSE基于HTTP协议,不需要特殊的协议支持,使用标准的HTTP连接。在建立连接后,将HTTP头部的 Content-Type 改成 text/event-stream 就可以了,后续发送消息要按照SSE数据格式发送。
SSE的数据格式非常简单,每条消息由多个字段组成,每个字段由字段名、冒号和字段值组成,以换行符分隔。
一个完整的SSE消息示例:
id: 1\n
event: message\n
data: {"message": "Hello, World!"}\n\n
运维Agent设计
设计范式:什么是Plan-Execute-Replan?
Plan-Execute-Replan是一种Multi-Agent(多智能体)协作的任务执行模式,核心思路是:先规划、再执行、
随时调整。
人话:先出一个大体的方案,执行过程中根据实时反馈的结果再决定要不要重规划
https://jcnrb3mdvlfy.feishu.cn/sync/NUvHdw6Yzs9Lf0bfUpncQNcUnjg
如何实现运维Agent(plan-execute-replan)的?
所有节点共享一个PlanExecuteState
[图片]
搭建:LangGraph工作流
三个节点通过 StateGraph 连接, replanner 之后根据状态中是否存在 response 进条件路由:
def _build_graph(self):
workflow = StateGraph(PlanExecuteState)
# 添加三个节点
workflow.add_node("planner", planner)
workflow.add_node("executor", executor)
workflow.add_node("replanner", replanner)
# 固定边: planner -> executor -> replanner
workflow.set_entry_point("planner")
workflow.add_edge("planner", "executor")
workflow.add_edge("executor", "replanner")
# 条件边: replanner 根据状态决定结束还是继续执行
def should_continue(state: PlanExecuteState) -> str:
if state.get("response"):
return END # 已生成最终响应,结束流程
if state.get("plan"):
return "executor" # 还有步骤,继续执行
return END
workflow.add_conditional_edges("replanner", should_continue, {
"executor": "executor",
END: END
})
return workflow.compile(checkpointer=MemorySaver())
其他
你的项目用的是什么模型?
- 向量模型我使用的是阿里的text-embedding-v4
- 语言模型我使用的是qwen3-max
如果你的Agent召回的答案不准确,大模型会胡说八道吗?
- 这里我使用到了相似度阈值这个参数,这是用于筛选向量检索结果的关键参数。该阈值通常以余弦相似度表示,高于此值的文档会被保留并输入大模型生成答案,低于此值的则被过滤。(余弦相似度越接近1越相似)
- 在项目里我设置的阈值是0.8。为什么设置这么高呢?是因为我们使用的场景主要是针对告警的处理,所以一定
要准确准确再准确。
那其实还会有另一个问题,如果没有召回任何片段,大模型会有幻觉,乱回答吗?
实际上不会的,因为我从system prompt里面约束了大模型。“
严格按照文档的内容回答,不允许使用文档外的任何信息。“
“如果请求超出了你的能力范围,清晰地说明你的局限性”
谈谈你对MCP的理解?
我们可以把MCP想象成电脑的USB-C接口
键盘、U盘、显示器就是不同的MCPServer,它们提供各自独特的功能。
电脑就是Agent,它作为MCPClient,通过统一的USB-C接口(即MCP协议)来连接和使用所有外设(MCPServer)。
这样一来,无论你更换电脑还是外设,只要都支持USB-C标准,就能即插即用,非常方便。
MCP协议正是为AI使用工具带来了这种即插即用的便利性。最直观的感受就是相同的Tool,可以给很多Agent使用,不需要重复写代码。
你知道Agent Skills吗?
Skills 是一种自然语言指令文件,通常是 Markdown 格式,用来教 Agent"在什么场景下、按照什么方法、遵循什么规范来完成特定任务"。
如何避免大模型幻觉?
我主要从三个方面来控制:
第一是强约束的Prompt设计,在系统Prompt中明确要求:“严格按照文档内容回答,不允许使用文档外的任何信息”、“如果不知道答案,明确说不知道,不要编造”。这样可以从源头上约束大模型的输出。
第二是RAG增强,思路就是:在AI回答之前,先去知识库里搜一搜,找到最相关的内容,然后把这些内容"喂"给大模型,让它基于真实的文档来生成回答。
第三是相似度阈值过滤,我设置了0.8的高阈值,这个阈值就可以很大程度上筛选出最相关的数据。
如何解决大模型幻觉问题?
1.RAG的思路就是:在AI回答之前,先去知识库里搜一搜,找到最相关的内容,然后把这些内容"喂"给大模型,让它基于真实的文档来生成回答。
2.没有ReAct的时候,AI遇到不确定的问题只能"硬编"一一也就是大模型幻觉问题,有了ReAct,AI 会先想"这个问题我不确定,我得查一下",然后去调用工具获取真实数据,再基于真实数据来回答。从"凭记忆猜"变成了"查了再说",准确率自然大幅提升。
你的项目是如何存储上下文的?
用的是LangGraph的checkpointer机制,调用MemorySaver()用于会话管理。把每个会话的状态保存在服务内存里,通过 thread_id 区分不同用户或不同会话。
MemorySaver 本身没有一个固定的“保存多少轮”的限制,它主要受两个限制:
第一是 服务器内存大小。
因为它是存在 Python 进程内存里的,对话越多、用户越多,占用内存就越大。
第二是 大模型的上下文窗口限制。
即使我们在内存里保存了很多历史消息,也不能无限塞给大模型。比如模型最多支持 8K、32K 或 128K tokens,那最终传给模型的内容也不能超过这个限制。
所以我们项目里不会无脑把所有历史都传给模型,一般会做截断,比如只保留最近几轮对话,或者对更早的历史做摘要。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)