零基础学 Agent :记忆系统——让 Agent 认识你的客户 第 4 期

0 阅读20分钟

图片

大家好,我是AI淇橦学。

上期我们做出了第一个能真正跑通的工具模块——读模板、填内容、保存文件,整个流程在终端里跑起来了。

但仔细想想,第3期的程序里其实没有任何「AI」——write_content 做的只是字符串替换,把【客户名称】换成「深圳科技有限公司」,这是最普通的文本处理,和 AI 没有关系。

这一期我们做两件事:

第一件:接入大模型 API,给 Agent 装上真正的 AI 大脑。  从这期开始,Agent 里的决策和理解,都由真实的大模型来完成。

第二件:给 Agent 装上记忆系统。  建立客户资料知识库,输入「深圳那家做传感器的」,大模型理解你的意思,找到对应客户,自动填写报价单。

做完这期,你会得到:

  • 一个封装好的 llm.py 模块,可以调用国产大模型(本教程使用智谱 GLM 的 glm-4-flash
  • Agent 能记住你的使用偏好(不用每次重新配置)
  • 客户资料知识库,用大模型做语义理解,输入关键词自动匹配客户
  • 在终端里演示:说「深圳科技」,大模型理解后找到客户,自动完成报价单填写

一、AI 为什么没有记忆——上下文窗口

图片

在动手之前,先把一个底层概念说清楚,否则后面的设计你会看不懂为什么要这么做。

把 AI 的工作状态想象成一张桌面。你说的话、AI 的回复、工具执行的结果,全都摆在这张桌面上。

问题是:这张桌面面积有限。  内容太多,最早放上去的东西就会被推掉——AI 就「忘记」了。这个桌面大小叫「上下文窗口」,以 Token 计量(约 1 个汉字 = 1.5 个 Token),不同模型上限不同,但都有上限。

更关键的是:每次对话结束,桌面清空。  下次打开程序,是全新的空桌面,上次的一切不见了。

这就是 AI 「没有记忆」的本质——不是忘了,是根本没有地方存。

所以,要给 Agent 加记忆,必须由我们自己来设计「存在哪里、什么时候取出来用」。


二、三种记忆类型,分别解决不同问题

记忆问题没有一个万能方案,针对不同场景有三种机制:

第一种:短期记忆

就是当次任务的上下文。Agent 在处理一份报价单的过程中,记住「已经填了哪些字段、还剩哪些没填」——任务完成后这些信息就可以丢弃了。这种记忆第3期的程序里已经天然存在,不需要额外设计。

第二种:长期记忆

把重要的配置信息存入本地文件,下次启动程序还在。比如:你的模板文件夹路径、日期格式偏好、默认报价有效期……这些信息不应该每次都要重新告诉 Agent。

第三种:知识库记忆(RAG)

你有几十个客户的资料,不可能每次都全部读进来让 AI 处理(Token 不够用)。RAG 的作用是:建一个可以搜索的客户资料库,你说「深圳科技」,它自动找到最匹配的客户信息。

这一期我们把第二种和第三种都做出来。


三、RAG 是什么——用档案柜来理解

图片

RAG = Retrieval Augmented Generation,检索增强生成。名字拗口,但思路很简单:

💡 一句话理解:在 AI 执行任务之前,先从你的资料库里找到最相关的内容,一起交给 AI 参考——让它基于真实资料工作,而不是靠猜。

用生活场景类比:你有一个装了几百份文件的档案柜。每次需要某份文件时,不是把整个档案柜搬给助理(搬不动),而是先在档案柜里找到最相关的那几份,只把这几份给助理参考。RAG 做的就是这件事——自动地、快速地从大量文档里找到最相关的内容。

RAG 的完整 5 步流程:

① 切片:把每份客户资料切成小段,保留「来自哪个文件」的信息

② 向量化:把每段文字转换成一串数字(向量),代表这段文字的「语义指纹」。语义相近的文字,数字也相近——「深圳科技有限公司」和「深圳那家做传感器的」的向量比「深圳科技」和「北京餐饮公司」的向量近得多

③ 存入向量数据库:把所有向量存进专门的数据库,建好索引。这步只做一次

④ 检索:你输入「深圳科技」,这句话也被转成向量,在数据库里找距离最近的片段

⑤ 生成:把找到的客户资料 + 你的指令一起交给 AI,AI 基于真实资料来填报价单

为什么不直接用关键词搜索?

关键词搜索只找包含完全相同词语的内容。你搜「深圳科技」,找不到备注里写的「那家做工业传感器的深圳客户」。

语义搜索理解含义——「深圳科技」「深圳那家传感器公司」「SZ科技」在语义上都很接近,都能被找到。对销售场景来说,你经常只记得客户的片段信息,语义搜索能帮你找到,关键词搜索找不到。


四、接入国产大模型 API

重要说明:  这一期我们需要调用大模型 API,会消耗少量 API 费用(建议预留 5-10 元测试预算)。如果你暂时不想花钱,可以跳过这一期,直接看第 5 期。

国产大模型有很多选择,推荐以下几款(任选其一即可):

模型厂商API 文档特点
智谱 GLM智谱AIopen.bigmodel.cn/dev/api开发友好,免费额度较多,本教程使用
豆包字节跳动www.volcengine.com/docs/82379性价比高,文档清晰,适合新手
通义千问阿里云help.aliyun.com/zh/model-st…功能完善,企业级稳定性
文心一言百度cloud.baidu.com/doc/WENXINW…中文理解能力强

这期我以智谱 GLM 为例,使用 `glm-4.7 模型(其他模型流程类似,只是 API 调用方式不同)。


步骤 1:注册并获取 API Key

以智谱 GLM 为例:

  1. 打开 智谱AI开放平台
  2. 注册/登录账号
  3. 进入「API Key 管理」
  4. 创建新的 API Key,复制保存(只显示一次,务必保存好)

⚠️ 重要提示:API Key 相当于你的密码,不要泄露给他人,不要上传到公开的 GitHub 仓库。


步骤 2:封装 llm.py 模块

打开 Codex,,发送以下提示词:


📋 发给 Codex 的提示词(直接复制使用):

123456789101112131415161718192021222324252627282930帮我创建一个 llm.py 文件,封装智谱 GLM API 调用。
 
【使用智谱 GLM API】
- API 地址:https://open.bigmodel.cn/api/paas/v4/chat/completions
- 模型:glm-4-flash(智谱最新模型,速度快、成本低)
- 不使用 SDK,直接用 requests 库调用 API
 
【需要实现的函数】
 
1. chat(messages, model="glm-4-flash")
   - 输入:messages 列表,格式为 [{"role": "user", "content": "..."}]
   - 使用 requests 库调用智谱 API
   - 请求头:Authorization: Bearer {API_KEY}
   - 请求体:{"model": model, "messages": messages}
   - 返回:模型的文本回复(字符串)
   - 打印:API 调用的 token 使用情况
   - 错误处理:网络超时、API 错误、返回格式错误等
 
2. encode_text(text)
   - 输入:一段文本
   - 调用智谱的 embedding API(如果有的话),或者用 chat 模型生成文本摘要
   - 返回:文本的向量表示(list of floats)
   - 如果没有 embedding API,可以暂时用简单的文本哈希代替
 
【技术要求】
- 使用 requests 库(Python 标准库,无需安装额外依赖)
- 代码有清晰的中文注释
- 每个函数要有错误处理(网络超时、API 错误等)
- API Key 从环境变量读取(os.getenv("ZHIPU_API_KEY")),不要硬编码
- 设置合理的超时时间(30秒)

Codex 生成代码后,在终端里设置环境变量:

Windows:

1set ZHIPU_API_KEY=你的API_Key

Mac/Linux:

1export ZHIPU_API_KEY=你的API_Key

然后运行测试:

1python llm.py

如果看到正常的返回结果,说明 API 接入成功。


五、实操开始:给 Agent 装上记忆系统

现在动手。我们在第3期的 sales-agent 项目基础上继续,不需要新建项目。

这期的实操分 4 步:

  1. 建立长期记忆——用配置文件存偏好设置
  2. 准备客户资料文件
  3. 用 Codex 生成知识库模块(基于大模型的 RAG)
  4. 测试:输入客户关键词,大模型自动匹配客户,完成报价单填写

第一步:建立长期记忆(配置文件)

把下面这段内容复制进去,根据你的实际情况修改:

12345678910{
  "template_folder": "templates",
  "output_folder": "output",
  "date_format": "YYYY年MM月DD日",
  "currency_format": "人民币",
  "quote_validity_days": 30,
  "company_name": "你的公司名称",
  "salesperson_name": "你的名字",
  "contact_phone": "你的联系电话"
}

📌 把 公司名称你的名字联系电话 改成你自己的真实信息。这些信息会自动填入每份报价单。

这个文件就是 Agent 的「长期记忆」——每次启动程序,它都会先读取这个文件,知道你的偏好设置,不需要你重新告诉它。


第二步:准备客户资料文件

在 sales-agent 文件夹里新建一个子文件夹,命名为 customers

然后在 customers 文件夹里新建一个文件 客户资料.json,把下面的内容复制进去(这是示例数据,之后可以换成你真实的客户)

当然,这个地方你也可以交给Codex去做,我这样是为了让你初次学习体验一下,你可以专门的创建一个客户资料,直接告诉Codex帮你保存就可以。

1234567891011121314151617181920212223242526272829303132333435[  {    "id""C001",    "company_name""深圳科技有限公司",    "contact_person""李总",    "contact_phone""138-0001-0001",    "industry""工业传感器制造",    "address""广东省深圳市南山区科技园",    "notes""主要采购工业传感器套件,对价格敏感,付款周期30天",    "last_quote""2025-03-15",    "preferred_products": ["XS-2000B传感器""XS-3000控制模块"]
  },
  {
    "id": "C002",
    "company_name""上海贸易集团",
    "contact_person""王经理",
    "contact_phone""139-0002-0002",
    "industry""进出口贸易",
    "address""上海市浦东新区陆家嘴",
    "notes""批量采购为主,要求交货期不超过15天,开具增值税发票",
    "last_quote""2025-04-20",
    "preferred_products": ["XS-1000基础套件"]
  },
  {
    "id": "C003",
    "company_name""北京智能装备公司",
    "contact_person""张总",
    "contact_phone""136-0003-0003",
    "industry""智能制造设备",
    "address""北京市朝阳区望京",
    "notes""注重产品稳定性和售后服务,预算充足,决策周期较长",
    "last_quote""2025-05-01",
    "preferred_products": ["XS-3000控制模块""XS-4000高精度套件"]
  }
]

📌 你之后可以随时往这个文件里加更多客户,每次加完,重新运行一次「建立知识库」的命令,新客户就会被纳入搜索范围。

你的文件夹结构现在应该是这样的:

12345678sales-agent/
├── templates/
│   └── 报价单模板.docx
├── output/
├── customers/
│   └── 客户资料.json
├── config.json
└── agent.py

第三步:用 Codex 生成知识库模块(基于大模型)

图片

打开 Codex,然后把下面这段提示词发给 Codex:


📋 发给 Codex 的提示词(直接复制使用):

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354我在做一个销售报价单 Agent,现在需要给它加一个记忆模块,
文件名是 memory.py,请帮我实现以下功能:
 
【背景说明】
- 项目结构:customers/客户资料.json 存放客户信息,config.json 存放配置
- 客户资料是一个 JSON 数组,每个客户有:id、company_name、contact_person、
  contact_phone、industry、address、notes、last_quote、preferred_products
- 我需要能通过自然语言描述来搜索客户,比如「深圳科技」或「做传感器的那家」
- 使用大模型 API 来做语义理解和匹配(已封装好的 llm.py)
 
【需要实现的功能】
 
1. load_config()
   - 读取 config.json,返回配置字典
   - 如果文件不存在,返回默认配置并打印提示
   - 打印:已加载配置
 
2. load_customers()
   - 读取 customers/客户资料.json,返回客户列表
   - 打印读取到的客户数量
 
3. search_customer_with_llm(query, customers, llm_func)
   - 输入:搜索关键词(自然语言描述)、客户列表、大模型函数
   - 构造提示词:让大模型根据客户资料,找到最匹配的客户
   - 提示词模板:
     """
     以下是客户资料列表:
     {客户列表,每个客户一行,包含 id、company_name、industry、notes}
 
     用户搜索:{query}
 
     请根据以上客户资料,找到最匹配的用户搜索意图的客户。
     返回格式:只返回客户ID,例如:C001
     """
   - 调用 llm.chat() 发送请求
   - 解析大模型返回的客户ID
   - 返回:匹配到的客户对象(如果找不到返回 None)
   - 打印:搜索「xxx」,找到客户:公司名
 
4. save_quote_history(customer_id, output_file, config)
   - 把本次报价记录追加写入 customers/报价历史.json
   - 记录内容:客户ID、输出文件名、时间戳
   - 打印:已记录本次报价历史
 
【在文件末尾加一个演示函数 demo_search()】
- 加载配置和客户数据
- 依次搜索三个关键词:「深圳科技」「上海贸易」「智能制造」
- 打印每次搜索结果,展示找到了哪个客户
 
【技术要求】
- 从 llm.py 导入 chat 函数
- 代码有清晰的中文注释
- 每个函数要有错误处理
- 大模型调用失败时提供友好的错误提示

Codex 直接生成并创建 memory.py

测试知识库是否正常:  在终端里运行:

1python memory.py

你应该看到类似这样的输出:

图片


第四步:把记忆系统接入主程序

现在把 memory.py 和第3期的 agent.py 连接起来,让整个流程变成:

输入客户关键词 → 大模型理解并搜索客户资料 → 自动填写报价单 → 保存新文件

打开 Codex 对话框,把下面这段提示词发给Codex(这次是修改 agent.py):


📋 发给 Codex 的提示词(直接复制使用):

12345678910111213141516171819202122232425262728293031323334353637383940请帮我修改 agent.py,把记忆系统接入主流程。
 
【当前状态】
- agent.py 里有三个工具函数:read_file、write_content、save_file
- memory.py 里有记忆模块:load_config、load_customers、search_customer_with_llm、save_quote_history
- llm.py 提供了 chat() 函数,可以调用大模型
 
【需要修改的内容】
把 agent.py 底部的 main() 函数改成新的交互流程:
 
1. 启动时自动加载配置(load_config)和客户数据(load_customers)
   - 打印:Agent 启动中,正在加载配置和客户数据...
 
2. 读取报价单模板,打印找到的占位符列表
 
3. 在终端提示用户输入:「请输入客户名称或关键词(例如:深圳科技、上海那家贸易公司):」
 
4. 用 search_customer_with_llm 搜索客户,传入 llm.chat 函数
   - 找到客户后,打印:找到客户「xxx」,是否使用?(y/n)
   - 用户确认后继续
 
5. 从客户资料自动提取填写信息:
   - 客户名称 → company_name
   - 联系人 → contact_person
   - 联系电话 → contact_phone
   - 报价日期 → 今天的日期(用 config 里的 date_format 格式)
   - 销售员 → config 里的 salesperson_name
   - 其他模板里有但客户资料没有的字段(如产品名称、报价金额)→ 在终端提示用户手动输入
 
6. 调用 write_content 填写内容,调用 save_file 另存为新文件
   - 文件名格式:报价单_{客户名称}_{日期}.docx
 
7. 调用 save_quote_history 记录本次操作
 
8. 打印完成提示:✅ 报价单已生成:output/报价单_xxx_xxx.docx
 
【注意】
- 从 memory.py 和 llm.py 导入需要的函数
- 产品名称、报价金额这类每次都不同的字段,用 input() 让用户在终端输入
- 代码要有清晰的中文注释

Codex 修改完 agent.py 后,在终端里运行:

1python agent.py

你会看到类似这样的交互过程:

1234567891011121314151617181920212223242526🚀 Agent 启动中,正在加载配置和客户知识库...
✅ 已加载配置
✅ 已读取 3 个客户,知识库建立完成
 
📋 读取模板:templates/报价单模板.docx
   找到待填写字段 8 个:【客户名称】【联系人】【联系电话】【报价日期】
   【产品名称】【产品型号】【报价金额】【备注】
 
请输入客户名称或关键词:深圳科技
 
🔍 搜索中...
   找到客户「深圳科技有限公司」(匹配度:82%)
   联系人:李总 | 电话:138-0001-0001
   是否使用该客户?(y/n):y
 
✅ 已自动填入客户信息
   需要手动输入以下字段:
   产品名称:工业传感器套件
   产品型号:XS-2000B
   报价金额:58,000元
   备注:含安装调试服务
 
✏️ 正在填写报价单...
💾 正在保存文件...
✅ 报价单已生成:output/报价单_深圳科技有限公司_2025年615日.docx
📝 已记录本次报价历史

第五步:验收结果

运行完成后,做以下检查:

功能验收:

  • 输入「深圳科技」能正确找到「深圳科技有限公司」
  • 输入「上海贸易」能正确找到「上海贸易集团」
  • 客户的名称、联系人、电话自动填入,无需手动输入
  • 手动输入的字段(产品、金额)能正确填入对应位置
  • output 文件夹里生成了新文件,文件名包含客户名和日期
  • 原始模板文件内容未被修改
  • customers/报价历史.json 里有本次操作的记录

现在你的 Agent 有了记忆:  它认识你的客户,知道你的配置偏好,用大模型理解你的意图,并且会记录每次报价历史。


六、遇到问题怎么办

情况一:搜索结果不准确,找到了错误的客户

在 Codex 对话框里说:「search_customer_with_llm 搜索『深圳科技』时返回了错误的客户,请优化提示词,要求大模型仔细对比 company_name 和 notes 字段」

情况二:API 调用失败,提示认证错误

检查环境变量是否设置正确:

12345# Windows
echo %ZHIPU_API_KEY%
 
# Mac/Linux
echo $ZHIPU_API_KEY

确认 API Key 没有过期,且有足够的额度。

情况三:大模型返回格式不正确

在 Codex 对话框里说:「大模型返回的内容不是纯客户ID,而是一段话,请优化提示词,强调只返回客户ID(如 C001),不要返回其他内容」

情况四:客户资料.json 读取失败

确认文件路径:customers/客户资料.json,注意文件夹名是 customers,JSON 格式要正确(可以把文件内容粘贴到 jsonlint.com 检查格式是否正确)

情况五:日期格式显示不对

在 Codex 对话框里说:「报价日期显示的是 2025-06-15 这种格式,但我希望是 2025年6月15日,请修改日期格式化的代码,读取 config.json 里的 date_format 配置来决定格式」


七、这期做了什么——小结

这期你给 Agent 做了三件事:

第一件:接入了国产大模型 API

  • 封装了 llm.py 模块,可以调用智谱 GLM/豆包/通义千问等国产大模型
  • 本教程使用智谱 GLM 的 glm-4-flash 模型,不依赖 SDK,直接用 requests 调用
  • 从此以后,Agent 的决策和理解都由真实的大模型来完成,不再是简单的字符串替换

第二件:装上了两层记忆

  • 长期记忆(config.json):记住你的配置偏好,每次启动自动加载
  • 客户知识库(RAG):存放客户资料,用大模型做语义理解,输入关键词自动匹配

第三件:实现了智能客户搜索

  • 你输入「深圳科技」或「那家做传感器的」,大模型理解你的意思
  • 从客户资料库里找到最匹配的客户,自动填入报价单

现在的流程是:你输入客户关键词 → 大模型理解并搜索客户 → 自动填入已知信息 → 你只需要补充产品和金额 → 生成报价单。

坦白说,做完这个功能之后,我觉得效率提升挺明显的。以前每次都要改代码里的客户信息,现在只需要输入一个模糊的关键词,大模型就能理解并自动匹配,省了不少时间。

这个方案特别适合的场景:

  • 客户数量超过 10 个,经常需要复用客户信息
  • 客户信息比较复杂(公司名、联系人、地址、备注等)
  • 你经常只记得客户的部分信息(比如「深圳那家做传感器的」)
  • 需要大模型理解你的自然语言表达,而不是精确匹配关键词

但现在还有一个问题:每次只能处理一个客户。如果你有 10 份报价单要做,还是要跑 10 次程序。下期我们来解决这个问题——给 Agent 加上规划能力,让它自己制定计划、批量处理多份报价单,你只需要告诉它「帮我处理这 10 个客户的报价单」,它自己把事情做完。


下期预告:  现在你每次只能处理一个客户。如果你有一批客户要同时出报价单,Agent 能不能自己规划步骤、批量搞定?第5期我们来做这件事——让 Agent 学会「自己想清楚要做什么,再去做」,从「你推一步它走一步」变成「你说目标,它自己做完」。

思考题:  你试着往 客户资料.json 里加了你真实的客户信息吗?用大模型搜索的时候准确吗?你用的是哪款国产大模型?体验如何?评论告诉我。


关注公众号「AI淇橦学」,和 AI 一起成长。

有问题或建议?后台留言即可。