ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从零搭建带知识库与长期记忆的AI智能体:原理与代码实现

从零搭建带知识库与长期记忆的AI智能体:原理与代码实现 随着今年“智能体”概念持续升温身边很多同学都在尝试搭建自己专属的 AI 智能体。有人用它做客服问答有人用它做内容创作助手也有人想做一个既能回答问题、又能主动帮你记忆知识的学习型智能体。今天这篇文章我打算从“记住谁发明了钢琴键”这个具体场景切入完整拆解一个带知识库和长期记忆的智能体是如何设计与实现的。之所以选“钢琴键发明”这个素材是因为它属于典型的事实型知识问答答案明确、背景丰富、适合做记忆测试。通过这个案例你可以把整套思路直接迁移到历史、法律、医学、产品说明书等任何知识密集型场景。文章包含三部分内容第一记忆型智能体的设计思路第二一套完整的 Python 可运行代码第三Dify、Coze 等低代码平台的可选搭建路径。文末还整理了一份常见问题排查清单和最佳实践建议后端初学者、AI 应用开发者、产品经理都能在文章里找到自己需要的内容。1. 项目背景为什么需要做一个“知识记忆智能体”1.1 从钢琴键的发明说起先来说一个很多人并不陌生的知识点现代钢琴的发明者是意大利人巴托洛梅奥·克里斯托福里Bartolomeo Cristofori大约在 1700 年前后他在佛罗伦萨为美第奇家族制作了第一架钢琴。这架钢琴最初的名字叫“gravicembalo col piano e forte”意思是“能弹奏弱音和强音的羽管键琴”。之所以叫钢琴Piano正是因为它首次实现了通过手指触键力度来控制音量强弱能做到 piano弱和 forte强的动态变化。至于黑白相间的钢琴键布局其实继承自更早的羽管键琴和管风琴键盘体系并不是钢琴发明时才凭空出现的。如果我要做一个“记住谁发明了钢琴键”的智能体它需要处理的问题就不仅是简单回答“克里斯托福里”还要能够识别用户不同方式的提问例如“钢琴是谁发明的”“钢琴键的历史”“piano forte 是什么”把相关背景知识组织成一段自然流畅的回答在学习过程中记录用户对哪些知识已经掌握、哪些还容易记错根据记忆情况主动出题帮助用户巩固。这就不是一段简单的 if-else 脚本能完成的了而是一个典型的“知识检索 记忆管理 多轮对话”智能体。1.2 记忆型智能体能解决什么问题我们把问题再放大一点看。过去我们做问答系统无非两条路规则匹配写大量的关键词规则命中就返回答案。优点是简单缺点是维护成本高问法一变就失效。大模型直接问答把问题丢给 GPT、文心一言、通义千问这类大模型。优点是理解能力强缺点是模型可能“编造”知识对私有知识或固定事实的准确性没有保障。记忆型智能体则把两者结合起来先用本地知识库保存权威、准确的事实信息再用大模型做语言理解和回答组织最后用一套持久化存储记录用户的学习历史和偏好。这样既保证了回答有据可依又能让智能体越用越懂你。具体到“钢琴键历史”这个场景记忆型智能体要解决的核心痛点有三个第一事实准确性。大模型可能不清楚“克里斯托福里”这个相对冷门的人名但本地知识库可以保证答案来源稳定。第二个性化记忆。不同用户学习进度不同有人刚入门有人已经了解钢琴发展史。智能体需要记住每个人的水平并做对应的出题和讲解。第三长期记忆。聊天窗口一关记忆不能丢。我们要把用户的学习记录持久化到数据库下一次对话还能继续。1.3 技术路线选择目前搭建知识记忆智能体主要有两条路线路线代表平台/技术适合人群特点低代码平台Dify、Coze扣子、字节跳动的智能体平台产品经理、运营、快速验证拖拽式编排知识上传即用无需写复杂代码代码开发Python 向量检索 大模型 API后端开发者、算法工程师灵活可控容易集成到自有系统这两条路线我都在实际项目中用过。低代码平台胜在快上传一篇知识文档、配置一个 prompt 模板一个基础智能体几分钟就能跑通代码开发则适合需要精细控制记忆逻辑、需要对接内部系统的场景。本文的核心演示会采用 Python 代码实现方便你从头理解智能体的工作原理。在第五章我也会补充低代码平台的实现思路让你两种方案都能上手。2. 环境准备与项目结构2.1 运行环境在开始写代码之前先列一下本文示例所需的运行环境。版本不需要完全一致只要不是相差太大都能跑通操作系统Windows 10/11、macOS、Linux 均可Python 版本3.9 及以上Python 第三方库requests用于调用大模型 API可选数据库SQLitePython 自带不需要额外安装IDE 或编辑器PyCharm、VS Code 均可。说明一下本文的代码核心部分不依赖任何第三方大模型 SDK我尽量使用 Python 标准库完成。只有 4.5 节的“接入大模型增强回答”部分使用 requests 调用 HTTP API。如果你只想看纯本地方案可以跳过那一小节。2.2 项目目录结构我建议你把整个项目放在一个独立目录中结构如下piano_history_agent/ ├── agent.py # 智能体主程序 ├── knowledge.json # 知识库文件 ├── memory.db # SQLite 记忆数据库首次运行后生成 ├── requirements.txt # 第三方依赖清单 └── README.md # 项目说明文档其中agent.py是完整可运行的智能体程序包含知识检索、记忆存储、对话回答、主动测验四个模块knowledge.json保存钢琴历史和钢琴键相关的结构化知识条目memory.db是 SQLite 数据库用于持久化用户学习记录requirements.txt仅记录 requests 这一个第三方库方便后续扩展。2.3 初始化依赖在项目目录下执行下面命令创建虚拟环境并安装依赖cd piano_history_agent python -m venv venv source venv/bin/activate # Windows 下请使用 venv\Scripts\activate pip install requests如果你想把依赖保存到 requirements.txt可以执行pip freeze requirements.txt到这里环境就准备好了。接下来进入关键部分智能体的核心设计。3. 核心设计知识库、记忆与检索在动手写代码前我们先把架构想清楚。下面是一张简化的模块关系图用文字形式表达用户提问 ↓ 输入预处理分词、清洗 ↓ 知识检索模块knowledge search ↓ 回答生成模块大模型 or 模板 ↓ 输出回答 ↓ 记忆更新写入 SQLite ↓ 主动测验根据记忆状态选题整个智能体由四层组成3.1 知识库层知识库层负责保存智能体“知道”的事实型知识。对于钢琴历史这个场景我会把知识条目设计成 JSON 结构每个条目包含 id、标题、关键词集合和正文内容。例如{ id: piano_inventor, title: 钢琴发明者, keywords: [钢琴, 发明, 克里斯托福里, 巴托洛梅奥], content: 现代钢琴由意大利人巴托洛梅奥·克里斯托福里于1700年前后发明…… }知识库和向量数据库的区别在于知识库只是一个普通的 JSON 文件或关系表回答通过关键词匹配来检索向量数据库则会把文本转成向量用余弦相似度召回最相关的片段。本文先实现一个不依赖外部服务的知识库体现核心原理。如果知识量超过几千条建议后续切换为向量检索方案。3.2 记忆层记忆层是“记住”二字的实现关键。它需要做到记录用户曾经问过的问题记录每道题目回答正确还是错误根据准确率生成下一次复习题目数据写入 SQLite重启程序也不丢失。这里我用一张简单的表来设计记忆字段字段名类型含义idINTEGER自增主键user_idTEXT用户标识questionTEXT提问内容answerTEXT回答内容is_correctINTEGER是否正确1 表示正确0 表示错误created_atTEXT创建时间记忆层不需要做成复杂的图数据库。对一个演示级智能体来说SQLite 足够而且便于查看和排查。3.3 检索与匹配层检索层负责根据用户输入找出最合适的知识条目。核心思路是对用户问题做简单清洗把问题拆成若干个关键词遍历知识库计算每条知识的匹配得分返回得分最高的条目。如果最高得分低于某个阈值则返回“未找到答案”并提示用户补充更多信息。这样能避免智能体在不知道答案时强行输出内容。在 4.5 节接入大模型后检索层只负责“找到证据”大模型负责“生成回答”两者职责分离。4. 完整代码实现下面进入文章的实操核心部分。我会把完整可以运行的代码拆成多个小节逐段解释。你也可以直接复制组合出一个完整的agent.py文件。4.1 准备知识库数据先创建knowledge.json文件。这个文件存放钢琴历史的核心事实。为了演示效果我准备了 6 条知识覆盖钢琴发明、钢琴键布局、钢琴名称由来、钢琴键数量等多个角度[ { id: piano_inventor, title: 钢琴的发明者, keywords: [钢琴, 发明, 克里斯托福里, 巴托洛梅奥, 意大利], content: 现代钢琴由意大利人巴托洛梅奥·克里斯托福里Bartolomeo Cristofori于1700年前后发明。他长期在佛罗伦萨为美第奇家族制作乐器最初将新乐器命名为gravicembalo col piano e forte。 }, { id: piano_key_history, title: 钢琴键的历史, keywords: [钢琴键, 键盘, 黑键, 白键, 历史], content: 钢琴键的黑白布局并非钢琴发明时独创而是沿用了更早的羽管键琴和管风琴键盘体系。钢琴键的排列方式经历了数百年演进才形成今天的七白五黑十二个半音格局。 }, { id: piano_name_meaning, title: 钢琴名称的由来, keywords: [钢琴, 名称, piano, forte, 弱音, 强音], content: 钢琴在意大利语中写作pianofortepiano表示弱音forte表示强音。因为钢琴能够通过手指触键力度控制音量强弱所以用这两个词命名这是它区别于羽管键琴等早期键盘乐器的关键特征。 }, { id: piano_black_keys, title: 钢琴黑键的作用, keywords: [钢琴, 黑键, 半音, 升降号, 作用], content: 钢琴黑键代表半音每个八度内有五个黑键分别对应C#/Db、D#/Eb、F#/Gb、G#/Ab、A#/Bb。黑键的出现让钢琴可以演奏升降音和转调是音乐表现力扩展的重要设计。 }, { id: piano_88_keys, title: 现代钢琴的88键标准, keywords: [钢琴, 88键, 白键, 黑键, 标准], content: 现代钢琴通常有88个琴键包含52个白键和36个黑键覆盖从A0到C8共7又1/4个八度。88键标准在19世纪后期逐渐固定下来兼顾了演奏曲目范围和琴体尺寸的平衡。 }, { id: cristofori_legacy, title: 克里斯托福里的贡献与遗留, keywords: [克里斯托福里, 钢琴, 发明, 贡献, 美第奇], content: 克里斯托福里共存活下来的钢琴大约只有三架其中最著名的一架约1720年制造现藏于美国纽约大都会艺术博物馆。他发明的击弦机结构奠定了现代钢琴的基础。 } ]这个知识库的设计有三个好处每条知识带有关键词数组方便程序做匹配字段命名清晰后续如果换用向量数据库可以直接复用 id 和 content 字段内容覆盖了“谁发明”“怎么发展”“为什么叫钢琴”等常见问题。4.2 初始化记忆数据库接下来写数据库初始化函数。SQLite 是 Python 内置模块不需要额外安装。我们只需要执行一条建表语句即可。import sqlite3 import os DB_PATH os.path.join(os.path.dirname(os.path.abspath(__file__)), memory.db) def init_db(): conn sqlite3.connect(DB_PATH) cursor conn.cursor() cursor.execute( CREATE TABLE IF NOT EXISTS memory_records ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT NOT NULL, question TEXT NOT NULL, answer TEXT NOT NULL, is_correct INTEGER DEFAULT 0, created_at TEXT DEFAULT (datetime(now, localtime)) ) ) conn.commit() conn.close() print(记忆数据库初始化完成, DB_PATH) if __name__ __main__: init_db()这里要说明几个设计细节使用IF NOT EXISTS防止重复建表保留created_at时间戳后续可以做复习间隔分析user_id字段用于区分多用户防止不同用户的学习记录互相干扰。4.3 实现知识检索模块知识检索是整个智能体的核心。我在这里实现一个基于关键词权重打分的简化算法import json import os import re KNOWLEDGE_PATH os.path.join(os.path.dirname(os.path.abspath(__file__)), knowledge.json) def load_knowledge(): with open(KNOWLEDGE_PATH, r, encodingutf-8) as f: return json.load(f) def preprocess_text(text): 简单清洗去掉标点、统一小写 text text.lower() text re.sub(r[^\w\u4e00-\u9fa5], , text) return text.strip() def search_knowledge(question, top_k1): 根据问题关键词检索知识库返回得分最高的知识条目 knowledge load_knowledge() question_clean preprocess_text(question) question_tokens set(question_clean.split()) results [] for item in knowledge: score 0 for kw in item.get(keywords, []): kw_clean preprocess_text(kw) for token in question_tokens: if token and (token in kw_clean or kw_clean in token): score 1 results.append((score, item)) results.sort(keylambda x: x[0], reverseTrue) if not results or results[0][0] 0: return None return [item for score, item in results[:top_k]]这段代码做了什么load_knowledge()从 JSON 文件加载知识库preprocess_text()去掉标点、统一小写让匹配更稳定search_knowledge()遍历知识库用关键词重叠程度打分。虽然这个匹配逻辑比较朴素但你已经能看到检索模块的基本思想。实际项目中关键词打分可以替换成 BM25、TF-IDF、向量余弦相似度等方式整体架构不会变。4.4 实现记忆写入与复习规划记忆模块负责两件事记录用户每一次问答是否答对以及根据错误次数生成复习建议。def save_memory(user_id, question, answer, is_correct): conn sqlite3.connect(DB_PATH) cursor conn.cursor() cursor.execute( INSERT INTO memory_records (user_id, question, answer, is_correct) VALUES (?, ?, ?, ?), (user_id, question, answer, 1 if is_correct else 0) ) conn.commit() conn.close() def get_wrong_questions(user_id, limit5): 获取用户近期答错的题目用于复习 conn sqlite3.connect(DB_PATH) cursor conn.cursor() cursor.execute( SELECT question, answer, COUNT(*) as error_count FROM memory_records WHERE user_id ? AND is_correct 0 GROUP BY question ORDER BY error_count DESC LIMIT ? , (user_id, limit) ) rows cursor.fetchall() conn.close() return rowssave_memory很简单负责插入一条记忆记录。get_wrong_questions则从历史记录中提取出错频次最高的题目这样智能体就能“针对薄弱点”出题。这种设计虽然简单但已经具备了间隔重复Spaced Repetition的雏形每次答错都记录复习时优先取出错误次数最多的题目。真正成熟的间隔重复算法会引入记忆衰减曲线但在演示阶段错误次数足以说明问题。4.5 接入大模型 API 增强回答如果只用模板拼接知识库内容回答会显得生硬。这里我们增加一个可选的增强层把检索到的知识背景作为“上下文”让大模型生成更自然的回答。需要说明现在各家大模型接口格式大同小异通常都是 OpenAI 兼容的/chat/completions接口。下面的代码以最常见的环境变量方式读取 API Key方便你适配不同厂商import requests import os OPENAI_BASE_URL os.getenv(OPENAI_BASE_URL, https://api.openai.com/v1/chat/completions) OPENAI_API_KEY os.getenv(OPENAI_API_KEY, ) def generate_answer_with_llm(question, knowledge_content): 用大模型结合知识库内容生成回答 if not OPENAI_API_KEY: return f未配置大模型 API返回知识库原文{knowledge_content} prompt ( 你是一个耐心的历史知识讲解助手。请基于下面的知识内容回答用户问题。\n f知识内容{knowledge_content}\n f用户问题{question}\n 要求回答要准确、口语化并补充关键背景。 ) try: resp requests.post( OPENAI_BASE_URL, headers{ Authorization: fBearer {OPENAI_API_KEY}, Content-Type: application/json }, json{ model: gpt-4o-mini, messages: [ {role: system, content: 你是知识讲解助手。}, {role: user, content: prompt} ], temperature: 0.3 }, timeout30 ) resp.raise_for_status() data resp.json() return data[choices][0][message][content].strip() except Exception as e: return f调用大模型接口失败{e}知识库原文{knowledge_content}这里有几个值得注意的工程点把 API Base、Key 放在环境变量里不要硬编码到代码中避免密钥泄露temperature设置为 0.3降低随机性提高事实型回答的稳定性调用失败时不会直接报错退出而是降级返回知识库原文保证基础可用如果当前环境没有配置 Key函数会自动走降级逻辑所以即使没有付费 API 也能跑通整套智能体。很多初学者容易犯的错误是只 prompt 一个“请回答”就让大模型自由发挥。正确的做法是像上面这样先把检索到的知识片段拼进 prompt再要求模型基于知识片段回答。这样既保留了大模型的语言组织能力又限制了它的编造空间。4.6 编写主对话循环与测验逻辑最后把上述模块组装成一个完整的命令行智能体。它需要支持两种模式问答模式和测验模式。def chat(): print( 钢琴历史记忆智能体 ) print(你可以这样提问) print( 1. 钢琴是谁发明的) print( 2. 钢琴键的历史) print( 3. 钢琴为什么叫 piano) print(输入 exit 退出对话输入 quiz 进入测验模式。) print() user_id input(请输入你的用户名用于记忆存储).strip() or default_user while True: try: question input(\n你问).strip() except (KeyboardInterrupt, EOFError): print(\n再见) break if not question: continue if question.lower() in (exit, quit, q): print(好的学习记录已保存再见) break if question.lower() quiz: run_quiz(user_id) continue matched search_knowledge(question, top_k1) if matched is None: print(智能体数据库中暂时没有找到相关答案请尝试换个问法。) continue knowledge_item matched[0] content knowledge_item[content] answer generate_answer_with_llm(question, content) print(智能体, answer) # 记录用户是否学到了新知识 is_correct input(这个问题你原本就知道吗(y/n)).strip().lower() in (y, yes, 对) save_memory(user_id, question, content, is_correct) def run_quiz(user_id): questions [ { question: 现代钢琴的发明者是谁, options: [A. 巴赫, B. 巴托洛梅奥·克里斯托福里, C. 贝多芬, D. 莫扎特], answer: B }, { question: 钢琴最初的名字是, options: [A. clavichord, B. harpsichord, C. gravicembalo col piano e forte, D. organ], answer: C }, { question: 现代钢琴通常有多少个琴键, options: [A. 76, B. 85, C. 88, D. 92], answer: C } ] correct_count 0 print(\n 测验模式 ) print(答对进入下一题答错会记录到复习列表。\n) for i, q in enumerate(questions, 1): print(f第 {i} 题{q[question]}) for option in q[options]: print(option) user_answer input(你的选择).strip().upper() if user_answer q[answer]: print(回答正确) correct_count 1 save_memory(user_id, q[question], q[options], True) else: print(f回答错误正确答案是 {q[answer]}) save_memory(user_id, q[question], q[options], False) print(f\n本次测验完成答对 {correct_count}/{len(questions)} 题。) wrong_list get_wrong_questions(user_id) if wrong_list: print(\n以下题目你最近经常答错建议优先复习) for q, _, cnt in wrong_list: print(f - {q}错误 {cnt} 次) if __name__ __main__: init_db() chat()把上面 4.1 到 4.6 的代码按顺序合并到同一个agent.py文件中就可以直接运行了。5. 运行与测试5.1 启动智能体在项目目录下执行python agent.py首次运行会看到记忆数据库初始化完成的提示然后进入交互界面 钢琴历史记忆智能体 你可以这样提问 1. 钢琴是谁发明的 2. 钢琴键的历史 3. 钢琴为什么叫 piano 输入 exit 退出对话输入 quiz 进入测验模式。5.2 测试知识问答输入“钢琴是谁发明的”程序会检索知识库中piano_inventor条目。如果配置了大模型 API回答会是生成后的自然语言如果没有配置则会提示并输出知识库原文你问钢琴是谁发明的 智能体现代钢琴由意大利人巴托洛梅奥·克里斯托福里Bartolomeo Cristofori于1700年前后发明。他长期在佛罗伦萨为美第奇家族制作乐器最初将新乐器命名为gravicembalo col piano e forte。 这个问题你原本就知道吗(y/n)我输入y这条记录就会被写入memory.db。再次启动程序时数据库里的记录仍然存在。5.3 测试记忆与复习功能进入测验模式你问quiz 测验模式 答对进入下一题答错会记录到复习列表。 第 1 题现代钢琴的发明者是谁 A. 巴赫 B. 巴托洛梅奥·克里斯托福里 C. 贝多芬 D. 莫扎特 你的选择A 回答错误正确答案是 B可以看出如果回答错误程序会把问题、答案、错误标记写入数据库。等到测验结束后智能体会自动列出错误频率最高的问题。这样就实现了“记住谁发明”之后的“复习巩固”闭环。6. 平台方案用 Dify 或 Coze 快速搭建如果不想写代码也可以使用 Dify、Coze 这类低代码智能体平台快速搭建。这里我们以 Dify 为例说一下思路。Dify 是当前比较流行的开源 LLMOps 平台支持知识库、工作流、Agent 编排。要搭建“钢琴历史记忆智能体”只需要三步创建知识库上传一份包含钢琴历史的 Markdown 或 PDF 文档Dify 会自动切分并建立向量索引创建应用选择“聊天助手”或“Agent”类型在系统提示词中说明“你是一个钢琴历史讲解助手”关联知识库在应用设置里绑定刚创建的知识库设置召回模式。如果你想实现“记忆”功能Dify 提供对话变量和会话持久化能力可以用来记录用户学习进度。Coze扣子平台的思路也类似。你先在“知识”中上传资料然后创建 Bot并在人设与回复逻辑中描述智能体定位。Coze 的优势在于国内生态完善插件丰富适合快速接入飞书、微信等渠道。低代码平台的优点是零门槛但缺点也非常明显知识检索细节、记忆策略、测验逻辑都被平台封装起来你无法做深度定制。对于快速验证一个想法低代码平台确实节约时间但如果要做成生产级系统代码方案仍然是更稳妥的选择。7. 常见问题与排查思路在实际开发和运行过程中比较容易遇到下面几类问题。我整理了一个排查清单问题现象常见原因解决思路输入问题后返回“没有找到答案”知识库中没有匹配关键词或者匹配阈值过高检查knowledge.json关键词是否覆盖用户问法在search_knowledge中打印得分调试匹配逻辑回答内容与知识库不一致大模型在生成时“自由发挥”降低temperature在 prompt 中明确要求“只能基于知识内容回答”如果仍不稳定可改为直接返回知识库原文运行时报错module requests not found未安装 requests执行pip install requests或者在 venv 中重新安装依赖记忆记录丢失数据库路径不对或程序在不同目录下运行确认DB_PATH使用绝对路径检查memory.db是否生成在项目根目录中文关键词匹配不佳preprocess_text切词逻辑过于简单可以使用 jieba 分词替换简单 split提高中文匹配准确率调用大模型接口超时网络问题或 API 配置错误先检查环境变量OPENAI_API_KEY是否正确用 curl 测试接口连通性超时时间可以适当调大我把第一条再展开说几句。知识匹配是这类智能体最容易翻车的环节。钢琴是谁发明的这句话经过清洗后关键词是[钢琴, 是谁, 发明的]。在piano_inventor的关键词中“钢琴”“发明”都能命中所以得分 2。而piano 是谁发明的由于piano匹配到pianoforte的一部分也能得分。看起来还好但如果用户问“键盘乐器是什么时候出现的”匹配效果就可能变差。解决办法有两种一是扩充关键词列表把近义词、上下位词放进去二是引入词向量模型用语义相似度替代字面匹配。生产环境中我建议直接上向量检索。8. 最佳实践与工程建议8.1 知识库与记忆分离管理很多开发者一开始容易把知识库和记忆混在一起。其实两者职责完全不同知识库是“权威事实”应该由业务方统一维护记忆是“用户个性化状态”应该按用户维度隔离。在实际项目中知识库变更走发布流程记忆数据则需要做备份和定期清理。如果你把两者混在同一张表后续权限控制和数据生命周期管理都会变得很麻烦。8.2 回答必须可溯源在事实型问答场景中用户最反感的是“一本正经地胡说八道”。所以无论是否接入大模型都要让回答能够溯源到具体知识条目。建议把知识条目 id 一起返回并在界面或日志中记录。这样一旦出现错误回答你可以直接定位是知识库错了还是检索错了还是大模型生成错了。8.3 记忆策略不要过度设计记忆模块不是越复杂越好。对于早期版本只需要记录“问过什么、答对没有、时间戳”三件事就够了。等产品跑出真实用户数据后再引入遗忘曲线、复习间隔等高级策略。我见过不少团队一上来就做“短期记忆 长期记忆 情感记忆”结果复杂到难以维护用户却感知不到差别。正确的做法是先用最小可用方案跑通再做基于数据的功能迭代。8.4 安全与权限边界本文示例是一个纯本地的教育演示工具不存在敏感数据问题。但如果你的智能体要接入企业知识库或者保存用户的私密问答记录就必须考虑记忆数据库加密存储知识库按角色做权限隔离不允许智能体回答超出授权范围的问题大模型 API Key 放在服务端环境变量中不要下发到浏览器端。8.5 预留多轮上下文目前的示例是“单轮问答 独立测验”。如果你想支持多轮对话需要在提问时把历史对话记录一并传给回答生成函数。最简单的做法是在chat()循环中维护一个messages数组在调用大模型时追加进去。9. 总结与后续学习建议通过“记住谁发明了钢琴键”这个小而完整的案例我们实现了一个具备知识检索、持久化记忆、主动测验三个核心能力的智能体。你学到的不只是钢琴历史更是一套可以复用到任意事实型知识场景的智能体架构。如果你要继续深入学习可以从下面几个方向入手检索增强把关键词匹配替换成向量检索使用sentence-transformers或各类 Embedding API记忆增强引入间隔重复算法实现更科学的复习计划多模态接入让智能体不仅能回答文字问题还能识别钢琴乐谱图片交付集成把命令行程序封装成 FastAPI 服务接入 Web 页面或微信机器人。智能体的核心不是模型有多大而是能不能在合适的时机找到合适的知识并记住用户真正需要的东西。希望这套代码能帮你走好第一步。如果你在运行或改造过程中遇到问题欢迎在评论区留言讨论。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进