


















本文基于 Ollama + Qwen2:0.5b 本地模型 ,完成了三个经典的 NLP 任务:
(另附了基于langchain_openai的ChatOpenAI配合deepseek线上大模型接口处理Prompt提示词工程)
| 任务 | 目标 | 核心技术 |
|---|---|---|
| 文本分类 | 判断句子属于哪个类别 | Few-shot + System Prompt |
| 信息抽取 | 从文本中提取结构化实体 | Few-shot + Schema 约束 + JSON 解析 |
| 语义匹配 | 判断两个句子语义是否相似 | Few-shot + 二元分类 Prompt |
system_prompt = "现在你是一个文本分类器,你需要按照要求将我给你的句子分类到:{class_list}类别中。"
user_prompt = f"“{sentence}”是 {class_list} 里的什么类别?直接输出类别结果,不要给出解释等其他内容。"
python
class_examples = {
"新闻报道": "今日,股市经历了一轮震荡...",
"财务报告": "本公司年度财务报告显示...",
"公司公告": "本公司高兴地宣布成功完成...",
"分析师报告": "最新的行业分析报告指出...",
}
python
| 技巧 | 作用 |
|---|---|
| System Prompt 明确角色 | 让模型知道自己是“分类器” |
| 限制输出格式 | 直接输出类别结果,不要给出解释 |
| Few-shot 覆盖所有类别 | 每个类别给一个示例,避免类别偏见 |
输入:
央行发布公告宣布降低利率,以刺激经济增长。
输出:
新闻报道
代码
"""
利用 LLM 进行文本分类任务。
"""
from rich import print
from rich.console import Console
import ollama
from langchain_openai import ChatOpenAI
from config import Config
import re
conf = Config()
llm = ChatOpenAI(
model=conf.model_name,
api_key=conf.api_key,
base_url=conf.base_url,
temperature=1.0,
max_tokens=1024,
max_retries=3,
timeout=60,
)
class_examples = {
"新闻报道": "今日,股市经历了一轮震荡,受到宏观经济数据和全球贸易紧张局势的影响。投资者密切关注美联储可能的政策调整,以适应市场的不确定性。",
"财务报告": "本公司年度财务报告显示,去年公司实现了稳步增长的盈利,同时资产负债表呈现强劲的状况。经济环境的稳定和管理层的有效战略执行为公司的健康发展奠定了基础。",
"公司公告": "本公司高兴地宣布成功完成最新一轮并购交易,收购了一家在人工智能领域领先的公司。这一战略举措将有助于扩大我们的业务领域,提高市场竞争力",
"分析师报告": "最新的行业分析报告指出,科技公司的创新将成为未来增长的主要推动力。云计算、人工智能和数字化转型被认为是引领行业发展的关键因素,投资者应关注这些趋势",
}
def init_prompts():
"""
初始化前置prompt,便于模型做 incontext learning。
"""
class_list = list(class_examples.keys())
pre_history = [
{
"role": "system",
"content": f"现在你是一个文本分类器,你需要按照要求将我给你的句子分类到:{class_list}类别中。",
}
]
for _type, exmpale in class_examples.items():
pre_history.append(
{"role": "user", "content": f"“{exmpale}”是 {class_list} 里的什么类别?"}
)
pre_history.append({"role": "assistant", "content": _type})
return {"class_list": class_list, "pre_history": pre_history}
def inference(sentences: list, custom_settings: dict):
"""
推理函数。
Args:
sentences (List[str]): 待推理的句子。
custom_settings (dict): 初始设定,包含人为给定的 few-shot example。
"""
for sentence in sentences:
with console.status("[bold bright_green] Model Inference..."):
sentence_with_prompt = f"“{sentence}”是 {custom_settings['class_list']} 里的什么类别?直接输出类别结果, 不要给出解释等其他内容。"
response = ollama.chat(
model="qwen2:0.5b",
messages=[
*custom_settings["pre_history"],
{"role": "user", "content": sentence_with_prompt},
],
)
response = response.message.content
print(f'response--->{response}')
if __name__ == "__main__":
console = Console()
sentences = [
"今日,央行发布公告宣布降低利率,以刺激经济增长。这一降息举措将影响贷款利率,并在未来几个季度内对金融市场产生影响。",
"本公司宣布成功收购一家在创新科技领域领先的公司,这一战略性收购将有助于公司拓展技术能力和加速产品研发。",
"公司资产负债表显示,公司偿债能力强劲,现金流充足,为未来投资和扩张提供了坚实的财务基础。",
"最新的分析报告指出,可再生能源行业预计将在未来几年经历持续增长,投资者应该关注这一领域的投资机会",
"PDD公司2025年财报显示, 公司预计亏损7000w到1个亿之间"
]
custom_settings = init_prompts()
print('custom_settings--->', custom_settings)
inference(sentences, custom_settings)
python
schema = {
"金融": ["日期", "股票名称", "开盘价", "收盘价", "成交量"],
"新闻": ["日期", "新闻标题", "新闻内容"],
}
python
IE_PATTERN = "{}\n\n提取上述句子中{}的实体,并按照JSON格式输出,上述句子中不存在的信息用['原文中未提及']来表示,多个值之间用','分隔。"
python
ie_examples = {
"金融": [{
"content": "2023-01-10,股票古哥-D美股开盘价100美元...",
"answers": {
"日期": ["2023-01-10"],
"股票名称": ["古哥-D[EOOE]美股"],
"开盘价": ["100美元"],
"收盘价": ["102美元"],
"成交量": ["520000"],
},
}],
}
python
def clean_response(response: str):
if "```json" in response:
res = re.findall(r"```json(.*?)```", response, re.DOTALL)
if len(res) and res[0]:
response = res[0]
response = response.replace("、", ",")
try:
return json.loads(response)
except:
return response
python
| 技巧 | 作用 |
|---|---|
| Schema 约束 | 明确要抽取哪些字段 |
| 兜底处理 | ['原文中未提及'] 处理缺失信息 |
| 正则提取 | 处理模型输出的 Markdown 包裹 |
| 标点替换 | 、 → , 避免 JSON 解析失败 |
输入:
2023-02-15,股票佰笃[BD]美股开盘价10美元,收盘价13美元,成交量460,000
输出:
{"日期": ["2023-02-15"], "股票名称": ["佰笃[BD]美股"], "开盘价": ["10美元"], "收盘价": ["13美元"], "成交量": ["460,000"]}
python
代码
import json
import ollama
import re
from rich import print
schema = {
"金融": ["日期", "股票名称", "开盘价", "收盘价", "成交量"],
"新闻": ["日期", "新闻标题", "新闻内容"],
}
IE_PATTERN = "{}\n\n提取上述句子中{}的实体,并按照JSON格式输出,上述句子中不存在的信息用['原文中未提及']来表示,多个值之间用','分隔。"
ie_examples = {
"金融": [
{
"content": "2023-01-10,股市震荡。股票古哥-D[EOOE]美股今日开盘价100美元,一度飙升至105美元,随后回落至98美元,最终以102美元收盘,成交量达到520000。",
"answers": {
"日期": ["2023-01-10"],
"股票名称": ["古哥-D[EOOE]美股"],
"开盘价": ["100美元"],
"收盘价": ["102美元"],
"成交量": ["520000"],
},
}
],
"新闻": [
{
"content": "2025-01-10,央行发布公告宣布降低利率,以刺激经济增长。这一降息举措将影响贷款利率,并在未来几个季度内对金融市场产生影响。",
"answers": {
"日期": ["2025-01-10"],
"新闻标题": ["央行发布公告宣布降低利率"],
"新闻内容": [
"这一降息举措将影响贷款利率,并在未来几个季度内对金融市场产生影响。"
],
},
}
],
}
def init_prompts():
"""
初始化前置prompt,便于模型做 incontext learning。
"""
ie_pre_history = [
{"role": "system", "content": "你是一个信息抽取助手。"},
]
for _type, example_list in ie_examples.items():
for example in example_list:
sentence = example["content"]
properties_str = ", ".join(schema[_type])
schema_str_list = f"“{_type}”({properties_str})"
sentence_with_prompt = IE_PATTERN.format(sentence, schema_str_list)
ie_pre_history.append(
{"role": "user", "content": f"{sentence_with_prompt}"}
)
ie_pre_history.append(
{
"role": "assistant",
"content": f"{json.dumps(example['answers'], ensure_ascii=False)}",
}
)
return {"ie_pre_history": ie_pre_history}
def clean_response(response: str):
"""
后处理模型输出
Args:
response (str): _description_
"""
if "```json" in response:
res = re.findall(r"```json(.*?)```", response, re.DOTALL)
if len(res) and res[0]:
response = res[0]
response = response.replace("、", ",")
try:
return json.loads(response)
except:
return response
def inference(sentences: list[dict[str, str]],
custom_settings: dict):
"""
推理函数
Args:
sentences (List[str]): 待抽取的句子。
custom_settings (dict): 初始设定,包含人为给定的 one-shot/few-shot example。
"""
for item in sentences:
sentence = item["text"]
cls_res = item["cls"]
if cls_res not in schema:
print(
f"The type model inferenced {cls_res} which is not in schema dict, exited."
)
continue
properties_str = ", ".join(schema[cls_res])
schema_str_list = f"“{cls_res}”({properties_str})"
sentence_with_ie_prompt = IE_PATTERN.format(sentence, schema_str_list)
messages = [
*custom_settings["ie_pre_history"],
{"role": "user", "content": sentence_with_ie_prompt},
]
response = ollama.chat(model="qwen2:0.5b", messages=messages)
res_content = response["message"]["content"]
print(f'res_content-->{res_content}')
if __name__ == "__main__":
sentences = [
{
"text": "2023-02-15,寓意吉祥的节日,股票佰笃[BD]美股开盘价10美元,虽然经历了波动,但最终以13美元收盘,成交量微幅增加至460,000,投资者情绪较为平稳。",
"cls": "金融",
},
{
"text": "2023-04-05,市场迎来轻松氛围,股票盘古(0021)开盘价23元,尽管经历了波动,但最终以26美元收盘,成交量缩小至310,000,投资者保持观望态度。",
"cls": "金融",
},
{
"text": "2025-01-10,央行发布公告宣布降低利率,以刺激经济增长。这一降息举措将影响贷款利率,并在未来几个季度内对金融市场产生影响。",
"cls": "新闻",
},
]
custom_settings = init_prompts()
inference(sentences, custom_settings)
python
system_prompt = "现在你需要帮助我完成文本匹配任务,当我给你两个句子时,你需要回答我这两句话语义是否相似。只需要回答是否相似,不要做多余的回答。"
user_prompt = f'句子一: {sentence1}\n句子二: {sentence2}\n上面两句话是相似的语义吗?'
python
examples = {
"是": [
('公司ABC发布了季度财报,显示盈利增长。', '财报披露,公司ABC利润上升。'),
],
"不是": [
('黄金价格下跌,投资者抛售。', '外汇市场交易额创下新高。'),
('央行降息,刺激经济增长。', '新能源技术的创新。')
]
}
python
| 技巧 | 作用 |
|---|---|
| 正负样本均衡 | 同时提供“是”和“不是”的示例 |
| 限制输出 | 只回答是否相似,不要做多余的回答 |
| 结构化输入 | 句子一: ...\n句子二: ... 清晰分隔 |
输入:
句子一: 股票市场今日大涨,投资者乐观。
句子二: 持续上涨的市场让投资者感到满意。
输出:
是
代码
"""
利用 LLM 进行文本匹配任务。
"""
from rich import print
from rich.console import Console
import ollama
examples = {
'是': [
('公司ABC发布了季度财报,显示盈利增长。', '财报披露,公司ABC利润上升。'),
],
'不是': [
('黄金价格下跌,投资者抛售。', '外汇市场交易额创下新高。'),
('央行降息,刺激经济增长。', '新能源技术的创新。')
]
}
def init_prompts():
"""
初始化前置prompt,便于模型做 incontext learning。
"""
pre_history = [{"role": "system",
"content": "现在你需要帮助我完成文本匹配任务,当我给你两个句子时,你需要回答我这两句话语义是否相似。只需要回答是否相似,不要做多余的回答。"}, ]
for key, sentence_pairs in examples.items():
for sentence_pair in sentence_pairs:
sentence1, sentence2 = sentence_pair
pre_history.append(
{"role": "user", "content": f'句子一: {sentence1}\n句子二: {sentence2}\n上面两句话是相似的语义吗?'})
pre_history.append({"role": "assistant", "content": key})
return {'pre_history': pre_history}
def inference(
sentence_pairs: list,
custom_settings: dict
):
"""
推理函数
Args:
sentence_pairs (List[str]): 待推理的句子对。
custom_settings (dict): 初始设定,包含人为给定的 few-shot example。
"""
for sentence_pair in sentence_pairs:
with console.status("[bold bright_green] Model Inference..."):
sentence1, sentence2 = sentence_pair
sentence_with_prompt = f'句子一: {sentence1}\n句子二: {sentence2}\n上面两句话是相似的语义吗?'
response = ollama.chat(model="qwen2:0.5b",
messages=[*custom_settings["pre_history"],
{"role": 'user', "content": sentence_with_prompt}])
response = response["message"]["content"]
print(f'>>> [bold bright_red]sentence_pair:{sentence_pair}')
print(f'>>> [bold bright_green]inference answer:{response}')
if __name__ == '__main__':
console = Console()
sentence_pairs = [
('股票市场今日大涨,投资者乐观。', '持续上涨的市场让投资者感到满意。'),
('油价大幅下跌,能源公司面临挑战。', '未来智能城市的建设趋势愈发明显。'),
('利率上升,影响房地产市场。', '高利率对房地产有一定冲击。'),
]
custom_settings = init_prompts()
print(f'custom_settings-->{custom_settings}')
inference(
sentence_pairs,
custom_settings
)
python
| 经验 | 说明 |
|---|---|
| System Prompt 定角色 | 让模型明确自己的任务身份 |
| Few-shot 是核心 | 1-3 个示例比长篇指令更有效 |
| 限制输出格式 | 减少模型“废话”,便于解析 |
| 后处理容错 | 正则提取 + 标点替换 + try-catch |
| 小模型能力有限 | 0.5B 能跑,但 1.5B/7B 更稳定 |
Prompt 不是写作文,而是写“约束”。Few-shot 是给模型看标准答案,后处理是给模型兜底。三者配合,小模型也能做出稳定的效果。
希望这篇总结对你有帮助!你的代码结构清晰、容错完善,已经是一个很成熟的 Prompt 工程实践了。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。