
1. 为什么你的 LangChain 提示词总是“差点意思”很多人第一次用 LangChain 写提示词都会经历一个相似的阶段把需求直接塞进PromptTemplate跑通之后发现输出时好时坏换个问法就崩。问题往往不在模型而在提示词本身缺少结构。LangChain 提示词工程的核心不是把一句话写得更长而是把“背景、目标、步骤、语气、受众、格式”这些隐含信息显式地交给模型。这也是 COSTA 框架能派上用场的地方。COSTA 是六个维度的缩写Context背景、Objective目标、Steps步骤、Tone语气、Audience受众、Format格式。它解决的是一个很实际的问题——模型对你脑子里的上下文一无所知。你不说清楚“你是谁、要干什么、按什么顺序、说给谁听、输出成什么样”模型就只能靠猜。猜对了是运气猜错了是常态。这篇内容聚焦 LangChain 提示词工程入门主线就是 COSTA 框架。我会带你从零写一个可复制的PromptTemplate再扩展到FewShotPromptTemplate少样本提示最后用思维链CoT把推理过程显式化并给出链式调用和输出对比验证的完整步骤。适合刚接触 LangChain、想让提示词从“能用”变成“稳定好用”的开发者。你不需要提前精通 LangChain只要能跑 Python、装过依赖就能跟着做下来。少样本提示和思维链不是两个孤立技巧。少样本提示解决的是“格式和模式”问题——模型不知道你要什么样式你给它几个例子照葫芦画瓢思维链解决的是“推理过程”问题——模型直接给答案容易跳步出错你要求它一步步推导。两者结合就是少样本思维链在 LangChain 里可以用FewShotPromptTemplate配合示例中的推理步骤来实现。下面从环境准备开始一步步落地。2. TaoToken 前置准备与 LangChain 环境搭建在写提示词之前先把模型调用通道准备好。LangChain 本身不提供模型它负责编排真正干活的是背后的 LLM。这里我用 TaoToken 作为模型接入层它兼容 OpenAI 风格的接口LangChain 的ChatOpenAI可以直接对接改一下base_url和api_key就行。先拿 Key。打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后在控制台创建 API Key。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite API Keys 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。Key 拿到后先存到环境变量里别硬编码进代码。export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api注意 base_url 这里写的是https://taotoken.net/api不带任何查询参数。LangChain 的 OpenAI 兼容客户端会自动在末尾拼接/v1/chat/completions这类路径所以你不要手动加/v1否则会出现路径重复导致 404。接着装依赖。建议用虚拟环境Python 3.9 以上。python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install langchain langchain-openai装完之后验证一下版本LangChain 迭代快不同版本 API 有差异。pip show langchain langchain-openai我实测下来langchain-openai这个包是必须的老的langchain.llms.OpenAI已经拆出去了如果你照着旧教程写from langchain.llms import OpenAI会直接报 ImportError。这一点在排障章节还会再提。环境变量和依赖都就绪后先写一个最小的连通性测试确认模型能通再进入提示词部分。这一步别跳过否则后面提示词调半天最后发现是 Key 或 base_url 的问题白费功夫。import os from langchain_openai import ChatOpenAI llm ChatOpenAI( modelgpt-4o-mini, api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ[TAOTOKEN_BASE_URL], temperature0.3, ) resp llm.invoke(用一句话说明什么是提示词工程) print(resp.content)如果这行能打印出内容说明通道没问题。model参数填你账号下可用的模型 ID具体可用列表可以在模型对话页 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 里确认。temperature 设 0.3 是为了让提示词实验的输出更稳定做结构化任务时别开太高。这里有个细节LangChain 的ChatOpenAI接收的是消息列表invoke传字符串时它会自动包成 HumanMessage。但一旦你开始用PromptTemplate传进去的就是格式化后的字符串最终还是会走消息封装。理解这一层后面排查“为什么模板变量没被替换”会轻松很多。3. 用 COSTA 框架写可复制的 PromptTemplate 配置现在进入正题。COSTA 框架的价值在于把提示词拆成可维护的模块而不是一坨字符串。在 LangChain 里PromptTemplate支持变量占位正好可以把 COSTA 的六个维度做成变量按需填充。先看一个不用框架的“裸提示词”长什么样from langchain_core.prompts import PromptTemplate naive PromptTemplate.from_template(帮我写一个关于{topic}的故事) print(naive.format(topic太空冒险))输出大概是“写一个关于太空冒险的故事”模型返回的内容往往泛泛而谈。问题在于主角是谁、什么风格、要几个情节、给谁看全都没说。用 COSTA 改写把六个维度显式化。下面这段可以直接复制路径和变量名保持一致from langchain_core.prompts import PromptTemplate costa_template PromptTemplate.from_template( 你现在的角色背景是{context} 你的核心目标是{objective} 请按以下步骤执行 {steps} 语气要求{tone} 目标受众{audience} 输出格式要求{format} ) prompt costa_template.format( context你是一位儿童文学作者擅长写太空题材的短篇故事, objective写一个适合睡前阅读的太空冒险故事, steps1. 设定主角和飞船名称\n2. 设计三个冒险情节\n3. 用温暖的方式收尾, tone轻松、口语化、有画面感, audience6到10岁的儿童, format标题 三段正文每段不超过80字, ) print(prompt)打印出来的 prompt 就是一段结构完整的指令。把它丢给模型输出会明显更聚焦。这里的关键不是模板本身多复杂而是你把“隐含要求”变成了“显式变量”。以后要调整只改对应变量不用重写整段话。COSTA 不要求每次六个维度全写。简单任务可以只保留 Context、Objective、Format 三个。比如做数据提取extract_template PromptTemplate.from_template( 背景{context} 目标{objective} 输出格式{format} 输入内容{input} )但复杂任务尤其是需要模型按特定流程走的Steps 和 Tone 就很重要。Steps 相当于给模型一个执行清单Tone 决定输出的“人味”。Audience 常被忽略但它直接影响用词深度——给儿童和给工程师写同一件事措辞完全不同。如果你在做长期编码或 Agent 类项目提示词模板会反复复用建议把 COSTA 模板单独放一个模块文件比如prompts/costa.py用常量管理。这样团队协作时不会出现“每个人改一版提示词”的混乱。需要更系统地管理模型调用和额度可以在 Coding Plan 页 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 看下适合长期开发的方案。把 COSTA 模板和模型串起来用 LCEL 管道写法from langchain_core.output_parsers import StrOutputParser chain costa_template | llm | StrOutputParser() result chain.invoke({ context: 你是一位儿童文学作者, objective: 写一个太空冒险故事, steps: 1. 设定主角\n2. 三个情节\n3. 温暖收尾, tone: 轻松口语化, audience: 6到10岁儿童, format: 标题 三段正文, }) print(result)|是 LangChain 表达式的组合符左边输出喂给右边。StrOutputParser负责把模型返回的消息对象转成纯字符串。这套写法比老的LLMChain更直观也是现在推荐的方式。4. FewShotPromptTemplate 少样本提示与思维链实战COSTA 解决的是“说清楚”少样本提示解决的是“给样板”。有些任务的格式很特殊你用文字描述半天不如直接给两三个例子。LangChain 提供了FewShotPromptTemplate专门干这个。先看少样本提示的基本结构。假设我们要让模型学会一种自定义的符号运算二鸟59这种表达里“鸟”代表加号。直接问模型它不知道但给两个例子它就懂了。from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate examples [ {input: 二英53, output: 5}, {input: 四鹦鹉7, output: 11}, ] example_prompt PromptTemplate.from_template(输入{input}\n输出{output}) few_shot FewShotPromptTemplate( examplesexamples, example_promptexample_prompt, prefix根据下面的例子推断符号含义并计算, suffix输入{input}\n输出, input_variables[input], ) print(few_shot.format(input二鸟59))打印结果会把两个示例和当前问题拼在一起。模型看到“英”和“鹦鹉”都代表加号就能推断“鸟”也是加号输出 5914。这就是少样本提示的核心——不是下指令而是给模式。现在把思维链加进来。思维链的关键是让模型展示推导过程而不是直接给答案。经典的球类问题是杂耍者可以杂耍 16 个球其中一半是高尔夫球一半的高尔夫球是蓝色的问有多少个蓝色高尔夫球。不加推理模型容易答 8正确是 16÷2÷24。零样本思维链最简单在问题后加一句“请一步一步推理”cot_template PromptTemplate.from_template( {question}\n请一步一步推理并给出最终结论。 )少样本思维链则是在示例里就把推理步骤写出来cot_examples [ { question: 小明有10个苹果吃了2个又买了5个现在有几个, reasoning: 初始10个吃掉2个剩8个再买5个8513个。, answer: 13, }, ] cot_example_prompt PromptTemplate.from_template( 问题{question}\n推理{reasoning}\n答案{answer} ) cot_few_shot FewShotPromptTemplate( examplescot_examples, example_promptcot_example_prompt, prefix请模仿下面的推理方式先展示推理过程再给答案。, suffix问题{question}\n推理, input_variables[question], )模型看到示例里有“推理”字段就会照着先推导再给结论。实测下来少样本思维链比零样本思维链更稳定因为示例把“推理该长什么样”也定义清楚了。把少样本思维链和 COSTA 结合可以这样组织Context 说明任务类型Objective 说明要推理Steps 里明确“先推理后结论”Format 规定输出结构示例则提供推理样板。这种组合在需要模型做多步判断的场景里特别有用比如代码审查、数据校验、逻辑题。再进一步是自我批判。思路是把生成和评审分成两步第一步让模型产出答案第二步把答案连同审查维度一起丢回去让它自己找问题。审查维度可以包括边界场景空列表、单元素、变量命名、结构清晰度。在 LangChain 里用两条链串联即可review_template PromptTemplate.from_template( 请审查下面的内容从边界场景、命名规范、结构清晰度三个维度指出问题\n{content} ) review_chain review_template | llm | StrOutputParser()先跑生成链再把结果喂给 review_chain。这一步在代码生成场景里能明显减少低级错误。注意别把“自我批判”理解成模型真的会反思它只是换了个提示词视角重新生成但效果确实比一次性输出好。5. 常见报错排查401、local proxy failed 与 reading choices提示词写得再好通道不通也白搭。这一节把 LangChain 接 TaoToken 时最容易撞上的几个报错列出来对照着排查。401 Unauthorized。最常见的原因是 Key 没读到或写错。先确认环境变量真的生效echo $TAOTOKEN_API_KEY如果输出为空说明 export 没在当前 shell 生效或者你换了终端。Windows 下用echo %TAOTOKEN_API_KEY%。另一个原因是 Key 前后带了空格或换行复制时容易带上。建议在代码里打印len(api_key)确认长度合理。还有一种情况是把 base_url 写成了带/v1的地址导致请求路径变成/v1/v1/chat/completions有些网关会返回 401 而不是 404容易误判。local proxy failed / Connection error。这类报错通常是网络层问题。先确认base_url拼写正确是https://taotoken.net/api不是https://taotoken.net/api/末尾斜杠有时会导致路径拼接异常。如果你本地配了系统级网络设置Python 的 requests 可能会读取环境变量里的HTTP_PROXY导致请求被劫持。检查一下env | grep -i proxy如果有输出且不是你想要的临时清掉再跑unset HTTP_PROXY HTTPS_PROXYreading choices / KeyError: choices。这个报错说明返回的 JSON 里没有choices字段通常是接口返回了错误信息但 LangChain 按成功响应去解析。把原始返回打出来看import requests, os r requests.post( f{os.environ[TAOTOKEN_BASE_URL]}/v1/chat/completions, headers{Authorization: fBearer {os.environ[TAOTOKEN_API_KEY]}}, json{model: gpt-4o-mini, messages: [{role: user, content: hi}]}, ) print(r.status_code, r.text)常见原因是模型 ID 写错或者账号下没有该模型的权限。返回体里一般会有明确的 error message照着改就行。ImportError: cannot import name OpenAI from langchain.llms。这是版本问题。新版 LangChain 把模型类拆到了langchain-openai正确写法是from langchain_openai import ChatOpenAI。如果你在旧项目里看到from langchain.llms import OpenAI要么升级代码要么装对应旧版本但建议直接迁移到新写法。OAuth 相关报错。如果你用的是 Claude Code 或 Codex 这类工具可能会遇到 OAuth 认证失败。这类工具通常需要单独配置认证信息比如 Codex 的auth.json。以 Codex 为例配置文件里需要写全三件套Base URL、API Key、Model ID。Base URL 填https://taotoken.net/apiKey 填你的 TaoToken KeyModel ID 填可用模型。三件套缺一个都会认证失败。Claude Code 的接入类似具体配置步骤可以在接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里对照。如果你用 CC Switch 或 Cline MCP 这类工具同样要确认这三项都填对尤其是 Base URL 别多加/v1。排查顺序建议固定下来先看 Key 是否存在且正确再看 base_url 是否规范然后用 requests 直接打接口看原始返回最后才怀疑提示词或代码逻辑。这样能省下大量来回试错的时间。6. 从提示词到稳定链路把 COSTA 用进日常开发提示词工程不是一次性写完就完事。COSTA 框架、少样本提示、思维链这三样本质上都是让模型的行为更可预测。可预测意味着可维护可维护才能进生产。我自己的习惯是任何要复用的提示词先按 COSTA 拆一遍把能变量化的部分抽出来如果输出格式特殊就补两三个少样本示例如果任务涉及多步推理就在 Steps 里明确要求展示过程必要时加一条自我批判链。这套流程走下来提示词的调试次数会明显下降。LangChain 的表达式写法让这套组合很轻。一个完整的链路可以是COSTA 模板负责结构化输入FewShotPromptTemplate 负责给格式样板模型负责生成StrOutputParser 负责收尾需要的话再接一条 review 链。每一段都可以单独测试出问题也好定位。如果你打算把这套东西用到实际项目里建议先把模型调用通道固定下来。TaoToken 的 API 地址是 https://taotoken.net/api Key 在 API Keys 页管理接入细节看文档。需要验证模型输出效果时可以直接在模型对话页试如果是长期编码或 Agent 场景Coding Plan 会更合适。把通道、模板、示例、验证这四件事分开管理提示词工程才算真正落地。