如何在保证模型性能条件下优化Prompt降低使用成本及响应延迟?

发布于 2024-7-18 11:16
浏览
0收藏

随着大模型应用的不断发展,提示工程技术也在快速迭代更新,越来越多的任务通过精妙的Prompt或者agentic workflow等方式解锁。但随之而来,大量详细的、巨大的prompt却会带来高的成本以及缓慢的响应。这也使得高成本和高延迟成为了大模型应用落地生产的主要障碍。随着当下LLM应用已经不再是单次的对话,而是复杂的组合AI系统(伯克利:即使模型再强大,复合AI系统( Compound AI Systems)都将会是一种领先的应用模式)都将会是一种领先的应用模式),提示规模爆炸性增长,这样的问题变得更加尖锐。

就以最近很火的GraphRAG为例,处理64页的文稿,就花了7美元,使用成本相当的高,这在研究和演示场景这样的情况并不突出,但是真到需要处理大规模数据,服务大量用户的实际生产场景中,这样的情况是无法接受的。

Prompt会很大的主要原因是它包含了很多内容,比如任务描述,场景约束,工具描述,多轮的交互记忆等等,在每一次和大模型交互时,都需要将其提供给大模型,再加上系统框架的必要的再封装,会导致实际提交给LLM比用户提交的更大。

成本和延迟与prompt大小及调用次数密切相关,那如何才能在不降低精度的情况下,减少Prompt大小以及降低LLM调用次数呢?下面是Jan Majewski在开发它的应用(房产搜索助理)时总结prompt大小与成本延迟的量化关系以及五个优化的思路。

1)量化关系

  • 成本

如何在保证模型性能条件下优化Prompt降低使用成本及响应延迟?-AI.x社区

  • 延迟

如何在保证模型性能条件下优化Prompt降低使用成本及响应延迟?-AI.x社区

对于成本,输出token是输入token的 3 倍,但同时对于复杂的任务来讲,提示(输入token)会比输出要长得多,减少输入token带来的收益依然可观。 对于延迟,主要是由输出token决定的,其处理时间是输入token的 200 倍。 

2)优化手段:

1. 将大的prompt拆分成多层次调用 

在撰写prompt时不必将所有内容都写到一个大的prompt中,比如把规划和执行分开,Jan Majewski指出他的应用性能提升的关键之一在于将Prompt拆分成两个部分:决策Agent,它对下一步可以采取的措施有总体指导,以及如何处理来自模型的输出;执行Agent/Chats,它对具体步骤(如报价搜索、数据比较或房地产知识)有详细说明。

如何在保证模型性能条件下优化Prompt降低使用成本及响应延迟?-AI.x社区

这种架构允许首先选择需要使用的特定任务提示,而无需在每次调用时发送大量token执行指令,从而将token的平均使用量减少了 60% 以上。

2. 关注发送给LLM的最终Prompt

如前面提到,LLM 收到的最终Prompt可能与最初用户撰写的Prompt相差很大。 框架在使用工具、内存、上下文和 Agent 的内部推理时,都会自动扩展Prompt,这也会使prompt增加数千个token。另外,在LLM应用执行过程中,涉及到了很多的环节,可能进行了几十次调用,如何监控和排错也就十分重要。对于开发者来讲,使用 LangSmith 进行深入分析是一个比较好的选择,近日dify也集成了这样的可观测工具。

3.可以通过编码,减少LLM调用量。

有时候一些任务使用常规的代码实现更为高效经济,而无需都撰写Prompt操纵LLM来实现。比如,使用 Python 函数处理 LLM 调用的上游/下游一些琐碎的任务。当前,大部分的LLM应用开发的框架都支持将传统函数与LLM调用混合在一起使用,比如Promptflow,langchain等。比如下面的一段代码,可以直接使用python lib完成语言检测,这样就可以明确语言类型明确传递给LLM,无需在Prompt中去限定有关语言的描述,从而减少在 LLM 的处理复杂度以及Prompt大小。

from langdetect import detect


prompt = """
Summarize the following message in  {language}:
Message: {input} 
"""


prompt = ChatPromptTemplate.from_template(prompt)


def detect_language(input_message):
    input_message["language"] = detect(input_message["input"])
    return input_message


detect_language_step= RunnablePassthrough.assign(input_message=detect_language)


chain_summarize_in_message_language = (
    detect_language_step
    | RunnablePassthrough.assign(
            language=lambda x: x["input_message"]["language"]
            ) 
    | prompt 
    | llm )

4. 慎用Agent,它们会导致token消耗大大增加

如何在保证模型性能条件下优化Prompt降低使用成本及响应延迟?-AI.x社区

能够使用工具的Agent能够极大的扩展LLM的能力范围,但它们同时也非常消耗token。下面的图表显示了 Agent的一般处理流程,可以看到Agent 通常需要调用 LLM 至少两次:首先计划如何使用工具,然后解析其输出以提供最终答案。对于一些较为简单的任务,Agent 的方法可能有些重,而使用 Completion 的简单指令提示则能以两倍的速度提供类似的结果。

5. 使用 LLM 进行推理,但使用 SQL 或 Python 进行统计计算

虽然,现在的LLM能力相较于之前已经有了很大提高,比如通过精心构造Prompt完成数据分析(新加坡提示工程大赛冠军最强Prompt工程技巧分享,仅用大模型也能做数据分析),但对于数据计算来讲,仍然不如Python和SQL来的高效准确经济。

建议做法是使用 LLM 理解问题和数据,然后将其转换为更合适的分析语言(如SQL或Python)进行数据处理汇总,最后再将结果提供给 LLM 进行分析洞察。

总结

Jan Majewski给出了一些常见的思路来减少Prompt的大小以及减少LLM的调用,除此之外,还有很多prompt压缩、LLM Cache等技术降低应用成本及减少应用延迟。未来笔者还将介绍这一领域的进展,欢迎关注。

参考:

​https://towardsdatascience.com/streamline-your-prompts-to-decrease-llm-costs-and-latency-29591dd0e9e4​

​https://www.youtube.com/watch?v=EuzDssiyLmo​

​https://blog.baeke.info/2024/07/07/trying-out-graph-rag/​

本文转载自​AI工程化​,作者: ully 

已于2024-7-18 11:20:52修改
收藏
回复
举报
回复
相关推荐