传统 LLM 应用开发痛点:
model = OpenAI(api_key) # 选择模型
prompter = Prompter('ner.jinja') # 选择任务模板
result = Pipeline(prompter, model).fit(text) # 执行流水线
ner.jinja
, qa_gen.jinja
){% for example in examples %}
输入:{{example.text}}
输出:{{example.entities}}
{% endfor %}
输入:{{text_input}}
输出:
domain
控制领域术语(如医疗→金融)模型类型 | 支持情况 | 调用方式示例 |
---|---|---|
OpenAI | ✅ GPT-3.5/4 | OpenAI(api_key) |
PaLM 2 | ✅ 谷歌云 | PaLM(api_key, project_id) |
Hugging Face | ✅ 本地/远程模型 | HuggingFaceModel('bert-base') |
DeepSeek | ✅ 国产模型 | DeepSeek(api_key) |
from promptify import Prompter, OpenAI, Pipeline
text = "93-year-old female with hypertension and chronic atrial fibrillation"
model = OpenAI("sk-xxx")
prompter = Prompter('ner.jinja') # 医疗实体模板
result = Pipeline(prompter, model).fit(
text,
domain="medical",
labels=["Age", "Condition"]
)
输出:
[
{"E": "93-year-old", "T": "Age"},
{"E": "hypertension", "T": "Condition"},
{"E": "chronic atrial fibrillation", "T": "Condition"}
]
技术亮点:
labels
参数)result = Prompter(model).fit(
'multilabel_classification.jinja',
domain='medical',
text_input=text
)
输出:
{
'conditions': ['Hypertension', 'Atrial Fibrillation'],
'age_group': 'Geriatric',
'priority': 'High'
}
创新点:动态生成分类体系(非固定标签),适应开放场景。
prompter.fit('qa_gen.jinja',
domain='literature',
text_input=novel_excerpt)
输出:
[
{"Q": "What did Alice fall into?", "A": "a deep well"},
{"Q": "Was the fall expected?", "A": "No, it was sudden"}
]
教育价值:一键生成测验题目,支持难度控制参数(如 difficulty="high"
)。
指标 | 手工编写 | Promptify |
---|---|---|
开发时间 | 2小时/任务 | 10分钟/任务 |
跨模型适配 | 需重写 prompt | 更换模型参数即可 |
输出稳定性 | 依赖模型版本和随机种子 | 内置解析器保证结构化 |
领域迁移成本 | 重新设计示例 | 修改 domain 参数 |
维护复杂度 | 高(散落多个 prompt 文件) | 低(模板集中管理) |
测试数据:基于医疗文本分类任务,GPT-4 模型,平均 10 次运行结果。
医疗病历自动化
金融风控
教育内容生成
模板优化策略
##JSON [{"entity":..., "type":...}]
domain="legal"
自动加载法律词典性能调优
Pipeline(
prompter,
model,
temperature=0.3, # 降低随机性
max_tokens=500, # 避免过长输出
parse_strategy='retry_3' # 错误时重试3次
)
扩展自定义工具
继承 Prompter
类实现专利分析模板:
class PatentPrompter(Prompter):
def __init__(self):
super().__init__('patent.jinja')
def fit(self, text, country='CN'):
return super().fit(text, jurisdiction=country)
工具 | 优势 | 劣势 |
---|---|---|
LangChain | 生态丰富,支持链式调用 | 配置复杂,学习曲线陡峭 |
LlamaIndex | 检索增强专精 | 实体识别等任务弱于 Promptify |
Promptify | 极简接口,开箱即用 | 高级功能需自行扩展 |
适用人群:
- NLP 工程师:快速验证模型效果
- 数据科学家:专注算法而非 prompt 调试
- 教育/医疗从业者:无代码生成专业内容
- 初学者:低门槛实践 LLM 应用开发
通过标准化接口解决碎片化 prompt 问题,Promptify 正成为 LLM 应用开发的“加速器”。
形态 | 能力范围 | 技术核心 | 局限性 |
---|---|---|---|
聊天机器人 | 问答知识库 | RAG | 被动响应,无行动能力 |
AI 助手 (Assistant) | 单步工具调用 | Function Calling | 无法处理多步复杂任务 |
AI 代理 (Agent) | 自主规划+多步行动 | ReAct 框架 | 需设计行动闭环 |
ReAct 的核心突破:
将 推理(Reason) 和 行动(Act) 循环结合,模仿人类“思考→执行→观察→调整”的决策过程。
system_prompt = """
You run in a loop of Thought, Action, Observation, Answer.
Use Thought to plan steps.
Use Action to call tools. Available tools:
- fetch_real_time_info(query): 实时搜索
- calculate(expression): 数学计算
- get_current_time(): 获取时间
Example: # 关键!提供明确示例
Question: 地球质量的两倍是多少?
Thought: 需先查地球质量
Action: fetch_real_time_info: mass of earth
Observation: 地球质量为5.972×10²⁴kg
Thought: 计算5.972e24 * 2
Action: calculate: 5.972e24 * 2
Observation: 1.1944e25
Answer: 1.1944×10²⁵kg
"""
设计技巧:
- 强制循环格式:要求模型严格按
Thought→Action→Observation→Answer
输出- 工具说明书:明确每个工具的输入/输出格式(如
calculate:
后接数学表达式)- 少样本示例:展示完整决策链条,降低模型幻觉概率
# 工具字典:名称→函数映射
available_actions = {
"fetch_real_time_info": fetch_real_time_info, # 调用Serper API
"calculate": lambda expr: eval(expr), # 数学计算(安全风险需处理)
"get_current_time": datetime.now().strftime # 获取当前时间
}
def fetch_real_time_info(query: str) -> str:
""" 实时搜索(简化版) """
params = {'q': query, 'api_key': SERPER_KEY}
res = requests.get('https://google.serper.dev/search', params).json()
return res['organic'][0]['snippet'] # 返回第一条摘要
工具设计要点:
- 接口统一:所有工具输入为字符串,输出为字符串(Observation需文本化)
- 安全隔离:
eval()
需沙箱处理(实际项目用numexpr
替代)
def AgentExecutor(question: str, max_turns=5):
bot = ChatBot(system_prompt) # 加载系统提示词
next_prompt = question
action_re = re.compile(r'^Action: (\w+):?\s*(.*)$', re.MULTILINE) # 解析Action
for _ in range(max_turns):
response = bot(next_prompt) # 获取模型输出
actions = action_re.findall(response) # 提取Action指令
if actions: # 发现工具调用
tool_name, tool_input = actions[0]
tool_func = available_actions[tool_name]
observation = tool_func(tool_input) # 执行工具
next_prompt = f"Observation: {observation}" # 反馈结果
else: # 无工具调用,结束循环
return response # 直接输出Answer
return "Reached max turns limit!" # 防死循环
核心机制:
- 正则解析:用
r'^Action: (\w+):?\s*(.*)$'
精准抓取工具调用- 循环控制:
max_turns
限制最大步数(避免无限循环)- 观察反馈:将工具结果作为下一轮输入,驱动模型继续思考
Question: 阿里成立多少年了?
Thought: 需要知道阿里巴巴的成立年份和当前年份
Action: fetch_real_time_info: 阿里巴巴成立年份
模型自主拆解问题:成立时长 = 当前年 - 成立年
# 调用 fetch_real_time_info("阿里巴巴成立年份")
Observation: 阿里巴巴集团成立于1999年,创始人是马云。
Observation: 阿里巴巴集团成立于1999年
Thought: 需要获取当前年份
Action: get_current_time:
利用第一次结果触发新动作
# 调用 get_current_time()
Observation: 2025-06-15 14:30:00 # 假设当前年=2025
Thought: 计算 2025 - 1999 = 26
Action: calculate: 2025 - 1999
Observation: 26
Answer: 阿里巴巴成立了26年。
eval()
为安全计算库(如 numexpr
)tool_input
做 SQL 注入/XSS 检测# 并行执行独立任务
def parallel_act(actions):
with ThreadPoolExecutor() as executor:
obs = executor.map(lambda a: tools[a[0]](a[1]), actions)
return list(obs)
复杂任务自动化
可解释性强
Thought
步骤可追溯,适合审计敏感操作(如金融决策)灵活扩展
available_actions
,无需修改核心逻辑适用场景:
- 旅行规划(查景点→算距离→订酒店)
- 学术研究(搜论文→下PDF→写摘要)
- 运维诊断(查日志→分析错误→执行修复)
ReAct 的本质是将 AI 从“问答机”升级为“执行者”,通过:
与 LangChain/LlamaIndex 等框架相比,手写 ReAct 的优势在于:
- 零依赖:仅需标准库 + OpenAI API
- 完全可控:深度定制工具和决策逻辑
- 学习价值:透彻理解 Agent 运行机制