记录下学习agent应用开发的第二天(上下文关联、保存会话内容、读取历史会话)

记录下学习agent应用开发的第二天(上下文关联、保存会话内容、读取历史会话)
各位访问大哥能否留一些宝贵建议给小弟没人的话就当个人日常vlog虽然第一天运行的聊天机器人可以跑通但是无法关联上下文文本不算是严格意义上的聊天只是单向的问答反馈。比如下面我让它解释了冒泡排序接着想让它举个例子但由于没有关联上下文机器人把“举个冒泡排序的例子”理解为让它举个学习知识点的例子。为了解决这个问题我在这个聊天机器人基础上创建了二代聊天机器人主要解决丢失上下文的问题。一代聊天机器人在接收用户的请求后调用api模型思考再输出每次只获取一条用户输入的文本内容思考也仅围绕这条内容进行。二代聊天机器人会提前创建一个历史记录表list每次用户和机器人的问答完毕后会把内容存入这个表下一次用户提问时所输入的文本内容会和这个list一起发送给机器人机器人就会根据历史会话和新请求文本来思考回答通过这种方式就实现了聊天机器人关联上下文文本。 day2: 带对话记忆的 AI 编程老师 新增 - 对话历史history 列表AI 能记住之前聊了什么 - !clear 命令清空记忆重新开始 import os from pathlib import Path from openai import OpenAI from dotenv import load_dotenv # day2 文件夹在项目根目录下.env 在根目录所以往上一级找 root Path(__file__).parent.parent # day2/ 的上一级 项目根目录 load_dotenv(root / .env) client OpenAI( api_keyos.getenv(DEEPSEEK_API_KEY), base_urlos.getenv(DEEPSEEK_BASE_URL), ) SYSTEM_PROMPT 你是一个编程老师名字叫小码。 规则 1. 用中文回答口语化像和朋友聊天一样 2. 解释概念时用通俗的例子不要堆术语 3. 如果用户让你写代码要逐行解释每一行是干什么的 4. 回答控制在 200 字以内除非用户明确要求详细 def chat(messages: list) - str: 把整段对话历史发给 AI返回回答 response client.chat.completions.create( modeldeepseek-v3.2, messagesmessages, temperature0.7, max_tokens800, ) return response.choices[0].message.content def main(): # 对话历史初始只有系统角色设定 history [ {role: system, content: SYSTEM_PROMPT} ] print( * 50) print( 小码 AI 编程老师 0.2 (quit 退出, !clear 清空记忆)) print( * 50) while True: user_input input(\n你: ).strip() if not user_input: continue if user_input.lower() in (quit, exit, q): print(小码: 再见! 有问题随时回来~) break if user_input !clear: history [{role: system, content: SYSTEM_PROMPT}] print([记忆已清空]) continue # 把用户消息加入历史 history.append({role: user, content: user_input}) print(小码: , end, flushTrue) try: answer chat(history) print(answer) # 把 AI 的回答也加入历史 history.append({role: assistant, content: answer}) except Exception as e: import traceback print(f\n出错了: {e}) traceback.print_exc() # 发失败了把刚才加入的用户消息移除 history.pop() if __name__ __main__: main()因为第一天创建的tutor.py文件和存api的文件.env在同一文件夹下所以可以同目录直接调用。第二天创建的tutor_v2.py文件放在项目文件夹下的新子文件夹里与.env文件不在同目录刚开始我是直接把.env的地址写进去ai优化后如下图让程序自己返回上级目录去找目标文件.env这样好处是在别的环境下也可以自己寻址而不用手动修改地址。我觉得这个细节对我有帮助也体现代码的可移植性。root Path(__file__).parent.parent # day2/ 的上一级 项目根目录 load_dotenv(root / .env)启动虚拟环境运行代码测试聊天机器人关联上下文功能通过。清空聊天内容测试机器人是否记忆清除的内容。结果是清空历史聊天后再和机器人互动相当于开启一个新的会话记录删除的内容不会污染新会话。不足的是历史记录只是存在内存里关掉程序后无法找回之前的内容。晚上还有时间我想着给这个聊天机器人加一个保存记忆功能每次启动它可以像豆包、千问等ai一样读取历史会话记录来延续之前的对话。我的思路是使用json来存用户和机器人的会话记录每次启动机器人时查看json文件的内容如果存在则读取后转为list类似上下文关联喂给模型模型就会基于json所存的记录来进行后面的会话在每次对话后一问一答程序会把整个历史记录list表转为json覆盖写入存储文件。用户手动清空聊天内容后json文件为空程序下一次运行时找不到历史会话记录就会按照正常提示词开启新会话。 day3: 能失忆后恢复的 AI 编程老师 新增 - 聊天记录自动存到 chat_history.json 文件 - 下次打开自动恢复之前的对话 import json import os from pathlib import Path from openai import OpenAI from dotenv import load_dotenv # 找到 .env在项目根目录day2 的上一级 root Path(__file__).parent.parent load_dotenv(root / .env) client OpenAI( api_keyos.getenv(DEEPSEEK_API_KEY), base_urlos.getenv(DEEPSEEK_BASE_URL), ) SYSTEM_PROMPT 你是一个编程老师名字叫小码。 规则 1. 用中文回答口语化像和朋友聊天一样 2. 解释概念时用通俗的例子不要堆术语 3. 如果用户让你写代码要逐行解释每一行是干什么的 4. 回答控制在 200 字以内除非用户明确要求详细 # 聊天记录存这个文件 HISTORY_FILE Path(__file__).parent / chat_history.json def load_history() - list: 从文件读取之前的聊天记录文件不存在就返回只有角色设定的新列表 if HISTORY_FILE.exists(): with open(HISTORY_FILE, r, encodingutf-8) as f: return json.load(f) else: return [{role: system, content: SYSTEM_PROMPT}] def save_history(history: list): 把聊天记录写入文件 with open(HISTORY_FILE, w, encodingutf-8) as f: json.dump(history, f, ensure_asciiFalse, indent2) def chat(messages: list) - str: 把整段对话历史发给 AI返回回答 response client.chat.completions.create( modeldeepseek-v3.2, messagesmessages, temperature0.7, max_tokens800, ) return response.choices[0].message.content def main(): # 启动时加载之前的聊天记录 history load_history() if len(history) 1: print(f[恢复了 {len(history) // 2} 轮历史对话]) print( * 50) print( 小码 AI 编程老师 0.3 (quit 退出, !clear 清空记忆)) print( * 50) while True: user_input input(\n你: ).strip() if not user_input: continue if user_input.lower() in (quit, exit, q): print(小码: 再见! 有问题随时回来~) break if user_input !clear: history [{role: system, content: SYSTEM_PROMPT}] save_history(history) print([记忆已清空]) continue history.append({role: user, content: user_input}) print(小码: , end, flushTrue) try: answer chat(history) print(answer) history.append({role: assistant, content: answer}) # 每次对话后立刻存盘 save_history(history) except Exception as e: import traceback print(f\n出错了: {e}) traceback.print_exc() history.pop() if __name__ __main__: main()我最初的想法是用户在完成会话准备退出的时候再一起存这样可以减少存储次数性能会高一点。但是我把代码给deepseek优化后它把存储频率改为每次问答后就存解释是避免断电、程序崩溃等情况下丢失会话数据。我认为这个改动很好因为我的方案节省下来的时间可以忽略不计这点开销不值一提。真正的取舍不是性能是丢不丢得起数据。下面就测试一下三代聊天机器人读取历史会话功能。第一次聊天会话内容关闭程序并查看json文件内容[ { role: system, content: 你是一个编程老师名字叫\小码\。\n规则\n1. 用中文回答口语化像和朋友聊天一样\n2. 解释概念时用通俗的例子不要堆术语\n3. 如果用户让你写代码要逐行解释每一行是干什么的\n4. 回答控制在 200 字以内除非用户明确要求详细 }, { role: user, content: 你好我叫小王 }, { role: assistant, content: 你好小王我是小码老师很高兴认识你今天想学点什么编程知识吗 }, { role: user, content: python特点 }, { role: assistant, content: Python就像“编程界的乐高”特点就是简单好玩\n\n1. **简单易懂**代码像英语句子比如 print(\你好\)\n2. **功能强大**能做网站、数据分析、AI啥都行\n3. **免费开源**谁都能用还有超多现成“积木”库\n\n就像用积木搭房子Python让你用很少的代码做很多事想试试写第一行代码吗 } ]第二次聊天会话内容总结第二天我给聊天机器人添加了关联上下文、保存会话内容并继续历史会话的功能。通过创建临时的list存上下文内容来实现上下文关联但是关闭程序后占用的内存返还给系统临时的会话内容就丢失了。于是我用json来存历史会话记录每次对话一问一答后就把整个历史记录表list(包括之前的所有会话内容)转为json覆写原文件。今天我在学习和写代码过程中收获最大的就是真正的取舍不是性能是丢不丢得起数据这句话因为我还保留着学生思维虽然现在还真是学生去优化代码没从实际用户体验出发考虑未知因素带来的影响今后我会多加注意。第二天就到这里吧。