
真要感谢我们团队Leader那天下午他把我叫到工位前说内部想做一个“知识库问答智能体”给研发和运维同学查故障手册、接口文档、历史案例用资料已经整理出来了一共2000多篇Markdown给我一个月时间先跑通一版。我当时对AI Agent是彻彻底底的小白嘴上说着“可以研究一下”脑子里飘过的全是问题AI Agent和普通ChatGPT窗口到底有什么区别大模型不能直接喂文档吗为什么还要单独做一个“智能体”Function Calling到底是什么这些问题我全都答不上来。这一篇就是把那30天里踩过的坑、补过的课、写过的代码以及最终成品串起来。过程谈不上高深却足够真实。如果你也正被安排做内部知识库问答智能体或者刚准备系统学习AI Agent这篇应该能帮你少走至少一个星期的弯路。1. 开工前先摸清家底我的“AI Agent水平”和目标设定1.1 我所谓的小白到底有多白先说清楚我的起点。我是做后端开发的Java和Python都算熟练日常写过不少接口、消息队列、数据处理脚本对Linux部署和Docker也不陌生。但AI相关的东西我之前仅限于“会用ChatGPT查问题”“用Copilot补代码”完全没写过Agent、没用过LangChain也没正经调过Embedding模型。这个定位很重要因为网上很多教程要么默认你已经懂了大模型原理要么直接给你LangChain代码让你复制新手根本分不清是哪里出了问题。我的优势在于写代码和排查问题不怵所以30天足够我从“AI概念盲”变成“能把Agent落地的人”。如果你连编程也不太熟可能要再预留一些时间。我的知识库问答智能体要面向内部研发团队文档主要是故障案例、部署手册、接口说明、SQL报错历史。Leader给的验收标准有三条能回答常见问题、答案必须带来源、知识库里查不到时要直接说不知道不能编。1.2 目标不止是学会是做出能上岗的知识库问答智能体这个目标直接决定了我后面所有的选择。如果只是“学会AI Agent”我完全可以照着文档跑几个例子就收工。但要做知识库问答智能体就必须认真处理文档切分、向量检索、引用溯源、模型幻觉这些工程问题。我给自己定的“能上岗”标准内部知识库中常见问题回答准确率达到80%以上每条回答都要能追溯到原始文档的标题和位置知识库没有对应内容时系统要明确回复“未找到”而不是硬凑答案普通同事能通过网页问问题不需要我帮忙调命令行。后来事实证明第3条是最难的也是这个项目能不能被同事信任的分水岭。1.3 30天四阶段先别想着“全都要”30天看起来不长但如果每天按两到三个小时投入其实可以走完一条完整的落地链路。我把时间切成了四段前两段的任务很轻但后两段压力很大。阶段时间核心目标核心产出概念期第1~7天搞懂AI Agent、RAG、工具调用到底是什么一篇自己能讲明白的笔记最小Agent第8~14天让模型具备调用外部工具的能力一个可以跑起来的CLI小工具知识库问答v0.1第15~21天打通文档切分、向量检索、生成回答内部Web页面引用来源工程化与评估第22~30天评测迭代、修幻觉、部署可给团队试用的在线服务现在回头看这个划分最大的价值是“时间盒”。AI Agent可以学的东西太多了多智能体、复杂规划、模型微调、流式中间状态哪一个展开都是几周的坑。如果没有明确做知识库问答这个主线我大概率会在第10天就被各种框架带跑偏。2. 第1~7天把“能用ChatGPT”误会成“懂Agent”是第一道坎2.1 第一天被问到三个概念直接露馅接手任务后第二天Leader拉了一个对齐会。会上有人问咱们要做的是RAG还是Agent我当时差点脱口而出“这不都差不多吗”之所以没说出来是因为我自己也不确定。会后我把三个概念写在纸上大模型、RAG、AI Agent。我发现根本没法画清它们之间的关系。于是开始疯狂查资料。那几天我看了不少文章但大部分都避重就轻直到我看懂了“员工入职”这个类比思路一下子通了。假设你是团队主管招来一个能力很强但什么都不懂的新员工。这个员工本身就是大模型肚子里有大量书本知识。问题是他不知道你们公司的流程、不知道问题该找谁、也不知道数据库密码存在哪。RAG解决的是“知识缺失”问题——你给新员工发了一份公司内部手册让他遇到不懂的先翻手册。至于怎么判断该不该翻手册、翻完之后怎么用手册本身不会告诉他。AI Agent则更进一步你不仅发了手册还教他一套做事方法——接到任务先拆解遇到不懂的查手册仍然不懂就调用公司系统查数据查完之后再汇总汇报。这套“感知、决策、行动、观察结果”的循环就是Agent的骨架。2.2 我用“新员工入职”把Agent的运行机制盘明白了把类比落到技术上AI Agent并不是一个新的大模型而是一种“大模型外围系统”的架构。大模型是大脑外围系统是手和脚。官方一点的表述是Agent 大模型 规划能力 记忆 工具使用。当时这个概念刷屏我记了不下十遍但真正理解它是在第14天写出第一个工具调用之后。记忆又分短期记忆和长期记忆短期记忆相当于当前对话的上下文窗口长期记忆就像向量数据库或外部存储用来存那些“模型记不住但又很重要的东西”。我第一周的核心收获就是这句话AI Agent的价值不在于模型而在于你给它搭了什么样的外围世界。这个外围世界里有函数、有资料、有规则模型只是那个负责理解任务、调动资源的“调度员”。2.3 第一周我真正吃透的五个知识点我把自己从零开始记下的基础知识点浓缩成五条每一条都是后面代码的基石。第一大模型本身不会调用工具。它只会输出文本。所谓Function Calling是厂商在模型训练和接口层做了特殊处理让模型在合适的时候输出一段结构化的“调用请求”再由你的代码真正执行函数。这个认知帮我避开了很多玄学问题。第二Agent运行的主循环非常简单。给模型系统提示词把用户问题放进去模型要么输出文字回答要么输出要调用的工具名和参数。如果是后者你的代码就执行工具把结果作为新的上下文发给模型模型再看一次。这个循环可以写成不超过50行代码。第三Chain of Thought思维链不是魔法而是让模型把思考过程显式写出来。很多Agent框架的prompt里都有一句“先分析问题再决定下一步动作”就是这个意思。第四RAG和Agent不是竞争关系而是配合关系。知识库问答智能体通常会先做RAG检索再把检索结果交给Agent或大模型去组织回答。如果这个Agent还能根据问题决定是否需要调用不同的检索器它就是带工具的Agent。第五Token和上下文窗口是所有工程问题的源头。模型不是数据库不能把所有知识全部塞进去。Agent里的每一步工具调用、检索返回的每一段内容最终都会被拼进上下文里。上下文一长费用变高、响应变慢、模型还可能抓不住重点。2.4 给同样零基础的人第一周学习资料怎么选我的资料选择原则很简单优先看官方文档再看那些带真实运行过程和报错截图的文章。系统性的概念推荐去读一篇叫“LLM Powered Autonomous Agents”的综述讲Agent的起源和组件讲得很全。如果你想感受Agent真正的研究起点可以去找ReAct那篇论文不用全懂只看它的运行逻辑就够了。不推荐一上来就啃LangChain源码或Transformer论文那是让人放弃学习最快的路径。第一周的重点是建立心智模型不是成为论文复现专家。3. 第8~14天第一个能调用工具的Agent帮我理解了工程价值3.1 技术选型能跑起来比用高级框架重要得多概念期过了第8天我开始动手。一开始有个诱惑是直接用LangChain或者LlamaIndex搭一个Agent代码量很少看起来很高端。但我最终还是忍住了理由有三条。第一我当时连底层循环都还没亲手写过如果直接把LangChain包装好的AgentExecutor拿过来出了问题我很难判断是LLM响应不稳定还是框架配置不对。第二知识库问答业务的逻辑并不复杂核心就是把“检索工具”交给模型让模型决定什么时候检索。这个逻辑用原生代码写完全可行。第三我要给团队演示如果只会在框架里改配置后面无法应对Leader突然提的“能不能换个检索策略”这种需求。所以我最后的技术栈非常简单LLM接口走内网统一网关格式对齐OpenAI的chat completions规范语言PythonFastAPI作为后端前端先用HTML一个简单的搜索框向量库Chroma本地版当时实验数据量不大完全够用检索功能Python手写不引入重型Agent框架。3.2 工具调用链路从模型决定到代码执行的完整闭环我的第一个目标不是做知识库而是让模型能通过工具拿到“当前时间”。这个例子看起来简单但它能验证整条链路是否通顺。大模型API支持tools参数。我先定义一个工具名字叫get_current_time描述是“获取当前服务器时间”参数里面只需要一个空对象{}。当用户问“现在几点”时模型判断这个问题需要调用工具就会在返回内容里带出tool_calls字段。关键代码长这样当时我看懂这个循环后Agent的大门就算打开了def run_agent(user_input, max_steps5): messages [ {role: system, content: 你是一个乐于助人的助理。如果你需要某类外部信息请调用对应工具。}, {role: user, content: user_input} ] for _ in range(max_steps): response client.chat.completions.create( modelqwen2.5-14b-instruct, messagesmessages, toolsTOOLS, ) msg response.choices[0].message if not msg.tool_calls: return msg.content messages.append(msg) for tool_call in msg.tool_calls: fn_name tool_call.function.name fn_args json.loads(tool_call.function.arguments) result execute_tool(fn_name, fn_args) messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result, ensure_asciiFalse), }) return 已达最大执行步数停止处理这个循环看起来简单但它解决了一个很重要的问题模型不再是“一次性回答”而是可以根据工具返回的结果决定要不要继续追问或者执行下一个动作。Agent行为和普通AI助手的本质区别就在这里。3.3 实测踩坑JSON解析、上下文膨胀和死循环那一周我大概有一半时间在调试。第一个坑是模型返回的参数不是严格JSON。比如它偶尔会返回json包裹的字符串或者参数名多一个空格。后来我写了解析函数先尝试标准json.loads失败就提取首尾大括号再解析再失败就正则抓key和value。宁可慢一点也不能让流程崩在解析上。第二个坑是上下文膨胀。有一次我让Agent调用一个返回日志的工具工具把完整日志全部拼进messages结果第二轮调用时模型已经忘了最初用户问的是什么。解决办法是控制工具返回内容大小只返回摘要或前几十行真正的完整文本放进单独的结果文件里需要时再取。这个习惯放到知识库场景同样适用——检索到的文档片段是要被模型“读”的不是全部塞给它。第三个坑是没有设置最大循环次数。模型在连续调用同一个工具时不亦乐乎第一次调用返回结果后它觉得自己还需要再调最后陷入死循环。后来我把max_steps设为5并且每一步都在日志里打印函数名、参数、耗时。没有这些日志出了问题就只能靠玄学修复。第14天的晚上我终于做到在命令行输入“现在几点了”Agent会调用工具然后回答正确时间。那一刻我突然理解了为什么说Agent不是模型能力的简单体现它更是一个完整的工程系统。4. 第15~21天知识库问答智能体从构思到上线RAG是真实答案的来源4.1 为什么没选微调而是RAG动手做知识库问答前团队讨论过两个方案微调大模型或者用RAG。我的选择是RAG原因很直接。微调相当于把知识“背”进模型的参数里。它适合场景比较固定、风格需要统一的场合比如让模型学会某种特定输出格式。但我们的内部文档每周都可能更新今天刚发生的故障案例明天就想能被搜到如果用微调每次都要重新训练模型周期长且成本高。更重要的是微调后用户还是看不到答案来自哪份文档出了问题无法追责。RAG则是开卷考试。用户提问后系统先去文档库里检索最相关的几段内容再把内容和问题一起交给大模型让模型根据给出的片段作答。这样文档更新只需要替换索引里的内容而且回答过程中我们可以把检索到的原文编号展示出来同事可以点开核对。对一项内部工具来说“答案是否有出处”决定了它能不能被信任。RAG和微调完全可以结合比如先微调让模型理解内部术语再叠加RAG获取最新知识。但对30天的项目来说RAG是性价比最高的路线。4.2 数据处理的隐藏工作量清洗和文档切分我原本以为做知识库问答智能体最核心的代码是“调大模型接口生成回答”真正动手才发现80%的精力都花在了数据准备上。文档切分尤其是中文Markdown的切分是第一个让我熬夜的问题。最开始我尝试按固定字符长度切每500个字符一刀。结果很快发现一个文档段落会被拦腰切成两半模型拿到的片段经常是一段不完整的SQL语句或者一大段没有上下文的表格。即便我在片段之间加了重叠效果依然很差。后来我从LangChain和LlamaIndex的文档里找到思路先按文档结构切再按段落长度切。具体到Markdown要优先保留标题层级。我的规则是按一级标题、二级标题把整篇文章拆成大章节大章节内部再按空行切段落段落超过600个字符时在大标题或自然句号处拆分相邻两片设置120个字符的重叠防止关键上下文被切断代码块和表格能整段保留就整段保留不跨块切割。def split_markdown(md_text): sections split_by_heading(md_text) chunks [] for section in sections: blocks split_by_blank_line(section) for block in blocks: chunks.extend(split_by_length(block, max_chars600, overlap120)) return chunks这版规则不复杂但解决了检索结果碎片化问题。后来我又发现文档里的“前置知识”和“旧版本过期说明”这类文字很干扰检索。比如用户问“怎么部署订单服务”命中的往往是已经标记为“不适用于新版本”的章节。于是我在切分前先做一轮清洗去掉明显过期的导读、把关键词标签统一、在特殊文本前补充说明。4.3 检索链路迭代从向量召回到BM25再到重排第一版知识库问答我用的是纯向量检索把用户问题转为向量在Chroma里找出最相似的5段文档。实际跑下来效果很一般很多包含“502错误”“连接池满了”这种精确关键词的问题向量检索居然没有把相关文档排在前面。后来我加了BM25关键词检索和向量检索各取50条结果再用RRF算法合并排序。这一步提升非常明显原因是内部故障描述里有很多专有名词关键词命中非常可靠而向量检索处理语义表达强但关键词重合少的问题两者刚好互补。重排我用了同领域的一个开源cross-encoder小模型。它会将检索回来的100段候选和历史问题逐一算相关性分数我取分数最高的前5段喂给大模型。这个过程让“能搜到”变成了“搜得准”是准确率提升最明显的一步。不要觉得“混合检索重排”听起来复杂其实每一步都有现成轮子。向量召回用ChromaBM25用rank_bm25重排用HuggingFace的Pipeline。工程难点不是调用这些工具而是调参数向量检索的top_k取多少、BM25的权重、重排后还有什么阈值判定“没有找到答案”这些都要靠评测数据来说话。4.4 带引用回答让AI把“证据”摆出来知识库问答智能体和普通聊天机器人最大的不同是回答必须可验证。我在构造Prompt时会给模型传输经过重排的文档片段并明确告诉它你只能依据“参考资料”回答用户问题。如果参考资料中没有相关内容请回答“知识库中暂未找到答案”。在你引用的正文后标注对应编号例如[1]、[2]。检索片段在进入Prompt前会被编号。最终模型生成的答案里如果用了第一段内容就会带上[1]。我在前端把[1]渲染成指向源文档的链接点击即可跳转到内部文档原始页面。这个功能看起来只是一个小改进但它解决了两个问题。第一同事看到回答时敢于相信因为他们可以点开原文核对。第二一旦回答错了研发团队能定位是检索错了还是生成错了。上线后同事反馈最多的一句话变成了“下次把这些文档的更新权限配上就更好了”。5. 第22~30天让它从“能答”到“靠谱”5.1 没有评测集后面所有优化都是玄学知识库问答跑到第20天时Demo给Leader演示了几次效果都很惊艳。但我知道它在特定问题上仍然会编。让我紧张的是我不知道它哪些问题会编什么时候会编。如果直接上线第一次被同事问到没文档覆盖的冷门问题它张口就来一段“合理”的错误答案整个系统的信任就崩了。所以第22天我干了一件笨但重要的事从文档库里挑出了50道有代表性的问题覆盖命名解释、排错过程、SQL写法、版本兼容和知识库外问题。每题配备参考答案和来源文档编址。然后我把系统答案和参考答案人工比对分数分成三档完全正确/部分正确/错误拒绝。这套评测集帮我验证了一个残酷事实第一版纯向量检索重排的效果并没有演示时那么神准确率只有62%。之后我每一轮改动都会用这50道题重新跑一遍看涨看跌。加入BM25混合召回后分数提升到81%再加入“低分拒答”逻辑后整体可接受率到了85%以上。版本准确率引用正确率备注纯向量检索强制回答62%47%能答但喜欢编向量BM25RRF强制回答75%69%搜得准了一点重排Top581%78%效果明显低分拒答和“不知道”逻辑86%82%不硬答后信任感提升5.2 多轮会话、指代消解和“不知道”的边界上线前我发现另一个容易被忽略的问题同事在网页上提问往往不是一次性问完的。他们会先问“为什么生产环境接口老超时”得到答案后再追问一句“那MySQL这边需要改吗”。这里面的“那”指的是前文的问题背景直接把这个追问送去检索结果非常差。我给系统加了一个多轮改写步骤把“当前问题最近几轮对话摘要”送给一个小模型让它把追问改写成一个不依赖上下文的问题。这一步很轻量但对检索效果提升帮助巨大。比如上面的追问会被改写成“生产环境接口超时MySQL连接池等数据库侧参数需要修改吗”。需要注意的是不是所有场景都需要这个步骤。如果只是单轮问答就没必要为了写改写而引入额外延迟。“不知道”的边界也要调得很细。如果重排后最高分文档的相关性只有0.3模型还硬要回答大概率在编。我设了一个阈值低于阈值的片段不进入生成阶段直接向用户展示“知识库目前没有找到相关答案请换个表达试试”。对于知识库外的测试题这个逻辑的拒绝准确率从早期的11%一路上升到84%。5.3 时延、并发与部署小团队工具的务实选择知识库问答智能体跑通后下一个问题是怎么让同事用起来。先不考虑做App我们只需要一个团队内部可访问的网页。后端我用FastAPI包了一个服务逻辑很简单网页提交问题后端调用多轮改写、检索、重排、生成最后返回答案和引用源。页面不加花哨功能就一个搜索框和答案区。模型部署采用的是量化后的14B开源模型。最初试过满血跑A卡服务器显存不太够换成AWQ量化后单张显卡勉强能支撑。开发测试阶段并发量很低我就没上更复杂的推理框架直接用了一个模型服务容器线上压测发现一个检索请求大约2到3秒返回其中大头是模型生成时间。后来我给重复问题加了缓存同样的提问如果不带新上下文直接从缓存里返回内部工具完全够用。这个阶段的杀手锏是日志。我把每次提问的问题、改写的检索词、重排Top5的文档编号及分数、最终答案都写成了结构化日志。每次同事说“它回答得不对”我能很快从日志里判断是改写写偏了还是检索没召回还是生成阶段没按Prompt走没有日志后面所有调优都无从谈起。5.4 正式开放给团队前后我做的一次小范围试运行上线前的最重要动作不是写文档而是找三位真实用户帮我试。我找了运维同事和两个后端同事让他们用平时工作中真正困扰的问题去问。结果发现一个有意思的问题团队内部有很多简称比如“结算服务简称CS”“生产环境有人直接写prod有人写线上”直接拿去检索命中率偏低。解决方式不是造一个很大的同义词表而是在文档清洗阶段和检索阶段各做一个轻量替换把高频同义说法都归一化成文档里的标准术语。另外我在Prompt里加了一句话如果用户使用内部简称请按照知识库上下文理解不要自行发明解释。效果立竿见影。6. 第30天复盘假设重回起点我这个AI小白会有哪些不同做法6.1 一版版跑出来的真实变化复盘一个重要维度是看数据变化。一开始我的知识库问答准确率只有62%很多情况下模型是从文档里掐头去尾摘一段话强行放到回答里读起来像模像样但往往没过脑子。后来混合检索加上去准确率到了75%以上。再加重排到了81%。再加上拒答逻辑和改写逻辑最终评测集的可接受率在86%左右。这个提升过程告诉我大模型问答项目的天花板并不只在模型而在数据准备、检索链路和边界控制这三件事。无脑换更大的模型不一定有效有时候数据切分规则改一下涨分比换模型还快。6.2 最值得的时间和最浪费时间的几件事如果重新分配这30天我会砍掉一些行为。花得最值的是前一周的概念学习。没有那一周我后面写代码会非常容易写歪。其次是数据切分和检索链路的迭代因为知识库问答的核心就是“找到对的文档再让模型回答”。浪费时间的也不少。第10天左右我在无关紧要的切片重叠参数上反复调了很久希望找到一个万能值后来意识到重叠只是辅助手段主要逻辑是把“语义完整的块”切好参数差不多就行。还有一段时间我在研究怎么给前端做一个漂亮的答案流式输出但因为时间有限又没做好后来暂时搁置等上线稳定后再考虑。对“内部工具”来说功能可靠永远优先于视觉效果。6.3 给下一个AI小白的10条经验最后把这些天攒下的经验整理成10条算是带“血”的提醒。先手写一遍Agent主循环再决定要不要用LangChain。写过一次你就会明白框架只是替你完成了这段循环而已。大模型本身不会调用工具它只是输出一段调用请求。如果哪个环节没反应先查你的代码有没有真正执行这个函数。RAG效果的瓶颈大概率在数据切分和召回不要在提示词上死磕。引用来源是知识库问答智能体的生命线。没有来源的回答对内部知识工具来说没有价值。从第一天开始就要让系统有“不知道”的能力。比起编一个错误答案“不知道”更安全。要有评测集。哪怕只有30道题也比靠拍脑袋调参强。日志一定要全。没有日志AI系统在你眼里就是一个黑盒。多轮问题要单独做处理。别把聊天窗口的上下文一股脑丢给检索。大模型API的参数调优可以放一放先把“检索到正确文档”这件事做好结果自然好。30天可以做很多事但不要贪心做多智能体。把一个知识库问答智能体做扎实比搭一个华而不实的Agent demo强太多。第30天下午我把这个系统开放给了我们组内的十几位同事。当晚有人在群里说了一句“它回答的那个Linux内核参数问题标出来的来源文档居然是真的而且是半年前那个事故复盘。”看到这句话我知道这一个月没白过。AI Agent对小白来说并不是什么高不可攀的东西它更像一套需要被认真对待的工程方法数据、检索、模型、边界一环扣一环。能踏踏实实把这几个环节串起来你已经超过绝大多数只会在网上看概念的人了。