新闻详情

新闻详情

首页 / 资讯中心 / 详情

AI工程从零搭建:Prompt、Agent与RAG落地全指南

发布时间:2026/10/1 9:13:05来源:尧图网络
AI工程从零搭建:Prompt、Agent与RAG落地全指南
“ai-engineering-from-scratch”这个标题我第一眼看到的时候其实挺有感触的。不少朋友私信问我说自己在Kaggle上刷了几个比赛或者跟着教程微调过一个开源模型就算入行AI了吗我的看法是那叫“AI算法实验”离“AI工程”还差着一整条生产链路。所谓AI工程不是把模型跑通就完事而是要解决数据怎么来、特征怎么算、模型怎么上线、上线之后怎么监控、出问题了怎么回滚这一整套问题。今天我就以这个标题为线索把从零搭建一个AI工程项目的完整链路拆开讲透覆盖技术选型、Prompt设计、Agent架构、RAG落地、服务化部署以及上线后的评估与迭代。不说虚的全部是能直接抄作业的内容。这个项目适合谁三类人第一类是刚入门不久、想把手里的模型变成一个真正可用产品的开发者第二类是在业务团队里负责AI落地需要快速搭建概念的算法工程师第三类是想转型AI方向但一直被“工程化”三个字卡住的后端工程师。不管你属于哪一类这篇文章希望让你少走至少三个月的弯路。1. 思路先行AI工程和AI炼丹根本是两回事1.1 先搞清楚你到底在做哪一个层级的AI工程很多人一听到AI工程第一反应是“训练模型”。这个认知需要纠正。训练模型只是AI工程里最上游的一环甚至对于绝大多数业务场景来说根本不需要你从零训练一个大模型你要做的是“用模型”和“编排模型”。我习惯把AI工程分成三个层级来理解第一层模型层。这是研究团队的主场涉及数据清洗、特征工程、模型架构设计、训练调参、分布式训练等。这个层级追求的是“模型指标”准确率、召回率、困惑度、BLEU分数等等。普通业务团队通常不碰这一层因为成本和周期都不是一个量级。第二层应用层。这是大多数AI工程师真正的主战场。你做的不是训练模型而是怎么把现成的模型能力封装成业务可用的功能。比如调用大模型的API做文案生成、把开源模型部署成内部服务、用LangChain或者原生代码编排一个Agent。这层追求的是“业务指标”响应速度、成本、用户体验、任务完成率。第三层系统层。这是最容易忽视但决定项目生死的一层。你要考虑并发、鉴权、限流、降级、缓存、日志、链路追踪、灰度发布、模型版本管理。说白了AI工程和传统后端工程在这一层是殊途同归的只是业务逻辑从“查数据库”变成了“调模型”。所以从零开始做AI工程第一个要建立的心态就是你不是来炼丹的你是来盖房子的。地基是系统层承重墙是应用层装修才是模型层。1.2 技术栈选型别一上来就上全家桶我见过太多团队项目刚启动就迫不及待地引入LangChain、LlamaIndex、向量数据库、Docker、K8s全套组件结果两个月过去了连一个能用的Demo都没有时间全花在调试框架兼容性上了。我的建议是按需引入能少用就少用。从零开始最核心的技术栈其实只要四样一是模型调用层。如果预算允许直接用商业APIOpenAI、DeepSeek、智谱、通义都可以选择标准很简单看你的应用场景对中文支持度、延迟、成本、数据合规的要求。如果必须私有化部署那就选开源模型Qwen系列和Llama系列是当前最稳妥的底座。二是任务编排层。第一版项目不建议上LangChain这类重框架。为什么因为框架抽象了很多底层逻辑出了问题你连排查都不知道从哪查起。先用手写代码来完成Agent的循环、记忆、工具调用等你把这套逻辑彻底摸透了再决定要不要引入框架来提升效率。你用框架节省的时间最终都会在调试框架的时间上还回去。三是存储层。如果涉及RAG检索增强生成需要一个向量数据库。Milvus适合大规模生产环境但起步阶段用轻量的方案就足够。Qdrant和Chroma都是不错的选择个人更推荐Qdrant因为它在过滤条件和标量字段的支持上做得比Chroma更成熟后面你做大规模知识库过滤时就知道这个优势有多重要了。同时还需要一个传统关系型数据库来存用户、会话、日志等结构化管理数据PostgreSQL是首选一个库搞定关系数据和向量检索减少一个运维组件。四是服务化层。FastAPI是当前AI服务封装的实际标准自动生成API文档、异步支持好、上手极快。网关层面第一版项目可以直接用Nginx不需要上微服务全家桶。你的核心目标是用最小的成本把模型能力变成一个别人能调用的服务而不是先造一个微服务大观园。1.3 为什么“模型能力工程封装”这条路最好走AI工程从零开始不需要你做太多创新。最稳的路径就是模型能力由大模型提供工程价值由你来创造。什么意思模型理解自然语言、生成文本、总结归纳的能力是厂商已经训练好的你调API就行。你要做的核心工作是把这些能力封装成符合业务需求的接口设计好输入输出的协议让模型在合适的时机调用合适的工具再把模型的输出以合规、稳定的方式交付给用户。举个最直观的例子。假设你要做一个企业内部的知识库问答系统。模型本身不知道你们公司的制度文档、产品手册、历史决策记录你需要做的是第一步把文档数据清洗、切片、向量化存入向量数据库这叫知识接入。第二步用户提问时先从向量库里检索相关片段再把片段和原始问题一起交给模型这叫检索增强。第三步设计好系统提示词约束模型只能基于检索内容回答避免幻觉这叫约束生成。第四步把这个流程封装成API接入企业IM或者网页前端这叫服务集成。看到了吗整个过程没有一行训练代码但你做的事情就是一个标准的AI工程。你的核心交付物不是模型而是“模型数据流程服务”组合而成的系统能力。2. 核心零件逐个拆Prompt、Agent、RAG怎么落地2.1 Prompt Engineering你写的不是提示词是交互协议很多刚开始接触大模型开发的朋友对Prompt的理解停留在“让AI帮我写一篇文章”这个层面。但在AI工程里Prompt远不是这么简单。它本质上是模型与业务系统之间的交互协议是一段需要被精心设计的“系统说明书”。一个生产级的System Prompt至少要覆盖五个维度的信息第一个维度角色设定。告诉模型“你是谁你以什么身份工作”。比如“你是一名企业IT服务台的智能助手负责解答员工关于办公软件使用的问题”。别小看这一步角色设定直接影响模型的语气、知识偏好和回答风格。第二个维度任务说明。明确模型需要完成什么任务。要具体到输入是什么、输出是什么、中间要不要经过思考步骤。比如“根据用户的问题从提供的参考文档中提取答案。如果参考文档中没有相关内容明确回答’知识库中未找到相关信息’不要自行编造”。第三个维度约束条件。这是最容易遗漏的部分也是最关键的部分。约束条件包括不要用多余的解释、不要编造数据、不要提及你是一个AI、输出格式必须是JSON等等。这些约束直接决定了模型输出的可用性。尤其是输出格式约束如果模型输出的格式不稳定下游解析代码分分钟炸掉。第四个维度案例示范。给模型一个或两个输入输出的样例让它理解你的期望风格。比如“问题如何重置企业邮箱密码参考文档... 答案请访问企业IT门户选择账号管理-密码重置需通过手机验证”。Few-shot示例对模型输出的稳定性提升非常明显尤其是在输出格式比较复杂的情况下。第五个维度兜底策略。告诉模型遇到边界情况怎么办。比如“如果用户表达不明确请列出问题请用户澄清”、“如果无法理解用户意图请告知用户转接人工服务”。没有兜底策略的Prompt在线上环境会暴露出非常低质量的回答。从工程角度来看Prompt不应被硬编码在业务代码里。正确的做法是将System Prompt、Few-shot示例、输出格式说明等抽成独立的配置模块按版本管理支持动态切换。这样当Prompt调整导致效果变化时你可以快速回滚而不是改一行代码就要重新发布整个服务。2.2 Agent架构从“一问一答”到“自主执行”的关键一跃有了基础的Prompt设计你只能做一个“聪明的聊天机器人”。要让AI真正变成能完成任务的Agent得给它装上三件套工具、记忆、循环。所谓工具就是模型可以调用的外部功能。典型的工具包括搜索引擎、数据库查询接口、企业内部的业务API、计算器、代码解释器等。这里的关键在于模型本身不会主动调用工具你需要把每个工具描述成模型能读懂的函数定义让它在思考过程中决定“这个任务需要调用XX工具”然后生成调用参数由你的代码真正执行调用再把结果返回给模型。这里有个初学者必踩的坑工具描述写得太模糊。你写“search_documents(query: str)”模型根本不知道这个工具覆盖哪些文档范围、返回什么格式。正确的写法是“search_documents(query: str) - 在企业知识库中搜索员工手册、IT指引、行政制度等相关文档返回结果为JSON数组每个元素包含标题、正文摘要、匹配得分”。模型是靠着这个描述来决定“我该不该用这个工具”的描述质量直接决定工具调用的准确率。所谓记忆分为短期记忆和长期记忆。短期记忆就是当前对话上下文中的历史消息你需要把多轮对话的内容传给模型它才能理解“刚才聊了什么”。长期记忆则是把用户的历史偏好、历史操作记录、项目背景等结构化数据持久化存储在需要时加载到上下文中。所谓循环就是让模型进入一个“思考-行动-观察”的迭代过程。模型先基于当前上下文和用户目标决定下一步做什么如果决定调用某个工具你的代码执行工具并把结果返回给模型模型根据工具结果继续推理判断是再调工具还是输出最终答案。这个循环会一直持续到模型认为目标完成或者达到你设定的最大循环次数。手写Agent循环并没有那么神秘核心代码逻辑不复杂。关键是你要理解这个循环的每一步在做什么。当你真正理解了你会发现自己可以对这个循环做各种定制化改造加上安全审核节点、加上人工审批节点、加上成本控制逻辑等等。这些能力是你在框架的黑盒里学不到的。2.3 RAG让模型学会查资料而不是瞎编RAG检索增强生成是目前大模型应用落地最刚需的技术方案没有之一因为它的核心价值是解决幻觉问题。用生活化的方式理解RAG模型就像一个学富五车但记忆模糊的资深顾问他肚子里有海量的背景知识但他并不会读阅你们公司的内部资料。RAG做的事情就是在顾问开口回答之前先派一个助手去资料室把相关文档翻出来摆在顾问面前让顾问照着资料回答。RAG的工程实现核心在三个环节一是文档预处理。这一步直接决定最终检索效果的上限。开发者常见的错误是把Word文档整篇扔进去让它向量化。这会导致检索单元过大一段关于“审批流程”的内容混杂在大量的无关文本中向量相似度被稀释最终检索出来的片段和用户问题匹配度很低。正确的做法是先做格式转换PDF/Word/HTML转纯文本再做结构清洗去掉页眉页脚、水印、无关图片描述再按语义结构做切片Markdown标题层级、段落、语义完整性最后是向量化。切片大小没有绝对标准我的经验是中文场景下200-500字之间是一个比较平衡的范围。二是检索策略。基础做法是把用户原始问题向量化在向量库里做相似度搜索TopK取回最相似的几个片段。但真实场景下单独靠向量检索远远不够。用户问题里经常包含一些关键实体词比如“工单编号”、“服务器型号”这些词在语义向量空间里区分度并不高需要配合关键词检索BM25或者结构化字段过滤来提升精度。生产级方案目前主流做法是混合检索将向量检索和BM25关键词检索的结果拼接去重用Rerank模型或LLM精排接口对候选集再做一次相关性排序然后把最相关的5-8个片段送进生成环节。这个链路虽然多了一步但效果提升是立竿见影的。三是上下文构造。系统Prompt里要明确告诉模型回答只能基于用户提供的知识片段不依赖大模型内部知识如果内容不相关必须说不知道。然后把检索到的片段按照“先序号标注、再拼接”的格式传进去这样模型可以精确引用。还需要控制送入模型的总Token数避免知识片段过多导致输入超限同时控制成本。3. 实操过程从零搭一个可运行的AI问答Agent理论说再多不如直接跑一个项目。下面我带你从零开始实现一个带RAG和工具调用能力的AI问答Agent代码全部基于OpenAI兼容接口无论你选哪家国产模型还是OpenAI官方模型只要接口兼容这套代码都能直接跑通。3.1 第一步搭建项目骨架和配置管理先初始化一个Python项目我推荐使用Python 3.10以上的版本后面用到的技术特性更多一些。项目目录结构按照这个模板来ai_engineering_project/ ├── app/ │ ├── __init__.py │ ├── config.py # 配置管理 │ ├── llm.py # 模型调用封装 │ ├── memory.py # 会话记忆管理 │ ├── tools.py # 工具函数定义 │ ├── agent.py # Agent核心循环 │ └── rag.py # RAG检索模块 ├── data/ │ ├── raw/ # 原始文档 │ └── processed/ # 切片后的文档 ├── tests/ # 单元测试 ├── requirements.txt └── .env # 环境变量配置配置管理部分我用Pydantic Settings来写它能把环境变量、.env文件、默认值三者统一管理起来后续部署到不同的环境开发、测试、生产只需要维护不同的.env文件# app/config.py from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): model_config SettingsConfigDict(env_file.env, env_file_encodingutf-8) # 模型配置 llm_api_key: str llm_base_url: str https://api.deepseek.com/v1 llm_model: str deepseek-chat temperature: float 0.3 max_tokens: int 2048 # RAG配置 embedding_model: str BAAI/bge-large-zh-v1.5 chunk_size: int 350 chunk_overlap: int 50 top_k: int 6 collection_name: str kb_chunks # 向量库配置 vector_db_path: str ./data/vectordb # Agent配置 max_agent_iterations: int 5 settings Settings()这里有两个细节要重点说明。第一个是temperature参数的设置在Agent场景中我建议调到0.3以下因为Agent在执行工具调用时只允许使用规则固定的JSON格式temperature太高会导致输出格式飘逸一会儿用单引号一会儿用双引号解析器会疯掉。第二个是把max_tokens设置得足够长Agent在思考时往往会输出比较长的推理过程如果max_tokens太短它可能在输出完思考过程后就被截断来不及输出工具调用参数。3.2 第二步实现LLM调用层和结果解析模型调用层是整套系统的“发动机”。我先封装一个基础的LLM调用函数让任何上层模块Agent、RAG都能复用它# app/llm.py import json from typing import Dict, List, Any from openai import OpenAI from .config import settings _client OpenAI(api_keysettings.llm_api_key, base_urlsettings.llm_base_url) def chat_completion( messages: List[Dict[str, str]], temperature: float None, max_tokens: int None, response_format: str None, ) - str: 统一的模型调用入口所有模块都走这个函数 kwargs { model: settings.llm_model, messages: messages, temperature: temperature if temperature is not None else settings.temperature, max_tokens: max_tokens if max_tokens is not None else settings.max_tokens, } if response_format json: kwargs[response_format] {type: json_object} resp _client.chat.completions.create(**kwargs) return resp.choices[0].message.content def extract_json(text: str) - Dict[str, Any]: 从模型输出中安全提取JSON对象 text text.strip() try: # 直接解析 return json.loads(text) except json.JSONDecodeError: pass # 处理模型输出被Markdown代码块包裹的情况 if text.startswith(): text text.replace(json, ).replace(, ).strip() try: return json.loads(text) except json.JSONDecodeError: pass # 尝试截取第一个JSON对象段 start text.find({) end text.rfind(}) if start ! -1 and end start: try: return json.loads(text[start:end1]) except json.JSONDecodeError: pass # 兜底把非法的Python dict字面量转成合法JSON text text.replace(, ) try: return json.loads(text) except json.JSONDecodeError: raise ValueError(f无法从模型输出中提取JSON: {text[:200]})这里要聊聊我在实际项目中踩过的坑。不同模型对“输出JSON”的理解差异很大。有的模型会乖乖输出纯JSON有的会在JSON外面套一个Markdown代码块有的会先输出一段解释再输出JSON有的甚至会把键名打上单引号这是Python dict风格的非法JSON。所以我在每个项目里都会放一个健壮的JSON提取函数把各种异常情况都覆盖到。这个函数看起来不起眼但它在真实场景里能帮你省下大量排查时间因为模型输出格式的抖动是线上最频繁遇到的一类问题。3.3 第三步实现Agent循环和工具调用现在来实现Agent的核心循环。这一版的Agent逻辑是先把用户的自然语言问题转成一个结构化的“任务计划”然后循环执行“判断-调用-观察-再判断”。我先定义两个工具函数。第一个是获取服务器状态的工具第二个是计算器工具。为了让模型能看懂工具每个工具都附带了一份详细的描述文档# app/tools.py from typing import Dict, Any import json TOOL_DESCRIPTIONS [ { type: function, function: { name: get_server_status, description: 查询指定服务器的实时运行状态包括CPU使用率、内存使用率、磁盘IO、网络延迟等指标。服务器ID格式为host-xxx如host-01、host-02。, parameters: { type: object, properties: { server_id: { type: string, description: 服务器ID格式为host-xxx } }, required: [server_id] } } }, { type: function, function: { name: calculator, description: 执行数学计算支持加、减、乘、除、幂运算等基础运算。用于处理用户需要的数值计算场景。, parameters: { type: object, properties: { expression: { type: string, description: 数学表达式例如1234*256 } }, required: [expression] } } } ] def get_server_status(server_id: str) - Dict[str, Any]: 模拟查询服务器状态实际项目中替换为调用真实监控API # 这里只是一个模拟实现真实场景下应该调用运维监控系统的API mock_data { host-01: {cpu: 23.5, mem: 45.2, disk_io: 12.3, net_delay: 1.2}, host-02: {cpu: 78.9, mem: 62.1, disk_io: 45.6, net_delay: 3.8}, host-03: {cpu: 32.1, mem: 28.9, disk_io: 8.9, net_delay: 0.9}, } if server_id not in mock_data: return {error: f服务器 {server_id} 不存在或未接入监控系统} return mock_data[server_id] def calculator(expression: str) - Dict[str, Any]: 执行数学计算只允许数字和运算符禁止注入代码 allowed_chars set(0123456789-*/(). ) for ch in expression: if ch not in allowed_chars: return {error: f表达式中包含非法字符: {ch}} try: result eval(expression, {__builtins__: {}}, {}) return {result: result} except Exception as e: return {error: f计算失败: {str(e)}}注意我在工具函数里都做了安全性校验。AI工程线上最容易出问题的点之一就是工具函数的安全漏洞。因为模型输出的参数是不可信的工具函数必须像处理用户输入一样处理模型输出。计算器看起来简单但如果不对表达式做字符白名单校验就可能变成任意代码执行漏洞。这个习惯一定要养成。接下来是Agent主循环# app/agent.py from typing import List, Dict, Any from .llm import chat_completion, extract_json from .tools import TOOL_DESCRIPTIONS, get_server_status, calculator SYSTEM_PROMPT 你是一个智能运维助手负责帮助用户查询服务器状态、执行运维相关计算并给出合理的运维建议。 你有以下工具可以调用 - get_server_status: 查询服务器实时状态 - calculator: 执行数学计算 工作流程 1. 分析用户意图判断是否需要调用工具 2. 如果需要调用工具请严格按照JSON格式输出工具调用参数{action: 工具名, parameters: {...}} 3. 收到工具执行结果后继续分析结果并决定下一步行动 4. 如果不需要调用工具或已经收集到足够信息输出面向用户的最终回答 注意事项 - 不要编造服务器运行数据所有数据必须来自工具调用结果 - 如果用户询问的服务器不在已知列表中明确告知用户 - 输出最终回答时语气简洁、专业 def run_agent(user_query: str, history: List[Dict[str, str]] None) - str: Agent主入口根据用户问题循环执行工具调用直到得到最终回答 messages [{role: system, content: SYSTEM_PROMPT}] if history: messages.extend(history) messages.append({role: user, content: user_query}) for _ in range(settings.max_agent_iterations): response chat_completion(messages, response_formatjson) try: parsed extract_json(response) except ValueError: # 模型没有返回JSON直接把它当最终回答返回 return response action parsed.get(action, ) if action in (final_answer, 回答, answer): return parsed.get(content, response) if action in (get_server_status, calculator): tool_params parsed.get(parameters, {}) # --- 工具实际执行真实项目中这里要加参数校验和审计日志 --- if action get_server_status: tool_result get_server_status(tool_params.get(server_id, )) elif action calculator: tool_result calculator(tool_params.get(expression, )) # ------------------------------------------------------ tool_message f工具{action}执行结果{json.dumps(tool_result, ensure_asciiFalse)} messages.append({role: assistant, content: response}) messages.append({role: user, content: tool_message}) continue # 模型返回了不明动作给它一些引导让它回到正轨 messages.append({role: assistant, content: response}) messages.append({role: user, content: 你的输出格式似乎不正确。请重新输出JSON格式的回复其中action字段必须是get_server_status、calculator或final_answer三选一。}) return 已达到最大处理轮次请简化问题后重试。这个循环的核心逻辑就是我在前面说的“思考-行动-观察”三拍节奏。每次模型输出一条JSON代码解析它判断它要做什么执行对应的工具把结果反馈回去让模型继续推理。直到模型输出final_answer才把控制权还给用户。我把System Prompt写成了引导模型输出结构化JSON的方式这是Agent实现路径里比较轻量的一种做法适合需求比较简单、工具数量在5个以内的场景。如果你的工具数量超过5个建议切换到大模型原生的function calling机制让模型的API层直接输出结构化的工具调用请求而不是靠解析JSON字符串。两种方案我都在生产环境用过各有优劣原生function calling更稳定JSON方案更可控且不依赖厂商的特定实现。贵司如果用了不同家的模型JSON方案的可移植性会更好。3.4 第四步接上RAG让回答有据可依接下来是RAG模块。这里用一个轻量的实现先用FastAPI启动一个向量服务或者直接用本地文件做向量存储。为了演示清晰我直接用一个轻量级方案——基于Python dict的临时向量存储换到生产环境你可以无缝替换为Qdrant或Milvus的实现。第一步是把文档切片。我写一个按标题层级切片的函数# app/rag.py import re import hashlib from typing import List, Dict, Any def chunk_document(text: str, chunk_size: int 350, overlap: int 50) - List[Dict[str, str]]: 按标题层级和语义段落对文档切片 text re.sub(r\n{3,}, \n\n, text.strip()) lines text.split(\n) chunks [] current_title current_chunk for line in lines: line line.strip() if not line: continue # 识别标题行开启新的语义块 if re.match(r^(#|##|###|####)\s, line): title re.sub(r^(#|##|###|####)\s, , line) if title ! current_title: current_title title # 如果当前块加上新行超过chunk_size先存档开新块 if len(current_chunk) len(line) chunk_size and current_chunk: chunks.append({ title: current_title, content: current_chunk.strip() }) # 设置重叠区保留上一块的尾部内容避免切断了语义 current_chunk current_chunk[-overlap:] \n line else: current_chunk \n line if current_chunk.strip(): chunks.append({ title: current_title, content: current_chunk.strip() }) return chunks字段切片策略我建议按下面的对照表来定方案。文档类型切片策略推荐切片大小理由规章制度、操作手册按章节段落切片300-500字每一条制度/操作步骤相对独立增大切片可以保持操作流程完整技术文档、API文档按代码块注释块切片200-400字代码块需要保持完整不能把函数定义和调用切开问答对、FAQ整对切片整对问答对不可拆散拆了就无法匹配语义新闻文章按段落主题聚合300字左右新闻上下文关联紧适合中等粒度这里有一个很多人的效率误区就是把整篇文档一股脑切好然后等到用的时候再慢慢检索。更好的方式是对切片后的文档做向量化并入库查询时先把用户问题向量化再在向量库里做相似度搜索。向量库的方案我建议直接从本地文件起步你需要控制的是“切多少、存哪里、怎么查”这三个核心问题而不需要在第一阶段就上分布式系统。3.5 第五步用FastAPI把Agent封装成服务有了Agent和RAG剩下的工作就是把它封装成一个对外可调用的服务。用FastAPI实现代码非常短# app/api.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel, Field from typing import List, Optional from .agent import run_agent from .rag import search_knowledge_base app FastAPI(titleAI Agent Service, version0.1.0) class QueryRequest(BaseModel): query: str Field(..., min_length1, max_length2000, description用户问题) history: Optional[List[dict]] Field(None, description历史对话消息列表) use_rag: bool Field(True, description是否启用知识库检索增强) class QueryResponse(BaseModel): answer: str sources: Optional[List[str]] None app.post(/v1/agent/query, response_modelQueryResponse) def agent_query(req: QueryRequest): try: # 如果启用RAG先检索知识库把相关片段拼接到上下文中 context sources [] if req.use_rag: relevant_docs search_knowledge_base(req.query, top_k5) if relevant_docs: context \n\n.join([ f[文档{idx1}] {doc[title]}\n{doc[content]} for idx, doc in enumerate(relevant_docs) ]) sources [doc[title] for doc in relevant_docs] augmented_query req.query if context: augmented_query f用户问题{req.query}\n\n参考知识库内容\n{context} answer run_agent(augmented_query, req.history) return QueryResponse(answeranswer, sourcessources if sources else None) except Exception as e: raise HTTPException(status_code500, detailfAgent执行失败: {str(e)}) app.get(/health) def health_check(): return {status: ok}到这里一个最小可用的AI工程就成型了有配置管理、有统一的模型调用层、有带工具调用的Agent循环、有RAG检索增强、有对外API封装。虽然简单但它具备了一个生产级AI工程的完整骨架。4. 工程上线前后的坑一个一个填常见问题速查我整理了在做AI工程落地时最常遇见的几类问题按主题分类直接给结论和解决方案。4.1 模型输出不稳定解析老是出错这是新手碰到的第一堵墙。明明在代码里写了json.loads模型输出的却不是合法JSON。解决思路有三层第一层改System Prompt。不要只说“输出JSON”要明确告诉模型输出纯JSON对象、不要Markdown代码块、不要额外的解释文字示例给出一个完整的输出样例。第二层改解析容错。正如我前面写的extract_json函数把提取JSON的容错逻辑写足覆盖代码块包裹、前后缀文字、单引号键名等问题。第三层改模型参数。temperature调低到0.3以内甚至如果有必要设为0。temperature越高模型的随机性越大输出格式的稳定性就越差。最后如果任务追求绝对的格式稳定请使用模型的JSON Mode或结构化输出功能。绝大多数主流模型厂商都提供了这个能力能保证输出一定是合法JSON。4.2 检索不到相关内容RAG效果很差绝大多数RAG效果不好的原因不是向量库不行也不是模型不行而是文档切片和检索策略没做好。排查的思路按照下面的顺序一步步来先检查切片质量。把切片后的文档打开来看有没有一句话被拦腰截断的、有没有大段无意义的空白、有没有把两个完全无关的主题切在一个块里。再检查向量化模型。中文场景请务必使用中文优化的Embedding模型例如BGE系列或者M3E系列不要用为英文优化的模型直接跑中文效果差异非常明显。再检查检索链路。单纯依赖向量检索在专有名词和精确ID匹配上会失效。加入BM25关键词检索做混合召回再做融合排序效果往往有质的提升。最后检查TopK和相关性阈值。TopK设得太小比如3相关文档可能漏掉设得太大比如20又会把大量噪声片段塞进上下文模型反而被干扰。我的经验是5-8是一个比较平衡的区间。相关性阈值一般设置在0.4-0.6之间低于阈值的片段直接丢弃。这个阈值需要通过小批量真实查询来标定不要凭感觉拍。4.3 上下文窗口爆炸Token成本失控Agent循环里一个隐藏的风险就是上下文无限膨胀。每轮工具调用的描述信息、工具执行结果、历史对话都会累积在上下文中几轮下来Token消耗就翻了好几倍。解决方案是做好上下文压缩和记忆管理。具体做法历史消息按时间做截断只保留最近几轮的关键消息过长的工具结果做摘要化处理把详细日志压缩成“工具XX执行成功返回字段A、B、C”对Agent的中间推理过程做降权不进入长期记忆。这些手段都在不损失核心质量的前提下明显压缩了Token用量。我个人的经验是上线前一定要做一次单次对话Token成本的压测。找一个问得最复杂的问题走完整个Agent循环统计总消耗Token数和最终费用。如果单次成本超过你的心理价位优先考虑压缩上下文其次才是切换更便宜的模型。4.4 工具调用参数非法业务接口返回错误Agent调用外部工具时有个高频故障现象模型生成的参数在语法上合法但在业务语义上不合法。比如它把“host-01服务器”传成了“服务器host-01”业务接口自然返回404。在Agent的工具调用层一定要加一层参数预处理。包括类型强制转换字符串数字转int、枚举值白名单校验只允许设定的值、格式规范化去空格、统一大小写、空值兜底判断。你永远不要假设模型输出的参数是100%准确的你的代码要做那个“最后一道防线”。5. 上线之后才算数的工程化评估、监控与迭代5.1 离线评估别只靠感觉说“效果不错”很多团队做AI应用评估方式就是“自己问几个问题看看回答得还行”。这种方法完全不够用。一个严谨的离线评估集应该包含底线性场景问答、摘要、分类、边界性场景拒绝回答、澄清请求、超长输入、恶意性场景Prompt注入、越权提问、诱导输出敏感信息最少准备50-100个样本并且由业务方和开发方共同评审标注。评估指标上两类必须同时看一类是客观指标例如检索命中率、格式合法率、工具调用成功率、平均响应时间、单次成本另一类是主观指标需要由人工对回答的相关性、完整性、安全性、语气偏好打分。把这两类指标维护成一张“AI效果月报”每次迭代模型或修改Prompt都必须重跑一遍评估集做回归对比。没有评估体系支撑的Prompt调优都是在靠运气工作。5.2 在线监控线上观测和调试的三大支柱AI服务上线后你必须建立三个维度的监控业务维度、模型维度、系统维度。以这个Agent服务为例。业务维度要监控每日调用量、问答成功率、用户反馈率、平均对话轮数这些直接反映产品价值。模型维度要监控Token消耗、首Token延迟、单次响应耗时、工具调用解析失败率、检索空结果比例、特定输入下的输出格式异常率。系统维度要监控CPU、内存、并发数、网络状态。工具调用解析失败率这个指标我要重点强调。它反映了模型输出和解析器之间的“沟通故障率”。在Agent上线初期这个指标会比较高随调试深入会逐渐下降并趋于稳定。一旦这个指标出现突变上升往往意味着模型供应商那边更新了行为你的解析器需要同步调整。这类问题靠人肉眼发现可能滞后很久但指标自动告警能在几分钟内捕捉到。5.3 持续迭代Prompt版本管理比代码版本管理更容易被忽视最后提一个很容易被忽视但极其重要的点Prompt和配置的版本管理。把System Prompt、工具描述、评估集、RAG切片策略全部纳入版本管理和代码同步提交、同步发布、同步回滚。在我的团队里每次调整Prompt都要求附带一份变更记录改了什么、为什么改、离线评估集上指标变化、线上灰度效果。这样做的原因很简单Prompt调优往往是一个不断试错的过程今天改的Prompt效果不错下周可能因为模型升级而失效想要回退到原来那版时你必须有记录可查。我见过不止一个团队项目上线三个月后没人说得清楚当前线上跑的Prompt是谁什么时候改的。这种团队一旦遇到线上回答质量骤降连排查的方向都没有。6. 从零到一之后还能怎么长一个从零搭建的AI项目做到这个程度已经具备了完整的产品雏形。接下来往哪走有几个很有价值的方向。一个是把单Agent升级为多Agent协作。把“一个Agent处理所有事情”拆成“多个Agent各司其职”一个规划Agent负责任务拆解一个检索Agent负责知识获取一个执行Agent负责工具调用一个审核Agent负责结果校验。多个Agent之间通过消息队列传递任务形成一条AI流水线。这种模式适合业务流程比较复杂、单Agent难以覆盖的场景比如自动生成周报、自动处理工单、自动做竞品分析。另一个是把工作流可视化。核心思路是用界面上拖拽节点的方式来构建AI应用把Prompt、检索、工具、判断、分支这些模块变成可视化节点业务人员也能参与AI应用的搭建。还有一条路是往垂直领域深耕。把一个看起来通用的Agent做成某个细分领域的专家。例如法律文书审查Agent、医疗报告初步分析Agent、金融合规问答Agent。一个通用的AI问答系统可能没有多大壁垒但当它具备了某个领域的知识库、领域专属工具链、领域特有的规则校验之后壁垒就自然形成了。就我个人的体会而言从零开始做AI工程最大的收获不是技术多强而是当你亲手把一个模型从代码里接出来绑定上数据、工具、流程、服务让真实用户开始使用之后你对AI技术的理解会和纯粹阅读文档完全不同。那些踩过的坑、填过的洞、线上告警的深夜才是工程能力真正的来源。如果你也正在从零开始走这条路希望你少踩几个坑也欢迎把你的经验分享回来。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Java编译链路:从javac到JIT即时编译的完整解析 2026/10/1 11:38:24

Java编译链路:从javac到JIT即时编译的完整解析

1. 从程序员视角出发:为什么需要搞懂这条编译链路先从一个最常见的场景聊起。你写了一个超简单的类,按下IDE里那个绿色三角形,程序跑起来了。但在"你按下运行"和"CPU开始干活"之间,到底发生了什么&#xff1f…

阅读更多 →
YOLOv5人群密度检测实战:从检测框到人/㎡热力图 2026/10/1 11:38:24

YOLOv5人群密度检测实战:从检测框到人/㎡热力图

简介:本资源是一套基于改进YOLOv5的人群密度检测系统完整实现方案,面向深度学习初学者与计算机视觉开发者,解决公共场所人流密集场景下的实时目标检测与计数难题。项目通过替换主干网络为FasterNet、引入Soft-NMS抑制冗余框、采用最优运输分配…

阅读更多 →
AI工程化实践指南:从RAG到模型部署的完整链路解析 2026/10/1 11:38:11

AI工程化实践指南:从RAG到模型部署的完整链路解析

1. 理解AI工程化:先弄明白这活儿到底在干什么 ai-engineering这个名字这两年出现频率越来越高,但很多人的理解还停留在“会调模型、会写Prompt”这个层面。我见过不少从传统开发转过来的朋友,一上来就问“我应该先学PyTorch还是先学LangChain…

阅读更多 →
从零搭建AI工程体系:数据、特征、模型三层契约与可观测性实践 2026/10/1 11:38:11

从零搭建AI工程体系:数据、特征、模型三层契约与可观测性实践

1. 从零搭建AI工程体系,为什么我劝你别一上来就调包 很多人第一次接触AI工程,脑子里想的都是“赶紧跑通一个模型”。装个环境,pip install几个库,拿现成的预训练权重推理一把,看到输出结果就觉得自己入门了。这种路径不…

阅读更多 →
iOS发布证书与描述文件:从Xcode Archive到App Store上架指南 2026/10/1 11:38:11

iOS发布证书与描述文件:从Xcode Archive到App Store上架指南

离预定的上架日期只剩两三天,编译、调试、真机测试全部通过,结果走到 Archived 这一步,Xcode 突然弹出一句 “No signing certificate found”。这种卡在临门一脚的状况,我在开发者社区里见过太多次,自己也踩过一整个下…

阅读更多 →
Snowflake数据架构实战:从存算分离到虚拟仓库选型 2026/10/1 11:38:11

Snowflake数据架构实战:从存算分离到虚拟仓库选型

1. 从传统数仓到云数仓:为什么我会在数据架构方案里押注Snowflake这几年做大数据项目,最深的感受是:数据架构这件事,越来越像一个“选型博弈”。早期我带着团队做网约车大数据综合项目,技术栈基本固定——Hadoop 做底层…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉