经常有朋友拿着一个LLM的API Key问我:"这东西到底怎么用?"我写了prompt它能回,但真要做点正经事——让它读完一份合同、生成结构化数据、接入业务系统——就不知道从哪下手了。这其实是大多数人卡住的地方:把LLM的使用方法等同于"写提示词"。但真正在生产环境里跑过模型的人都知道,提示词只是最表层的一环,后面还有模型选型、上下文管理、结构化输出、工具调用、成本控制、效果评估,整整一条链路。
这篇文章我就按自己在多个项目里实际操作LLM的经验,从模型基本原理讲到API调用,再到RAG、评估、报错排查这些进阶玩法,尽量一次说透。适合两类人看:一类是刚拿到API Key、想从"会聊天"升级到"会接入系统"的开发者;另一类是在做技术选型、想知道除了调prompt之外还有哪些关键环节的产品或研究人员。
1. LLM不是聊天机器人:先校正使用前提
1.1 你面对的是一个概率模型,不是一个搜索引擎
很多人第一次接触LLM时有个误解:以为它像搜索引擎一样,内部存着海量知识,你问什么它"查"出来给你。其实不是。大语言模型(Large Language Model)本质是一个"给定上文、预测下一个词"的概率模型。你在对话框里输入一句话,模型不是在数据库里检索答案,而是根据训练时学到的统计规律,一个token一个token地往后"补全"。
这个区别听起来抽象,但对使用方式的影响极其直接。搜索引擎是精确匹配,问"苹果"就返回苹果相关页面;LLM是概率生成,你问"苹果",它可能补全"是一种水果",也可能补全"公司发布了新手机",完全取决于上下文里你给了多少约束。所以你会发现,同一个模型,prompt写清楚了,输出就靠谱;prompt写得含糊,输出就飘忽。这不是模型"不稳定",而是概率模型的天然特性。
1.2 理解"下一个token预测"才是用对prompt的起点
既然模型是"补全"逻辑,那prompt的真正作用就不是"提问",而是"给定足够明确的前文,让后续的补全方向被牢牢锁住"。我经常用一个类比:你和朋友玩接话游戏,你说"今天天气真",朋友大概率接"好";你说"今天天气真不错,我们下午去公园",朋友就大概率接"散步吧"或者"野餐"。前文信息越充分,后文越可预期。
这就解释了为什么"少样本提示"(few-shot)比"空手提问"可靠得多。不是模型喜欢看例子,而是例子提供了前文分布,把输出空间压缩到了你期望的范围内。实操的时候,我会在system prompt里写清楚角色和任务,再给两个输入输出样例,最后才放真实输入。这一套组合下来,输出稳定性的提升比换更强型号的模型还明显。
1.3 能力边界先摸清:幻觉、时效性与上下文
用LLM之前还必须认清它的三个短板。第一是幻觉:模型不知道答案时不会老实说"不知道",而是会基于概率编一个听起来合理的回答。第二是时效性:模型的知识截止于训练数据那天,之后发生的事情它不知道。第三是上下文窗口:它一次能"记住"的内容有上限,超过的部分会被忽略,不是你想塞多少就塞多少。
这三个短板决定了LLM适合干什么、不适合干什么。适合的是总结、改写、分类、抽取、生成初稿、代码辅助这类"语言处理"任务;不适合的是需要精确事实、实时数据、强逻辑链的任务——除非你配合RAG、工具调用、人工校验等手段来兜底。我看到很多失败的LLM项目,本质上就是把模型当成了"万能数据库",让它回答训练数据之外的问题,又没有任何校验机制。这不是模型废,是用法错了。
这些年LLM应用的边界也在不断扩展,比如有的研究团队在尝试用LLM做公立医院债务风险的智能预警与化解策略,这种场景就是把模型的"语义理解+生成"能力叠加在结构化财务数据之上,本质上还是用工程手段补足模型不擅长的那部分。用好LLM的第一步,就是别让它单独扛事。
2. Token是计费单位,更是模型的思考粒度
2.1 中英文Token差异,直接决定你的成本
Token(词元)是LLM处理文本的最小单位。它不是完整的单词或汉字,而是模型分词器切出来的片段。英文里一个单词通常切成一到两个token,比如"chat"可能是一个token,"conversation"可能被切成"con"和"versation";中文里一个汉字大约对应0.6到1.5个token,一段1000字的纯中文文本,可能要烧掉1500到2000个token。
这个差异直接影响成本。同样一段话,中文比英文"贵"是常态。API按token计费,输入和输出都要收费,而且不同模型的单价差出好几倍。我在项目里做成本估算时有个粗算方法:用户一次会话平均消耗多少token,乘以日均会话数,再乘以单token价格,基本就是一天的模型成本。很多人账单爆掉,不是用量超了预期,而是根本没用这个公式算过。
2.2 注意力机制里的K、Q、V:一次讲透"你是谁、要找什么、能提供什么"
去年我注意到有个热词被反复提起:"LLM的token三个点,Key我是谁、Query我在找什么、Value我能提供什么"。这其实是Transformer注意力机制(Attention Mechanism)里Q/K/V的通俗化总结,也是理解LLM工作方式的关键。
当一个token进入模型后,它会被映射成三个向量:Query(查询向量)、Key(键向量)、Value(值向量)。你可以用图书馆借书的场景来理解:Key是书架上的标签,标识这本书是什么内容;Query是你手头要找的书单描述,代表你此刻关注什么;Value是书里的具体正文,是真正要被读取的信息。模型计算注意力时,就是把你的Query拿去和所有位置的Key做匹配,算出每个位置的"相关度分数",再用这个分数给对应的Value做加权求和。相关度高的token,它的信息就会被重点"读取";相关度低的,就会被忽略。
这个机制落到使用层面有两层启示。第一,你prompt里的每个词都在产生Query,也在提供Key和Value,所以"写了什么"直接决定模型注意力往哪放。你反复强调"以JSON格式输出",模型注意力就会往JSON格式上集中;你给了几个高质量示例,示例里的结构就会被模仿。第二,当上下文很长时,注意力会分散,关键信息会被"淹没"在冗长文本里。所以不是所有资料都该塞进prompt,而是要把最核心的信息放在最显眼的位置,比如开头和结尾,或者明确说"请优先参考第三条内容"。
提示:很多人以为"让模型读的资料越长,它理解越透彻",实测恰恰相反。信息密度低的长文本反而会稀释注意力,导致模型漏掉关键约束。必要资料请先摘要、再拼装。
2.3 上下文窗口不是越大越好,填充率才是关键指标
现在的模型动辄支持128K、200K的上下文窗口,很多人的第一反应是"太好了,终于能一次处理整本书了"。但我实测下来的感受是:上下文窗口大,不等于你该把它填满。
有两个原因。一是成本:你输入给模型的每一个token都要付钱,prompt越长,单次要价越高,而且是每次请求都重复计算。二是注意力问题:模型对超长上下文的"记忆"能力远没有宣传得那么理想,真正重要的信息在被大量无关内容稀释之后,模型抓取关键点的准确率会明显下降。
我自己的经验是把单次请求的上下文填充率控制在窗口的50%以下,超过这个比例就先做一轮摘要或分段处理。比如处理一份50页合同,正确的做法是先让模型分段抽取关键条款,再汇总整理,而不是把整份合同一次性塞给它"帮我总结一下"。后者看似省事,实际效果不稳定,遇到长文本里的细节要求,经常漏项。
3. 从拿到API Key到跑通第一个生产级调用
3.1 完整调用链路拆解:接口、鉴权、消息格式
先说一个基本但极其重要的概念:现在绝大多数主流模型服务商都提供了兼容OpenAI格式的接口。也就是说,你只要会调一套Chat Completions接口,就能在DeepSeek、Qwen、GLM等不同模型之间无缝切换。这大大降低了上手门槛。
一条完整的调用链路长这样:先去模型服务商的官方平台申请API Key,拿到你的专属凭证;然后找到该服务商提供的接口地址(Base URL);接着按OpenAI兼容格式发送请求,请求体里包含模型名称、消息列表、温度等参数;最后解析返回结果里的content字段。我用Python写过很多次,最简版本长这样:
import os from openai import OpenAI client = OpenAI( api_key=os.getenv("LLM_API_KEY"), base_url=os.getenv("LLM_BASE_URL") ) resp = client.chat.completions.create( model="qwen-plus", messages=[ {"role": "system", "content": "你是严谨的合同审核助手,只输出结构化结论。"}, {"role": "user", "content": "请审核以下合同条款,列出风险点。"} ], temperature=0.3, max_tokens=2048 ) print(resp.choices[0].message.content)注意到几个细节了吗?api_key和base_url我都是从环境变量里读的,绝不硬编码在代码里。这样既防止Key泄露,也方便切换不同服务商——换一家模型,只需要改环境变量,不用动代码。temperature设成0.3,因为审核类任务需要确定性,温度太高输出会发散。max_tokens设了上限,防止模型偶尔"话痨"导致账单失控。
3.2 第三方API使用技巧:多服务多Key的配置管理
当项目里同时接了好几个模型服务商的API,配置管理就会变成一个容易让人头疼的问题。每个服务商有自己的API Key、自己的Base URL、自己的模型命名规则,如果都在代码里写死,换模型就要改代码重新部署,非常被动。
我建议的做法是统一走环境变量或配置文件管理所有服务的Key和URL,然后用一个服务标识来决定当前请求走哪条链路。伪代码大概是:
SERVICE_CONFIG = { "deepseek": { "base_url": "https://api.deepseek.com/v1", "api_key_env": "DEEPSEEK_API_KEY", "default_model": "deepseek-chat" }, "qwen": { "base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1", "api_key_env": "QWEN_API_KEY", "default_model": "qwen-plus" }, "glm": { "base_url": "https://open.bigmodel.cn/api/paas/v4", "api_key_env": "GLM_API_KEY", "default_model": "glm-4" } }这样做的最大好处是解耦。业务代码只认"服务名",不认具体的URL和模型名。哪天GLM出了新版本,或者你想把某个任务切到另一个模型,改配置就行,业务逻辑完全不动。
社区里还有一些现成的配置管理工具,比较有代表性的像CC Switch,它把多家服务商的Base URL和API Key集中管理,在图形界面里一键切换当前生效的配置。对于个人开发者或者小团队来说,这种工具能省掉不少来回改环境变量的琐碎操作。不过我自己的风格是:个人实验可以用这类工具,生产环境还是坚持"代码+配置文件"的方式,因为可审计、可追溯,出问题能快速定位。
3.3 模型选型:不是越贵越大就越好
很多团队在选模型时会陷入"参数越大越好"的惯性思维。但实际上,不同任务对模型能力的需求差异极大。
简单总结一下我现在的选型逻辑:如果任务是封闭式的,比如文本分类、情感判断、信息抽取,这类任务输出空间有限,中小模型完全胜任,用大模型反而浪费;如果任务是开放式的,比如代码生成、复杂推理、长文创作,这类任务需要模型有很强的"脑力",才值得上旗舰模型;如果是翻译、改写、摘要这类中等难度任务,中间档模型往往是性价比最好的选择。
以实际场景举例,我之前做一个工单自动分类系统,一开始用旗舰模型,准确率和延迟都不错,但成本很高。后来把模型换成中档型号,准确率只掉了约2个百分点,成本却降了将近一半。分类任务里那2个点完全可以通过加规则兜底补回来。反过来,做代码生成功能时,我坚持用能力更强的模型,因为代码错误导致的调试时间成本,远高于模型本身的价差。
这里还有一个常被忽略的点:同一个模型的不同版本,能力差异可以很大。很多服务商同时提供多个版本,版本号之间可能相差好几代。选型时以实际评测数据为准,别只看名字里是不是带"最新"两个字。
3.4 当服务商多到记不住时,LLM网关的作用要清楚
如果你只是个人调用几个API,用配置管理就够了。但如果你是团队负责人,成员有十几个人,每个人都在直接调用各家API,问题就来了:Key怎么管理?谁能调用哪个模型?月度费用算谁的?限流被触发怎么办?
行业里对此的标准解法是引入LLM网关(LLM Gateway)。网关作为统一入口,所有业务请求先到网关,由网关负责鉴权、限流、模型路由、用量统计和成本分摊。业务侧不直接接触各家API Key,而是只对接网关暴露的内部接口。这样即便某家服务商涨价或者模型下线,也只需要在网关层切换,业务代码完全无感。
提示:个人项目不需要一上来就搭网关,那是给自己找负担。但写代码时请保留一层薄薄的"服务封装",把各家API的差异挡在业务之外。这个习惯养成之后,团队规模上去时平滑过渡到网关会非常自然。
4. 让LLM从"聊天"变成"干活"的两条关键路径
4.1 结构化输出:JSON模式与Function Calling
让LLM从"能聊天"进化到"能干活"的第一步,是让它的输出变得可解析、可校验、可被程序直接消费。一个只能输出自然语言段落的模型,没法接进业务流程;但一个能稳定输出JSON的模型,就可以充当业务流水线上的一环。
目前主流服务商都支持JSON输出模式,你可以在请求参数里开启,也可以在prompt里明确要求"只输出JSON,不要其他内容"。我的经验是两者结合:开启JSON模式的同时,在prompt里给出完整的JSON schema示例。比如:
请按以下JSON结构输出,不要输出任何解释性文字: { "风险等级": "高/中/低", "风险点": ["条款编号", "问题描述"], "建议": "修改建议" }这一步做完,返回结果就能直接json.loads()解析。不过实测中还有两个坑:一是极少数情况下模型仍然会多输出反引号标记或者前后缀文字,所以解析代码一定要做"从返回文本中提取JSON片段"的兜底处理;二是JSON的字段命名要符合模型习惯,用中文键名没有障碍,但最好保持固定顺序,降低模型的随机性。
4.2 上下文为王:System Prompt、Few-Shot与工具调用
如果结构化输出解决了"模型怎么说"的问题,那上下文工程解决的就是"模型依据什么说"的问题。一个设计得当的System Prompt,顶得上换一个更强的模型。
我常用的System Prompt模板包含四个部分:角色定义(你是谁)、任务描述(你要干什么)、输出约束(格式边界)、负面约束(绝对不能做什么)。比如:
你是高级法务审核助手。 任务:审核用户提供的合同片段,标注风险条款。 约束:只输出JSON,不输出解释;风险等级必须是高/中/低三档。 禁止:不要编造合同中不存在的条款。在这套基础之上,再叠加几个Few-Shot示例,把"合格输出"的样子展示给模型看。模型不需要你解释规则,它需要你提供足够多的高质量"前文"来引导补全方向。
再进一步就是工具调用(Function Calling/Tool Use),这也是现在各种AI Agent产品的基础能力。核心逻辑是:你先告诉模型有哪些工具可用,每个工具的参数schema长什么样;模型根据用户需求决定"该调用哪个工具、传什么参数";你执行工具后把结果返回给模型,模型再基于结果继续回答或行动。这套机制让LLM突破了"纯语言"的边界——它能去查数据库、读文件、执行代码、调用API了。
4.3 用工程手段压制幻觉:引用溯源、校验与重试
模型幻觉不可能被"提示词写得好"完全消灭,只能通过工程手段压制。我的实操组合拳有三招。
第一招是引用溯源。涉及事实性回答时,要求模型标注答案依据"来自上下文中的哪一段"。如果模型说不出来源编号,基本可以判定它是编的。第二招是规则校验。对模型输出做程序化检查,比如日期格式对不对、金额能不能解析成数字、JSON schema是否合法,凡是能程序校验的就不依赖模型自觉。第三招是重试与投票。对高风险判断,可以让模型以不同温度生成三次,取多数票作为最终结果;或者实在不确定时直接让模型回答"信息不足,无法判断",把决策权交回给流程。
这些听起来不复杂,但每一条都是我在真实项目中踩坑换来的。没有这些兜底机制,LLM的幻觉就会在某个意想不到的时间点给你制造事故——比如把合同的甲方乙方搞反,或者在一段测试代码里生成了根本不存在的API方法。
编码场景是目前工具调用做得最成熟的领域之一。像Claude Code这类编码助手,本质上就是把LLM的对话能力和一套"读文件、改文件、跑测试"的工具绑定在一起。你给它一个任务,它自己规划步骤、读代码、修改代码、执行测试,然后把结果告诉你。用这种工具时最重要的经验是:任务边界要收窄,一次只让它干一件事;同时必须有版本控制,让它可以放心试错,反正改坏了能回滚。
这个思路往测试方向延伸,就有了"基于LLM的单元测试"玩法:让模型读一段函数代码,自动生成对应的测试用例。这里有个重要提醒——模型生成的测试用例只能当"候选",不能直接信任。它在生成边界条件时经常拍脑袋,很多测试断言本身就有问题。我实际使用时会让模型先生成用例,保证用例能跑通,再由人来补充关键边界和断言逻辑。LLM在这个场景干的活是"提效",不是"负责"。
5. 进阶玩法:RAG、评估与本地化部署
5.1 RAG不是把文档全塞进Prompt
RAG(Retrieval-Augmented Generation,检索增强生成)是目前让LLM回答私有知识问题的标准方案。很多人第一次听说RAG时会想:是不是把知识库的文档全部塞进prompt,让模型基于这些内容回答?这是RAG最常见的误解。
真正的RAG分四步。第一步,把知识库的文档切成合理的片段(chunk),切成千字左右的块;第二步,把这些块做向量化,也就是用Embedding模型转成向量并存入向量数据库;第三步,用户提问时,把问题也转成向量,去向量库里做相似度检索,找出最相关的几个片段;第四步,只把这几个片段拼进prompt,让模型基于它们回答。
这个方案的精髓在于"检索后再生成",而不是"堆砌后再生成"。"只把最相关的片段给模型"这七个字,就是RAG和"全塞进去"的本质区别。
RAG的进阶形态也值得关注。GraphRAG在文档切块之外,先用LLM把文档里的实体和关系抽取出来,构建知识图谱,检索时走图结构做多跳查询,适合"A和B之间经由C存在什么关系"这类复杂问题。本体RAG(Ontology RAG)则在检索前引入领域本体来约束概念和关系,在法律、医疗这类术语严谨的行业里,能显著减少模型的实体混淆。至于LLM Wiki这类知识库实践,核心思路是一样的:把团队的经验用结构化的wiki沉淀下来,再通过RAG让LLM基于wiki内容回答。wiki的条理性天然适合被切块和检索,比直接扔一堆PDF进去靠谱得多。
5.2 LLM as Judge:用模型评估模型的实操要点
模型效果评估是LLM落地中最容易被忽略的环节。人类评估费时费力还不一致,于是越来越多团队采用"LLM as Judge"——让另一个模型来给结果打分或做对比排序。
但这个做法有很明显的陷阱。第一个是偏好偏差:如果评估模型本身是某家的旗舰模型,它会倾向于给自己家模型生成的内容打高分。第二个是位置偏差:把候选A放前面还是放后面,会影响评判结果。第三个是评价标准漂移:评判标准写得不具体,模型每次打分的依据都不一样。
我的应对措施是:评估模型和生成模型尽量来自不同厂商;在prompt里把评价维度拆成独立的评分项,比如"准确性0-5分""完整性0-5分""格式规范性0-5分",每个维度给明确标准;至少用两个评估模型各评一次,取平均分;最后抽20条结果让人工复核,校验机器评分和人评分的一致性。这样一套流程下来,机器评估的结果才具备参考价值。
5.3 从云端API到本地部署:ONNX推理的适用场景
不是所有LLM应用都适合走云端API。如果你的场景涉及高敏感数据、需要离线运行,或者对单次请求延迟有极致要求,本地部署就是绕不开的选项。
ONNX(Open Neural Network Exchange)是深度学习模型的一种开放中间格式。把训练好的LLM转成ONNX格式后,可以用ONNX Runtime在本地CPU或GPU上直接推理。相比直接从PyTorch推理,ONNX的好处是推理性能优化更好、部署环境更轻量,而且不依赖原始训练框架。
实际部署时我踩过几个坑。一是量化:把模型从FP16压到INT4或INT8能显著降低显存和内存占用,但量化后的模型在生成质量和支持的算子范围上会有微妙差异,必须实测。二是算子兼容性:不是所有模型结构都能顺利转成ONNX,转换前先查一下模型是否支持导出。三是显存规划:即便量化后,一个7B模型在INT4下通常也需要4GB左右的内存,你需要提前评估目标机器带不带的动。本地部署适合中小尺寸模型,旗舰模型想在本地流畅跑,成本会非常离谱。
6. 高频报错与坑点实录:我的排查经验
6.1 "provider rejected the request schema or tool payload"到底是什么问题
"llm request failed: provider rejected the request schema or tool payload."——这是我在做工具调用功能时遇到频率最高的报错,没有之一。它的字面意思是"服务商拒绝了你的请求,因为工具Schema或工具参数载荷有问题"。
这类报错一般有三层原因。第一层是工具Schema本身不合法:你声明的工具参数JSON Schema格式有误,比如类型写错、缺少required字段、枚举值不合法。服务商会用严格的JSON Schema校验器校验你的定义,任何不合规都会直接拒绝。第二层是模型返回的tool_calls与工具Schema不一致:模型生成了工具调用,但工具名不匹配、参数个数对不上、参数值类型错误,也在这一层拦截。第三层是历史消息中有残留的tool_calls:在多轮对话里,如果上一轮的assistant消息带着tool_calls记录,而后续的tool消息没有按规范配对,请求同样会失败。
我的排查顺序是固定的:先把请求体里的tools参数单独拎出来,用JSON校验器检查格式;然后确认每条assistant消息里的tool_calls是否都对应着合法的tool消息;最后把完整的messages列表打出来人工过一遍,看消息序列是否完整。90%的问题在第三步就能定位——很多时候是因为代码里拼接历史消息时漏掉了某条tool消息,导致序列断链了。
6.2 Token计费陷阱:为什么账单比你预期高
每个月看到API账单比预估超出一截,几乎成了LLM应用的惯例。我总结过几个最常见的超支原因。
第一个是System Prompt被反复计费。很多人把超长的System Prompt写在每次请求里,这些token每次都要重新计费,日积月累数字非常可观。我的做法是在能容忍的情况下精简System Prompt,能写100字绝不写500字。第二个是未开启输出长度限制。某些模型默认输出长度偏大,模型在不需要长输出的任务里也会"洋洋洒洒"写一大段,这部分输出的单价通常比输入还贵。第三个是重试导致的隐性用量。代码里加了自动重试逻辑时,每次重试都要重新计算输入token,失败频率高时用量就成倍增长。第四个是无意中的上下文累积。把历史消息越堆越长,每次对话都会重新处理全部历史,token消耗呈线性甚至超线性增长。
提示:上线前做一个最简单的用量日志埋点,记录每次请求的prompt_tokens和completion_tokens,回头看账单时,你会庆幸当初写了这20行代码。
6.3 合规与安全:什么内容不能交给LLM处理
LLM的便利性很容易让人放松警觉。我在实际项目中给自己定的铁律是:敏感数据不直接上传。这里的敏感包括个人身份信息、用户密码、内部合同条款、未公开的业务数据等。如果需要用LLM处理含敏感信息的文本,先脱敏再送进模型,输出后再做反向映射。这个流程多写了一层代码,但能规避的风险不是用钱能衡量的。
另一个容易忽视的问题是服务条款。不同模型服务商对数据留存、训练使用的政策差异很大,有的会默认用你的请求数据继续训练模型。如果你在to B场景下代人处理数据,必须在接第三方API前确认数据合规边界,必要时选择提供"数据不用于训练"承诺的服务商或走私有化部署。这些不是可以事后补的功课,一旦泄露再补救就是事故了。
我个人的体会是,LLM的坑始终存在于"模型能力"和"工程约束"之间的那层缝隙里。你越依赖模型自觉,它就越会给你惊喜;你越把约束写成代码,输出就越可控。所以把上面这些经验落到自己的项目里时,记住一个原则:好用的LLM应用,不是模型选得多强,而是你为这个模型搭了多稳的护栏。