文章内容来源于:叶小钗

什么是 Agent?

2025 年被称作 AI Agent 元年,到了 2026 年,更是直接被定义为 Agent 大年。就像最近火出圈的 OpenClaw,本身就是一个 Agent。眼下各式各样的 Agent 正在不断涌现,未来很可能彻底改变我们工作和生活的方式。

也正因如此,Agent 这个词出现的频率高到离谱,可真要问一句 Agent 到底是个啥,能说清楚的人没几个。

Agent 这个词来源于拉丁语 agere,原本的意思就是“去做、去行动”。从概念上来讲,Agent 就是行动者,是一个能主动做事、感知周围环境,还能围绕目标自己行动的个体。

放到 AI 领域里,AI Agent 也就是智能体,就是把这种“能行动的能力”给到 AI 系统。

它不再是那种只会被动接指令、给答案的大模型,而是一个能自己感知、自己做决定、自己动手执行的智能个体。简单来讲:传统大模型的强项是“回答问题”,而 Agent 的强项是“把任务做完”。

它能明白你想要达成的目标,自动把步骤拆开、规划好执行路径,再调用各种工具,一步一步把事情实打实做完:

图片

不过最近,我觉得最经典的还是这张图:

图片

它把 Agent 是什么讲得更明白,还隐约道出了它的发展规律:这是一场 Workflow 复杂度的迁移,是泛化能力极强的 Workflow,也可以说是 Agentic Workflow!

弄懂这句话,就懂了什么叫让 AI 自己干活。其实 Agent 本身,也只是模型使用方式里的一种而已。

怎么让 AI 真正做事?

现在我们常用的大模型,比如 GPT、通义千问、DeepSeek 这些,学了海量的公开知识,推理和逻辑能力都很强。它们的核心运行逻辑就是,接收我们输入的内容,经过计算推理后,直接输出一段结果给我们。

拿 DeepSeek 官方的 API 调用举个例子:

import os
from openai import OpenAI
client = OpenAI(
    api_key=os.environ.get('DEEPSEEK_API_KEY'),
    base_url="https://api.deepseek.com")
response = client.chat.completions.create(
    model="deepseek-chat",
    messages=[
        {"role": "system", "content": "You are a helpful assistant"},
        {"role": "user", "content": "Hello"},
    ],
    stream=False
)
print(response.choices[0].message.content)

从这段代码就能看出来:

模型接收的 messages 里,包含系统提示和用户的问题;

模型最后只会输出一段文字 content,然后就停止运行了;

也就是说,大模型本身不会做任何实际操作,它只会“告诉你该怎么做”,不会“帮你动手做”。

那要怎么才能让 AI 真正完成一项任务呢?答案很简单:给 AI 配上完成任务需要的各种能力。

如果一件事没有 AI 也能完成,那就说明我们已经有对应的工具或者函数了。接下来只需要把这些函数“告诉”AI,再引导它在需要的时候,选择合适的函数就行。

下面我们就以开发一个旅游规划助手智能体为例,详细讲讲怎么让 AI 真正动起来做事。

开发 Agent

我们通过做一个旅游规划助手智能体的案例,一步步拆解让 AI 自主做事的全过程:

图片

先设计功能和函数

在接入 AI 之前,首先要保证就算没有 AI,用户也能自己完成旅游规划。所以我们得先设计好旅游助手的核心功能,再写好对应的函数:

- 查询天气:根据目的地获取未来几天的天气情况

- 查询热门景点:列出目的地的热门景点,附带简介、门票等信息

- 查询酒店:根据目的地和入住日期,推荐附近酒店及价格

- 查询公交路线:规划两个地点之间的公共交通路线

没有 AI 的时候,用户得自己一步步操作:先查天气定出行时间,再查景点挑想去的地方,接着查附近酒店,最后查景点和酒店之间的交通路线。

靠这些工具用户完全能自己做行程规划,就是步骤太麻烦了。

让 AI 接手整个规划流程

我们想要的效果是,只说一句“帮我规划下周去北京的行程”,AI 就能自动调用上面这些函数,拿到信息后生成一份完整的旅游计划。

要实现这个效果,关键就在系统提示词。我们需要在提示词里告诉 AI 这几件事:

它的身份和要完成的任务、它能使用哪些工具,也就是对应的函数 、要用什么样的结构化格式,比如 JSON,告诉我们它想调用哪个工具、以及判断收集到的信息够不够用

这里顺便问一句:为什么要用 JSON 格式呢?

AI 模型本身输出的是自然语言文本,要让程序能看懂 AI 的想法,再去执行对应的函数,就需要 AI 用结构化的数据格式,比如 JSON,输出它的决策。

我们解析完 JSON 之后,就知道该调用哪个函数、传什么参数。

其实用不用 JSON 无所谓,就算用 XML 也可以,只要模型容易理解、程序方便解析就行。

系统提示词案例

下面是给旅游规划助手写的系统提示词案例,明确要求 AI 返回结果时用 JSON 格式,JSON 里要包含这些字段:

- action:动作类型,分为 call_tool(调用工具)和 respond(直接回答用户)

- tool:当 action 是 call_tool 时,填写要调用的工具名称,比如 get_weather

- parameters:调用工具需要的参数,用键值对形式呈现

- isSufficient:判断当前信息是否足够完成需求,true 代表可以直接回答,false 代表还需要继续查信息

- message:当 action 是 respond 时,填写要输出的自然语言回答

你是一位专业的旅游规划助手。你的目标是根据用户的需求,提供详尽、合理的旅游行程建议。
你有以下工具可以使用,每个工具都有对应的名称和参数。

get_weather(目的地, 日期) - 查询目的地天气预报。
get_attractions(目的地) - 查询热门景点列表(含简介、门票、开放时间)。
get_hotels(目的地, 入住日期, 退房日期) - 查询推荐酒店及价格。
get_route(起点, 终点) - 查询公共交通路线。

你必须输出一个 JSON 对象,不得包含其他任何文本。JSON 对象应包含以下字段: 
action: 字符串,值为 "call_tool" 或 "respond"。 
tool: 当 action 为 "call_tool" 时,此处填写要调用的工具名称(如 "get_weather");否则留空。 
parameters: 当 action 为 "call_tool" 时,此处填写调用工具所需的参数对象(例如 {"目的地": "北京", "日期": "2025-03-15"});否则为空对象。
isSufficient: 表示当前收集到的信息是否足够完成用户的需求。如果为 true,则下一步应直接回答用户;如果为 false,则还需继续调用工具获取更多信息。 
message: 当 action 为 "respond" 时,此处填写你要对用户说的自然语言回答;否则留空。

工作流程:
1. 你需要理解用户的请求,提取关键信息。
2. 如果需要调用工具获取信息,你需要将action的值设置成"call_tool"同时设置 parameters 的值,并将 isSufficient 设为 false。
3. 当你已经获得足够信息,可以回答用户的问题,你需要将action设置为"respond",在 message 中给出完整的旅游规划建议,并将 isSufficient 设为 true。

说到这,Agent 的本质也就出来了,其实就是靠循环实现的:

循环调用

把用户的问题和系统提示词一起发给 AI,AI 经过推理后,会按照提示词约定的格式输出内容。我们需要在代码里解析这个 JSON,拿到参数后做后续处理。

当 action 的值是 call_tool 时,就根据 tool 和 parameters 调用对应的函数,拿到结果后,把结果当成新消息加入对话,再重新请求模型。

当 action 的值是 respond 时,就把 message 展示给用户,结束整个对话:

图片

下面是一段简化的 Python 伪代码示例:

import json
import openai
def get_weather(destination, date):
    return f"{destination} {date} 天气晴朗"
def get_attractions(destination):
    return f"{destination} 的热门景点有故宫、颐和园..."
# ... 其他函数
# 系统提示词(如上)
system_prompt = "..."
messages = [
    {"role": "system", "content": system_prompt},
    {"role": "user", "content": "帮我规划下周去北京的行程"}
]
client = OpenAI(
    api_key=os.environ.get('DEEPSEEK_API_KEY'),
    base_url="https://api.deepseek.com")
while True:
    response = client.chat.completions.create(
    model="deepseek-chat",
    messages=messages,
    stream=False
    )
    # 解析 JSON
    try:
        decision = json.loads(response.choices[0].message.content)
    except:
        print("模型输出非 JSON,错误处理...")
        break
    if decision["action"] == "call_tool":
        tool_name = decision["tool"]
        params = decision["parameters"]
        # 调用对应工具
        if tool_name == "get_weather":
            result = get_weather(**params)
        elif tool_name == "get_attractions":
            result = get_attractions(**params)
        # ... 其他工具
        # 将工具结果加入对话
        messages.append({"role": "tool", "content": result, "tool_call_id": tool_name})
        # 继续循环
    elif decision["action"] == "respond":
        print(decision["message"])
        break

看到这里,一个简单的旅行助手智能体就做好了!用户只需要说一句话,它就能自主调用工具,完成一整套旅游规划。

回头看看我们用到的技术,其实特别简单:

- 大模型:作为核心的推理引擎

- 系统提示词:在里面定义好工具的功能和使用规则

- 提前写好的函数:提供实际做事的能力

- 解析 JSON 的代码:把模型的决策转成函数调用

能看出来,核心就是模型加工具。

通过提示词告诉模型有哪些工具能用、工具名称和参数是什么、什么时候用,模型就能自己规划并调用工具完成任务,整个过程一点都不复杂。

不过把所有工具的定义和说明都写在提示词里,从工程角度来说并不美观:

- 提示词会变得特别长,不好维护

- 工具一多,修改和版本管理就很麻烦

- 模型的输出格式全靠提示词约束,稳定性不够

早在 2022 年,论文《ReAct: Synergizing Reasoning and Acting in Language Models》就开始研究工程实现,之后各大模型才陆续推出 Function Calling、Tools Calling 这类功能。

GPT 的 Function Calling 也就是函数调用,是专门为大模型设计的原生工具调用机制。我们可以用结构化的方式给模型注册工具,模型会用标准格式返回调用请求,省去了自己解析 JSON 的麻烦,也让工具管理更清晰高效。

接下来我们就详细讲讲 Function Calling,看看它怎么让智能体开发变得更规范。

Function Calling

Function Calling 最早是 OpenAI 在 2023 年 6 月 13 日,在 API 更新里以标准化接口形式正式推出的。

当时 OpenAI 发布了新版的 gpt-3.5-turbo 和 gpt-4 模型,新增了 functions 参数。开发者可以描述可用的函数,模型会智能判断要不要调用这些函数,再返回符合函数格式的 JSON 对象。

很快,其他模型厂商比如 Anthropic Claude、Google Gemini、通义千问、DeepSeek 都跟进了这项功能,Function Calling 也成了现代大模型的标配能力。

我们来看看用 DeepSeek 的 function calling 做旅行规划助手,代码会简洁很多。

定义工具(函数)

需要按照模型 API 要求的格式定义工具,每个工具包含名称、描述和参数结构,也就是 json schema。

tools = [
{
"type": "function",
"function": {
    "name": "get_weather",
    "description": "查询目的地的天气预报",
    "parameters": {
        "type": "object",
        "properties": {
            "destination": {
                "type": "string",
                "description": "目的地城市名称"
            },
            "date": {
                "type": "string",
                "description": "查询日期,格式为 YYYY-MM-DD,如果不指定则返回未来几天的天气"
            }
        },
        "required": ["destination"]
    }
}
},
# 其他函数 也和get_weather 这个方法一样定义 这里我们省略
]

改写系统提示词

模型支持 tools 参数后,提示词里就不用详细写工具信息了,只需要定义 AI 的角色和任务目标就行:

system_prompt = "你是一位专业的旅游规划助手。
你的目标是根据用户的需求,
调用可用的工具获取信息,并整合成一份详尽的旅游行程建议。"

循环交互

我们需要和模型循环交互:如果模型返回需要调用工具,程序就根据模型给的工具名称和参数执行代码,把工具执行结果加到提示词里,再继续请求模型;如果模型说不用调用工具了,就代表这是最终答案,直接输出给用户就行。

图片

import openai
import json
# 初始化客户端(DeepSeek API 兼容 OpenAI 格式)
client = openai.OpenAI(
    api_key="your-deepseek-api-key",  # 替换为你的 API Key
    base_url="https://api.deepseek.com"
)
# 工具的具体实现(模拟数据)
def get_weather(destination, date=None):
    # 实际场景中应调用天气 API
    return f"{destination} 的天气晴朗,气温15-25℃,适合出行。"
# 其他方法省略...
llm = OpenAI(
    api_key=os.environ.get("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)
messages = [
    {"role": "system", "content": "你是一个天气助手"},
    {"role": "user", "content": input}
]
# 第一步定义的标准格式
while True:
    result = llm.chat.completions.create(
      messages=messages, 
      model="deepseek-chat", 
      stream=False, 
      tools=tools)
    # 大模型输出的结果 有工具调用,说明模型思考后 需要调用工具
    if result.choices[0].message.tool_calls:
        tool_call = result.choices[0].message.tool_calls[0]
        function_name = tool_call.function.name
        function_args = tool_call.function.arguments
        print(tool_call.id,function_name, function_args)
        messages.append({"role": "assistant", "content": None, "tool_calls": [{"id": tool_call.id, "type": "function", "function": {"name": tool_call.function.name, "arguments": tool_call.function.arguments}}]})
        # 调用对应的函数
        if function_name == "get_weather":
            result = get_weather(function_args)
        elif function_name == "get_attractions":
            result = get_attractions(function_args)
        elif function_name == "get_hotels":
            result = get_hotels(function_args)
        elif function_name == "get_route":
            result = get_route(function_args)
        else:
            result = f"未知工具: {function_name}"
         messages.append({"role": "tool", "content": result, "tool_call_id": tool_call.id})
    else:
         break

图片

我们用大模型加 Function Calling 的方式,做出了一个能自主完成任务的旅行智能体。但这个智能体还不够完善,它记不住对话历史。

比如用户做完一次规划后接着问:“帮我把早上的景点换成更有历史底蕴的”,模型会一脸懵,它根本不知道“早上的景点”指的是什么。

因为每次模型调用都是独立的,它只会根据当前输入的提示词生成答案,不会主动回顾之前的记录。

想让模型记住之前的内容,不能指望模型自己查历史,得在工程层面手动保存每一轮对话交互记录,下次调用时,把完整的对话历史,包括用户问题、模型回复、工具调用结果等,全都拼到提示词里当成上下文给模型。

只有这样,模型才能明白当前问题和之前对话的关联,给出合理的回答,毕竟模型能识别的只有提示词里的内容。

那怎么给智能体加上记忆能力呢?接下来我们就给旅行助手加上对话历史存储和管理功能,让它真正能持续对话。

记忆能力

想让智能体真正实现持续对话,核心是解决“记忆”问题。所谓记忆,就是模型在当前输入之外,能调用的所有信息。

这些信息可能来自历史对话、外部存储或者系统内部状态,核心目的只有一个:给当前推理补充必要的上下文。

搭建记忆能力,需要解决三个核心问题:

- 记在哪里:也就是存储机制,用数据库还是内存

- 怎么记住:也就是写入策略,区分短期记忆和长期记忆

- 怎么想起:也就是检索机制,需要的时候怎么高效找到相关信息

针对这些问题,现在有多种记忆实现方式,各有侧重,适用场景也不同:

图片

上下文记忆

这是最基础的记忆方式,实现也最简单:把历史对话按时间顺序原封不动拼到当前提示词里,一起发给模型。模型靠阅读完整对话历史,保持语义连贯。

优点:实现成本低,适合做原型测试或者短对话场景

缺点:受模型 Token 上限限制,对话越长成本越高,不支持跨会话或长期记忆

本质:属于短期、一次性的情景记忆

滑动窗口记忆

滑动窗口记忆是在上下文记忆基础上做的约束:只保留最近固定轮数的对话,更早的内容直接删掉。它主要是为了控制 Token 成本,不是增强记忆能力。

优点:能有效控制提示词长度,降低开销

缺点:关键信息一旦被滑出窗口,就彻底没了

适用场景:上下文有效期明确、业务流程短的对话

本质:可以理解成对情景记忆的生命周期管理

摘要记忆

摘要记忆是让模型把历史对话压缩,把大量情景信息提炼成一段简要描述,后续对话用摘要代替原始内容。

优点:大幅减少 Token 消耗,还能保留对话整体脉络

缺点:摘要过程一定会丢失信息,质量全靠模型的总结能力

适用场景:需要保留整体脉络、对细节精度要求不高的场景

本质:把情景记忆转成低精度的语义记忆

向量记忆

向量记忆属于长期记忆方式。把用户对话、偏好、经验知识转成向量存在向量数据库里,用户提问时,把问题也转成向量,在数据库里找语义相似的内容。

优点:不受对话长度限制,支持跨会话长期记忆,能按语义匹配相关信息

缺点:检索结果是语义相似而非精确匹配,实现复杂度高

适用场景:需要长期积累知识、提供个性化服务的智能体

本质:目前 Agent 系统里最常用的语义记忆工程实现 这几种记忆方式不是只能用一种,实际使用中经常组合。比如用滑动窗口存短期上下文,向量记忆存长期用户偏好,再搭配摘要记忆定期压缩历史。

记忆系统的实现

考虑到难度和阅读体验,这里只用伪代码演示!

想让智能体拥有记忆能力,需要设计一个记忆管理系统,分为短期记忆和长期记忆两部分。下面是简化版伪代码,展示怎么保存和查询记忆,再把结果拼到提示词里。

图片

短期记忆

短期记忆说白了就是记住用户刚说过的话,但不能无限记,毕竟大模型的上下文窗口有限,塞太多不仅贵,还会让模型混乱。

最常用的方法就是滑动窗口,只保留最近 N 轮对话,超出的直接丢弃。

为什么留最近几轮?因为用户刚聊的内容,和当前问题关联性最强,更早的内容交给长期记忆处理就行。

代码实现上,用 Python 自带的 collections.deque 设置最大长度,新消息进来会自动把旧消息挤出去,很方便:

from collections import deque
class ShortTermMemory:
    def __init__(self, max_messages=20):
        """
        初始化短期记忆。
        :param max_messages: 最多保留的消息条数(而非对话轮数)。每条消息对应一个 role(user/assistant/tool)。
        """
        self.messages = deque(maxlen=max_messages)
    def add(self, message: dict):
        """添加一条消息到短期记忆。message 格式需符合 OpenAI 消息格式。"""
        self.messages.append(message)
    def get_all(self) -> list:
        """返回当前短期记忆中所有消息(按时间顺序)。"""
        return list(self.messages)
    def clear(self):
        self.messages.clear()

长期记忆

长期记忆用来存需要跨会话保留的信息,比如用户的旅行偏好、之前聊过的目的地、历史规划里的特殊要求等。这些信息不能用滑动窗口存,时间久了、对话多了就会被清掉。

长期记忆的经典实现是向量检索:把文本转成向量存进向量数据库,需要回忆时,把当前问题也转成向量,通过相似度找到最相关的历史内容。

为什么用向量检索?因为用户每次提问的说法都不一样,关键词匹配必须内容一致才能搜到,向量能捕捉语义相似性,比关键词更智能。

想让检索结果更靠谱,可以搭配问题重写、BM25 关键字查询,最后再用重排优化。

下面的代码用 Python 列表模拟向量数据库的存储和查询,实际项目可以换成 Chroma、FAISS、Pinecone 这些专业工具。embedding_model 可以用 sentence-transformers、OpenAI Embeddings、通义千问向量模型等。

import numpy as np
from typing import List, Dict
class LongTermMemory:
    def __init__(self, embedding_model):
        self.embedding_model = embedding_model
        self.vectors = []          # 存储向量
        self.texts = []             # 存储原始文本
        self.metadatas = []         # 存储元数据(如时间戳、重要性等)
    def _embed(self, text: str) -> np.ndarray:
        return self.embedding_model.encode(text)
    def add(self, text: str, metadata: dict = None):
        """将一段文本存入长期记忆。"""
        vector = self._embed(text)
        self.vectors.append(vector)
        self.texts.append(text)
        self.metadatas.append(metadata or {})
    def query(self, query_text: str, top_k: int = 3) -> List[str]:
        """根据查询文本,返回最相关的 top_k 条记忆文本。"""
        if not self.vectors:
            return []
        query_vec = self._embed(query_text)
        # 计算余弦相似度
        similarities = [
            np.dot(query_vec, v) / (np.linalg.norm(query_vec) * np.linalg.norm(v))
            for v in self.vectors
        ]
        top_indices = np.argsort(similarities)[-top_k:][::-1]
        return [self.texts[i] for i in top_indices]

记忆管理器(整合短期与长期)

记忆管理器专门负责管理记忆存储,还提供构建最终提示词的方法。核心逻辑是:

\1. 从短期记忆里拿到最近的对话历史

\2. 从长期记忆里检索和当前问题相关的背景知识

\3. 把长期记忆当成系统提示的一部分,短期记忆按顺序排列,最后加上当前用户输入,组成完整的 messages 列表 ``

class MemoryManager:
    def __init__(self, embedding_model, short_term_max_messages=20, long_term_top_k=3):
        self.short_term = ShortTermMemory(max_messages=short_term_max_messages)
        self.long_term = LongTermMemory(embedding_model)
        self.long_term_top_k = long_term_top_k
    def add_short_term(self, message: dict):
        self.short_term.add(message)
    def add_long_term(self, text: str, metadata: dict = None):
        # 实际应用中可在此处进行重要性过滤
        self.long_term.add(text, metadata)
    def build_messages(self, current_query: str, system_prompt_base: str = "") -> List[dict]:
        #  从长期记忆检索
        long_memories = self.long_term.query(current_query, top_k=self.long_term_top_k)
        #  构建最终的系统提示
        if long_memories:
            memory_context = "以下是可能与当前问题相关的历史记忆:\n" + "\n".join(f"- {mem}"for mem in long_memories)
            system_content = f"{system_prompt_base}\n\n{memory_context}"
        else:
            system_content = system_prompt_base
        #  获取短期记忆中的最近消息
        short_context = self.short_term.get_all()
        # 将消息组合到一起
        messages = [{"role": "system", "content": system_content}]
        messages.extend(short_context)
        messages.append({"role": "user", "content": current_query})
        return messages

在对话循环中使用记忆管理器

下面把记忆管理器集成到之前的旅行规划助手对话循环里,关键改动有这些:

  • 每次用户输入后,用 build_messages() 构造带记忆的上下文
  • 每次模型回复后,把用户消息和助手消息存进短期记忆
  • 在合适的时机,比如用户明确说偏好、生成最终规划后,把关键信息存进长期记忆
memory = MemoryManager(embedding_model=embedding_model)
system_base = "你是一位专业的旅游规划助手。你可以调用工具获取天气、景点、酒店和路线信息。"
tools = [...]  # 同之前的 Function Calling 工具定义
while True:
    user_input = input("用户:")
    if user_input.lower() in ("exit", "quit"):
        break
    # 构建带记忆的消息
    messages = memory.build_messages(user_input, system_prompt_base=system_base)
    # 工具调用循环(同之前)
    while True:
        response = client.chat.completions.create(
            model="deepseek-chat",
            messages=messages,
            tools=tools,
            tool_choice="auto"
        )
        assistant_msg = response.choices[0].message
        messages.append(assistant_msg)
        if not assistant_msg.tool_calls:
            final_answer = assistant_msg.content
            break
        for tool_call in assistant_msg.tool_calls:
            # 调用工具并追加结果(代码略,同前)
            # ...
            pass
    # 将本轮交互存入短期记忆
    memory.add_short_term({"role": "user", "content": user_input})
    memory.add_short_term({"role": "assistant", "content": final_answer})
    # 判断是否需要存入长期记忆
    # 示例:如果用户明确说了偏好,就存;否则不存。这里简单演示,实际可用模型判断。
    if"我喜欢"in user_input or "偏好"in user_input:
        memory.add_long_term(f"用户偏好:{user_input}", metadata={"type": "preference"})
    # 也可以将最终生成的旅游计划存入长期记忆
    if"规划"in user_input and final_answer:
        memory.add_long_term(f"旅游计划:{final_answer}", metadata={"type": "plan"})
    print(f"助手:{final_answer}")

这段伪代码展示了记忆系统的核心架构,大家可以根据实际业务需求,选择合适的记忆存储和检索方案。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐