大模型应用技术架构
大模型应用技术的特点:**门槛低,天花板高**。由浅入深四条路线: **1. 纯 Prompt**:一问一答,不问不答。 **2. Agent + Function Calling**: - Agent:AI 主动提要求;Function Calling:AI 要求执行某个函数 - 你提一个问题,AI 先问你这个问题的前提条件满足哪些,再去调工具完成 **3. RAG(Retrieval-Augmented Generation,检索增强生成)**: - Embeddings:把文字转换为易于相似度计算的编码(向量) - 向量数据库:把向量存起来方便查找;向量搜索:找最相似的向量 - 类比:考试答题时到书上找相关内容,再结合题目组成答案 **4. Fine-tuning(精调/微调)**:努力学习考试内容,长期记住,活学活用。
如何选择技术路线(不严谨但常用的思路)——其中最容易被忽略的是**准备测试数据**: ```text 需求 → 先纯 Prompt 试 → 效果不够? ├─ 缺知识/缺实时性 → RAG ├─ 要操作业务系统 → Function Calling / Agent └─ 稳定性/成本/速度/私有化 → Fine-tuning ``` 值得尝试 Fine-tuning 的情况: 1. 提高模型输出的稳定性 2. 用户量大,降低推理成本的意义大 3. 需要提高生成速度 4. 需要私有部署
**合规、安全是首要考虑因素,否则有可能血本无归**: - 安全指数据安全 - 合规指不违法;要用开源且免费的;公司与组织之间优先选组织(公司前期免费后期一般会收费) 测试与榜单: - 用 ChatALL(https://chatall.ai)同时对比多个模型,高效 - 值得相信的榜单:LMSYS Chatbot Arena Leaderboard(真人盲测投票)
Prompt 工程
Prompt 工程的特点:**起点低,天花板高**。 核心技巧: - **把大模型当人看**:一句表达一个意思,清晰明了无歧义 - **业务特征分解**:用简单的模块拼接完整意图——要有宏观完整的特征图(不漏),每个特征尽量独立(不重),表达清晰 - **模型擅长的格式**:GPT 对 Markdown 友好;Claude 对 XML 友好 - **具体不抽象**,越详细越好;丰富多场景多举例;减少歧义(明确指出"不要...避免...") - **重在补充**:模板的价值是提醒我们别漏掉什么,而非必须遵守 - **不断尝试**:有时一字之差对生成概率影响很大,也可能毫无影响
**侧重开头与结尾** 大模型对 prompt 开头和结尾的内容更敏感(斯坦福论文 Lost in the Middle 证明: 重要信息要放在输入的开始或结尾,中间的内容容易"丢失")。 - 开头:简练地提示观点/目的 - 中间:描述细节/步骤/注意事项 - 结尾:总结/强调,或提出真正的问题 **丰富的示例**:写好一个/多个示例让大模型比葫芦画瓢(one-shot / few-shot / in-context learning), 实践证明对输出正确性帮助很大。 **多轮对话**:把多轮问答放进 prompt,大模型就能理解上下文。
典型 Prompt 的六个构成要素: | 要素 | 说明 | |------|------| | 角色 | 定义最匹配任务的角色,如"你是一位软件工程师" | | 指示 | 对任务进行描述 | | 上下文 | 与任务相关的背景信息(多轮交互中尤其重要) | | 例子 | 必要时举例(few-shot),对正确性帮助很大 | | 输入 | 任务的输入信息,明确标识 | | 输出 | 输出格式描述(JSON/XML),便于后续模块自动解析 | 「定义角色」为什么有效?——在开头把问题域收窄,减少二义性。
把大模型用于对话系统的核心思路(NLU → 策略 → NLG): 1. **NLU**:把输入的自然语言对话转成结构化信息(JSON / 类的属性) 2. **策略**:用传统软件手段处理结构化信息,得到处理策略 3. **NLG**:把策略转成自然语言输出 即:大模型负责"理解"和"表达",业务逻辑仍由确定性代码掌控——这是工程上最稳的用法。
Function Calling
Function Calling 让大模型连接真实世界、对接真逻辑系统,弥补两大缺陷(知识不全/无真逻辑)。 工作机制(把 AI 当人看就懂了): 1. 通过 Actions 的 schema,GPT 能读懂各 API 能做什么、怎么调用(相当于人读 API 文档) 2. 拿到 prompt,GPT 分析是否要调用 API 才能解决问题(相当于人读需求) 3. 如果要调用,生成调用参数(相当于人编写调用代码) 4. 外层程序真正调用 API(相当于人运行程序) 5. API 返回结果,GPT 读懂结果并整合到回答中(相当于人整理结果输出结论) 注意:这个过程中 GPT 已经是个 agent 了。 接口里的 `tools` 最初版本叫 `functions`,是个有趣的演变指向。 官方接口文档:https://platform.openai.com/docs/guides/function-calling
**OpenAI GPTs**:无需编程就能定制对话机器人的平台——可放自己的知识库(实现 RAG)、 通过 actions 对接专有数据和功能、内置 DALL·E 3 文生图与 Code Interpreter。仅 Plus 会员可用。 平替: - 字节 Coze(扣子):国际版可免费使用 GPT-4;中国版用云雀大模型,功能强大 - Dify(https://dify.ai/):开源、中国公司开发、功能最丰富、可本地部署、支持几乎所有大模型,有 GUI 也有 API 既然有这类免开发工具,为什么还要学大模型开发技术? 1. 它们无法针对业务需求做极致调优 2. 它们与其它业务系统的集成不是特别方便
RAG 原理
**LLM 固有的局限**:知识不是实时的;知识具有通用性、缺少针对性(不知道你私有的领域/业务知识)。 **RAG(Retrieval Augmented Generation,检索增强生成)**: 通过分片去除大量无用信息、检索少量有效信息来增强生成模型的能力。 - Retrieval /rɪˈtriːvl/:检索、取回 - Augmented /ɔːɡˈmentɪd/:增广、扩维 - Generation:生成 类比开卷考试:到书上找相关内容,再结合题目组成答案。
**文本向量化(Embeddings)**: 1. 将文本转成 n 个浮点数,每个数对应一个维度 2. 一个数组对应 n 维空间的一个点,文本向量又叫 Embeddings 3. 向量之间可以计算距离,距离远近对应语义相似度大小 余弦相似度: $$\cos\theta = \frac{A \cdot B}{\|A\| \cdot \|B\|} = \frac{\sum_i A_i B_i}{\sqrt{\sum_i A_i^2}\sqrt{\sum_i B_i^2}}$$ sbert 向量化示例: ```python from sentence_transformers import SentenceTransformer model = SentenceTransformer("all-MiniLM-L6-v2") sentences = [ "This framework generates embeddings for each input sentence", "The quick brown fox jumps over the lazy dog." ] embeddings = model.encode(sentences) print(embeddings.shape) # (2, 384) ``` 扩展阅读:https://www.sbert.net
RAG 搭建四步: ```text 1. 文档加载,并按一定条件切割成片段 2. 将切割的文本片段灌入检索引擎(ES 关键词 / 向量数据库) 3. 封装检索接口 4. 构建调用流程:Query → 检索 → Prompt → LLM → 回复 ``` 向量数据库可选:chromadb(轻量本地)、faiss、Milvus、Qdrant、pgvector 等。
RAG 实战:ES 与 PDF 检索
```bash pip install pdfminer.six ``` ```python from pdfminer.high_level import extract_pages from pdfminer.layout import LTTextContainer def extract_text_from_pdf(filename, page_numbers=None, min_line_length=1): '''从 PDF 文件中(按指定页码)提取文字''' paragraphs, buffer, full_text = [], '', '' for i, page_layout in enumerate(extract_pages(filename)): if page_numbers is not None and i not in page_numbers: continue for element in page_layout: if isinstance(element, LTTextContainer): full_text += element.get_text() + '\n' # 按空行分隔,重组为段落 for text in full_text.split('\n'): if len(text) >= min_line_length: buffer += (' ' + text) if not text.endswith('-') else text.strip('-') elif buffer: paragraphs.append(buffer) buffer = '' if buffer: paragraphs.append(buffer) return paragraphs paragraphs = extract_text_from_pdf("llama2.pdf", min_line_length=10) ```
```bash pip install elasticsearch7 nltk ``` ```python from elasticsearch7 import Elasticsearch, helpers from nltk.stem import PorterStemmer from nltk.tokenize import word_tokenize from nltk.corpus import stopwords import nltk, re nltk.download('punkt') nltk.download('stopwords') def to_keywords(input_string): '''英文文本只保留关键字:去符号 → 切词 → 去停用词 → 取词根''' no_symbols = re.sub(r'[^a-zA-Z0-9\s]', ' ', input_string) word_tokens = word_tokenize(no_symbols) stop_words = set(stopwords.words('english')) ps = PorterStemmer() return ' '.join(ps.stem(w) for w in word_tokens if w.lower() not in stop_words) es = Elasticsearch(hosts=['http://127.0.0.1:9200'], verify_certificates=False) index_name = "index" if es.indices.exists(index=index_name): es.indices.delete(index=index_name) es.indices.create(index=index_name) actions = [ {"_index": index_name, "_source": {"keywords": to_keywords(para), "text": para}} for para in paragraphs ] helpers.bulk(es, actions) ``` 经典信息检索参考:https://nlp.stanford.edu/IR-book/information-retrieval-book.html
用 streamlit 快速把检索服务做成 Web 应用: ```bash pip install streamlit streamlit_extras cd /opt/www/pdfsearch nohup streamlit run app.py >/tmp/streamlit.log 2>&1 & # 访问 http://服务器IP:8501/ ``` streamlit 适合给算法/RAG Demo 快速包一层 UI,不适合重前端交互的生产系统。
Agent 与微调
AutoAgent 的 prompt 要点(来自实践): 1. **不要对要素的取值/定义做任何假设,确保信息来自给定的数据源,不要编造信息(DO NOT MAKE UP ANY INFORMATION)** ——GPT 不理解时会像人一样选一个最大概率的事物,往往是不对的; 要求它不理解时不要假设,而是再去查、再去确定 2. **已明确获得取值的子概念,完整备注在其后**——问题过长时防止遗忘关键信息 3. **工具调用失败时,改变参数或参数格式再试**——有时工具选对了但参数错了 4. **已经得到的信息不要反复查询**——防止死循环 5. 按设计决定是否允许向用户提问(不是所有智能体都不能问)
**Fine-tuning(精调/微调)**:fine 取"精细"之意,tuning 取"调谐、调整"之意。 预训练的好处: - 通过"完型填空"方式学习大量语言,推理空白该是什么,形成语言模型 - 节省数据与训练成本,形成通用的模型底座 在通用底座上用垂直领域少量数据继续训练,效果优于直接用少量垂直数据从头训练: 解决了垂直领域数据量不足的问题,降低了总体成本。 大模型微调的工程做法:原模型参数**冻结**不变,额外增加少量参数(如 LoRA Adapter)参与训练, 显存与算力需求大幅降低。 LoRA 的核心思想——用低秩分解近似权重增量: $$\Delta W = BA, \quad B \in \mathbb{R}^{d \times r},\ A \in \mathbb{R}^{r \times k},\ r \ll \min(d, k)$$ 前向变为 $h = Wx + BAx$,只训练 A、B 两个小矩阵。 经验之谈:不建议从"提升大模型性能"角度发力(包括微调),建议做智能体(AutoAgent)。
Semantic Kernel(SK):微软出品的 LLM 编排组件(注意:网传"SK 是 OpenAI 组件、做分词/词性标注/句法分析"的说法 是把 NLP 预处理流程张冠李戴了,实际 SK 的职责是把 LLM 调用、提示词模板、函数/插件、记忆(向量检索) 编排成可复用的"技能",定位与 LangChain 类似)。 同类组件/平台对比: | 组件 | 出品 | 定位 | |------|------|------| | LangChain | 社区 | 链式编排,生态最大 | | LlamaIndex | 社区 | 数据索引与 RAG 见长 | | Semantic Kernel | 微软 | 企业级插件编排 | | Dify / Coze | 公司 | 低代码平台,GUI + API |
参考
     Lost in the Middle 
     Function Calling 官方文档 
     sbert