ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

大模型协作礼仪:从上下文管理到Agent编排的完整指南

大模型协作礼仪:从上下文管理到Agent编排的完整指南 同一个模型为什么在不同人手里效果差别那么大有人拿 LLM 写代码又快又稳有人拿它做客服却总是胡编乱造有人把 Agent 跑得井然有序有人堆了十几个工具却总是陷入死循环有人把几十万字的资料丢进一个 Prompt 里得到的结果反而比只给三段示例更差。这些问题的根源往往不在模型参数也不在框架版本而在于我们如何使用 LLM。换句话说今天需要补的一课不是“怎么提问”而是一整套LLM Etiquette大语言模型协作礼仪。LLM Etiquette 不是要求你对模型说“请”“谢谢”而是指用户、开发者和系统架构在跟大模型协作时应该遵守的规范什么时候给多少上下文、什么时候约束输出、什么时候把知识外置成 RAG、什么时候用 Agent 编排而不是把所有任务都塞进一个 Prompt。我的判断很直接在模型能力接近的今天谁掌握这套协作规范谁就能把同一个模型用出完全不同的下限。这篇文章会把 LLM Etiquette 拆成交互层、开发层、模型层、知识层和工程层五个维度结合上下文管理、Agent 编排、FP16/FP32/BF16 精度选择、LLM Wiki 范式等热门话题给出可落地的代码和排查思路。无论你是第一次用大模型还是正在做生产级 LLM 应用这篇文章都值得收藏备用。1. 什么是 LLM Etiquette它到底解决什么问题1.1 从“礼貌”到“规范”很多文章把“如何与 AI 对话”简化成“把需求说清楚”。实际上当 LLM 进入批量调用、Agent 编排、模型微调、企业知识库这些工程场景后靠“把需求说清楚”远远不够。这里说的 LLM Etiquette是指围绕大模型建立的一整套约束和习惯交互层人如何在对话里给模型明确指令如何管理上下文窗口。开发层开发者如何设计工具调用、Agent 循环、失败重试和降级策略。模型层在推理和训练时选择合适的数值精度避免性能与精度的失衡。知识层哪些知识应该通过检索增强获得哪些只能靠模型参数记忆。工程层权限、审计、成本、安全边界如何设计。这些原本分散在各处的实践被“Etiquette”这个词串起来之后就有了一个统一视角如何让大模型在真实任务中稳定、可控、可预期地工作。1.2 它解决什么问题如果只看模型发布时的演示你会觉得大模型无所不能。但进入真实项目后最常见的三个问题分别是效果不稳定同样的 Prompt上一轮输出完美下一轮开始胡说尤其上下文变长之后更明显。成本失控每个会话都塞入大量历史消息Token 耗费直线上升业务还没起量账单先爆了。行为不可控Agent 在循环里反复调用工具或者输出格式偶尔变一次导致下游解析直接崩掉。这些问题不是模型“变笨了”而是我们缺少一套与模型协作的礼仪。比如重要指令放在哪里、非必要信息是否进入上下文、工具描述是否足够明确、精度是否选对都会直接改变结果。1.3 对三类读者都有价值LLM Etiquette 不是 AI 算法工程师专属。如果你是普通用户它能让你更快得到一个准确回答如果你是后端开发者它能帮你避免上线后改 Prompt 改到崩溃如果你是技术负责人它能帮你建立一套团队统一使用 LLM 的规范避免每个人各写各的 Prompt效果参差不齐。2. 交互层礼仪把上下文当作稀缺资源2.1 模型不是搜索引擎很多人使用 LLM 时有个习惯把越多的资料丢给它认为它“知道”得越多回答就越准确。这是对新手最常见的误解。大模型的上下文窗口是固定的每一轮对话都会把所有历史消息重新计算一遍。这带来两个后果无关信息会占据注意力干扰模型对重点指令的把握。Token 越多计算越慢成本越高错误概率也越高。正确的礼仪是把上下文当作稀缺资源只放当前任务真正需要的信息。2.2 最小上下文原则这里给出一条可执行的判断标准如果我从上下文中删掉这段历史模型的回答质量不会下降那么这段历史就不该进入请求。实际操作中常见做法是System 提示词里只写角色、任务、输出规则不写业务聊天记录。用户消息里尽量保留关键事实删除与本次任务无关的寒暄。长对话场景用摘要替代原始历史。下面是一个 Python 调用大模型接口的示例展示了如何用最小上下文思路构造请求# 文件路径examples/min_context.py import json def build_payload(user_query: str, retrieved_context: str) - str: 构造对话请求遵循最小上下文原则 1. system 只承担角色定义和输出约束。 2. user 消息里只包含本次查询和必要的检索结果。 3. 不使用历史聊天记录。 system_prompt ( 你是技术文档助手。只能基于给定的上下文回答问题 不要编造引用不要猜测不存在的版本号。若信息不足明确说不知道。 ) messages [ {role: system, content: system_prompt}, { role: user, content: ( f请基于下面的上下文回答问题。\n\n f上下文\n{retrieved_context}\n\n f问题{user_query} ), }, ] # 这里仅为演示结构实际调用时请替换为你的接口地址和鉴权方式 return json.dumps({model: your_model, messages: messages, temperature: 0.2}) if __name__ __main__: demo_query 如何配置 LLM 的上下文窗口 demo_context 上下文窗口决定了模型一次能处理的 token 数量。超过限制时需要进行截断或摘要。 print(build_payload(demo_query, demo_context))这个示例的核心不是调用某个特定 SDK而是展示一种构造消息的思路system 只负责定调user 只携带必要信息。2.3 结构化输出礼仪除了控制输入LLM Etiquette 还要求对输出做约束。一个常见的失误是不限制输出格式让模型自由发挥导致下游 JSON 解析失败。更稳妥的礼仪是在 System 提示词里明确输出结构并在用户消息里给出一个“目标格式示例”。这比事后写正则去清洗输出可靠得多。# 文件路径examples/structured_output.py import json system_prompt 你将收到一段客服对话请提取用户情绪和意图。 只输出 JSON不要输出额外解释。 JSON 结构如下 {emotion: positive|negative|neutral, intent: 退换货|咨询价格|投诉|其他} .strip() user_message 你们这个商品发货太慢了我要申请退款。 messages [ {role: system, content: system_prompt}, {role: user, content: user_message}, ] # 实际请求后获得文本 response_text {emotion: negative, intent: 退换货} # 无论模型返回什么都要做一次容错解析 try: parsed json.loads(response_text) print(parsed[emotion], parsed[intent]) except json.JSONDecodeError: print(解析失败应触发重试或提示模型修正输出格式)这个示例展示了两个礼仪点一是提前声明输出格式二是代码层保留容错逻辑因为即使格式声明得再清楚模型偶尔也会“不听话”。3. 开发层礼仪从 Prompt 到 Agent 的边界感3.1 为什么需要编排框架当任务从单轮问答变成“查天气、订机票、写报告、发邮件”这类多步骤任务时只靠一个 Prompt 已经无法覆盖。这也是 LLM Agent 和编排框架最近热度很高的原因。LLM Agent 的核心是让模型通过“思考、调用工具、观察结果、再思考”的循环来完成任务。但如果没有一套边界规则Agent 很容易失控循环调用同一个工具、无限发散、忽略用户的核心目标。编排框架比如 LangChain、LangGraph 以及各种开源的 Agent 框架解决的核心问题就是把 Agent 的循环过程变成可控的、可恢复的流程。它让开发者能定义节点、工具、条件分支和终止条件。与其把 Agent 当作“全自动助手”不如把它看作一个有明确工作边界的实习生你要告诉它有哪些工具、每个工具什么时候用、什么情况下停下来以及最大尝试次数。3.2 给 Agent 写“行为准则”下面是一个简化版本的 Agent 循环示例不依赖具体框架用来演示 Agent 礼仪中最关键的两点工具描述和终止条件。# 文件路径examples/minimal_agent.py 一个最小可运行的 Agent 循环示意。 重点不在代码而在设计 - 模型只做决策不直接执行风险操作。 - 每次最多执行 3 步防止无限循环。 - 工具必须返回结构化结果和状态。 import json from typing import Dict, List def call_llm(messages: List[Dict[str, str]]) - str: # 实际项目中替换为真实模型调用 # 这里简化模拟返回一个 JSON 动作 return json.dumps({action: get_weather, args: {city: 北京}}) def get_weather(city: str) - str: # 示例工具只允许查询天气不提供写操作 return f{city} 今天晴气温 25 摄氏度。 tools { get_weather: { description: 查询指定城市的天气参数 city 为城市名只读工具。, function: get_weather, } } def run_agent(user_task: str, max_steps: int 3): messages [ { role: system, content: ( 你是一个任务执行器。你必须使用工具完成任务。 请严格按 JSON 格式输出{\action\:\工具名\,\args\:{...}}。 如果任务完成或无法继续输出 {\action\:\finish\}。 ), }, {role: user, content: user_task}, ] for step in range(max_steps): response call_llm(messages) parsed json.loads(response) action parsed.get(action) if action finish: print(fAgent 在第 {step 1} 步完成任务。) return if action not in tools: print(f未知工具 {action}终止执行。) return tool_func tools[action][function] result tool_func(**parsed.get(args, {})) messages.append({role: assistant, content: response}) messages.append({role: tool, content: result}) print(达到最大步骤数已自动终止。) if __name__ __main__: run_agent(请告诉我北京今天的天气。)这个示例里最重要的规范是给每个工具写明确的功能描述和只读/读写边界并设置最大循环步数。真实项目中还要加上超时、重试、人工审批节点。3.3 控制流程而不是让它自由发挥Agent 的能力并不等于自由度。在生产环境里更推荐的做法是把高风险动作删除、转账、发布设计为独立节点需要人工确认。把工具分成只读和可写两类不同角色使用不同权限。对 Agent 执行的每一步打印日志便于回溯。当模型连续两次返回相同结果时主动终止并通知用户。这些措施看起来“不够智能”却是保证 Agent 在真实业务中能存活下来的关键礼仪。4. 模型层礼仪FP16/FP32/BF16你选对精度了吗4.1 精度问题为什么值得关注热搜词里有一类高频问题LLM 大模型的精度问题FP16、FP32、BF16详解与实践。这个主题之所以热是因为精度直接影响三件事显存占用、推理速度、结果稳定性。大模型训练和推理时默认使用浮点数。常见精度包括精度类型占用大小数值范围典型用途FP324 字节精度高范围广CPU 推理、精度验证FP162 字节范围小小数值易溢出部分 GPU 推理、训练加速BF162 字节范围与 FP32 接近精度稍低大模型训练、混合精度推理FP16 的问题在于范围小。当梯度或中间激活值过大时容易变成inf或nan。BF16 保留了 FP32 的指数范围因此在大模型场景下更稳定。这也是很多主流框架在训练和推理时使用 BF16 的原因。4.2 什么时候用哪种精度这里给出一个通用建议本地 CPU 或老 GPU 环境没有强制优化场景优先考虑 FP32保证正确性。显存受限且 GPU 支持 BF16优先使用 BF16兼顾范围与效率。已经验证过模型在 FP16 下表现稳定并且 GPU 算力支持可以使用 FP16 提升速度。对数值极其敏感的下游任务比如长文本评测建议同时跑一组 FP32 对比结果。在 Hugging Face Transformers 中可以通过torch_dtype参数快速设置精度# 文件路径examples/model_precision.py from transformers import AutoModelForCausalLM, AutoTokenizer model_id your_model_id # 示例使用 BF16 加载模型 tokenizer AutoTokenizer.from_pretrained(model_id) model AutoModelForCausalLM.from_pretrained( model_id, torch_dtypebfloat16, # 也可以写 torch.bfloat16 device_mapauto, ) # 推理示例 inputs tokenizer(介绍一下 LLM 上下文管理。, return_tensorspt) outputs model.generate(**inputs, max_new_tokens128) print(tokenizer.decode(outputs[0], skip_special_tokensTrue))需要特别提醒这里不要迷信“精度越低越快”。有些 GPU 对 FP16 有加速优化但 CPU 环境下 FP16 反而可能更慢。上线前一定要在目标硬件上做基准测试。4.3 一个容易踩的坑很多同学加载模型时发现显存不够于是直接把torch_dtype改成float16以为万事大吉。结果模型能跑但生成的文本中经常出现乱码或 NaN。这背后的原因往往不是模型本身有问题而是 FP16 的数值范围不够某个激活值溢出后导致后续计算崩坏。正确的排查顺序是先用 FP32 跑一遍确认模型是否正常再切 BF16最后才尝试 FP16。5. 知识层礼仪LLM Wiki 范式与 RAG 的边界5.1 Karpathy 提到的 LLM Wiki 是什么AI 社区里“LLM Wiki”是一个越来越受关注的概念。它的核心思想是不要试图让模型记住所有知识而是把知识放到外部结构化的知识库中模型只负责理解和检索后的合成。Andrej Karpathy 曾提到过类似的知识管理范式强调用 Wiki 式的双向链接构建个人或团队知识库再由 LLM 作为接口与用户交互。这种范式的价值在于它把模型从“记忆体”变成“推理引擎”极大减少幻觉。具体到落地就是最近很热门的Obsidian LLM Wiki 搭建个人知识库。使用 Obsidian 维护 Markdown 笔记通过链接形成知识网络再用 RAG检索增强生成把相关片段检索出来喂给 LLM。5.2 用检索增强替代“记忆”一个典型的 RAG 流程分成三步把文档切分成小块做嵌入向量索引。用户提问后利用向量相似度检索相关片段。把相关片段放入 Prompt让模型基于它回答。这里推荐一个“可运行但尽量简单”的 RAG 示例帮助你理解流程# 文件路径examples/simple_rag.py 最小 RAG 流程 - 使用文本去重、简单相似度检索代替向量数据库便于理解逻辑。 - 生产环境请替换为真正的 embedding 模型和向量库。 import re from difflib import SequenceMatcher # 1. 准备一个小知识库 knowledge [ LLM 上下文窗口决定了模型一次能处理的 token 数量。, BF16 保留了 FP32 的指数范围适合大模型训练与推理。, Agent 编排框架用于控制多步骤工具调用避免模型自由发挥。, RAG 指检索增强生成通过外部知识库减少幻觉。, ] def chunk_text(text: str, chunk_size: int 20) - list: # 简易切块生产环境建议按句或按语义切分 sentences re.split(r[。\n], text) chunks [] current for sentence in sentences: if len(current) len(sentence) chunk_size: chunks.append(current) current sentence else: current sentence if current: chunks.append(current) return chunks def retrieve(query: str, top_k: int 1) - list: scored [] for item in knowledge: score SequenceMatcher(None, query, item).ratio() scored.append((score, item)) scored.sort(keylambda x: x[0], reverseTrue) return [item for _, item in scored[:top_k]] if __name__ __main__: query 模型上下文窗口是什么 related retrieve(query) print(检索到, related)这段代码虽然简单但体现了 RAG 的核心礼仪只把和问题相关的片段交给模型而不是把所有文档一股脑塞进去。5.3 知识库建立时的礼仪在 Obsidian LLM Wiki 的场景里真正决定效果的不是模型而是知识质量。建议遵守每个主题用独立页面避免一篇文章塞入几十个概念。使用双链语法[[相关笔记]]把知识点连接起来。定期清理过期内容避免陈旧信息污染检索结果。对资料做摘要时保留关键版本号和来源链接。检索质量决定生成质量。这个原则在任何 RAG 应用中都不会变。6. 工程层礼仪权限、安全、成本与可观测性6.1 最小权限与内容过滤当 LLM 应用进入生产环境最危险的往往不是模型本身而是权限边界没设好。比如一个客服机器人如果同时绑定了数据库查询工具测试时没问题但遇到恶意输入时可能生成一条DROP TABLE语句。为了避免这种风险LLM 工程的权限礼仪应该包括给 LLM 可以访问的工具分配只读权限写操作必须走人工审批。在模型输出进入下游系统前增加内容过滤和 SQL 白名单校验。对用户输入做长度限制防止超长上下文攻击。所有涉及生产环境的操作先在小环境验证再灰度再全量。下面是一个伪代码级的安全校验示例# 文件路径examples/safety_layer.py import re def validate_sql(sql: str) - bool: 简单的 SQL 安全校验生产环境请使用专业的 SQL 白名单或解析器。 if not sql.strip().lower().startswith(select): return False if re.search(r(drop|delete|insert|update|alter|create), sql, re.I): return False return True # 模拟模型生成的 SQL model_output SELECT * FROM orders WHERE user_id123; if validate_sql(model_output): print(校验通过可以执行真实查询。) else: print(校验失败已拦截。)这里的关键原则是把模型当不可信输入源所有输出进入系统前必须校验。6.2 成本控制与降级LLM 的高质量回答是有代价的。如果业务系统不对 Token 做控制一个用户刷新十次页面账单就会吓人。成本礼仪可以从以下几个维度入手对单用户请求做限流比如每分钟最多 10 次。对短问题使用小模型只有复杂问题才调用大模型。对相同的查询使用缓存避免重复计算。当模型服务不可用或响应超时时降级为预设模板或提示“稍后重试”而不是无限等待。6.3 日志与审计LLM 应用的日志不能只记录接口状态还需要记录输入 Prompt 的快照可做脱敏后存储。模型返回内容、Token 消耗、耗时。是否走了工具调用、调用了哪个工具、返回值是什么。异常时的错误堆栈和模型原文输出。这些日志的用途不只是排错更是后续优化 Prompt 和评估模型效果的重要依据。7. LLM Etiquette 实践中的常见问题与排查方法问题现象可能原因排查方式解决方案上下文一长回答质量下降无关历史消息进入上下文查看请求日志里的消息列表确认是否塞入了大量历史用摘要替代历史只保留最终结果JSON 输出偶尔解析失败模型输出多余文字查看原始模型输出确认格式偏离情况System 里声明严格 JSON并做容错解析Agent 陷入死循环缺终止条件或工具描述不清观察完整日志中模型每步的 action 内容设置最大步数工具描述里写明确适用场景模型输出乱码或 NaNFP16 数值溢出用 FP32 跑同一段输入对比改用 BF16 或 FP32检索结果与问题无关知识库未切块或检索策略差打印检索结果片段人工判断相似度优化切块逻辑换用 embedding 向量库请求延迟波动大上下文窗口过长或并发超限观测耗时与 Token 数量关系限制单次请求 token 数增加缓存和限流数据库工具被触发危险语句模型绕过了只读限制检查工具权限配置增加统一 SQL 校验写操作走人工审批这张表里的每个问题我都在真实项目的代码评审里见过。如果一篇 LLM 应用代码没有考虑这些场景它迟早会在某个晚上报警。8. 一套可以直接用的 LLM Etiquette 清单这里整理一份落地清单适合打印出来贴在工位旁边也适合写进团队 Review 规范。Prompt 层面System 只负责角色和输出规则User 消息只保留必要信息。上下文层面设定 Token 预算历史消息用摘要代替原文。输出层面明确要求 JSON 或固定格式代码层保留解析失败重试。工具层面每个工具写明用途、参数、只读或可写高风险操作需要二次确认。循环层面Agent 必须有最大步数、超时时间、重复结果检测。模型层面加载模型时先确认精度显存不够优先考虑 BF16必要时刻对 FP32 与精度的结果做对比。知识层面RAG 只检索相关片段知识库要求结构清晰、双链关联、定期更新。工程层面所有外部输入不可信输出进系统前必须校验限流、缓存、降级、日志审计一个都不能少。评估层面建立 Prompt 与模型性能的回归测试集每次改 Prompt 或换模型都跑一遍而不是靠肉眼观察几条结果。9. 最后一件事LLM Etiquette 不是一套锁死的规则它更像是一种思维方式把模型当作一个有边界、会出错、需要协作配合的组件而不是无所不知的魔法盒。当你再遇到“模型效果不好”的问题时先不要急着换更大的模型也不需要立刻微调。花 30 分钟检查一下上下文塞了什么、工具边界有没有问题、精度设置是否正确、知识库检索是否精准。大概率能在不增加成本的情况下把效果拉高一大截。下一步你可以挑一个最关心的场景比如客服对话解析或者个人知识库问答用本文的规范重写一遍调用流程。跑几天后你会明显感觉到不是模型不够强而是之前的用法太粗糙。
返回列表