news 2026/9/12 4:36:04

从上下文窗口到向量数据库:构建AI Agent长效记忆的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从上下文窗口到向量数据库:构建AI Agent长效记忆的完整指南

做 Agent 做得越久,我越觉得“记忆”才是决定体验上限的那道坎。模型能力再强,如果每次对话都像第一次见面,聊两句就忘光你的名字、偏好和昨天刚交代的事情,那它充其量只是个“高级聊天框”,谈不上是你的助手。这个系列前面两篇聊了 Agent 的整体框架和工具调用,这篇我单独把记忆拎出来,完整讲一遍“让 Agent 记住你”这件事该怎么做:从记忆类型怎么划分、技术方案怎么选,到用 LangGraph 落地一个最小可跑的记忆模块,再到我实际踩过的坑。无论你是在做客服机器人、个人知识助手,还是带记忆的编程 Agent,这一篇都能给你一套可以直接抄作业的思路。

先说我自己的结论:记忆不是单一技术,而是一整套“写入、存储、召回、更新、遗忘”的工程闭环。很多人以为接个向量数据库就万事大吉,结果存了一堆乱七八糟的文本,召回时又答非所问,最后体验还不如不带记忆。真正好用的记忆系统,一定是有结构、有分层、有更新策略的。这篇文章我会把每个环节都拆开讲,也会给出能跑的最小代码示例,希望对正在做 AI Agent 的朋友有帮助。

1. 我理解的 Agent 记忆:先搞清楚要解决什么问题

1.1 没有记忆的 Agent,只是在假装聊天

前两年做大模型应用时,我最头疼的一个问题就是“上下文断层”。用户上午跟 Agent 说“我家里有两个小孩,一个 6 岁一个 10 岁,周末经常要去公园”,下午再问“帮我推荐周末亲子活动”,Agent 完全不记得之前的对话,从零开始猜需求。用户会明显觉得自己在跟一个“金鱼”聊天。

这个问题表面上看是“上下文窗口不够大”,实际上更核心的原因是:我们把所有对话都当成了一次性请求,没有把其中有价值的信息沉淀下来。大模型的上下文窗口本质上只是“短期工作区”,它负责当前这一轮的理解和生成,但它天然是易失的,关掉会话、超过窗口限制,信息就没了。要让 Agent“记住你”,就需要在模型之外单独构建一个持久化的记忆层。

我当时给团队定的目标是四个字:越用越懂。Agent 至少要能记住三类信息——用户说过的事实(比如家庭成员、职业、常用工具)、用户的偏好(比如喜欢简洁回答还是详细解释、讨厌术语)、以及历史对话里已经确认过的结论(比如上次已经推荐过某个方案,这次别再重复推荐)。让这些信息跨会话、跨请求地沉淀下来,才是“记住你”的本质。

1.2 我在动手之前,先把记忆分成了四类

刚开始做记忆模块时,我犯过一个错:把所有记忆都塞进同一个表里,结果查询、更新、召回全都混乱。后来参考认知科学里的记忆分类,把 Agent 的记忆拆成四类,整个架构才清晰起来。

记忆类型典型内容推荐存储更新频率
短期记忆当前对话上下文、正在处理的任务状态上下文窗口、Redis、内存缓存每轮更新
长期记忆用户事实、偏好、历史重要事件向量数据库、关系型数据库
程序性记忆工具调用流程、任务执行步骤代码、规则引擎、技能库低频
工作记忆当前任务的中间结果、临时变量状态对象、图状态高频

这四类的读写策略完全不一样。短期记忆要的是“快”,尽量少做语义加工,直接给模型拼接上下文就行;长期记忆要的是“准”,需要在写入时做抽取、去重和结构化;程序性记忆一般不太由对话动态生成,更多是 Agent 开发者预先定义,或者从历史工具调用中归纳出来;工作记忆则跟着任务生命周期走,任务结束就可以清掉。

把记忆分类这个动作最大的价值,是让我在做技术选型时不再纠结“用什么数据库统一存储”。短期记忆你用向量库就是浪费,长期记忆你要硬塞进上下文窗口也会很快爆掉。先分类,再决定每一类用哪个方案,这是做记忆模块的第一步,也是最容易被跳过但最值得花时间的一步。

2. 技术选型:不同记忆用不同存储,别让一套方案打天下

2.1 短时记忆不要硬塞给向量库

很多入门教程上来就是“给 Agent 装一个向量数据库”,其实短期记忆根本不需要向量化。短期记忆要解决的核心问题是:在一段连续对话里,怎么让模型不忘记前面说了什么。这里最常用的技术是上下文管理和滑动窗口。

我的做法是给对话设置一个“最近 N 轮”窗口,比如保留最近 5 轮完整消息,更早的消息如果信息密度高,就压缩成摘要放进上下文。这个摘要不是简单截断,而是调用模型用几句话把关键信息提炼出来,比如“用户提到自己是前端工程师,正在用 React 重构项目,周五要上线”。这样既控制 token 成本,又不丢失核心线索。

为什么不用向量库做短期记忆?因为向量召回本身有延迟,而且召回结果还需要再拼回上下文,链路长、不稳定。短期记忆是要“喂”给模型的,应该尽量贴近原始语义、顺序,而不是经过向量化之后的相似性匹配。缓存放不下或者上下文超限时,再做“摘要压缩”,这是成本收益比最高的方案。

我见过有团队把每轮对话都拆分成片段存入向量库,每个请求再从库里召回相关片段拼进上下文,结果用户问一个简单问题,系统先做 3 次向量查询,延迟多了几百毫秒,关键信息还经常被漏掉。原因就是短期对话有很强的顺序依赖,向量检索并不擅长处理这种“紧挨着前文”的语境。记住:短期记忆走上下文窗口,长期记忆才走向量库。

2.2 长期事实记忆,向量库加 Embedding 是基本盘

长期记忆要解决的核心问题是跨会话。用户上个月说过“我在备考 PMP”,这个月问“周末怎么安排”,Agent 应该联想到备考进度,主动建议安排复习时间。这种联想能力靠关键词匹配很难做到,因为“PMP”“考试”“复习”“周末安排”这些词在字面上并不完全重叠,但语义上是相关的,这时候就需要向量语义检索。

向量数据库选型,我实际测过几个常用方案:Chroma 适合本地原型,轻量、零配置,几千条数据体验很舒服;PostgreSQL 加 pgvector 适合本来就有 PG 的业务,少引入一个组件,数据还能用 SQL 管理;Milvus 适合真正的海量数据、高并发场景,但运维成本高;Redis 的向量检索则适合低延迟、小规模场景,复用已有缓存集群。我个人的建议是:个人项目可以先从 Chroma 或者本地的 SQLite 向量扩展开始,上了生产再多花力气上独立向量库。

Embedding 模型的选择同样关键。中英文混合场景下,我优先测试了开源的中文向量模型(比如 BGE 系列),整体效果明显好于直接用英文模型;维度上 1024 维或 768 维是主流,维度太高会占内存,太低了语义区分度又不够。选模型时要注意:最后所有写入向量库的文本,包括用户对话、知识文档、记忆条目,都要用同一个 Embedding 模型。各存各的,召回时查询向量和库里的向量不在同一空间,结果必然不对。

2.3 结构化画像:偏好与事实用 JSON 比向量更靠谱

向量库擅长语义召回,但它不擅长“精确回答”。用户说“我女朋友喜欢喝冰美式”,存向量库后你问“用户女朋友喜欢喝什么”,确实能召回相关片段,但如果要做个性化推荐、做规则判断,每次都要靠向量召回文本片段再让模型理解,既慢又不稳定。更靠谱的做法是:把高置信的事实和偏好抽成结构化 JSON 存起来。

我会在长期记忆里单独维护一个用户画像表,字段包括用户 id、偏好标签、关键事实、更新时间、来源会话 id 等。比如:

{ "user_id": "u_12345", "preferences": { "coffee": "冰美式", "answer_style": "concise", "language": "中文" }, "facts": [ {"key": "job", "value": "前端工程师"}, {"key": "children", "value": 2} ], "updated_at": "2025-04-10T18:30:00Z" }

这张表不需要模型每次召回,只要在构建系统提示词时用模板拼进去就行,精确、便宜、零延迟。比如用户问“给我推荐一杯咖啡”,系统提示词里已经有“用户偏好:咖啡=冰美式”,模型输出自然更贴合。

向量召回这时反而是查漏补缺的角色。对于没抽成结构化的、又比较重要的描述性记忆,比如“用户上次提到想去大理旅行,因为喜欢洱海边安静的环境”,这种细节很难全部压进 JSON,就靠向量库存原文、语义召回。所以我的长期记忆是两层结构:结构化画像负责“精确事实”,向量库负责“模糊语义”,两者各管一段,组合起来才是完整的长期记忆。

2.4 MCP 协议和记忆服务:统一接口还是自定义实现

最近 MCP(Model Context Protocol)协议讨论很火,它在 Tools、Resource、Prompt 三个层面给了统一标准,不少人也开始用 MCP 把记忆能力暴露给 Agent。我的看法是:MCP 适合做“记忆能力的标准化接口”,比如对外提供“写一条记忆”“查用户记忆”“删除记忆”这几个 Resource,让不同 Agent 都能通过统一协议读写,这在多 Agent 协作场景里很实用。

但我不建议把整套记忆逻辑全塞进 MCP Server 里就万事大吉。记忆系统需要后台异步更新、定时清理、冲突合并,这些都不是简单的请求响应能覆盖的。我会把 MCP 当作一层“门面”,真正的存取逻辑仍然放在独立的内存模块里,由 Agent 的主流程调用。比如用户说了一句话,主流程先做实体抽取和偏好识别,再决定是写入结构化画像还是向量库,最后才把结果暴露给需要访问记忆的其他服务。

同时要注意,MCP 工具的粒度不能太粗也不能太细。太粗,比如只有一个“save_all_memory”,Agent 不知道该不该调用,写进去的内容一团糟;太细,比如拆成“save_coffee_preference”“save_job_info”,工具数量爆炸,模型选工具都选不过来。我实践下来比较稳的粒度是围绕“记忆操作”而不是“记忆内容”:write_memory、search_memory、update_memory、delete_memory,再加 meta 里的 memory_type 区分短期、长期、结构化。

3. 落地实操:给 Agent 装一套能“记住你”的记忆模块

3.1 总体流程:写入、存储、召回、更新、遗忘

记忆模块不是一个装完就跑的一次性功能,而是一条持续运转的数据管道。我这里先给一个总体流程,后面小节再逐一展开细节。

  1. 写入阶段:每一轮对话结束后,判断这轮对话里是否有值得长期留存的信息。判断依据可以是规则(比如出现“我喜欢”“我讨厌”“我在做”等表达),也可以交给大模型做信息抽取。抽取出的信息包括:用户说了什么事实、表达了什么偏好、是否与旧记忆冲突。

  2. 存储阶段:把抽取结果写入对应存储。偏好和事实写入结构化画像,描述性信息写入向量库,关键结论可以追加到长期摘要。这一步要注意去重和合并,避免同一个事实被重复存储。

  3. 召回阶段:在模型生成回答前,根据当前用户问题和会话状态,从记忆系统里召回相关信息,拼进提示词。召回分两类:结构化画像直接读取,语义记忆向量检索 top-k。

  4. 更新阶段:当用户新表达与旧记忆不一致时,以最新为准。旧记忆不能直接删,要有状态标记或者版本号,避免“今天说喜欢喝热拿铁,明天说错了”这种反复横跳把画像搞乱。

  5. 遗忘阶段:定期清理低置信、长期未命中的记忆条。长期不访问的记忆可以归档,超过 TTL 的临时记忆直接删除。遗忘不是 bug,是让记忆系统保持健康的必要机制。

我当时是先用日志把每一步的输入输出都打出来,跑完 100 条真实对话,再逐步调整抽取规则和更新策略。记忆模块最大的特点是“没有显而易见的正确”,必须用真实数据反复调。

3.2 用 LangGraph 跑通一个最小记忆流程

LangGraph 很适合做 Agent 的状态流编排,因为记忆本身就是跨节点的状态。我下面给一个简化版的最小实现,目标是在每次对话前从记忆库召回信息,对话结束后把新信息写入记忆库。

from langgraph.graph import StateGraph, END from typing import TypedDict, List import chromadb class AgentState(TypedDict): user_id: str messages: List[dict] memory_results: List[str] # 初始化向量库 client = chromadb.PersistentClient(path="./agent_memory") collection = client.get_or_create_collection("user_memory") def recall_memory(state: AgentState): user_id = state["user_id"] query = state["messages"][-1]["content"] # 召回与该问题语义相关的记忆 results = collection.query( query_texts=[query], n_results=3, where={"user_id": user_id} ) return {"memory_results": results["documents"][0]} def generate_answer(state: AgentState): memory_text = "\n".join(state["memory_results"]) context = f"以下是该用户的记忆信息:\n{memory_text}" # 这里接入你自己的 LLM 调用 # response = llm.chat(context + str(state["messages"])) return {"messages": [{"role": "assistant", "content": "基于记忆的回答"}]} def save_memory(state: AgentState): user_id = state["user_id"] last_user_msg = [ m for m in state["messages"] if m["role"] == "user" ][-1]["content"] # 简化处理:把用户消息作为记忆写入 # 生产环境应该用抽取后的结构化数据 collection.add( documents=[last_user_msg], ids=[f"{user_id}_{hash(last_user_msg)}"], metadatas=[{"user_id": user_id, "time": "2025-04-10"}] ) return state # 构建图 graph = StateGraph(AgentState) graph.add_node("recall", recall_memory) graph.add_node("generate", generate_answer) graph.add_node("save", save_memory) graph.set_entry_point("recall") graph.add_edge("recall", "generate") graph.add_edge("generate", "save") graph.add_edge("save", END) app = graph.compile()

这段代码的意图很简单:recall 节点在回答前先查记忆,generate 节点把记忆信息拼进提示词,save 节点在回答后写入新记忆。实际项目里需要替换成正确的 LLM 调用、更严谨的抽取逻辑和去重策略,但整体骨架是通用的。LangGraph 的好处是状态对象 AgentState 天然承载 user_id、messages、memory_results,你不用自己维护复杂的全局变量。

有一点要注意:save_memory 不应该保存每一轮所有内容,那会造成大量重复和噪音。我在生产代码里是先调用一个抽取函数,只有抽取到“值得记住”的信息才入库。判断标准可以是:包含具体偏好、明确事实、或与旧记忆存在更新关系。否则宁可少存,也不能乱存。

3.3 记忆更新:不是追加,而是合并

只写不更新,记忆模块很快就会被污染。一个典型场景:用户昨天说“我喜欢喝拿铁”,今天说“最近减脂,换成美式吧”。如果系统只做追加,向量库里同时存在“喜欢喝拿铁”和“喜欢喝美式”两条,召回时模型可能给出完全矛盾的推荐。我处理这类冲突的思路是“合并优先,追加兜底”。

具体的做法是给每条记忆加一个状态字段:active、superseded、archived。写入新记忆前,先检索一下有没有同主题的 active 记忆,如果有且内容冲突,把旧记忆标记为 superseded,同时写入新记忆。这样召回时优先取 active 记忆,历史信息不会完全丢失,又不会干扰当前判断。

还有一个容易忽略的点是“置信度”。用户闲聊时说了一句“我可能想去日本玩”,这是一个低置信意向,不应该立刻写入长期画像,否则用户明天随口改口,画像就乱套。我会给抽取结果打一个置信度分数,比如明确表达“我特别喜欢”“我讨厌”之类的高置信语料,直接写入;带“可能”“也许”“想一下”等模糊词的,先放进短期草稿区,等第二次确认再升级为长期记忆。这种机制能显著降低记忆漂移。不要小看这个细节,真实聊天里模糊表达远多于明确表达,没有置信度机制的记忆系统,就是个垃圾场。

4. 避坑指南:我在记忆模块里踩过的坑

4.1 找了个英文 Embedding 模型,中文召回效果稀碎

第一批上线时,为了省事我直接用了当时默认的英文 Embedding 模型,测试英文问题好像还行,一旦用户用中文提问,召回结果完全对不上。比如用户之前说“周末想去爬山”,改成中文问“有什么户外运动推荐”,返回的记忆条目经常是无关联的商品描述。问题不在向量库,而在 Embedding 模型对中文语义的理解不够。

后来换成了针对中文优化过的开源向量模型,并且用同一模型重新生成了全量索引,中文召回效果立刻好了很多。这里有两个操作要点:第一是切换模型后必须重建索引,旧索引的向量空间和新模型不一致,不重建会出现“查询正常但召回全是错”的诡异问题;第二是在生产环境给 Embedding 模型加一层封装,方便后续平滑替换,不要散落在一堆业务代码里。另外,如果你们的用户含有大量术语、专业名词(比如医学、法律),最好用自己的数据微调一个领域 Embedding,但这不是第一步要做的事,先用通用模型跑通,觉得差了再针对性优化。

4.2 重复写入:同一个事实存了几百遍

另一个容易踩的坑是把“用户说过的每句话”都当成记忆入库。我最早做的版本,用户一句“我住上海”就被写进了向量库,过两天用户又提了一次“我住在上海”,系统再写入一次。三个月下来,向量库里同一个事实的重复记录可能有几百条,一来浪费存储,二来召回时返回的全是相似的重复内容,浪费上下文空间,还让模型分不清哪个是最新版本。

我的解法分两层:写入前先做语义查重,用向量召回 top1,计算相似度,超过阈值的直接放弃写入,或者走更新分支;写入后加定时任务,定期按 user_id 聚合相似记录,把重复项归档。查重阈值要调,我这边 0.92 以上基本可以认定是重复,但也有误判场景,所以更稳妥的是把“语义重复但表达不同”的信息合进一句话,比如“用户住在上海,工作在杭州”,而不是简单丢弃。

4.3 隐私边界:记忆越全,风险越大

做记忆系统一定会接触到用户的隐私,比如联系方式、家庭住址、健康状况、工作单位。网上有很多讲“Agent 记住你”的教程只讲能力不讲边界,但我建议你在设计的第一天就把隐私边界想清楚。不是说不能存储,而是要区分哪些信息是服务所必需的,哪些信息只是闲聊中顺带提到的。我的原则是:明确收集、最小必要、支持删除。

明确收集是指写入前让用户知情,不能偷偷把“用户家住哪个小区”记下来还浑然不觉。最小必要是只保存你想用来做个性化的字段,无关信息不入库。支持删除是必须提供“清除我的记忆”功能,接口可以从 delete_memory_by_user_id 开始,同时清理结构化画像和向量库里的所有相关条目。别小看这块,很多 Agent 项目在演示时没人管,一上真实用户就出事。哪怕只是合规要求,也够你重写一遍。

4.4 每次请求都查一遍向量库,延迟高到崩溃

记忆召回如果放进在线链路,必须考虑延迟。最初我的实现很粗暴:用户每发一条消息,先向量召回,再从画像表读偏好,还要再查一遍历史摘要,三次串行请求走完才调大模型。结果单次请求因为记忆系统多了 600 到 800 毫秒延迟,用户体感明显变差。

优化思路是“缓存 + 异步”。用户画像属于低频变化的,可以直接缓存到 Redis,按 user_id 存一份 JSON,每次请求直接读缓存,只有画像变更时才回写。向量召回可以做成并行,和画像读取同时发起,不要串行。记忆写入放到对话结束之后异步执行,不要在用户等待回答时同步写库。还有一招是在非高峰时段做记忆预取,比如用户打开应用时先加载最近记忆到会话上下文,真正提问时就能少一次召回。

5. 常见问题速查与调试实录

5.1 明明存了,Agent 却说“我不记得”

这种情况我排查过很多次,原因多半不在“没存”,而在“没召回”或“没喂给模型”。常见原因有三个:

  • 召回阈值设得太高,导致相关记忆根本没进 top-k 结果。
  • 向量召回正常,但提示词里没有把召回结果拼进去,模型根本看不到记忆。
  • 存储时没带 user_id,检索时按当前用户过滤后为空。

排查方法是把记忆召回模块单独拉出来打日志,输出请求问题、召回 top5 的相似度分数、最终拼进提示词的记忆文本。我见过不少项目,日志一打就发现是过滤条件写错了,比如检索时传成了 session_id,而不是 user_id。调试记忆问题,别盲猜,先看日志。

5.2 记忆串台:A 用户说的话跑到了 B 用户头上

多用户场景下最怕的就是记忆串台。出现这种情况,八成都跟检索过滤条件有关:要么写入时 metadata 里没写 user_id,要么召回时没带过滤条件。Chroma 这类向量库支持 where 条件过滤,一定要记住写入和召回都按 user_id 隔离。

如果你们是多租户场景,建议在 collection 层面就按租户拆分,或者所有 metadata 统一加 tenant_id 和 user_id 两个字段。另外,测试时不要只用一个用户账号测,要同时创建两个测试账号,来回切换验证记忆是否真的隔离。这个坑我踩过,上线前没做双用户测试,结果一上生产就有人反馈“看到别人的偏好”,吓得我赶紧补隔离。

5.3 旧记忆误导模型:用户已经改主意,画像还停留在过去

记忆系统最大的副作用是“刻舟求剑”。用户明明说过喜欢喝拿铁,但后来改喝美式了,如果画像不同步,模型就会一直推荐拿铁。这类问题的根源是记忆更新策略没做好。我的建议是:所有长期画像字段必须有 updated_at,并且在召回时按时间过滤,过期记忆降权。

同时,要在提示词里告诉模型:“以下记忆信息来自不同时间,如果与当前用户表达冲突,以用户最新说法为准。”给模型一个处理冲突的指引,能避免模型完全被旧记忆带偏。生产环境可以再加一道规则:检测到用户明确否定旧记忆时,立刻触发画像更新,并把旧条目标记为 superseded。

5.4 记忆测试怎么做:别只测“还记得吗”

功能测试之外,我建议设计一套“记忆剧本”,专门验证记忆系统的写入、召回、更新、遗忘。比如:

  • 写入剧本:告诉 Agent“我在准备雅思考试”,再问“我最近在忙什么”,看是否记得。
  • 更新剧本:先说“我喜欢喝热拿铁”,隔一阵说“我现在改喝冰美式了”,再问“推荐杯咖啡”,看是否推荐冰美式。
  • 遗忘剧本:制造大量低置信碎片,检查它们是否进入草稿区而不是长期库。
  • 隔离剧本:两个用户分别写入不同偏好,交错提问,确认互不影响。
  • 删除剧本:调用删除接口后,确认向量库和画像表都清干净。

这套剧本建议写成自动化测试用例,每次修改记忆逻辑后直接跑一遍回归。记忆系统不像普通接口有明确的对错,只有通过一套稳定剧本持续验证,才能保证迭代过程中不悄悄变坏。

最后再分享一个我一直在用的习惯:记忆模块上线后,我会定期导出真实记忆样本,人工看 20 到 30 条记录,重点检查有没有重复、过时、错误、隐私风险。不要完全依赖自动化评估,肉眼扫一遍往往能发现测试用例覆盖不到的问题。让 Agent 记住你,不是把用户所有的话都塞进库,而是有选择、有结构、有更新地理解用户。在我做过的所有 Agent 项目里,记忆模块永远是投入产出比最高,也最需要耐心打磨的部分,希望这篇能给你省下一些弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 4:35:26

Java继承与内部类核心机制详解

1. Java继承机制深度解析Java继承是面向对象编程的三大特性之一(封装、继承、多态),它允许我们基于现有类创建新类。这种"is-a"关系在Java中通过extends关键字实现,是代码复用的重要手段。1.1 继承的核心语法与内存模型…

作者头像 李华
网站建设 2026/9/12 4:34:55

高效完成第一次作业的实用指南与技巧

1. 第一次作业的完整指南作为一名从业多年的教育工作者,我见过太多学生在面对第一次作业时手足无措的样子。第一次作业往往决定了学生对这门课程的第一印象,也影响着他们后续的学习动力。今天,我想分享一套经过实践检验的作业完成方法&#x…

作者头像 李华
网站建设 2026/9/12 4:34:54

Web数据可视化库企业级实测:Highcharts、ECharts、Plotly深度对比

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 4:34:49

Qt 5.14.2 aarch64静态交叉编译完整指南

前阵子做了一块ARM64开发板的图形应用移植,目标板跑的是精简版Linux系统,内存不大,磁盘空间也吃紧,但应用必须带完整的Qt界面。最开始的想法是动态链接,后来仔细一算依赖库加起来快两百兆,再加上系统里还得…

作者头像 李华
网站建设 2026/9/12 4:32:45

XopProtector开源Android加固:PVM虚拟化实现Dex/So/资源全栈防护

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 4:31:38

电力系统动态状态估计:鲁棒迭代扩展卡尔曼滤波器的Matlab实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华