Hugging Face Transformers 怎样只输出生成结果而不带输入提示词
在 Hugging Face Transformers 中调用 model.generate() 后,如果直接把返回的整行 token 交给 tokenizer 解码,decoder-only 模型通常会把输入提示词一起返回。这不是模型重复生成,而是返回序列包含了“输入 token + 新生成 token”。真正需要做的是先确定输入长度,再只解码新增部分。
官方文档:https://huggingface.co/docs/transformers/
这篇只讨论生成结果的边界,不涉及模型训练。最小原则可以先记住:decoder-only 按有效输入长度切片;encoder-decoder 不要机械套用同一个切片公式;批量输入要按行处理 padding。
问题现场:为什么输出里重复了 prompt
常见代码大致是这样:
from transformers import AutoTokenizer, AutoModelForCausalLM model_name = "distilgpt2" tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForCausalLM.from_pretrained(model_name) prompt = "Explain why caching helps inference." inputs = tokenizer(prompt, return_tensors="pt") # max_new_tokens 只限制新增 token,不代表返回值只含新增 token。 output_ids = model.generate(**inputs, max_new_tokens=32) # 直接解码整行会把 prompt 也带回结果。 full_text = tokenizer.decode(output_ids[0], skip_special_tokens=True) print(full_text)
这里的 output_ids[0] 是完整序列。对 decoder-only 模型,它通常从输入 token 开始,后面才是模型新生成的 token。因此修复重点不是把 prompt 从字符串里做替换,而是在 token 层找到边界。

最小修复:按输入长度截出新生成 token
单条、无 padding 的 decoder-only 输入,可以使用输入序列长度作为切片起点:
# input_ids 的长度就是完整序列中“输入提示词”占用的 token 数。 input_length = inputs["input_ids"].shape[1] new_token_ids = output_ids[0, input_length:] # 只解码切片后的 token,得到新增文本。 new_text = tokenizer.decode(new_token_ids, skip_special_tokens=True) print(new_text)
这段代码的关键不是 decode 的参数,而是先在 token 序列上切片。字符串层面用 replace(prompt, "") 有两个问题:模型可能改变空格或换行,prompt 也可能在生成内容中自然出现,字符串替换无法表达 token 边界。
max_new_tokens 仍然值得保留,它控制最多生成多少个新 token;它不会改变返回序列是否包含输入,也不是“只返回新文本”的开关。
从单条输入扩展到批量输入
批量场景里,不能把第一行的长度套给所有样本。右 padding 与左 padding 还会让输入张量的形状和有效 token 位置不同,所以应先确定 tokenizer 的 padding 策略,再按每一行的有效长度切片。
prompts = [
"Explain cache locality in one paragraph.",
"Explain tokenizer padding in one paragraph.",
]
# padding=True 让 batch 形成矩形;attention_mask 标出每行有效输入位置。
batch = tokenizer(prompts, padding=True, return_tensors="pt")
batch_output = model.generate(**batch, max_new_tokens=32)
texts = []
for row_ids, row_mask in zip(batch_output, batch["attention_mask"]):
# 只统计有效输入 token,避免把 padding 长度当成 prompt 长度。
valid_input_length = int(row_mask.sum().item())
new_ids = row_ids[valid_input_length:]
texts.append(tokenizer.decode(new_ids, skip_special_tokens=True))
for text in texts:
print(text)
上面的写法适合右 padding 的常见批量输入。若模型和 tokenizer 使用左 padding,完整输出序列的前缀布局需要结合模型的 padding 配置确认,不能只凭“总长度减去 padding 数量”猜切片位置。这里的检查点是:每行的有效输入长度、模型返回序列形状、解码后的新文本三者要对应。
decoder-only 和 encoder-decoder 不能混用公式
GPT 类 decoder-only 模型把输入作为生成序列的前缀,因此按输入长度截取通常成立。T5、BART 这类 encoder-decoder 模型的输入先进入 encoder,decoder 生成自己的序列,返回序列一般不等于“encoder 输入 token 加上 decoder 新 token”。
因此写通用封装时,先根据模型架构决定规则:
| 模型形态 | 返回序列的关注点 | 处理建议 |
|---|---|---|
| decoder-only | 输入 token 常位于返回序列前缀 | 按每行有效输入长度切片后 decode |
| encoder-decoder | decoder 输出有自己的序列边界 | 直接解码生成序列,并按特殊 token 规则处理 |
| 批量输入 | padding 会改变张量形状 | 读取 attention_mask,逐行处理 |

什么时候用 return_dict_in_generate
如果只要文本,默认返回的序列就够用;如果还要分数、hidden states、attentions 或 cache,可以打开结构化返回:
# 结构化返回用于同时读取 sequences 和可选的 scores 等字段。
generation = model.generate(
**inputs,
max_new_tokens=32,
return_dict_in_generate=True,
output_scores=True,
)
# sequences 仍然需要按模型类型判断边界,不会自动替你删除 prompt。
sequence_ids = generation.sequences[0]
input_length = inputs["input_ids"].shape[1]
new_text = tokenizer.decode(sequence_ids[input_length:], skip_special_tokens=True)
return_dict_in_generate=True 解决的是“返回哪些结构化字段”,不是“返回值是否只含新文本”。把这两个问题分开,排查会简单很多。
Pipeline 返回值为什么看起来不一样
如果改用 pipeline("text-generation"),pipeline 可能根据参数把完整文本或只包含新增文本的结果整理成字典。这里要以当前 Transformers 版本对应的 pipeline 参数和返回结构为准,不要把 pipeline 的行为直接推断到底层 model.generate()。
from transformers import pipeline
generator = pipeline("text-generation", model="distilgpt2", tokenizer="distilgpt2")
# return_full_text 是 pipeline 层的结果整理选项;它不是 generate 的参数。
result = generator(
"Explain cache locality.",
max_new_tokens=32,
return_full_text=False,
)
print(result[0]["generated_text"])
如果你的项目已经封装了 pipeline,可以优先使用它提供的结果选项;如果项目直接调用模型,则保留 token 级切片逻辑。两层 API 不要混着猜。
一张表排查“仍然带 prompt”
| 现象 | 优先检查 | 处理方向 |
|---|---|---|
| 输出从输入句子开始 | 是否直接 decode 完整 sequences | decoder-only 按有效输入长度切片 |
| 批量结果互相错位 | 是否复用了第一行长度 | 按 attention_mask 逐行计算 |
| 打开结构化返回后仍带输入 | 是否误把 return_dict_in_generate 当裁剪开关 | 仍然处理 sequences 的边界 |
| pipeline 与底层结果不同 | 是否混用了 pipeline 与 generate 的参数 | 分别按对应 API 处理 |
结论
“只输出生成结果”的稳定做法是先辨认模型架构,再在 token 层处理边界。对 decoder-only,单条输入通常从 input_ids.shape[1] 开始切;对批量输入,要结合每行的 attention_mask;对 encoder-decoder,不要把 encoder 输入当成 decoder 输出前缀。最后再调用 tokenizer 解码,得到的文本才不会因为字符串替换而留下边界问题。
相关问题
max_length 和 max_new_tokens 有什么区别? max_new_tokens只计算新增 token,更适合限制生成长度;max_length描述完整序列长度,旧代码里更容易和输入长度混淆。
为什么生成结果有时多一个空格? token 合并和 tokenizer 的空格规则可能让解码后的文本出现自然的前后空白。应先完成 token 切片,再按业务需要处理首尾空白。
能不能用字符串 replace 删除 prompt? 不建议。prompt 可能在答案中再次出现,字符串替换也无法可靠处理 token 化后的空格、换行和特殊 token。
Holo4 这类计算机使用代理怎样划分工具权限
- 上一篇
- Holo4 这类计算机使用代理怎样划分工具权限
- 下一篇
- LoRA 适配器怎样与基础模型分离加载
-
- 科技周边 · 人工智能 | 5分钟前 |
- 模型卡怎样记录训练数据和限制条件
- 400浏览 收藏
-
- 科技周边 · 人工智能 | 11分钟前 |
- Tokenizer 怎样处理超长输入的截断策略
- 500浏览 收藏
-
- 科技周边 · 人工智能 | 11分钟前 | LoRa Transformers PEFT merge_and_unload load_adapter adapter_config.json
- LoRA 适配器怎样与基础模型分离加载
- 102浏览 收藏
-
- 科技周边 · 人工智能 | 17分钟前 | ai agent · 工具调用 · 最小权限 工具权限 Computer Use Holo4 计算机使用代理
- Holo4 这类计算机使用代理怎样划分工具权限
- 212浏览 收藏
-
- 科技周边 · 人工智能 | 18分钟前 | 人工智能 · vLLM KV Cache gpu-memory-utilization max-num-batched-tokens max-num-seqs 批处理显存
- vLLM 怎样限制批处理显存上限
- 265浏览 收藏
-
- 科技周边 · 人工智能 | 18分钟前 |
- RAG 检索结果怎样保留来源片段和页码
- 307浏览 收藏
-
- 科技周边 · 人工智能 | 19分钟前 | 分布式 · 人工智能 · 多进程 多GPU Accelerate CUDA_VISIBLE_DEVICES
- Accelerate 怎样让多个进程分别绑定到不同 GPU
- 444浏览 收藏
-
- 科技周边 · 人工智能 | 23分钟前 | 人工智能 · MLFlow Model Registry 模型别名 champion 模型回滚
- MLflow 模型别名怎样把新版本切换到 champion 并支持回滚
- 296浏览 收藏
-
- 科技周边 · 人工智能 | 24分钟前 |
- PyTorch 怎样用 autocast 控制混合精度范围
- 248浏览 收藏
-
- 科技周边 · 人工智能 | 28分钟前 | AI工程 · 运行日志 Hugging Face Spaces Space日志 构建日志 fetch_space_logs
- Hugging Face Spaces 怎样查看应用运行日志
- 322浏览 收藏
-
- 科技周边 · 人工智能 | 47分钟前 | Hugging Face Transformers 半精度推理 float16 bfloat16
- Hugging Face Transformers 怎样为推理启用半精度
- 212浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 932次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 937次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1046次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1016次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 844次使用
-
- go格式“占位符”输入输出 类似python的input
- 2023-01-19 346浏览
-
- Golang如何调用Python代码详解
- 2023-01-07 235浏览
-
- HTTP 的 response 中的响应体和头部是分开发送的吗?
- 2023-01-28 387浏览
-
- B站等视频网站的弹幕用的是 websocket 还是轮询?
- 2023-02-16 447浏览
-
- Linux 下有什么命令行工具以时序显示 CPU 占用率?
- 2023-01-13 360浏览

