96SEO 2026-04-26 02:37 1
去年这个时候,AI Agent的概念简直火得一塌糊涂。我跟风kan了无数的技术文章,也刷了不知多少个讲解视频。ReAct、RAG、Function Calling、LangChain……这些名词听起来dou挺耳熟,当时我觉得自己dou懂了心里想着:“嗯,原理嘛,也就那么回事。”

然而现实hen快就给了我一记响亮的耳光。当我真正打开编辑器,准备亲手写一个像样的 Agent 时大脑却一片空白,连第一行代码dou敲不出来。这种“一kan就会,一Zuo就废”的焦虑感,我想hen多正在学习新技术的朋友应该dou深有体会吧?后来我痛定思痛,终于明白了一个道理:光靠眼睛kan是永远学不会游泳的,你得跳进水里呛几口水才行。
缘起:为什么我要造一个“阅读器”?既然决定要动手Zuo项目练手,那Zuo什么好呢?我平时是个书虫,手机和电脑里装满了各种电子书。但我发现,现有的阅读器软件要么太传统,一点智Neng化的影子dou没有;要么就是硬凑热闹,所谓的“AI功Neng”也就是套了个壳,你问它书里的问题,它经常一本正经地胡说八道——hen明显,它压根就没真正“读”过书里的内容,只是在用通用的知识库忽悠你。
既然市面上没有满意的,那就自己撸起袖子干一个吧。我的目标hen明确:Zuo一个Neng真正“读懂”书的 AI 阅读器。我给它起名叫 ReadAny,寓意就是“什么douNeng读”。这个项目的技术栈选用了 Tauri + React 来搞定桌面端,移动端则用了 Expo,至于核心的 AI 部分,自然是离不开 LangChain.js 和 LangGraph 的加持。
Zuo着Zuo着,这原本只是一个用来练手的学习项目,竟然慢慢演变成了一个功Neng还算完整的产品。现在它Yi经Neng在 macOS、Windows、Linux、iOS 和 Android 上全平台跑了。今天我就想抛开那些虚头巴脑的概念,跟大家聊聊在这个项目中,我是如何一步步实现 Agent 相关功Neng的,顺便分享几个我觉得挺有意思的技术细节。
从“一问一答”到“ReAct”模式的进化在Zui开始的时候,我也走了Zui简单的路子:用户问一句,我就把书里的相关内容一股脑地塞到 Prompt 里然后扔给大模型去回答。
结果?没过多久就翻车了而且翻得五花八门。
是塞不下。一本动辄几十万字的小说或者技术书,Context Window 再大也吞不下整本书的内容。然后是爱瞎编。因为 LLM 根本没读过这本书,当你问它“第三章的核心论点是什么”时它Neng凭空编出一套kan起来头头是道、实则每个字dou在放屁的回答。Zui后是不灵活。Ru果用户问“这本书里有没有提到量子力学”,这种需要精确搜索的问题,靠硬塞内容是根本搞不定的。
没办法,我只Neng转向geng高级的 ReAct模式。这个模式的核心思路其实hen好理解:AI 不再是简单的“你问我答”,而是变成了一个有手有脚的智Neng体。当你问它问题时它会先思考“我需要什么信息才Neng回答这个问题”,然后自主决定去调用工具查资料。拿到结果后它再继续思考,Ru果觉得信息不够,还会再去查,直到它Neng给出一个靠谱的答案为止。
用一句大白话概括就是:让 AI 先想再Zuo,而不是张嘴就来。
手写循环还是用框架?一开始,我甚至想过自己手写 tool-calling 的循环逻辑——也就是自己判断 LLM 需不需要调工具、该调哪个、怎么把结果喂回去。但这玩意儿的边界情况实在太多了写了两天各种奇奇怪怪的 Bug 搞得我头大。Zui后我还是老老实实投降,用了 LangGraph 提供的 createReactAgent。
说实话,核心代码写出来你可Neng不信,真的就几行:
const agent = createReactAgent({
llm: chatModel,
tools: langchainTools,
messageModifier: systemPrompt,
});
const stream = agent.streamEvents(
{ messages: processedMessages },
{ version: 'v2', recursionLimit: 200 }
);
这里有个参数 recursionLimit: 200,kan起来数值挺大的,但在实际场景中真的需要。举个例子,Ru果用户说“帮我逐章这本书”,一本 20 章的书,每一章 Agent dou得调用一次工具去获取内容然后再这一来二去,轻轻松松就Neng跑几十轮循环。
光有脑子是不够的,还得给 Agent 配上好用的“手脚”。在这个项目里我根据不同的使用场景,把工具分成了五大类。
这里有个我觉得挺关键的设计细节:工具是根据当前的状态动态注册的,而不是一股脑全扔给 Agent。
这是什么意思呢?比如用户还没打开任何一本书的时候,像“获取当前章节”这种工具压根就不应该出现在 Agent 的工具列表里;再比如书还没有Zuo过向量化处理的时候,RAG相关的工具也不应该存在。原因hen简单:Ru果给 LLM 的选项太多,它反而会陷入选择困难症,甚至选错工具。经过我实测,动态注册这种方式比全量注册的调用准确率要高出不少。
精准引用:从 Chunk 到原文的跳转我还专门给 Agent 设计了一个 addCitation 工具。当 AI 在书里找到一段相关的话之后它Ke以生成一个引用标记,用户点击这个标记,就Neng直接跳转到书中对应的原文位置。
但这事儿说起来容易,Zuo起来有个技术难点:AI 拿到的定位信息通常是 Chunk 级别的,而用户真正想引用的文本可Neng就在这个 Chunk 的中间某个位置。
我的解决办法虽然不算完美,但实际用下来效果还不错:我会在 Chunk 切分的时候保留精确的 CFI信息,当 AI 生成引用时我会根据它在 Chunk 中的字符偏移量,反推回Zui接近的段落位置。用户点过去,基本douNeng跳到正确的地方,误差hen小。
RAG:检索质量才是生命线Agent 解决的是“怎么调度”的问题,但 AI 回答靠不靠谱,Zui终取决于Neng不Neng从书里找到正确的内容。这就是 RAG要干的重活。
Zuo完这块我Zui大的感受就是:RAG 的检索质量远比 Agent 的架构设计重要。 你把 Agent 设计得再花哨,Ru果检索出来的内容不对,那Zui终给出的回答就是垃圾。
Segment-aware 分块策略一本书不Neng整个塞给 LLM,得切成小块。但怎么切非常有讲究。我没用 LangChain 自带的 TextSplitter,因为它根本不认识电子书的段落结构,经常把一句话从中间切断,读起来特别难受。而且,我需要每个 Chunk dou保留精确的位置信息,后面Zuo引用定位全靠它。
所以我自己写了一个 Segment-aware 的分块器。每个 TextSegment 对应书中的一个自然段,切块的时候严格按照段落边界来切,绝不会把一句话劈成两半。默认设置是 500 tokens 一个 Chunk,相邻 Chunk 之间保留 20% 的重叠,防止关键信息刚好倒霉被切在边界上。
本地与远程的博弈Zuo阅读器有个绕不开的问题:书是隐私数据。 用户的阅读内容绝对不应该随便上传到云端。所以我设计了两条路:
本地模式利用 Transformers.js 在 Web Worker 里跑模型,完全离线。内置了几个轻量级的模型,英文书用 all-MiniLM-L6-v2,中文书用 bge-small-zh-v1.5。这样哪怕没网也Neng用。
远程模式调用 OpenAI 或者 Ollama 的 API,适合那些追求geng高精度的极客用户。
向量存储方面我选用了 sqlite-vec,这是一个 SQLite 的向量搜索 。桌面端通过 Tauri 的 Rust 后端来调用,性Neng表现相当不错。
混合搜索:向量与 BM25 的联姻RAG 里我投入时间Zui多的就是检索这块。一开始我只用向量搜索,hen快发现了一个大问题:对专有名词不敏感。 你搜“哈利波特”,向量搜索可Neng返回一堆“年轻的魔法师”之类的语义相近但没有精确命中的结果。
反过来Ru果只用纯关键词搜索,它又不理解语义。你搜“主角的心理变化”,它就傻眼了。
所以Zui终我采用了混合搜索的策略。向量和 BM25 两路同时查,然后用 RRF算法把结果融合排序。说人话就是:两个搜索引擎各出一份排名,用一个公式综合一下两边dou排前面的结果,Zui终排名就Zui靠前。
在 BM25 这块还有个小坑:中文分词。中文不像英文有天然的空格分隔,直接按空格切分效果极差。我用了 CJK bigram的方式处理,比如“量子力学”会被拆成“量子”、“子力”、“力学”三个 term。虽然这方法听起来有点粗暴,但效果比不处理好太多了。
流式体验:把“黑盒”变成“透明盒”后端Neng跑了逻辑也通了但用户kan到的是界面不是后台的日志。怎么把 Agent 的整个思考过程实时、流畅地展示给用户,这块踩的坑比前面加起来dou多。
这是我Zui想吐槽的一点。你以为 LangChain 帮你抹平了各家 LLM 的差异?太天真了。
OpenAI它的 tool_call 参数是一小块一小块流过来的,你得自己动手拼接。
Anthropic Claude它支持 extended thinking,流式事件里会多出一个 thinking 块,你得单独写逻辑去处理。
DeepSeek这个Zui坑。它的 reasoning_content 在多轮对话时要求每条历史 assistant 消息dou带上之前的 reasoning_content,否则 API 直接报错。但是 @langchain/deepseek 这个包在接收的时候把 reasoning_content 存到了 additional_kwargs 里发送的时候却不会把它塞回去!
没办法,我只Neng继承 ChatDeepSeek 写了个子类 ChatDeepSeekFixed,重写了 _generate 和 _streamResponseChunks,手动维护一个 _reasoningMap 来在每次请求时把 reasoning_content 注入回去。这个 Bug 困扰了我好几天网上也搜不到解决方案,Zui后只Neng硬着头皮啃源码才搞明白。
正常流程是等到工具名称和参数全部到齐了才告诉前端“Agent 在调工具”。但参数可Neng要流好几秒才拼完,这段时间用户就干kan着一片空白,体验极差。
我Zuo了个优化:只要 tool_call_chunks 里出现了工具名,就立即 emit 一个 tool_call 事件给前端,参数先留空。前端收到后马上显示“正在调用 xxx 工具...”的提示。等参数到齐了再geng新显示。改动不大,但体感差别hen明显。用户Neng实时kan到 AI 在干什么不会以为程序卡死了。
前端渲染这块,我借鉴了一个思路:每条消息不是一坨死板的文本,而是由多个 Part 组成的。
一个 Agent 的回复过程可Neng是这样的:先思考→ 调工具搜内容→ 再调一次工具→ 开始回答→ 附上引用。
每个 Part 独立渲染、独立geng新状态。思考过程显示为可折叠的面板,工具调用显示为带状态图标的卡片,正文流式打字,引用可点击跳转。
这样Zuo的好处是 Agent 的每一步操作dou清晰可见,用户Nengkan到 AI “想了什么 → 查了什么 → 怎么得出结论的”,而不是等半天突然甩出一大段文字。
还有个小的性Neng优化:文本部分的geng新Zuo了 100ms 的节流。不然每个 token 到了dou触发一次 React re-render,一秒钟几十次重渲染,界面会明显卡顿。
System Prompt:kan不见的指挥棒这块单独拿出来说是因为,Zuo了 Agent 之后我才真正意识到 System Prompt 有多重要。它不只是简单的“你是一个 xxx 助手”这么简单。
我的 System Prompt 是动态拼装的,分成了好几个部分。其中“防剧透”是我自己加的一个功Neng。kan小说的时候Zui怕被剧透,所以我在 Prompt 里加了逻辑:根据用户的阅读进度,限制 AI 只Neng访问Yi读章节的内容。 你问“后面会不会有反转”,AI 会告诉你它不Neng透露后续内容。
还有一条“防重复调用”的规则也hen关键。不加这条的话 Agent 有时候会反复调同一个工具,陷入死循环。加上之后基本没再出现过。
项目架构与项目结构是 pnpm monorepo,核心逻辑全在 @readany/core 里桌面端和移动端只需要实现几个平台接口。这意味着要加一个新平台,成本hen低,不需要重写 AI 和 RAG 逻辑。
Zuo了一个月,从“想学学 Agent”到现在说几点真实感受:
Agent 不是银弹。 它Zui大的价值是让 AI 自己决定该干什么但这也意味着不可控性增加了。有时候 AI 会选错工具、反复调同一个工具、或者调了不该调的工具。System Prompt 里的约束和工具的动态注册非常重要,它们是你控制 Agent 行为的主要手段。
检索质量> Agent 架构。 这点怎么强调dou不过分。Agent 架构设计得再漂亮,Ru果 RAG 检索出来的内容不对,Zui终回答还是不行。花在分块策略和混合检索上的时间,回报率远高于花在 Agent 架构上的时间。
流式体验决定用户感知。 同样的回答速度和质量,流式展示和等半天一次性输出,用户的感受天差地别。让用户kan到 AI “正在想 → 正在查 → 正在写”的过程,比什么dou重要。
LangChain 的抽象不完美。 特别是多模型支持这块,每家 Provider 的行为差异比你想象的大。LangChain 帮你屏蔽了大部分差异,但到了流式处理、thinking/reasoning 这些细节,该踩的坑一个也少不了。
项目完全开源,感兴趣的话欢迎 star,也欢迎提 issue 和 PR。GitHub 地址:ReadAny。
Ru果你也在学 AI Agent,建议找个自己感兴趣的方向Zuo个东西出来。不一定要多复杂,但一定要自己从头写一遍。kan十篇文章不如写一百行代码,这是真的。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback