ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

AI应用开发实战:从零搭建可部署的会议纪要助手

AI应用开发实战:从零搭建可部署的会议纪要助手 1. 这不是“学AI”的计划而是“用AI造东西”的实战路线图最近翻遍了几十份所谓“AI应用开发学习计划”发现一个普遍问题它们要么堆砌术语像在背《人工智能导论》目录要么空谈“先学Python再学PyTorch最后搞大模型”却没人告诉你——真正卡住90%初学者的从来不是代码写不对而是根本不知道该让AI解决什么问题、怎么把它塞进一个能跑起来的程序里、更别说部署到别人能用的地方。我带过三十多个从零起步转行做AI应用的学员最常听到的抱怨是“学了三个月LangChain连个能查自己Excel文件的聊天框都搭不出来。”这说明什么说明市面上缺的不是知识清单而是一条从“我想做个能自动回邮件的工具”出发到“它现在正跑在我公司内网服务器上每天处理200封邮件”的完整路径。这个计划不教你怎么调参不讲Transformer底层原理只聚焦三件事第一识别你手头真实存在的、能被AI解决的小痛点第二用最低门槛的工具链把它变成一个可运行、可修改、可分享的最小可用应用MVP第三把这玩意儿稳稳当当放到你能控制的地方——可能是你自己的笔记本也可能是公司云服务器但绝不是某个随时可能下线的免费网页版。关键词里的“AI应用开发”四个字核心在“应用”——它得有界面、有输入、有输出、能被人用而不是一段在Jupyter里跑通就完事的代码。所以这份计划里你会看到大量具体到文件名、命令行参数、配置项截图级的细节比如为什么选Streamlit而不是Gradio来搭前端为什么第一次部署必须用Docker而不是直接pip install甚至包括如何绕过企业防火墙把本地服务暴露给同事测试——这些才是真实世界里每天发生的事。2. 整体设计逻辑放弃“从零造轮子”专注“把AI能力焊进现有流程”2.1 为什么坚决不走“先学理论再动手”的老路我试过两种教法一种是按传统课程顺序花六周讲完线性代数、概率论、神经网络基础再进入开发另一种是第一天就让学员用OpenAI API写一个能读取PDF并总结重点的脚本。结果非常明确前者60%的人在第三周就放弃因为看不到任何“成果”后者95%的人坚持到了结业因为他们第一天就做出了一个能帮自己节省半小时工作的工具。这不是降低标准而是尊重认知规律——人类大脑对“有用”的反馈远比对“正确”的反馈更敏感。所以这个计划的设计起点是所有学习内容必须绑定一个具体、微小、可验证的交付物。比如学向量数据库目标不是理解HNSW算法而是做出一个能让你用自然语言搜索自己三年会议纪要的本地搜索框学Agent框架不是复现ReAct论文而是让AI自动帮你把微信聊天记录里的待办事项提取出来填进Notion数据库。这种设计带来的连锁反应是工具选型必须极度务实。我们不会用PyTorch从头训练一个分类器而是直接调用Hugging Face上已有的、经过千人验证的模型我们不纠结于自建LLM推理服务而是优先用Ollama在本地跑通Llama3因为它一行命令就能装好且完全离线。这种“拿来主义”不是偷懒而是把有限的认知带宽全部集中在“如何让AI能力与业务场景咬合”这个核心问题上。就像木工学徒不会先花半年研究怎么砍树烧炭炼铁而是直接拿起一把磨好的凿子在师傅指导下雕出第一个榫卯。2.2 三层能力栈从“能跑”到“能用”再到“能扛”真正的AI应用开发不是单点技能而是一个能力栈。这个计划严格按三层递进第一层能跑Run——目标是让AI能力在你的机器上稳定输出结果。关键指标API调用成功率99%本地模型加载时间30秒错误时有明确日志指向具体哪一行代码或哪个配置项。这一层的核心是环境隔离与依赖管理我们会用CondaDocker双保险确保你在Mac上写的代码换到Windows同事电脑上也能一键启动而不是陷入“为什么他能跑我不能”的无解循环。第二层能用Use——目标是让非技术人员比如你的产品经理、销售同事能无障碍使用这个应用。关键指标无需安装任何软件打开浏览器输入网址即可操作输入框有清晰提示错误提示能告诉用户“请上传PDF而非图片”结果页面有复制按钮和下载选项。这一层的核心是前端交互设计与用户体验打磨我们会用Streamlit做原型因为它用Python写UI的效率是React的5倍且天然支持Markdown、图表、文件上传等AI应用刚需功能。第三层能扛Scale——目标是让应用在真实压力下不崩溃。关键指标并发10个请求时响应时间3秒连续运行72小时无内存泄漏意外断电后重启能自动恢复状态。这一层的核心是可观测性与容错设计我们会引入Prometheus监控CPU/内存/显存用Redis做任务队列防雪崩所有外部API调用都加超时和重试——不是为了应付百万用户而是保证你周五下午发给老板的演示链接周一早上依然能正常工作。这三层不是线性时间划分而是贯穿始终的思维习惯。比如写第一行调用OpenAI API的代码时就要同时考虑如果API返回429限流我的程序是直接报错让用户重试还是自动降级到本地小模型这个决策决定了你后续所有架构设计的方向。2.3 工具链选型为什么是这四件套而不是其他整个计划围绕四个核心工具构建它们不是随便选的而是经过上百次真实项目验证的“最小可靠组合”Ollama替代方案有LM Studio、Text Generation WebUI但Ollama胜在极简。ollama run llama3就能启动一个7B模型ollama list清楚显示所有已下载模型ollama serve直接提供标准OpenAI兼容API。没有复杂的Docker Compose编排没有需要手动调整的CUDA版本冲突。对于初学者少一个需要调试的环节就多一分坚持下去的信心。Streamlit对比GradioStreamlit的布局自由度更高能精确控制按钮位置、分栏宽度状态管理更直观st.session_state像全局变量一样自然且原生支持st.cache_resource这种针对LLM加载的专用缓存。更重要的是它生成的网页默认适配手机而Gradio需要额外配置。当你需要快速做一个给销售团队用的客户问答工具时Streamlit能让你在两小时内完成从代码到可分享链接的全过程。ChromaDB向量数据库选型中Pinecone太贵免费层限制严Weaviate配置复杂Milvus学习成本高。ChromaDB的优势在于纯Python实现pip install chromadb即装即用数据默认存在本地文件夹不用单独起数据库服务API极其简洁——collection.add()添加文档collection.query()查询没有索引重建、分片配置等概念。对于个人知识库、企业内部文档检索这类场景它用最短的学习曲线提供了足够可靠的性能。Docker为什么不用Vagrant或直接裸机部署因为Docker解决了“环境一致性”这个致命痛点。你本地用conda装的包同事用pip装的包服务器用apt装的包版本稍有差异就可能导致ImportError: cannot import name xxx。而Docker镜像一旦构建成功无论在哪台机器上运行都是完全一致的环境。计划中所有部署环节都会提供完整的Dockerfile示例包括如何把Ollama模型打包进镜像通过COPY预下载的模型文件如何设置--gpus all参数让容器访问GPU——这些细节正是决定“能跑”和“真能跑”的分水岭。这四件套的组合形成了一个闭环Ollama提供AI能力ChromaDB提供记忆能力Streamlit提供交互界面Docker提供稳定运行环境。它们之间没有冗余耦合替换其中任何一个都不会导致整个系统崩溃——比如某天你想换用Llama.cpp替代Ollama只需改一行API地址想换用FastAPI替代Streamlit只需重写前端部分后端逻辑完全不动。3. 核心实操环节从零开始搭建一个“会议纪要智能助手”3.1 第一周让AI读懂你的PDF且不崩目标上传一份上周的会议录音转文字稿TXT或PDF点击按钮自动生成三点结论、五个待办事项并高亮原文依据。为什么从PDF解析开始因为这是90%企业用户的第一个真实需求——他们有大量历史文档但无法被AI利用。网上教程总说“用PyPDF2读PDF”但实际踩坑无数扫描版PDF读出来全是乱码表格被拆成碎片页眉页脚混入正文。这里给出经过实测的方案文本提取阶段对纯文本PDF用pypdf对扫描版PDF必须用pdfplumbertesseractOCR。pdfplumber能精准定位文字坐标tesseract则负责图像识别。安装命令pip install pypdf pdfplumber pytesseract # Ubuntu需额外安装tesseract引擎 sudo apt-get install tesseract-ocr sudo apt-get install libtesseract-dev关键技巧pdfplumber的page.extract_text(x_tolerance1, y_tolerance1)参数能大幅改善表格文字错位问题x_tolerance值越小对齐精度越高但处理速度越慢实测1是平衡点。AI处理阶段不用写复杂prompt直接用LangChain的Document对象封装文本再用RecursiveCharacterTextSplitter按段落切分chunk_size500, chunk_overlap50。切分后喂给Ollama的Llama3模型prompt模板固定为你是一个专业的会议纪要整理员。请严格按以下格式输出 【结论】 1. ... 2. ... 【待办事项】 - [ ] 负责人XXX截止日YYYY-MM-DD依据原文第X段 - [ ] ... 【原文依据】 “原文引用句子”来自第X段这个结构化输出模板让后续解析JSON变得极其简单避免了用正则表达式硬匹配的脆弱性。本地验证技巧在Streamlit里加一个st.text_area显示原始提取文本再加一个st.text_area显示AI原始输出。这样当结果不对时你能立刻判断是文本提取错了还是AI理解错了——这是调试中最关键的分流点。我见过太多人卡在“AI输出乱码”结果发现是PDF解析时把中文全转成了问号。提示第一次运行时如果Ollama报错Failed to load model不要急着重装。先执行ollama list看模型是否真的下载成功再执行ollama show llama3 --modelfile确认模型配置最后检查~/.ollama/models目录下是否有对应模型文件。90%的“模型加载失败”问题根源都在路径权限或磁盘空间不足。3.2 第二周给AI装上“记忆”让它记住你公司的专有名词目标当用户提问“上次提到的‘星火计划’进展如何”AI能自动关联到三周前某份会议纪要中关于该项目的讨论并给出摘要。为什么向量数据库是必经之路因为大模型本身没有长期记忆。你每次提问都是独立会话它不记得上一句说了什么更不记得你上周提过的项目代号。ChromaDB就是给它装上的“外接硬盘”。实操步骤数据准备把过去半年的所有会议纪要、项目文档、产品说明书统一转成纯文本按文件名存入docs/文件夹。注意不要用Word或PDF原始文件必须是UTF-8编码的TXT避免编码问题导致向量化失败。向量化配置用sentence-transformers/all-MiniLM-L6-v2作为嵌入模型Embedding Model。它只有22MB加载快效果在中小规模语义检索中足够好。关键参数from sentence_transformers import SentenceTransformer embedder SentenceTransformer(all-MiniLM-L6-v2) # 批量嵌入每批32个文本避免OOM embeddings embedder.encode(texts, batch_size32, show_progress_barTrue)ChromaDB初始化创建持久化数据库路径设为./chroma_db这样重启Python进程数据不丢失。import chromadb client chromadb.PersistentClient(path./chroma_db) collection client.get_or_create_collection( namemeeting_minutes, metadata{hnsw:space: cosine} # 余弦相似度适合文本 ) # 添加文档id用文件名便于后续溯源 collection.add( documentstexts, metadatas[{source: f} for f in filenames], idsfilenames )检索增强RAG集成当用户提问时先用同一嵌入模型将问题向量化再用collection.query()搜索最相关的3个文档片段最后把片段拼接到prompt里交给LLMresults collection.query( query_embeddings[embedder.encode(question)], n_results3, include[documents, metadatas] ) context \n\n.join(results[documents][0]) full_prompt f根据以下背景资料回答问题\n{context}\n\n问题{question}注意不要在query()里设置n_results10。实测表明超过5个结果会引入大量噪声反而降低回答准确率。RAG的效果不取决于“找得多”而取决于“找得准”。建议用where参数加过滤条件比如where{source: {$contains: Q3}}限定只搜索季度报告。3.3 第三周让同事能用而不仅是你能用目标生成一个可分享的URL销售同事打开就能上传自己的会议记录无需安装任何软件。Streamlit部署的三个致命细节静态资源路径Streamlit默认把st.image()、st.audio()等媒体文件放在./.streamlit/static/下但生产环境必须用st.write(fimg src/static/{filename} /, unsafe_allow_htmlTrue)手动指定路径。否则本地能显示部署后404。文件上传大小限制默认限制100MB但会议录音转文字稿通常很小。在.streamlit/config.toml中添加[server] maxUploadSize 500单位是MB500足够应付绝大多数PDF。状态持久化st.session_state在页面刷新后清空但用户希望上传一次文档后续多次提问都基于同一份内容。解决方案是用st.cache_resource缓存ChromaDB客户端再用文件哈希值作为collection nameimport hashlib file_hash hashlib.md5(uploaded_file.getvalue()).hexdigest() collection_name fdoc_{file_hash[:8]} collection client.get_or_create_collection(namecollection_name)Docker部署实录Dockerfile核心内容FROM python:3.10-slim # 安装系统依赖 RUN apt-get update apt-get install -y \ tesseract-ocr \ libtesseract-dev \ rm -rf /var/lib/apt/lists/* # 复制Python依赖 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY . /app WORKDIR /app # 预加载Ollama模型关键 RUN ollama pull llama3 # 暴露端口 EXPOSE 8501 CMD [streamlit, run, app.py, --server.port8501, --server.address0.0.0.0]构建与运行# 构建镜像tag命名为meeting-assistant docker build -t meeting-assistant . # 运行容器映射8501端口挂载当前目录以便读取上传文件 docker run -p 8501:8501 -v $(pwd):/app/data meeting-assistant此时访问http://localhost:8501即可。若要让同事访问需将-p 8501:8501改为-p 0.0.0.0:8501:8501并确保防火墙开放8501端口。实操心得第一次部署失败90%是因为requirements.txt里漏写了ollama包。Ollama不是Python包而是独立服务但Streamlit应用里调用requests.post(http://localhost:11434/api/chat)时必须确保容器内能访问Ollama服务。解决方案是在Docker中用--network host模式运行或在docker-compose.yml中定义Ollama服务并链接。我们选择前者因为更简单直接。3.4 第四周让它扛住真实压力不只是Demo目标当5个销售同事同时上传10MB PDF并提问时系统响应时间仍低于3秒且不出现内存溢出。性能瓶颈诊断三板斧CPU瓶颈用htop观察如果Python进程CPU占用持续100%说明LLM推理或文本处理太重。解决方案降低chunk_size从500降到200减少单次送入模型的文本量或启用Ollama的num_ctx参数限制上下文长度。内存瓶颈用free -h看可用内存如果available低于1GB说明ChromaDB向量库或模型加载占满内存。解决方案在ChromaDB初始化时添加settingsSettings(anonymized_telemetryFalse)关闭遥测用collection.delete()定期清理过期collection最关键的是Ollama模型加载后用ollama ps查看内存占用选择llama3:8b而非llama3:70b——后者需要32GB显存前者4GB显存即可流畅运行。I/O瓶颈当多个用户同时上传大文件磁盘读写成为瓶颈。解决方案在Docker中用-v /fast_ssd:/app/data将上传目录挂载到SSD分区或在Streamlit代码中用st.file_uploader的accept_multiple_filesTrue一次性接收多个小文件而非单个大文件。监控配置在app.py开头加入Prometheus监控埋点from prometheus_client import Counter, Histogram, start_http_server REQUEST_COUNT Counter(app_requests_total, Total requests) REQUEST_LATENCY Histogram(app_request_latency_seconds, Request latency) st.cache_resource def init_monitoring(): start_http_server(8000) # 监控端口 init_monitoring() # 在主函数中包裹处理逻辑 with REQUEST_LATENCY.time(): REQUEST_COUNT.inc() # 原有处理逻辑...访问http://localhost:8000/metrics即可看到实时指标。当app_request_latency_seconds_bucket中le3.0的计数占比低于95%就说明需要优化。独家技巧在Streamlit里加一个隐藏按钮st.button(Force GC)点击后执行import gc; gc.collect()。这能在内存告警时手动触发垃圾回收避免因Python引用计数延迟导致的假性内存泄漏。这个技巧救过我三次线上事故。4. 常见问题与排查技巧实录那些文档里不会写的坑4.1 “Ollama run llama3 报错no space left on device”现象执行ollama run llama3时终端卡住几秒后报错提示磁盘空间不足但df -h显示根目录还有20GB剩余。根因Ollama默认将模型文件存放在~/.ollama/models而该路径所在分区通常是/home可能已满。更隐蔽的是Docker的overlay2存储驱动也会占用/var/lib/docker空间且docker system df显示的“Build Cache”可能高达数十GB。排查步骤ollama list查看模型列表确认是否已下载du -sh ~/.ollama/models查看Ollama模型实际占用docker system df -v查看Docker各组件占用ls -lh /var/lib/docker/overlay2/找出最大的layer ID。解决方法清理Dockerdocker system prune -a -f删除所有未使用的镜像、容器、网络移动Ollama路径编辑~/.ollama/config.json添加models: /mnt/fast_disk/ollama_models然后ollama serve重启服务终极方案在Dockerfile中用RUN mkdir -p /mnt/models ln -sf /mnt/models /root/.ollama/models创建软链接。注意不要用rm -rf ~/.ollama/models直接删除Ollama服务可能正在使用其中文件导致后续ollama list报错。必须先ollama serve停止服务再删除。4.2 “Streamlit页面空白控制台报错WebSocket connection failed”现象浏览器打开http://localhost:8501页面一片空白F12控制台显示WebSocket connection to ws://localhost:8501/_stcore/stream failed。根因Streamlit 1.30版本默认启用HTTPS重定向当通过HTTP访问时会尝试升级到HTTPS但本地没有SSL证书导致WebSocket握手失败。解决方法启动时加参数streamlit run app.py --server.enableCORSfalse --server.port8501或在.streamlit/config.toml中添加[server] enableCORS false port 8501 address 0.0.0.0更彻底的方案在Docker中用Nginx反向代理配置proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade;支持WebSocket。实操心得这个错误在Mac M1/M2芯片上出现频率极高因为Apple Silicon的虚拟化层对WebSocket有特殊要求。解决方案不是升级Streamlit而是降级到1.28.2版本pip install streamlit1.28.2该版本对此兼容性更好。4.3 “ChromaDB查询结果总是返回空但文档明明已添加”现象collection.add()执行成功collection.count()返回正确数字但collection.query()永远返回空列表。根因ChromaDB的query()方法默认只返回documents和ids不返回metadatas且n_results参数必须显式指定不能省略。更常见的是嵌入模型Embedding Model与查询时使用的模型不一致——比如存入时用all-MiniLM-L6-v2查询时误用了paraphrase-multilingual-MiniLM-L12-v2导致向量空间不匹配。排查步骤collection.peek()查看前几个文档确认documents字段有内容collection.get(ids[your_id])用已知ID精确获取确认数据存在collection.query(query_texts[test], n_results1)用简单测试词查询排除复杂query语法问题。解决方法确保嵌入模型绝对一致存入和查询必须用同一个SentenceTransformer实例显式指定include参数collection.query(query_embeddings[emb], n_results3, include[documents, metadatas])检查文本预处理all-MiniLM-L6-v2对中文支持很好但若文本含大量HTML标签或特殊符号需先re.sub(r[^], , text)清洗。独家技巧在query()前打印len(embedder.encode(test))确认嵌入向量维度是384all-MiniLM-L6-v2的标准维度。如果输出768或1024说明你加载了错误的模型。4.4 “Docker容器启动后Streamlit报错ModuleNotFoundError: No module named chromadb”现象Docker构建成功docker run后容器立即退出docker logs显示找不到chromadb模块。根因requirements.txt中chromadb版本与Python版本冲突。ChromaDB 0.4.20要求Python3.10但python:3.10-slim镜像中某些系统包版本过旧导致pip install chromadb编译失败静默跳过。排查步骤docker run -it meeting-assistant bash进入容器pip list | grep chroma查看是否安装pip install chromadb --no-cache-dir -v查看详细错误日志。解决方法在Dockerfile中升级pip和setuptoolsRUN pip install --upgrade pip setuptools wheel或指定兼容版本chromadb0.4.15该版本对Python 3.10兼容性最好最稳妥方案用conda替代pip在Docker中安装Miniconda再conda install -c conda-forge chromadb。注意不要在requirements.txt里写chromadb0.4.0版本范围太宽会导致不可控升级。必须锁定具体小版本号这是生产环境部署的铁律。4.5 “AI回答中出现大量重复句子像在念经”现象LLM输出中同一句话反复出现三四次比如“项目风险需要评估。项目风险需要评估。项目风险需要评估。”根因这是典型的“重复惩罚repetition_penalty”参数缺失。大模型在生成时若遇到概率相近的token容易陷入局部最优不断重复高概率词。Ollama默认不开启此参数而Hugging Face Transformers默认开启。解决方法在Ollama API调用中显式设置optionsdata { model: llama3, prompt: prompt, stream: False, options: { repeat_penalty: 1.2, # 1.0为不惩罚1.0增加惩罚 temperature: 0.7, num_predict: 512 } }repeat_penalty值推荐1.1~1.3过高会导致回答僵硬过低无效同时配合temperature0.7在随机性和确定性间取得平衡。实操心得这个参数对中文重复尤其有效。我曾用repeat_penalty1.0处理一份技术文档AI输出中“因此”一词重复12次调到1.25后重复消失且专业术语使用更准确。这不是玄学而是模型在softmax计算时对已生成token的logits进行衰减的数学结果。5. 学习节奏与里程碑每周交付一个可演示的成果5.1 时间分配原则20%学80%做这个计划拒绝“听课8小时实操2小时”的失衡模式。每周10小时学习时间严格按以下比例分配3小时环境搭建与故障排除——这不是浪费时间而是建立“我能掌控工具”的信心。比如第一周花2小时搞定Ollama在Windows WSL下的CUDA驱动问题比花2小时看理论视频更有价值。5小时核心功能开发——必须产出可运行代码。哪怕只有一行print(Hello AI)也要让它在Docker里跑起来。进度条不是“学完第3章”而是“完成了会议纪要提取的Streamlit界面”。2小时文档与分享——写一篇500字的简短笔记记录“今天解决了什么问题怎么解决的下次可以怎么优化”。这强迫你把碎片知识结构化也是未来简历的素材库。5.2 四周里程碑每个周末都有东西可秀Week 1结束一个本地运行的Streamlit应用能上传PDF/TXT点击按钮后在页面下方显示AI生成的结论和待办事项。代码不超过100行但必须能稳定运行。Week 2结束同一个应用增加了左侧导航栏点击“知识库”标签页能显示所有已上传文档列表点击任一文档右侧显示其内容摘要。ChromaDB已集成但查询功能暂未开放。Week 3结束应用新增“问答”标签页用户输入问题如“星火计划预算多少”AI自动检索知识库并给出答案且在答案末尾标注“依据Q3项目报告第5页”。Docker镜像已构建成功同事可通过IP地址访问。Week 4结束应用上线监控面板右上角显示实时QPS每秒查询数和平均延迟当延迟超过3秒时页面顶部弹出黄色警告条所有功能在5人并发测试下保持稳定。交付物是一份README.md包含部署命令、测试用例、已知问题列表。个人体会我最初做这个计划时给自己定的目标是“两周内做出能用的工具”。结果第一周就卡在PDF解析上花了三天才搞定扫描件OCR。但正是这三天让我彻底理解了文档预处理的复杂性——它不是AI的问题而是现实世界数据的顽疾。所以这个计划里所有“看似简单”的环节都预留了足够的排错时间。真正的学习发生在报错信息和Google搜索框之间而不是在教程视频的进度条里。
返回列表